diff --git a/src/boot/after_store.js b/src/boot/after_store.js index d2e7f488b5..9c1f007bd5 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -253,6 +253,7 @@ const getNodeInfo = async ({ store }) => { store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) store.dispatch('setInstanceOption', { name: 'shoutAvailable', value: features.includes('chat') }) store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') }) + store.dispatch('setInstanceOption', { name: 'pleromaCustomEmojiReactionsAvailable', value: features.includes('pleroma_custom_emoji_reactions') }) store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') }) store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 0d7ca8124a..349b043df5 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -98,6 +98,11 @@ const EmojiPicker = { required: false, type: Boolean, default: false + }, + hideCustomEmoji: { + required: false, + type: Boolean, + default: false } }, data () { @@ -280,6 +285,9 @@ const EmojiPicker = { return 0 }, allCustomGroups () { + if (this.hideCustomEmoji) { + return {} + } const emojis = this.$store.getters.groupedCustomEmojis if (emojis.unpacked) { emojis.unpacked.text = this.$t('emoji.unpacked') diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue index a63daa9743..eb46018e23 100644 --- a/src/components/emoji_reactions/emoji_reactions.vue +++ b/src/components/emoji_reactions/emoji_reactions.vue @@ -2,7 +2,7 @@
@@ -35,6 +49,8 @@ margin-top: 0.25em; flex-wrap: wrap; + --emoji-size: calc(1.25em * var(--emojiReactionsScale, 1)); + .emoji-reaction { padding: 0 0.5em; margin-right: 0.5em; @@ -45,8 +61,24 @@ box-sizing: border-box; .reaction-emoji { - width: 1.25em; + width: var(--emoji-size); + height: var(--emoji-size); margin-right: 0.25em; + line-height: var(--emoji-size); + display: flex; + justify-content: center; + align-items: center; + } + + .reaction-emoji-content { + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + line-height: inherit; + overflow: hidden; + font-size: calc(var(--emoji-size) * 0.8); + margin: 0; } &:focus { diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index 7f0963163b..face430ed7 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -80,3 +80,21 @@ export const ROOT_ITEMS = { criteria: ['announcements'] } } + +export function routeTo (item, currentUser) { + if (!item.route && !item.routeObject) return null + + let route + + if (item.routeObject) { + route = item.routeObject + } else { + route = { name: (item.anon || currentUser) ? item.route : item.anonRoute } + } + + if (USERNAME_ROUTES.has(route.name)) { + route.params = { username: currentUser.screen_name, name: currentUser.screen_name } + } + + return route +} diff --git a/src/components/navigation/navigation_entry.js b/src/components/navigation/navigation_entry.js index 81cc936a85..22ed77d9d9 100644 --- a/src/components/navigation/navigation_entry.js +++ b/src/components/navigation/navigation_entry.js @@ -1,5 +1,5 @@ import { mapState } from 'vuex' -import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js' +import { routeTo } from 'src/components/navigation/navigation.js' import OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faThumbtack } from '@fortawesome/free-solid-svg-icons' @@ -26,17 +26,7 @@ const NavigationEntry = { }, computed: { routeTo () { - if (!this.item.route && !this.item.routeObject) return null - let route - if (this.item.routeObject) { - route = this.item.routeObject - } else { - route = { name: (this.item.anon || this.currentUser) ? this.item.route : this.item.anonRoute } - } - if (USERNAME_ROUTES.has(route.name)) { - route.params = { username: this.currentUser.screen_name, name: this.currentUser.screen_name } - } - return route + return routeTo(this.item, this.currentUser) }, getters () { return this.$store.getters diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js index 9dd795aa11..ef78e44c0a 100644 --- a/src/components/navigation/navigation_pins.js +++ b/src/components/navigation/navigation_pins.js @@ -1,5 +1,5 @@ import { mapState } from 'vuex' -import { TIMELINES, ROOT_ITEMS, USERNAME_ROUTES } from 'src/components/navigation/navigation.js' +import { TIMELINES, ROOT_ITEMS, routeTo } from 'src/components/navigation/navigation.js' import { getListEntries, filterNavigation } from 'src/components/navigation/filter.js' import { library } from '@fortawesome/fontawesome-svg-core' @@ -31,14 +31,7 @@ const NavPanel = { props: ['limit'], methods: { getRouteTo (item) { - if (item.routeObject) { - return item.routeObject - } - const route = { name: (item.anon || this.currentUser) ? item.route : item.anonRoute } - if (USERNAME_ROUTES.has(route.name)) { - route.params = { username: this.currentUser.screen_name } - } - return route + return routeTo(item, this.currentUser) } }, computed: { diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 8d4cc2d16f..13e7f9b8ae 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -121,7 +121,16 @@ scope="global" keypath="notifications.reacted_with" > - {{ notification.emoji }} + + {{ notification.emoji }} diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 41cfcef0db..61f7317e22 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -129,6 +129,13 @@ .emoji-reaction-emoji { font-size: 1.3em; + max-width: 1.25em; + height: 1.25em; + width: auto; + } + + .emoji-reaction-emoji-image { + vertical-align: middle; } .notification-details { diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 47a4862396..8eed4b6043 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -1,9 +1,8 @@ import Popover from '../popover/popover.vue' -import { ensureFinalFallback } from '../../i18n/languages.js' +import EmojiPicker from '../emoji_picker/emoji_picker.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons' import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' -import { trim } from 'lodash' library.add( faPlus, @@ -20,105 +19,34 @@ const ReactButton = { } }, components: { - Popover + Popover, + EmojiPicker }, methods: { - addReaction (event, emoji, close) { + addReaction (event) { + const emoji = event.insertion const existingReaction = this.status.emoji_reactions.find(r => r.name === emoji) if (existingReaction && existingReaction.me) { this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) } else { this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) } - close() + }, + show () { + if (!this.expanded) { + this.$refs.picker.showPicker() + } }, onShow () { this.expanded = true - this.focusInput() }, onClose () { this.expanded = false - }, - focusInput () { - this.$nextTick(() => { - const input = document.querySelector('.reaction-picker-filter > input') - if (input) input.focus() - }) - }, - // Vaguely adjusted copypaste from emoji_input and emoji_picker! - maybeLocalizedEmojiNamesAndKeywords (emoji) { - const names = [emoji.displayText] - const keywords = [] - - if (emoji.displayTextI18n) { - names.push(this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args)) - } - - if (emoji.annotations) { - this.languages.forEach(lang => { - names.push(emoji.annotations[lang]?.name) - - keywords.push(...(emoji.annotations[lang]?.keywords || [])) - }) - } - - return { - names: names.filter(k => k), - keywords: keywords.filter(k => k) - } - }, - maybeLocalizedEmojiName (emoji) { - if (!emoji.annotations) { - return emoji.displayText - } - - if (emoji.displayTextI18n) { - return this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args) - } - - for (const lang of this.languages) { - if (emoji.annotations[lang]?.name) { - return emoji.annotations[lang].name - } - } - - return emoji.displayText } }, computed: { - commonEmojis () { - const hardcodedSet = new Set(['👍', '😠', '👀', '😂', '🔥']) - return this.$store.getters.standardEmojiList.filter(emoji => hardcodedSet.has(emoji.replacement)) - }, - languages () { - return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage) - }, - emojis () { - if (this.filterWord !== '') { - const keywordLowercase = trim(this.filterWord.toLowerCase()) - - const orderedEmojiList = [] - for (const emoji of this.$store.getters.standardEmojiList) { - const indices = this.maybeLocalizedEmojiNamesAndKeywords(emoji) - .keywords - .map(k => k.toLowerCase().indexOf(keywordLowercase)) - .filter(k => k > -1) - - const indexOfKeyword = indices.length ? Math.min(...indices) : -1 - - if (indexOfKeyword > -1) { - if (!Array.isArray(orderedEmojiList[indexOfKeyword])) { - orderedEmojiList[indexOfKeyword] = [] - } - orderedEmojiList[indexOfKeyword].push(emoji) - } - } - return orderedEmojiList.flat() - } - return this.$store.getters.standardEmojiList || [] - }, - mergedConfig () { - return this.$store.getters.mergedConfig + hideCustomEmoji () { + return !this.$store.state.instance.pleromaChatMessagesAvailable } } } diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue index a813b6fdc8..947536a1f3 100644 --- a/src/components/react_button/react_button.vue +++ b/src/components/react_button/react_button.vue @@ -1,73 +1,39 @@ @@ -135,11 +101,6 @@ color: $fallback--text; color: var(--text, $fallback--text); } - } - - .popover-trigger-button { - /* override of popover internal stuff */ - width: auto; @include unfocused-style { .focus-marker { diff --git a/src/components/settings_modal/helpers/float_setting.vue b/src/components/settings_modal/helpers/float_setting.vue new file mode 100644 index 0000000000..15edb3c3ee --- /dev/null +++ b/src/components/settings_modal/helpers/float_setting.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/settings_modal/helpers/integer_setting.js b/src/components/settings_modal/helpers/integer_setting.js deleted file mode 100644 index 8ad033e73a..0000000000 --- a/src/components/settings_modal/helpers/integer_setting.js +++ /dev/null @@ -1,11 +0,0 @@ -import Setting from './setting.js' - -export default { - ...Setting, - methods: { - ...Setting.methods, - getValue (e) { - return parseInt(e.target.value) - } - } -} diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue index e935dfb075..43fa7e1a90 100644 --- a/src/components/settings_modal/helpers/integer_setting.vue +++ b/src/components/settings_modal/helpers/integer_setting.vue @@ -1,40 +1,17 @@ - + diff --git a/src/components/settings_modal/helpers/number_setting.js b/src/components/settings_modal/helpers/number_setting.js new file mode 100644 index 0000000000..676a0d227f --- /dev/null +++ b/src/components/settings_modal/helpers/number_setting.js @@ -0,0 +1,24 @@ +import Setting from './setting.js' + +export default { + ...Setting, + props: { + ...Setting.props, + truncate: { + type: Number, + required: false, + default: 1 + } + }, + methods: { + ...Setting.methods, + getValue (e) { + if (!this.truncate === 1) { + return parseInt(e.target.value) + } else if (this.truncate > 1) { + return Math.trunc(e.target.value / this.truncate) * this.truncate + } + return parseFloat(e.target.value) + } + } +} diff --git a/src/components/settings_modal/helpers/number_setting.vue b/src/components/settings_modal/helpers/number_setting.vue new file mode 100644 index 0000000000..813357622a --- /dev/null +++ b/src/components/settings_modal/helpers/number_setting.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index f270216f11..8c7074a57f 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -60,14 +60,13 @@ export default { } }, backendDescription () { - console.log(get(this.$store.state.adminSettings.descriptions, this.path)) return get(this.$store.state.adminSettings.descriptions, this.path) }, backendDescriptionLabel () { - return this.backendDescription.label + return this.backendDescription?.label }, backendDescriptionDescription () { - return this.backendDescription.description + return this.backendDescription?.description }, shouldBeDisabled () { const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index e8f7016e78..3f2bcb13ba 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -2,6 +2,7 @@ import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' import ScopeSelector from 'src/components/scope_selector/scope_selector.vue' import IntegerSetting from '../helpers/integer_setting.vue' +import FloatSetting from '../helpers/float_setting.vue' import SizeSetting, { defaultHorizontalUnits } from '../helpers/size_setting.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' @@ -62,6 +63,7 @@ const GeneralTab = { BooleanSetting, ChoiceSetting, IntegerSetting, + FloatSetting, SizeSetting, InterfaceLanguageSwitcher, ScopeSelector, diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 641d850adf..f56fa8e0e2 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -269,6 +269,15 @@ {{ $t('settings.no_rich_text_description') }} +
  • + + {{ $t('settings.emoji_reactions_scale') }} + +
  • {{ $t('settings.attachments') }}

  • { : parseUser(data.target) output.from_profile = parseUser(data.account) output.emoji = data.emoji + output.emoji_url = data.emoji_url if (data.report) { output.report = data.report output.report.content = data.report.content diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index d6e973a1bb..43fe3c7305 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -21,8 +21,8 @@ export const applyTheme = (input) => { body.classList.remove('hidden') } -const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth }) => - ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth }) +const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth, emojiReactionsScale }) => + ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth, emojiReactionsScale }) const defaultConfigColumns = configColumns(defaultState)