From aa61998a300723bcb188f494846a88db183b4251 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 15:22:12 +0900 Subject: [PATCH 01/17] Move notification navi menu --- .../mastodon/features/ui/components/navigation_panel.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index 81f594ca6e..f97d785c1f 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -61,7 +61,10 @@ class NavigationPanel extends Component { {signedIn && ( - + <> + } text={intl.formatMessage(messages.notifications)} /> + + )} {!signedIn && explorer} @@ -82,7 +85,6 @@ class NavigationPanel extends Component { {signedIn && ( <> - } text={intl.formatMessage(messages.notifications)} /> From cf72dae0d09a9fe5cc3d86e93a3be9203587a2be Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 15:29:50 +0900 Subject: [PATCH 02/17] Add login visibility to fedibird_capabilities --- app/serializers/rest/instance_serializer.rb | 1 + app/serializers/rest/v1/instance_serializer.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 833fc93d07..3f90844c58 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -115,6 +115,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer :searchability, :kmyblue_markdown, :kmyblue_reaction_deck, + :kmyblue_visibility_login, ] capabilities << :profile_search unless Chewy.enabled? diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index b5a1d3abe6..ee2d2814d1 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -124,6 +124,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer :searchability, :kmyblue_markdown, :kmyblue_reaction_deck, + :kmyblue_visibility_login, ] capabilities << :profile_search unless Chewy.enabled? From 3f9a75c72f066c59f0705d343183dbd576b978d2 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 15:46:11 +0900 Subject: [PATCH 03/17] Fix reaction_deck sort --- app/controllers/api/v1/reaction_deck_controller.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index d3e06f3b09..0d790621e8 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -16,21 +16,24 @@ class Api::V1::ReactionDeckController < Api::BaseController end def create + deck = @deck + (deck_params['emojis'] || []).each do |data| raise ArgumentError if data['id'].to_i >= 16 || data['id'].to_i.negative? - exists = @deck.find { |dd| dd['id'] == data['id'] } + exists = deck.find { |dd| dd['id'] == data['id'] } if exists exists['emoji'] = data['emoji'].delete(':') else - @deck << { id: data['id'], emoji: data['emoji'].delete(':') } + deck << { 'id' => data['id'], 'emoji' => data['emoji'].delete(':') } end end - @deck = @deck.sort_by { |a| a['id'].to_i } - current_user.settings['reaction_deck'] = @deck.to_json + + deck = deck.sort_by { |a| a['id'].to_i } + current_user.settings['reaction_deck'] = deck.to_json current_user.save! - render json: @deck + render json: deck end private From f382b16fdeeac39601c11e086a2e3cb3a3c48fde Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 17:26:50 +0900 Subject: [PATCH 04/17] Fix reaction_deck api structure --- .../api/v1/reaction_deck_controller.rb | 56 +++++++++++++++++-- .../emoji_picker_dropdown_container.js | 4 +- .../components/reaction_emoji.jsx | 2 +- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index 0d790621e8..12716d3f99 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Api::V1::ReactionDeckController < Api::BaseController + include RoutingHelper + before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index] before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create] @@ -12,7 +14,7 @@ class Api::V1::ReactionDeckController < Api::BaseController end def index - render json: @deck + render json: remove_metas(@deck) end def create @@ -21,11 +23,29 @@ class Api::V1::ReactionDeckController < Api::BaseController (deck_params['emojis'] || []).each do |data| raise ArgumentError if data['id'].to_i >= 16 || data['id'].to_i.negative? + shortcode = data['emoji'].delete(':') + custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: nil) + custom_emoji_id = custom_emoji&.id + emoji_data = if custom_emoji + { + 'shortcode' => custom_emoji.shortcode, + 'url' => full_asset_url(custom_emoji.image.url), + 'static_url' => full_asset_url(custom_emoji.image.url(:static)), + 'width' => custom_emoji.image_width, + 'height' => custom_emoji.image_height, + } + else + { + 'shortcode' => shortcode, + } + end + exists = deck.find { |dd| dd['id'] == data['id'] } if exists - exists['emoji'] = data['emoji'].delete(':') + exists['custom_emoji_id'] = custom_emoji_id + exists['emoji'] = emoji_data else - deck << { 'id' => data['id'], 'emoji' => data['emoji'].delete(':') } + deck << { 'id' => data['id'], 'custom_emoji_id' => custom_emoji_id, 'emoji' => emoji_data } end end @@ -33,13 +53,39 @@ class Api::V1::ReactionDeckController < Api::BaseController current_user.settings['reaction_deck'] = deck.to_json current_user.save! - render json: deck + render json: remove_metas(deck) end private def set_deck - @deck = current_user.setting_reaction_deck ? JSON.parse(current_user.setting_reaction_deck) : [] + deck = current_user.setting_reaction_deck ? JSON.parse(current_user.setting_reaction_deck) : [] + @deck = remove_unused_custom_emojis(deck) + end + + def remove_unused_custom_emojis(deck) + custom_ids = [] + deck.each do |item| + custom_ids << item['custom_emoji_id'].to_i unless item['custom_emoji_id'].nil? + end + custom_emojis = CustomEmoji.where(id: custom_ids) + + deck.each do |item| + next if item['custom_emoji_id'].nil? + + custom_emoji = custom_emojis.find { |em| em.id == item['custom_emoji_id'].to_i } + remove = custom_emoji.nil? || custom_emoji.disabled + item['remove'] = remove if remove + end + deck.filter { |item| !item.key?('remove') } + end + + def remove_metas(deck) + deck.tap do |d| + d.each do |item| + item.delete('custom_emoji_id') + end + end end def deck_params diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js index 2fc8a6c59f..e0ffe095d3 100644 --- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js @@ -45,7 +45,7 @@ const getFrequentlyUsedEmojis = createSelector([ const { emojiCounters, reactionDeck } = data; let deckEmojis = reactionDeck .toArray() - .map((e) => e.get('emoji')) + .map((e) => e.getIn(['emoji', 'shortcode'])) .filter((e) => e) .map((e) => shortCodes[e] || e); deckEmojis = [...new Set(deckEmojis)]; @@ -70,6 +70,8 @@ const getFrequentlyUsedEmojis = createSelector([ emojis = deckEmojis.slice(0, DECK_SIZE).concat(emojis); + if (emojis.length <= 0) emojis = ['+1']; + return emojis; }); diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index 26036c4901..0d7756e418 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -13,7 +13,7 @@ import emojify from 'mastodon/features/emoji/emoji'; import { autoPlayGif } from 'mastodon/initial_state'; const MapStateToProps = (state, { emojiId, emojiMap }) => ({ - emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: '' })).get('emoji'), + emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).getIn(['emoji', 'shortcode']), emojiMap, }); From 7e4d9a2d0d652e1bbbee21b9bde23594b0b26494 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 17:33:47 +0900 Subject: [PATCH 05/17] Change instance setting max_items to max_emojis --- app/serializers/rest/instance_serializer.rb | 2 +- app/serializers/rest/v1/instance_serializer.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 3f90844c58..eff67cb837 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -86,7 +86,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_items: 16, + max_emojis: 16, }, reactions: { diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index ee2d2814d1..059ce3a4d5 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -92,7 +92,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_items: 16, + max_emojis: 16, }, reactions: { From 1cf9bb24d7fb891fa1484c322c4fb1e4b5bb56ac Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 18:01:09 +0900 Subject: [PATCH 06/17] Improve reaction_deck api --- .../api/v1/reaction_deck_controller.rb | 34 ++++++++----------- .../emoji_picker_dropdown_container.js | 2 +- .../components/reaction_emoji.jsx | 2 +- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index 12716d3f99..d8592bb5fc 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -25,28 +25,22 @@ class Api::V1::ReactionDeckController < Api::BaseController shortcode = data['emoji'].delete(':') custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: nil) - custom_emoji_id = custom_emoji&.id - emoji_data = if custom_emoji - { - 'shortcode' => custom_emoji.shortcode, - 'url' => full_asset_url(custom_emoji.image.url), - 'static_url' => full_asset_url(custom_emoji.image.url(:static)), - 'width' => custom_emoji.image_width, - 'height' => custom_emoji.image_height, - } - else - { - 'shortcode' => shortcode, - } - end - exists = deck.find { |dd| dd['id'] == data['id'] } - if exists - exists['custom_emoji_id'] = custom_emoji_id - exists['emoji'] = emoji_data + old = deck.find { |dd| dd['id'] == data['id'] } + emoji_data = old || { 'id' => data['id'] } + + if custom_emoji + emoji_data['name'] = custom_emoji.shortcode + emoji_data['url'] = full_asset_url(custom_emoji.image.url) + emoji_data['static_url'] = full_asset_url(custom_emoji.image.url(:static)) + emoji_data['width'] = custom_emoji.image_width + emoji_data['height'] = custom_emoji.image_height + emoji_data['custom_emoji_id'] = custom_emoji.id else - deck << { 'id' => data['id'], 'custom_emoji_id' => custom_emoji_id, 'emoji' => emoji_data } + emoji_data['name'] = shortcode end + + deck << emoji_data if old.nil? end deck = deck.sort_by { |a| a['id'].to_i } @@ -66,7 +60,7 @@ class Api::V1::ReactionDeckController < Api::BaseController def remove_unused_custom_emojis(deck) custom_ids = [] deck.each do |item| - custom_ids << item['custom_emoji_id'].to_i unless item['custom_emoji_id'].nil? + custom_ids << item['custom_emoji_id'].to_i if item.key?('custom_emoji_id') end custom_emojis = CustomEmoji.where(id: custom_ids) diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js index e0ffe095d3..2758e9009f 100644 --- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js @@ -45,7 +45,7 @@ const getFrequentlyUsedEmojis = createSelector([ const { emojiCounters, reactionDeck } = data; let deckEmojis = reactionDeck .toArray() - .map((e) => e.getIn(['emoji', 'shortcode'])) + .map((e) => e.get('name')) .filter((e) => e) .map((e) => shortCodes[e] || e); deckEmojis = [...new Set(deckEmojis)]; diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index 0d7756e418..ac17e56876 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -13,7 +13,7 @@ import emojify from 'mastodon/features/emoji/emoji'; import { autoPlayGif } from 'mastodon/initial_state'; const MapStateToProps = (state, { emojiId, emojiMap }) => ({ - emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).getIn(['emoji', 'shortcode']), + emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).get('name'), emojiMap, }); From c4efa4d98642e17102aba338cf6cd44dd20ce2a9 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 18:53:55 +0900 Subject: [PATCH 07/17] Add reaction deck remove api --- .../api/v1/reaction_deck_controller.rb | 12 +++++- .../mastodon/actions/reaction_deck.js | 39 +++++++++++++++++++ .../components/reaction_emoji.jsx | 24 +++++++++--- .../mastodon/reducers/reaction_deck.js | 4 +- .../styles/mastodon/components.scss | 8 +++- config/routes/api.rb | 1 + 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index d8592bb5fc..cac2a9fb00 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -4,10 +4,10 @@ class Api::V1::ReactionDeckController < Api::BaseController include RoutingHelper before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index] - before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create, :remove] before_action :require_user! - before_action :set_deck, only: [:index, :create] + before_action :set_deck, only: [:index, :create, :remove] rescue_from ArgumentError do |e| render json: { error: e.to_s }, status: 422 @@ -50,6 +50,14 @@ class Api::V1::ReactionDeckController < Api::BaseController render json: remove_metas(deck) end + def remove + deck = @deck.filter { |item| deck_params['emojis'].none? { |d| d['id'] == item['id'] } } + current_user.settings['reaction_deck'] = deck.to_json + current_user.save! + + render json: remove_metas(deck) + end + private def set_deck diff --git a/app/javascript/mastodon/actions/reaction_deck.js b/app/javascript/mastodon/actions/reaction_deck.js index 2914e8ceef..5b8be5d62f 100644 --- a/app/javascript/mastodon/actions/reaction_deck.js +++ b/app/javascript/mastodon/actions/reaction_deck.js @@ -8,6 +8,10 @@ export const REACTION_DECK_UPDATE_REQUEST = 'REACTION_DECK_UPDATE_REQUEST'; export const REACTION_DECK_UPDATE_SUCCESS = 'REACTION_DECK_UPDATE_SUCCESS'; export const REACTION_DECK_UPDATE_FAIL = 'REACTION_DECK_UPDATE_FAIL'; +export const REACTION_DECK_REMOVE_REQUEST = 'REACTION_DECK_REMOVE_REQUEST'; +export const REACTION_DECK_REMOVE_SUCCESS = 'REACTION_DECK_REMOVE_SUCCESS'; +export const REACTION_DECK_REMOVE_FAIL = 'REACTION_DECK_REMOVE_FAIL'; + export function fetchReactionDeck() { return (dispatch, getState) => { dispatch(fetchReactionDeckRequest()); @@ -77,3 +81,38 @@ export function updateReactionDeckFail(error) { skipLoading: true, }; } + +export function removeReactionDeck(id) { + return (dispatch, getState) => { + dispatch(removeReactionDeckRequest()); + + api(getState).post('/api/v1/remove_reaction_deck', { emojis: [{ id }] }).then(response => { + dispatch(removeReactionDeckSuccess(response.data)); + }).catch(error => { + dispatch(removeReactionDeckFail(error)); + }); + }; +} + +export function removeReactionDeckRequest() { + return { + type: REACTION_DECK_REMOVE_REQUEST, + skipLoading: true, + }; +} + +export function removeReactionDeckSuccess(emojis) { + return { + type: REACTION_DECK_REMOVE_SUCCESS, + emojis, + skipLoading: true, + }; +} + +export function removeReactionDeckFail(error) { + return { + type: REACTION_DECK_REMOVE_FAIL, + error, + skipLoading: true, + }; +} diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index ac17e56876..dadcb1982e 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -1,17 +1,22 @@ import PropTypes from 'prop-types'; -import { injectIntl } from 'react-intl'; +import { defineMessages, injectIntl } from 'react-intl'; import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { updateReactionDeck } from 'mastodon/actions/reaction_deck'; +import { updateReactionDeck, removeReactionDeck } from 'mastodon/actions/reaction_deck'; +import Button from 'mastodon/components/button'; import EmojiPickerDropdownContainer from 'mastodon/features/compose/containers/emoji_picker_dropdown_container'; import emojify from 'mastodon/features/emoji/emoji'; import { autoPlayGif } from 'mastodon/initial_state'; +const messages = defineMessages({ + remove: { id: 'reaction_deck.remove', defaultMessage: 'Remove' }, +}); + const MapStateToProps = (state, { emojiId, emojiMap }) => ({ emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).get('name'), emojiMap, @@ -19,6 +24,7 @@ const MapStateToProps = (state, { emojiId, emojiMap }) => ({ const mapDispatchToProps = (dispatch, { emojiId }) => ({ onChange: (emoji) => dispatch(updateReactionDeck(emojiId, emoji)), + onRemove: () => dispatch(removeReactionDeck(emojiId)), }); class ReactionEmoji extends ImmutablePureComponent { @@ -27,6 +33,7 @@ class ReactionEmoji extends ImmutablePureComponent { emoji: PropTypes.string, emojiMap: ImmutablePropTypes.map.isRequired, onChange: PropTypes.func.isRequired, + onRemove: PropTypes.func.isRequired, }; static defaultProps = { @@ -34,7 +41,7 @@ class ReactionEmoji extends ImmutablePureComponent { }; render () { - const { emojiMap, emoji, onChange } = this.props; + const { intl, emojiMap, emoji, onChange, onRemove } = this.props; let content = null; @@ -61,9 +68,14 @@ class ReactionEmoji extends ImmutablePureComponent { return (
- -
- {content} +
+ +
+ {content} +
+
+
+
diff --git a/app/javascript/mastodon/reducers/reaction_deck.js b/app/javascript/mastodon/reducers/reaction_deck.js index 12b4e8ef21..4ab0f9b4dd 100644 --- a/app/javascript/mastodon/reducers/reaction_deck.js +++ b/app/javascript/mastodon/reducers/reaction_deck.js @@ -1,11 +1,11 @@ import { List as ImmutableList, fromJS as ConvertToImmutable } from 'immutable'; -import { REACTION_DECK_FETCH_SUCCESS, REACTION_DECK_UPDATE_SUCCESS } from '../actions/reaction_deck'; +import { REACTION_DECK_FETCH_SUCCESS, REACTION_DECK_UPDATE_SUCCESS, REACTION_DECK_REMOVE_SUCCESS } from '../actions/reaction_deck'; const initialState = ImmutableList([]); export default function reaction_deck(state = initialState, action) { - if(action.type === REACTION_DECK_FETCH_SUCCESS || action.type === REACTION_DECK_UPDATE_SUCCESS) { + if(action.type === REACTION_DECK_FETCH_SUCCESS || action.type === REACTION_DECK_UPDATE_SUCCESS || action.type === REACTION_DECK_REMOVE_SUCCESS) { state = ConvertToImmutable(action.emojis); } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 7b5eff3f5c..5dddda6e0c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -7547,8 +7547,7 @@ noscript { .reaction_deck__emoji { &__wrapper { display: flex; - - margin: 8px 4px; + margin: 8px 16px 8px 4px; height: 32px; .emojione { @@ -7561,6 +7560,11 @@ noscript { margin-right: 24px; padding: 0; } + + &__content { + display: flex; + flex: 1; + } } } diff --git a/config/routes/api.rb b/config/routes/api.rb index 57543be8fb..378e7b57f5 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -55,6 +55,7 @@ namespace :api, format: false do resources :custom_emojis, only: [:index] resources :reaction_deck, only: [:index, :create] + post :remove_reaction_deck, to: 'reaction_deck#remove' resources :suggestions, only: [:index, :destroy] resources :scheduled_statuses, only: [:index, :show, :update, :destroy] resources :preferences, only: [:index] From b9dab37eaca1a88be336bb5dc005708b5172676a Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 20:42:36 +0900 Subject: [PATCH 08/17] Change reactiondeck to draggable, add-removable --- .../api/v1/reaction_deck_controller.rb | 30 ++++++ .../mastodon/actions/reaction_deck.js | 4 +- .../components/reaction_emoji.jsx | 29 +++--- .../mastodon/features/reaction_deck/index.jsx | 91 ++++++++++++++++++- app/serializers/rest/instance_serializer.rb | 2 +- .../rest/v1/instance_serializer.rb | 2 +- package.json | 1 + yarn.lock | 70 +++++++++++++- 8 files changed, 200 insertions(+), 29 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index cac2a9fb00..a65cd33e7f 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -18,6 +18,35 @@ class Api::V1::ReactionDeckController < Api::BaseController end def create + deck = [] + + (deck_params['emojis'] || []).each do |shortcode| + shortcode = shortcode.delete(':') + custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: nil) + + emoji_data = {} + + if custom_emoji + emoji_data['name'] = custom_emoji.shortcode + emoji_data['url'] = full_asset_url(custom_emoji.image.url) + emoji_data['static_url'] = full_asset_url(custom_emoji.image.url(:static)) + emoji_data['width'] = custom_emoji.image_width + emoji_data['height'] = custom_emoji.image_height + emoji_data['custom_emoji_id'] = custom_emoji.id + else + emoji_data['name'] = shortcode + end + + deck << emoji_data + end + + current_user.settings['reaction_deck'] = deck.to_json + current_user.save! + + render json: remove_metas(deck) + end + + def legacy_create deck = @deck (deck_params['emojis'] || []).each do |data| @@ -86,6 +115,7 @@ class Api::V1::ReactionDeckController < Api::BaseController deck.tap do |d| d.each do |item| item.delete('custom_emoji_id') + # item.delete('id') if item.key?('id') end end end diff --git a/app/javascript/mastodon/actions/reaction_deck.js b/app/javascript/mastodon/actions/reaction_deck.js index 5b8be5d62f..c1a1b0146e 100644 --- a/app/javascript/mastodon/actions/reaction_deck.js +++ b/app/javascript/mastodon/actions/reaction_deck.js @@ -47,11 +47,11 @@ export function fetchReactionDeckFail(error) { }; } -export function updateReactionDeck(id, emoji) { +export function updateReactionDeck(emojis) { return (dispatch, getState) => { dispatch(updateReactionDeckRequest()); - api(getState).post('/api/v1/reaction_deck', { emojis: [{ id, emoji: emoji.native || emoji.id }] }).then(response => { + api(getState).post('/api/v1/reaction_deck', { emojis }).then(response => { dispatch(updateReactionDeckSuccess(response.data)); }).catch(error => { dispatch(updateReactionDeckFail(error)); diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index dadcb1982e..d221ef857c 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -2,12 +2,10 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; -import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; -import { updateReactionDeck, removeReactionDeck } from 'mastodon/actions/reaction_deck'; import Button from 'mastodon/components/button'; import EmojiPickerDropdownContainer from 'mastodon/features/compose/containers/emoji_picker_dropdown_container'; import emojify from 'mastodon/features/emoji/emoji'; @@ -17,19 +15,10 @@ const messages = defineMessages({ remove: { id: 'reaction_deck.remove', defaultMessage: 'Remove' }, }); -const MapStateToProps = (state, { emojiId, emojiMap }) => ({ - emoji: (state.get('reaction_deck', ImmutableList()).toArray().find(em => em.get('id') === emojiId) || ImmutableMap({ emoji: { shortcode: '' } })).get('name'), - emojiMap, -}); - -const mapDispatchToProps = (dispatch, { emojiId }) => ({ - onChange: (emoji) => dispatch(updateReactionDeck(emojiId, emoji)), - onRemove: () => dispatch(removeReactionDeck(emojiId)), -}); - class ReactionEmoji extends ImmutablePureComponent { static propTypes = { + index: PropTypes.number, emoji: PropTypes.string, emojiMap: ImmutablePropTypes.map.isRequired, onChange: PropTypes.func.isRequired, @@ -40,8 +29,16 @@ class ReactionEmoji extends ImmutablePureComponent { emoji: '', }; + handleChange = (emoji) => { + this.props.onChange(this.props.index, emoji); + }; + + handleRemove = () => { + this.props.onRemove(this.props.index); + }; + render () { - const { intl, emojiMap, emoji, onChange, onRemove } = this.props; + const { intl, emojiMap, emoji } = this.props; let content = null; @@ -69,13 +66,13 @@ class ReactionEmoji extends ImmutablePureComponent {
- +
{content}
-
@@ -84,4 +81,4 @@ class ReactionEmoji extends ImmutablePureComponent { } -export default connect(MapStateToProps, mapDispatchToProps)(injectIntl(ReactionEmoji)); +export default connect(injectIntl(ReactionEmoji)); diff --git a/app/javascript/mastodon/features/reaction_deck/index.jsx b/app/javascript/mastodon/features/reaction_deck/index.jsx index a457272da5..feb309b804 100644 --- a/app/javascript/mastodon/features/reaction_deck/index.jsx +++ b/app/javascript/mastodon/features/reaction_deck/index.jsx @@ -1,4 +1,5 @@ import PropTypes from 'prop-types'; +import { useEffect, useState } from "react"; import { defineMessages, injectIntl } from 'react-intl'; @@ -10,15 +11,36 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; + +import { updateReactionDeck } from 'mastodon/actions/reaction_deck'; +import Button from 'mastodon/components/button'; import ColumnHeader from 'mastodon/components/column_header'; import LoadingIndicator from 'mastodon/components/loading_indicator'; import ScrollableList from 'mastodon/components/scrollable_list'; import Column from 'mastodon/features/ui/components/column'; + import ReactionEmoji from './components/reaction_emoji'; -const DECK_SIZE = 16; +// https://medium.com/@wbern/getting-react-18s-strict-mode-to-work-with-react-beautiful-dnd-47bc909348e4 +/* eslint react/prop-types: 0 */ +const StrictModeDroppable = ({ children, ...props }) => { + const [enabled, setEnabled] = useState(false); + useEffect(() => { + const animation = requestAnimationFrame(() => setEnabled(true)); + return () => { + cancelAnimationFrame(animation); + setEnabled(false); + }; + }, []); + if (!enabled) { + return null; + } + return {children}; +}; +/* eslint react/prop-types: 0 */ const customEmojiMap = createSelector([state => state.get('custom_emojis')], items => items.reduce((map, emoji) => map.set(emoji.get('shortcode'), emoji), ImmutableMap())); @@ -33,6 +55,10 @@ const mapStateToProps = (state, props) => ({ emojiMap: customEmojiMap(state), }); +const mapDispatchToProps = (dispatch) => ({ + onChange: (emojis) => dispatch(updateReactionDeck(emojis)), +}); + class ReactionDeck extends ImmutablePureComponent { static propTypes = { @@ -42,8 +68,40 @@ class ReactionDeck extends ImmutablePureComponent { emojiMap: ImmutablePropTypes.map, multiColumn: PropTypes.bool, intl: PropTypes.object.isRequired, + onChange: PropTypes.func.isRequired, }; + deckToArray = () => { + const { deck } = this.props; + + return deck.map((item) => item.get('name')).toArray(); + }; + + handleReorder = (result) => { + const newDeck = this.deckToArray(); + const deleted = newDeck.splice(result.source.index, 1); + newDeck.splice(result.destination.index, 0, deleted[0]); + this.props.onChange(newDeck); + }; + + handleChange = (index, emoji) => { + const newDeck = this.deckToArray(); + newDeck[index] = emoji.native || emoji.id.replace(':', ''); + this.props.onChange(newDeck); + }; + + handleRemove = (index) => { + const newDeck = this.deckToArray(); + newDeck.splice(index, 1); + this.props.onChange(newDeck); + }; + + handleAdd = () => { + const newDeck = this.deckToArray(); + newDeck.push('👍'); + this.props.onChange(newDeck); + } + render () { const { intl, deck, emojiMap, multiColumn } = this.props; @@ -69,9 +127,32 @@ class ReactionDeck extends ImmutablePureComponent { scrollKey='reaction_deck' bindToDocument={!multiColumn} > - {[...Array(DECK_SIZE).keys()].map(emojiId => - - )} + + + {(provided) => ( +
+ {deck.map((emoji, index) => ( + + {(provided2) => ( +
+ +
+ )} +
+ ))} + {provided.placeholder} + +
+ )} +
+
@@ -83,4 +164,4 @@ class ReactionDeck extends ImmutablePureComponent { } -export default connect(mapStateToProps)(injectIntl(ReactionDeck)); +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(ReactionDeck)); diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index eff67cb837..7b2154aed4 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -86,7 +86,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_emojis: 16, + max_emojis: 32_767, }, reactions: { diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index 059ce3a4d5..9c4ae9e3be 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -92,7 +92,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_emojis: 16, + max_emojis: 32_767, }, reactions: { diff --git a/package.json b/package.json index 13720c56b4..d96e9b189b 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "prop-types": "^15.8.1", "punycode": "^2.3.0", "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-helmet": "^6.1.0", "react-hotkeys": "^1.1.4", diff --git a/yarn.lock b/yarn.lock index ae89f81d37..773070a0a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1062,7 +1062,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== @@ -2006,7 +2006,7 @@ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== -"@types/hoist-non-react-statics@^3.3.1": +"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== @@ -2222,6 +2222,16 @@ dependencies: react-overlays "*" +"@types/react-redux@^7.1.20": + version "7.1.25" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88" + integrity sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-router-dom@^5.3.3": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" @@ -4222,6 +4232,13 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +css-box-model@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-declaration-sorter@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec" @@ -7940,6 +7957,11 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + memoize-one@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" @@ -9445,6 +9467,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +raf-schd@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + raf@^3.1.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -9482,6 +9509,19 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +react-beautiful-dnd@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" + integrity sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ== + dependencies: + "@babel/runtime" "^7.9.2" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.2.0" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" @@ -9568,7 +9608,7 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.1: +react-is@^17.0.1, react-is@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== @@ -9621,6 +9661,18 @@ react-redux-loading-bar@^5.0.4: prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" +react-redux@^7.2.0: + version "7.2.9" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d" + integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + react-redux@^8.0.4: version "8.0.5" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd" @@ -9871,7 +9923,7 @@ redux-thunk@^2.4.2: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== -redux@^4.0.0, redux@^4.2.1: +redux@^4.0.0, redux@^4.0.4, redux@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== @@ -11281,6 +11333,11 @@ tiny-invariant@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== +tiny-invariant@^1.0.6: + version "1.3.1" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" + integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== + tiny-queue@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" @@ -11685,6 +11742,11 @@ use-latest@^1.2.1: dependencies: use-isomorphic-layout-effect "^1.1.1" +use-memo-one@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" + integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ== + use-sync-external-store@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" From 2292a611357931f0f11cfc667bd39b4841e53dab Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 26 May 2023 21:16:35 +0900 Subject: [PATCH 09/17] Remove unused code --- .../api/v1/reaction_deck_controller.rb | 45 +------------------ .../mastodon/actions/reaction_deck.js | 39 ---------------- .../components/reaction_emoji.jsx | 2 +- .../mastodon/features/reaction_deck/index.jsx | 1 - .../mastodon/reducers/reaction_deck.js | 4 +- config/routes/api.rb | 1 - 6 files changed, 5 insertions(+), 87 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index a65cd33e7f..fe74738d4b 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -4,10 +4,10 @@ class Api::V1::ReactionDeckController < Api::BaseController include RoutingHelper before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index] - before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create, :remove] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, only: [:create] before_action :require_user! - before_action :set_deck, only: [:index, :create, :remove] + before_action :set_deck, only: [:index, :create] rescue_from ArgumentError do |e| render json: { error: e.to_s }, status: 422 @@ -46,47 +46,6 @@ class Api::V1::ReactionDeckController < Api::BaseController render json: remove_metas(deck) end - def legacy_create - deck = @deck - - (deck_params['emojis'] || []).each do |data| - raise ArgumentError if data['id'].to_i >= 16 || data['id'].to_i.negative? - - shortcode = data['emoji'].delete(':') - custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: nil) - - old = deck.find { |dd| dd['id'] == data['id'] } - emoji_data = old || { 'id' => data['id'] } - - if custom_emoji - emoji_data['name'] = custom_emoji.shortcode - emoji_data['url'] = full_asset_url(custom_emoji.image.url) - emoji_data['static_url'] = full_asset_url(custom_emoji.image.url(:static)) - emoji_data['width'] = custom_emoji.image_width - emoji_data['height'] = custom_emoji.image_height - emoji_data['custom_emoji_id'] = custom_emoji.id - else - emoji_data['name'] = shortcode - end - - deck << emoji_data if old.nil? - end - - deck = deck.sort_by { |a| a['id'].to_i } - current_user.settings['reaction_deck'] = deck.to_json - current_user.save! - - render json: remove_metas(deck) - end - - def remove - deck = @deck.filter { |item| deck_params['emojis'].none? { |d| d['id'] == item['id'] } } - current_user.settings['reaction_deck'] = deck.to_json - current_user.save! - - render json: remove_metas(deck) - end - private def set_deck diff --git a/app/javascript/mastodon/actions/reaction_deck.js b/app/javascript/mastodon/actions/reaction_deck.js index c1a1b0146e..11510d5d0d 100644 --- a/app/javascript/mastodon/actions/reaction_deck.js +++ b/app/javascript/mastodon/actions/reaction_deck.js @@ -8,10 +8,6 @@ export const REACTION_DECK_UPDATE_REQUEST = 'REACTION_DECK_UPDATE_REQUEST'; export const REACTION_DECK_UPDATE_SUCCESS = 'REACTION_DECK_UPDATE_SUCCESS'; export const REACTION_DECK_UPDATE_FAIL = 'REACTION_DECK_UPDATE_FAIL'; -export const REACTION_DECK_REMOVE_REQUEST = 'REACTION_DECK_REMOVE_REQUEST'; -export const REACTION_DECK_REMOVE_SUCCESS = 'REACTION_DECK_REMOVE_SUCCESS'; -export const REACTION_DECK_REMOVE_FAIL = 'REACTION_DECK_REMOVE_FAIL'; - export function fetchReactionDeck() { return (dispatch, getState) => { dispatch(fetchReactionDeckRequest()); @@ -81,38 +77,3 @@ export function updateReactionDeckFail(error) { skipLoading: true, }; } - -export function removeReactionDeck(id) { - return (dispatch, getState) => { - dispatch(removeReactionDeckRequest()); - - api(getState).post('/api/v1/remove_reaction_deck', { emojis: [{ id }] }).then(response => { - dispatch(removeReactionDeckSuccess(response.data)); - }).catch(error => { - dispatch(removeReactionDeckFail(error)); - }); - }; -} - -export function removeReactionDeckRequest() { - return { - type: REACTION_DECK_REMOVE_REQUEST, - skipLoading: true, - }; -} - -export function removeReactionDeckSuccess(emojis) { - return { - type: REACTION_DECK_REMOVE_SUCCESS, - emojis, - skipLoading: true, - }; -} - -export function removeReactionDeckFail(error) { - return { - type: REACTION_DECK_REMOVE_FAIL, - error, - skipLoading: true, - }; -} diff --git a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx index d221ef857c..7fb6f49285 100644 --- a/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx +++ b/app/javascript/mastodon/features/reaction_deck/components/reaction_emoji.jsx @@ -81,4 +81,4 @@ class ReactionEmoji extends ImmutablePureComponent { } -export default connect(injectIntl(ReactionEmoji)); +export default connect()(injectIntl(ReactionEmoji)); diff --git a/app/javascript/mastodon/features/reaction_deck/index.jsx b/app/javascript/mastodon/features/reaction_deck/index.jsx index feb309b804..0de2fdb98b 100644 --- a/app/javascript/mastodon/features/reaction_deck/index.jsx +++ b/app/javascript/mastodon/features/reaction_deck/index.jsx @@ -136,7 +136,6 @@ class ReactionDeck extends ImmutablePureComponent { {(provided2) => (
Date: Fri, 26 May 2023 22:27:35 +0900 Subject: [PATCH 10/17] Remove slicing deck --- .../compose/containers/emoji_picker_dropdown_container.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js index 2758e9009f..2bbebd3238 100644 --- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js @@ -34,7 +34,6 @@ const DEFAULTS = [ ]; const RECENT_SIZE = DEFAULTS.length; -const DECK_SIZE = 16; const getFrequentlyUsedEmojis = createSelector([ state => { return { @@ -68,7 +67,7 @@ const getFrequentlyUsedEmojis = createSelector([ emojis = []; } - emojis = deckEmojis.slice(0, DECK_SIZE).concat(emojis); + emojis = deckEmojis.concat(emojis); if (emojis.length <= 0) emojis = ['+1']; From 875065bf5f5abafe1a992f5f490f266696d19d2e Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 08:55:42 +0900 Subject: [PATCH 11/17] Fix not able to click sign in button --- .../mastodon/features/ui/components/sign_in_banner.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx index 25de95fd37..e54144b074 100644 --- a/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx +++ b/app/javascript/mastodon/features/ui/components/sign_in_banner.jsx @@ -17,7 +17,7 @@ const SignInBanner = () => { let signupButton; - const signupUrl = useAppSelector((state) => state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up')); + const signupUrl = useAppSelector((state) => state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up') || '/auth/sign_up'); if (registrationsOpen) { signupButton = ( From 19eb73a06309902e6820739b386152211fb8c45b Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 08:58:56 +0900 Subject: [PATCH 12/17] Fix more --- app/javascript/mastodon/features/interaction_modal/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index 1d26160753..284235ab67 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -13,7 +13,7 @@ import { registrationsOpen } from 'mastodon/initial_state'; const mapStateToProps = (state, { accountId }) => ({ displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']), - signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up'), + signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], '/auth/sign_up') || '/auth/sign_up', }); const mapDispatchToProps = (dispatch) => ({ From 7bd14cef25ce68500b627ad20d13dbc113d1a08c Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 09:29:22 +0900 Subject: [PATCH 13/17] Add translations --- app/javascript/mastodon/locales/en.json | 10 ++++++++++ app/javascript/mastodon/locales/ja.json | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 1ad38d9c2b..4b386cc154 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -116,6 +116,7 @@ "column.notifications": "Notifications", "column.pins": "Pinned posts", "column.public": "Federated timeline", + "column.reaction_deck": "Reaction deck", "column_back_button.label": "Back", "column_header.hide_settings": "Hide settings", "column_header.moveLeft_settings": "Move column to the left", @@ -134,6 +135,8 @@ "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is not public. Only public posts can be searched by hashtag.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer.lock": "locked", + "compose_form.markdown.marked": "Markdown is available", + "compose_form.markdown.unmarked": "Markdown is NOT available", "compose_form.placeholder": "What's on your mind?", "compose_form.searchability_warning": "Self only searchability is not available other mastodon servers. Others can search your post.", "compose_form.poll.add_option": "Add a choice", @@ -371,6 +374,7 @@ "mute_modal.hide_notifications": "Hide notifications from this user?", "mute_modal.indefinite": "Indefinite", "navigation_bar.about": "About", + "navigation_bar.antennas": "Antenna", "navigation_bar.blocks": "Blocked users", "navigation_bar.bookmarks": "Bookmarks", "navigation_bar.community_timeline": "Local timeline", @@ -392,6 +396,7 @@ "navigation_bar.pins": "Pinned posts", "navigation_bar.preferences": "Preferences", "navigation_bar.public_timeline": "Federated timeline", + "navigation_bar.reaction_deck": "Reaction deck", "navigation_bar.search": "Search", "navigation_bar.security": "Security", "not_signed_in_indicator.not_signed_in": "You need to login to access this resource.", @@ -487,6 +492,8 @@ "privacy.change": "Change post privacy", "privacy.direct.long": "Visible for mentioned users only", "privacy.direct.short": "Mentioned people only", + "privacy.login.long": "Visible for login users only", + "privacy.login.short": "Login only", "privacy.private.long": "Visible for followers only", "privacy.private.short": "Followers only", "privacy.public.long": "Visible for all", @@ -497,6 +504,8 @@ "privacy.unlisted.short": "Unlisted", "privacy_policy.last_updated": "Last updated {date}", "privacy_policy.title": "Privacy Policy", + "reaction_deck.add": "Add", + "reaction_deck.remove": "Remove", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -606,6 +615,7 @@ "status.edited": "Edited {date}", "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}", "status.embed": "Embed", + "status.expiration.add": "Set status expired time", "status.favourite": "Favourite", "status.filter": "Filter this post", "status.filtered": "Filtered", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 3da571fb1a..9b49eafd2c 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -117,6 +117,7 @@ "column.notifications": "通知", "column.pins": "固定された投稿", "column.public": "連合タイムライン", + "column.reaction_deck": "絵文字デッキ", "column_back_button.label": "戻る", "column_header.hide_settings": "設定を隠す", "column_header.moveLeft_settings": "カラムを左に移動する", @@ -135,6 +136,8 @@ "compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。", "compose_form.lock_disclaimer": "あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。", "compose_form.lock_disclaimer.lock": "承認制", + "compose_form.markdown.marked": "Markdown有効", + "compose_form.markdown.unmarked": "Markdownは有効になっていません", "compose_form.placeholder": "今なにしてる?", "compose_form.searchability_warning": "検索許可「自分のみ」はkmyblue内の検索でのみ有効です。他のサーバーでは「リアクションした人のみ」と同等に扱われます", "compose_form.poll.add_option": "追加", @@ -373,6 +376,7 @@ "mute_modal.hide_notifications": "このユーザーからの通知を隠しますか?", "mute_modal.indefinite": "無期限", "navigation_bar.about": "概要", + "navigation_bar.antennas": "アンテナ", "navigation_bar.blocks": "ブロックしたユーザー", "navigation_bar.bookmarks": "ブックマーク", "navigation_bar.community_timeline": "ローカルタイムライン", @@ -395,6 +399,7 @@ "navigation_bar.pins": "固定した投稿", "navigation_bar.preferences": "ユーザー設定", "navigation_bar.public_timeline": "連合タイムライン", + "navigation_bar.reaction_deck": "絵文字デッキ", "navigation_bar.search": "検索", "navigation_bar.security": "セキュリティ", "not_signed_in_indicator.not_signed_in": "この機能を使うにはログインする必要があります。", @@ -492,6 +497,8 @@ "privacy.change": "公開範囲を変更", "privacy.direct.long": "指定された相手のみ閲覧可", "privacy.direct.short": "指定された相手のみ", + "privacy.login.long": "ログインユーザーのみ閲覧可、公開", + "privacy.login.short": "ログインユーザーのみ", "privacy.private.long": "フォロワーのみ閲覧可", "privacy.private.short": "フォロワーのみ", "privacy.public.long": "誰でも閲覧可、ホーム+ローカル+連合TL", @@ -502,6 +509,8 @@ "privacy.unlisted.short": "未収載", "privacy_policy.last_updated": "{date}に更新", "privacy_policy.title": "プライバシーポリシー", + "reaction_deck.add": "追加", + "reaction_deck.remove": "削除", "refresh": "更新", "regeneration_indicator.label": "読み込み中…", "regeneration_indicator.sublabel": "ホームタイムラインは準備中です!", @@ -612,6 +621,7 @@ "status.edited_x_times": "{count}回編集", "status.embed": "埋め込み", "status.emoji_reaction": "スタンプ", + "status.expiration.add": "時限投稿を設定", "status.favourite": "お気に入り", "status.filter": "この投稿をフィルターする", "status.filtered": "フィルターされました", From 8e794d50b50140bcc76e1c136d35a122b43071df Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 09:29:39 +0900 Subject: [PATCH 14/17] Fix reaction deck dispatch error --- app/javascript/mastodon/features/reaction_deck/index.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/reaction_deck/index.jsx b/app/javascript/mastodon/features/reaction_deck/index.jsx index 0de2fdb98b..b1bc4ccfb9 100644 --- a/app/javascript/mastodon/features/reaction_deck/index.jsx +++ b/app/javascript/mastodon/features/reaction_deck/index.jsx @@ -45,7 +45,7 @@ const StrictModeDroppable = ({ children, ...props }) => { const customEmojiMap = createSelector([state => state.get('custom_emojis')], items => items.reduce((map, emoji) => map.set(emoji.get('shortcode'), emoji), ImmutableMap())); const messages = defineMessages({ - refresh: { id: 'refresh', defaultMessage: 'Refresh' }, + reaction_deck_add: { id: 'reaction_deck.add', defaultMessage: 'Add' }, heading: { id: 'column.reaction_deck', defaultMessage: 'Reaction deck' }, }); @@ -63,7 +63,6 @@ class ReactionDeck extends ImmutablePureComponent { static propTypes = { params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, deck: ImmutablePropTypes.list, emojiMap: ImmutablePropTypes.map, multiColumn: PropTypes.bool, @@ -147,7 +146,7 @@ class ReactionDeck extends ImmutablePureComponent { ))} {provided.placeholder} -
)} From f93679566ba84483548e5a61bced7ec2d05c5540 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 10:13:18 +0900 Subject: [PATCH 15/17] Add reactiondeck limit variable and improve sql --- app/controllers/api/v1/reaction_deck_controller.rb | 11 +++++++++-- app/models/user.rb | 2 ++ app/serializers/rest/instance_serializer.rb | 2 +- app/serializers/rest/v1/instance_serializer.rb | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/reaction_deck_controller.rb b/app/controllers/api/v1/reaction_deck_controller.rb index fe74738d4b..6229eb89d4 100644 --- a/app/controllers/api/v1/reaction_deck_controller.rb +++ b/app/controllers/api/v1/reaction_deck_controller.rb @@ -20,9 +20,16 @@ class Api::V1::ReactionDeckController < Api::BaseController def create deck = [] + shortcodes = [] (deck_params['emojis'] || []).each do |shortcode| - shortcode = shortcode.delete(':') - custom_emoji = CustomEmoji.find_by(shortcode: shortcode, domain: nil) + shortcodes << shortcode.delete(':') + break if shortcodes.length >= User::REACTION_DECK_MAX + end + + custom_emojis = CustomEmoji.where(shortcode: shortcodes, domain: nil) + + shortcodes.each do |shortcode| + custom_emoji = custom_emojis.find { |em| em.shortcode == shortcode } emoji_data = {} diff --git a/app/models/user.rb b/app/models/user.rb index b903344be9..a0678117d4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -65,6 +65,8 @@ class User < ApplicationRecord # to check their feed ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days.freeze + REACTION_DECK_MAX = 256 + devise :two_factor_authenticatable, otp_secret_encryption_key: Rails.configuration.x.otp_secret diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 7b2154aed4..5a06f51e59 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -86,7 +86,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_emojis: 32_767, + max_emojis: User::REACTION_DECK_MAX, }, reactions: { diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index 9c4ae9e3be..537132375e 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -92,7 +92,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer }, reaction_deck: { - max_emojis: 32_767, + max_emojis: User::REACTION_DECK_MAX, }, reactions: { From a62d4549150b59e980899941ed1de843fc84c3ba Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 11:02:45 +0900 Subject: [PATCH 16/17] Fix searchability missing with not-public posts --- app/models/status.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/status.rb b/app/models/status.rb index c210633941..2653140864 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -532,8 +532,8 @@ class Status < ApplicationRecord elsif visibility == 'limited' self.searchability = Status.searchabilities['limited'] else - s = [Status.searchabilities[searchability], Status.visibilities[visibility]].max - s = [s, 3].max + s = [Status.searchabilities[searchability], Status.visibilities[visibility] - 1].max + s = [s, 3].min self.searchability = s end end From dee69e4f8332b5cee9c0fd1248eab3bacd2f1410 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 27 May 2023 12:50:42 +0900 Subject: [PATCH 17/17] Remove redundant variables --- .../compose/containers/emoji_picker_dropdown_container.js | 5 +++-- .../mastodon/features/emoji/emoji_mart_data_light.js | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js index 2bbebd3238..455157b860 100644 --- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js @@ -6,7 +6,7 @@ import { hideRecentEmojis } from 'mastodon/initial_state'; import { useEmoji } from '../../../actions/emojis'; import { changeSetting } from '../../../actions/settings'; -import { shortCodes } from '../../emoji/emoji_mart_data_light'; +import unicodeMapping from '../../emoji/emoji_unicode_mapping_light'; import EmojiPickerDropdown from '../components/emoji_picker_dropdown'; @@ -42,11 +42,12 @@ const getFrequentlyUsedEmojis = createSelector([ }; }, ], data => { const { emojiCounters, reactionDeck } = data; + let deckEmojis = reactionDeck .toArray() .map((e) => e.get('name')) .filter((e) => e) - .map((e) => shortCodes[e] || e); + .map((e) => unicodeMapping[e] ? unicodeMapping[e].shortCode : e); deckEmojis = [...new Set(deckEmojis)]; let emojis; diff --git a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js index 32565b450d..11698937c0 100644 --- a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js +++ b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js @@ -7,7 +7,6 @@ import { unicodeToUnifiedName } from './unicode_to_unified_name'; const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed; const emojis = {}; -const shortCodes = {}; // decompress Object.keys(shortCodesToEmojiData).forEach((shortCode) => { @@ -34,12 +33,10 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => { short_names, unified, }; - shortCodes[native] = shortCode; }); export { emojis, - shortCodes, skins, categories, short_names,