From c5c8100d02290a366e1d1c8114a5c393ed0e207d Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 2 Dec 2025 11:30:08 +0100 Subject: [PATCH] Emoji: Update emoji categories with featured emoji (#37084) --- app/javascript/mastodon/api_types/custom_emoji.ts | 3 ++- app/javascript/mastodon/models/custom_emoji.ts | 1 + app/models/custom_emoji.rb | 4 ++++ app/models/custom_emoji_category.rb | 10 ++++++---- app/serializers/rest/custom_emoji_serializer.rb | 5 +++++ ...10_add_featured_emoji_to_custom_emoji_categories.rb | 8 ++++++++ ...te_add_featured_emoji_to_custom_emoji_categories.rb | 7 +++++++ db/schema.rb | 4 +++- 8 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20251201154910_add_featured_emoji_to_custom_emoji_categories.rb create mode 100644 db/migrate/20251201155054_validate_add_featured_emoji_to_custom_emoji_categories.rb diff --git a/app/javascript/mastodon/api_types/custom_emoji.ts b/app/javascript/mastodon/api_types/custom_emoji.ts index 05144d6f68d..099ef0b88b8 100644 --- a/app/javascript/mastodon/api_types/custom_emoji.ts +++ b/app/javascript/mastodon/api_types/custom_emoji.ts @@ -1,8 +1,9 @@ -// See app/serializers/rest/account_serializer.rb +// See app/serializers/rest/custom_emoji_serializer.rb export interface ApiCustomEmojiJSON { shortcode: string; static_url: string; url: string; category?: string; + featured?: boolean; visible_in_picker: boolean; } diff --git a/app/javascript/mastodon/models/custom_emoji.ts b/app/javascript/mastodon/models/custom_emoji.ts index 5297dcd4704..19ca951a5ca 100644 --- a/app/javascript/mastodon/models/custom_emoji.ts +++ b/app/javascript/mastodon/models/custom_emoji.ts @@ -11,6 +11,7 @@ export const CustomEmojiFactory = ImmutableRecord({ static_url: '', url: '', category: '', + featured: false, visible_in_picker: false, }); diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 25ba3d921b4..65a2faa9fd5 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -66,6 +66,10 @@ class CustomEmoji < ApplicationRecord :emoji end + def featured? + category&.featured_emoji_id == id + end + def copy! copy = self.class.find_or_initialize_by(domain: nil, shortcode: shortcode) copy.image = image diff --git a/app/models/custom_emoji_category.rb b/app/models/custom_emoji_category.rb index dfcc156080c..cc7db33ece6 100644 --- a/app/models/custom_emoji_category.rb +++ b/app/models/custom_emoji_category.rb @@ -4,14 +4,16 @@ # # Table name: custom_emoji_categories # -# id :bigint(8) not null, primary key -# name :string -# created_at :datetime not null -# updated_at :datetime not null +# id :bigint(8) not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# featured_emoji_id :bigint(8) # class CustomEmojiCategory < ApplicationRecord has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category, dependent: nil + belongs_to :featured_emoji, class_name: 'CustomEmoji', optional: true, inverse_of: :category validates :name, presence: true, uniqueness: true diff --git a/app/serializers/rest/custom_emoji_serializer.rb b/app/serializers/rest/custom_emoji_serializer.rb index 33da69da530..a173aeae19a 100644 --- a/app/serializers/rest/custom_emoji_serializer.rb +++ b/app/serializers/rest/custom_emoji_serializer.rb @@ -8,6 +8,7 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer attributes :shortcode, :url, :static_url, :visible_in_picker attribute :category, if: :category_loaded? + attribute :featured, if: :category_loaded? def url full_asset_url(object.image.url) @@ -21,6 +22,10 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer object.category.name end + def featured + object.featured? + end + def category_loaded? object.association(:category).loaded? && object.category.present? end diff --git a/db/migrate/20251201154910_add_featured_emoji_to_custom_emoji_categories.rb b/db/migrate/20251201154910_add_featured_emoji_to_custom_emoji_categories.rb new file mode 100644 index 00000000000..149b0b994ec --- /dev/null +++ b/db/migrate/20251201154910_add_featured_emoji_to_custom_emoji_categories.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class AddFeaturedEmojiToCustomEmojiCategories < ActiveRecord::Migration[8.0] + def change + add_column :custom_emoji_categories, :featured_emoji_id, :bigint, null: true + add_foreign_key :custom_emoji_categories, :custom_emojis, column: :featured_emoji_id, on_delete: :nullify, validate: false + end +end diff --git a/db/migrate/20251201155054_validate_add_featured_emoji_to_custom_emoji_categories.rb b/db/migrate/20251201155054_validate_add_featured_emoji_to_custom_emoji_categories.rb new file mode 100644 index 00000000000..3ff5ce7b5ef --- /dev/null +++ b/db/migrate/20251201155054_validate_add_featured_emoji_to_custom_emoji_categories.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ValidateAddFeaturedEmojiToCustomEmojiCategories < ActiveRecord::Migration[8.0] + def change + validate_foreign_key :custom_emoji_categories, :custom_emojis + end +end diff --git a/db/schema.rb b/db/schema.rb index e4e7db3868c..669a6dbf2e6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_11_19_093332) do +ActiveRecord::Schema[8.0].define(version: 2025_12_01_155054) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -404,6 +404,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_19_093332) do t.string "name" t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false + t.bigint "featured_emoji_id" t.index ["name"], name: "index_custom_emoji_categories_on_name", unique: true end @@ -1426,6 +1427,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_19_093332) do add_foreign_key "collections", "tags" add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade + add_foreign_key "custom_emoji_categories", "custom_emojis", column: "featured_emoji_id", on_delete: :nullify add_foreign_key "custom_filter_keywords", "custom_filters", on_delete: :cascade add_foreign_key "custom_filter_statuses", "custom_filters", on_delete: :cascade add_foreign_key "custom_filter_statuses", "statuses", on_delete: :cascade