From e64e6a03dd1e0978fee48f0596dcfbc7fd29958f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 28 Jun 2019 15:54:10 +0200 Subject: Add categories for custom emojis (#11196) Fix #7940 --- app/controllers/api/v1/custom_emojis_controller.rb | 2 +- .../compose/components/emoji_picker_dropdown.js | 30 ++++++++++++---------- app/javascript/mastodon/features/emoji/emoji.js | 3 +++ app/models/custom_emoji.rb | 2 ++ app/models/custom_emoji_category.rb | 15 +++++++++++ app/serializers/rest/custom_emoji_serializer.rb | 10 ++++++++ 6 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 app/models/custom_emoji_category.rb (limited to 'app') diff --git a/app/controllers/api/v1/custom_emojis_controller.rb b/app/controllers/api/v1/custom_emojis_controller.rb index 1bb19a09d..b6877fb3c 100644 --- a/app/controllers/api/v1/custom_emojis_controller.rb +++ b/app/controllers/api/v1/custom_emojis_controller.rb @@ -7,7 +7,7 @@ class Api::V1::CustomEmojisController < Api::BaseController def index render_cached_json('api:v1:custom_emojis', expires_in: 1.minute) do - ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer) + ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false).includes(:category), each_serializer: REST::CustomEmojiSerializer) end end end diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index c1429c756..e57c3c20c 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -6,7 +6,7 @@ import Overlay from 'react-overlays/lib/Overlay'; import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import detectPassiveEvents from 'detect-passive-events'; -import { buildCustomEmojis } from '../../emoji/emoji'; +import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji'; const messages = defineMessages({ emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, @@ -31,19 +31,6 @@ let EmojiPicker, Emoji; // load asynchronously const backgroundImageFn = () => `${assetHost}/emoji/sheet_10.png`; const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false; -const categoriesSort = [ - 'recent', - 'custom', - 'people', - 'nature', - 'foods', - 'activity', - 'places', - 'objects', - 'symbols', - 'flags', -]; - class ModifierPickerMenu extends React.PureComponent { static propTypes = { @@ -241,8 +228,23 @@ class EmojiPickerMenu extends React.PureComponent { } const title = intl.formatMessage(messages.emoji); + const { modifierOpen } = this.state; + const categoriesSort = [ + 'recent', + 'people', + 'nature', + 'foods', + 'activity', + 'places', + 'objects', + 'symbols', + 'flags', + ]; + + categoriesSort.splice(1, 0, ...Array.from(categoriesFromEmojis(custom_emojis)).sort()); + return (
{ keywords: [name], imageUrl: url, custom: true, + customCategory: emoji.get('category'), }); }); return emojis; }; + +export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set()); diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index e73cd9bd2..514cf4845 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -16,6 +16,7 @@ # uri :string # image_remote_url :string # visible_in_picker :boolean default(TRUE), not null +# category_id :bigint(8) # class CustomEmoji < ApplicationRecord @@ -27,6 +28,7 @@ class CustomEmoji < ApplicationRecord :(#{SHORTCODE_RE_FRAGMENT}): (?=[^[:alnum:]:]|$)/x + belongs_to :category, class_name: 'CustomEmojiCategory', optional: true has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce -strip' } } diff --git a/app/models/custom_emoji_category.rb b/app/models/custom_emoji_category.rb new file mode 100644 index 000000000..7d8c0ee2d --- /dev/null +++ b/app/models/custom_emoji_category.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: custom_emoji_categories +# +# id :bigint(8) not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# + +class CustomEmojiCategory < ApplicationRecord + has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category +end diff --git a/app/serializers/rest/custom_emoji_serializer.rb b/app/serializers/rest/custom_emoji_serializer.rb index 65686a866..aff58e4d9 100644 --- a/app/serializers/rest/custom_emoji_serializer.rb +++ b/app/serializers/rest/custom_emoji_serializer.rb @@ -5,6 +5,8 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer attributes :shortcode, :url, :static_url, :visible_in_picker + attribute :category, if: :category_loaded? + def url full_asset_url(object.image.url) end @@ -12,4 +14,12 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer def static_url full_asset_url(object.image.url(:static)) end + + def category + object.category.name + end + + def category_loaded? + object.association(:category).loaded? && object.category.present? + end end -- cgit