pass 2 + emoji store separation
This commit is contained in:
parent
24ce2dc0a5
commit
4156b1597a
12 changed files with 372 additions and 119 deletions
|
|
@ -22,7 +22,8 @@ import {
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
import { useAuthFlowStore } from 'src/stores/auth_flow'
|
import { useAuthFlowStore } from 'src/stores/auth_flow'
|
||||||
import { useI18nStore } from 'src/stores/i18n'
|
import { useI18nStore } from 'src/stores/i18n'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth'
|
import { useOAuthStore } from 'src/stores/oauth'
|
||||||
import App from '../App.vue'
|
import App from '../App.vue'
|
||||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||||
|
|
@ -78,29 +79,29 @@ const getInstanceConfig = async ({ store }) => {
|
||||||
const textlimit = data.max_toot_chars
|
const textlimit = data.max_toot_chars
|
||||||
const vapidPublicKey = data.pleroma.vapid_public_key
|
const vapidPublicKey = data.pleroma.vapid_public_key
|
||||||
|
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pleromaExtensionsAvailable',
|
name: 'featureSet.pleromaExtensionsAvailable',
|
||||||
value: data.pleroma,
|
value: data.pleroma,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'textlimit',
|
name: 'textlimit',
|
||||||
value: textlimit,
|
value: textlimit,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'accountApprovalRequired',
|
name: 'accountApprovalRequired',
|
||||||
value: data.approval_required,
|
value: data.approval_required,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'birthdayRequired',
|
name: 'birthdayRequired',
|
||||||
value: !!data.pleroma?.metadata.birthday_required,
|
value: !!data.pleroma?.metadata.birthday_required,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'birthdayMinAge',
|
name: 'birthdayMinAge',
|
||||||
value: data.pleroma?.metadata.birthday_min_age || 0,
|
value: data.pleroma?.metadata.birthday_min_age || 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (vapidPublicKey) {
|
if (vapidPublicKey) {
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'vapidPublicKey',
|
name: 'vapidPublicKey',
|
||||||
value: vapidPublicKey,
|
value: vapidPublicKey,
|
||||||
})
|
})
|
||||||
|
|
@ -161,14 +162,14 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
|
||||||
config = Object.assign({}, staticConfig, apiConfig)
|
config = Object.assign({}, staticConfig, apiConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyInstanceOption = (name) => {
|
const copyInstanceOption = (path) => {
|
||||||
if (typeof config[name] !== 'undefined') {
|
if (typeof config[name] !== 'undefined') {
|
||||||
store.dispatch('setInstanceOption', { name, value: config[name] })
|
useInstanceStore().set({ path, value: config[name] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(staticOrApiConfigDefault).forEach(copyInstanceOption)
|
Object.keys(staticOrApiConfigDefault).map(k => `instanceIdentity.${k}`).forEach(copyInstanceOption)
|
||||||
Object.keys(instanceDefaultConfig).forEach(copyInstanceOption)
|
Object.keys(instanceDefaultConfig).map(k => `prefsStorage.${k}`).forEach(copyInstanceOption)
|
||||||
|
|
||||||
useAuthFlowStore().setInitialStrategy(config.loginMethod)
|
useAuthFlowStore().setInitialStrategy(config.loginMethod)
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +179,7 @@ const getTOS = async ({ store }) => {
|
||||||
const res = await window.fetch('/static/terms-of-service.html')
|
const res = await window.fetch('/static/terms-of-service.html')
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const html = await res.text()
|
const html = await res.text()
|
||||||
store.dispatch('setInstanceOption', { name: 'tos', value: html })
|
useInstanceStore().set({ name: 'tos', value: html })
|
||||||
} else {
|
} else {
|
||||||
throw res
|
throw res
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +193,7 @@ const getInstancePanel = async ({ store }) => {
|
||||||
const res = await preloadFetch('/instance/panel.html')
|
const res = await preloadFetch('/instance/panel.html')
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const html = await res.text()
|
const html = await res.text()
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'instanceSpecificPanelContent',
|
name: 'instanceSpecificPanelContent',
|
||||||
value: html,
|
value: html,
|
||||||
})
|
})
|
||||||
|
|
@ -227,7 +228,7 @@ const getStickers = async ({ store }) => {
|
||||||
).sort((a, b) => {
|
).sort((a, b) => {
|
||||||
return a.meta.title.localeCompare(b.meta.title)
|
return a.meta.title.localeCompare(b.meta.title)
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', { name: 'stickers', value: stickers })
|
useInstanceStore().set({ name: 'stickers', value: stickers })
|
||||||
} else {
|
} else {
|
||||||
throw res
|
throw res
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +249,7 @@ const getAppSecret = async ({ store }) => {
|
||||||
|
|
||||||
const resolveStaffAccounts = ({ store, accounts }) => {
|
const resolveStaffAccounts = ({ store, accounts }) => {
|
||||||
const nicknames = accounts.map((uri) => uri.split('/').pop())
|
const nicknames = accounts.map((uri) => uri.split('/').pop())
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'staffAccounts',
|
name: 'staffAccounts',
|
||||||
value: nicknames,
|
value: nicknames,
|
||||||
})
|
})
|
||||||
|
|
@ -262,159 +263,163 @@ const getNodeInfo = async ({ store }) => {
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const metadata = data.metadata
|
const metadata = data.metadata
|
||||||
const features = metadata.features
|
const features = metadata.features
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'name',
|
path: 'name',
|
||||||
value: metadata.nodeName,
|
value: metadata.nodeName,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'registrationOpen',
|
path: 'registrationOpen',
|
||||||
value: data.openRegistrations,
|
value: data.openRegistrations,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'mediaProxyAvailable',
|
path: 'featureSet.mediaProxyAvailable',
|
||||||
value: features.includes('media_proxy'),
|
value: features.includes('media_proxy'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'safeDM',
|
path: 'featureSet.safeDM',
|
||||||
value: features.includes('safe_dm_mentions'),
|
value: features.includes('safe_dm_mentions'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'shoutAvailable',
|
path: 'featureSet.shoutAvailable',
|
||||||
value: features.includes('chat'),
|
value: features.includes('chat'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pleromaChatMessagesAvailable',
|
path: 'featureSet.pleromaChatMessagesAvailable',
|
||||||
value: features.includes('pleroma_chat_messages'),
|
value: features.includes('pleroma_chat_messages'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pleromaCustomEmojiReactionsAvailable',
|
path: 'featureSet.pleromaCustomEmojiReactionsAvailable',
|
||||||
value:
|
value:
|
||||||
features.includes('pleroma_custom_emoji_reactions') ||
|
features.includes('pleroma_custom_emoji_reactions') ||
|
||||||
features.includes('custom_emoji_reactions'),
|
features.includes('custom_emoji_reactions'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pleromaBookmarkFoldersAvailable',
|
path: 'featureSet.pleromaBookmarkFoldersAvailable',
|
||||||
value: features.includes('pleroma:bookmark_folders'),
|
value: features.includes('pleroma:bookmark_folders'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'gopherAvailable',
|
path: 'featureSet.gopherAvailable',
|
||||||
value: features.includes('gopher'),
|
value: features.includes('gopher'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pollsAvailable',
|
path: 'featureSet.pollsAvailable',
|
||||||
value: features.includes('polls'),
|
value: features.includes('polls'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'editingAvailable',
|
path: 'featureSet.editingAvailable',
|
||||||
value: features.includes('editing'),
|
value: features.includes('editing'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'pollLimits',
|
path: 'featureSet.mailerEnabled',
|
||||||
value: metadata.pollLimits,
|
|
||||||
})
|
|
||||||
store.dispatch('setInstanceOption', {
|
|
||||||
name: 'mailerEnabled',
|
|
||||||
value: metadata.mailerEnabled,
|
value: metadata.mailerEnabled,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'quotingAvailable',
|
path: 'featureSet.quotingAvailable',
|
||||||
value: features.includes('quote_posting'),
|
value: features.includes('quote_posting'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'groupActorAvailable',
|
path: 'featureSet.groupActorAvailable',
|
||||||
value: features.includes('pleroma:group_actors'),
|
value: features.includes('pleroma:group_actors'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'blockExpiration',
|
path: 'featureSet.blockExpiration',
|
||||||
value: features.includes('pleroma:block_expiration'),
|
value: features.includes('pleroma:block_expiration'),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'localBubbleInstances',
|
path: 'localBubbleInstances',
|
||||||
value: metadata.localBubbleInstances ?? [],
|
value: metadata.localBubbleInstances ?? [],
|
||||||
})
|
})
|
||||||
|
useInstanceStore().set({
|
||||||
|
path: 'featureSet.localBubble',
|
||||||
|
value: (metadata.localBubbleInstances ?? []).length > 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
useInstanceStore().set({
|
||||||
|
path: 'limits.pollLimits',
|
||||||
|
value: metadata.pollLimits,
|
||||||
|
})
|
||||||
const uploadLimits = metadata.uploadLimits
|
const uploadLimits = metadata.uploadLimits
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'uploadlimit',
|
name: 'limits.uploadlimit',
|
||||||
value: parseInt(uploadLimits.general),
|
value: parseInt(uploadLimits.general),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'avatarlimit',
|
name: 'limits.avatarlimit',
|
||||||
value: parseInt(uploadLimits.avatar),
|
value: parseInt(uploadLimits.avatar),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'backgroundlimit',
|
name: 'limits.backgroundlimit',
|
||||||
value: parseInt(uploadLimits.background),
|
value: parseInt(uploadLimits.background),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'bannerlimit',
|
name: 'limits.bannerlimit',
|
||||||
value: parseInt(uploadLimits.banner),
|
value: parseInt(uploadLimits.banner),
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'fieldsLimits',
|
name: 'limits.fieldsLimits',
|
||||||
value: metadata.fieldsLimits,
|
value: metadata.fieldsLimits,
|
||||||
})
|
})
|
||||||
|
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'restrictedNicknames',
|
name: 'restrictedNicknames',
|
||||||
value: metadata.restrictedNicknames,
|
value: metadata.restrictedNicknames,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'postFormats',
|
name: 'featureSet.postFormats',
|
||||||
value: metadata.postFormats,
|
value: metadata.postFormats,
|
||||||
})
|
})
|
||||||
|
|
||||||
const suggestions = metadata.suggestions
|
const suggestions = metadata.suggestions
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'suggestionsEnabled',
|
name: 'featureSet.suggestionsEnabled',
|
||||||
value: suggestions.enabled,
|
value: suggestions.enabled,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'suggestionsWeb',
|
name: 'featureSet.suggestionsWeb',
|
||||||
value: suggestions.web,
|
value: suggestions.web,
|
||||||
})
|
})
|
||||||
|
|
||||||
const software = data.software
|
const software = data.software
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'backendVersion',
|
name: 'backendVersion',
|
||||||
value: software.version,
|
value: software.version,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'backendRepository',
|
name: 'backendRepository',
|
||||||
value: software.repository,
|
value: software.repository,
|
||||||
})
|
})
|
||||||
|
|
||||||
const priv = metadata.private
|
const priv = metadata.private
|
||||||
store.dispatch('setInstanceOption', { name: 'private', value: priv })
|
useInstanceStore().set({ name: 'private', value: priv })
|
||||||
|
|
||||||
const frontendVersion = window.___pleromafe_commit_hash
|
const frontendVersion = window.___pleromafe_commit_hash
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'frontendVersion',
|
name: 'frontendVersion',
|
||||||
value: frontendVersion,
|
value: frontendVersion,
|
||||||
})
|
})
|
||||||
|
|
||||||
const federation = metadata.federation
|
const federation = metadata.federation
|
||||||
|
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'tagPolicyAvailable',
|
name: 'featureSet.tagPolicyAvailable',
|
||||||
value:
|
value:
|
||||||
typeof federation.mrf_policies === 'undefined'
|
typeof federation.mrf_policies === 'undefined'
|
||||||
? false
|
? false
|
||||||
: metadata.federation.mrf_policies.includes('TagPolicy'),
|
: metadata.federation.mrf_policies.includes('TagPolicy'),
|
||||||
})
|
})
|
||||||
|
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'federationPolicy',
|
name: 'federationPolicy',
|
||||||
value: federation,
|
value: federation,
|
||||||
})
|
})
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'federating',
|
name: 'federating',
|
||||||
value:
|
value:
|
||||||
typeof federation.enabled === 'undefined' ? true : federation.enabled,
|
typeof federation.enabled === 'undefined' ? true : federation.enabled,
|
||||||
})
|
})
|
||||||
|
|
||||||
const accountActivationRequired = metadata.accountActivationRequired
|
const accountActivationRequired = metadata.accountActivationRequired
|
||||||
store.dispatch('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'accountActivationRequired',
|
name: 'accountActivationRequired',
|
||||||
value: accountActivationRequired,
|
value: accountActivationRequired,
|
||||||
})
|
})
|
||||||
|
|
@ -526,7 +531,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
typeof overrides.target !== 'undefined'
|
typeof overrides.target !== 'undefined'
|
||||||
? overrides.target
|
? overrides.target
|
||||||
: window.location.origin
|
: window.location.origin
|
||||||
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
useInstanceStore().set({ name: 'server', value: server })
|
||||||
|
|
||||||
await setConfig({ store })
|
await setConfig({ store })
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ const EmojiInput = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
padEmoji() {
|
padEmoji() {
|
||||||
return this.$store.getters.mergedConfig.padEmoji
|
return useEmojiStore().mergedConfig.padEmoji
|
||||||
},
|
},
|
||||||
defaultCandidateIndex() {
|
defaultCandidateIndex() {
|
||||||
return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1
|
return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* suggest - generates a suggestor function to be used by emoji-input
|
* suggest - generates a suggestor function to be used by emoji-input
|
||||||
* data: object providing source information for specific types of suggestions:
|
* data: object providing source information for specific types of suggestions:
|
||||||
* data.emoji - optional, an array of all emoji available i.e.
|
* data.emoji - optional, an array of all emoji available i.e.
|
||||||
* (getters.standardEmojiList + state.instance.customEmoji)
|
* (useEmojiStore().standardEmojiList + state.instance.customEmoji)
|
||||||
* data.users - optional, an array of all known users
|
* data.users - optional, an array of all known users
|
||||||
* updateUsersList - optional, a function to search and append to users
|
* updateUsersList - optional, a function to search and append to users
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
||||||
import { ensureFinalFallback } from '../../i18n/languages.js'
|
import { ensureFinalFallback } from '../../i18n/languages.js'
|
||||||
import Checkbox from '../checkbox/checkbox.vue'
|
import Checkbox from '../checkbox/checkbox.vue'
|
||||||
import StillImage from '../still-image/still-image.vue'
|
import StillImage from '../still-image/still-image.vue'
|
||||||
|
|
@ -359,7 +360,7 @@ const EmojiPicker = {
|
||||||
if (this.hideCustomEmoji || this.hideCustomEmojiInPicker) {
|
if (this.hideCustomEmoji || this.hideCustomEmojiInPicker) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
const emojis = this.$store.getters.groupedCustomEmojis
|
const emojis = useEmojiStore().groupedCustomEmojis
|
||||||
if (emojis.unpacked) {
|
if (emojis.unpacked) {
|
||||||
emojis.unpacked.text = this.$t('emoji.unpacked')
|
emojis.unpacked.text = this.$t('emoji.unpacked')
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +370,7 @@ const EmojiPicker = {
|
||||||
return Object.keys(this.allCustomGroups)[0]
|
return Object.keys(this.allCustomGroups)[0]
|
||||||
},
|
},
|
||||||
unicodeEmojiGroups() {
|
unicodeEmojiGroups() {
|
||||||
return this.$store.getters.standardEmojiGroupList.map((group) => ({
|
return useEmojiStore().standardEmojiGroupList.map((group) => ({
|
||||||
id: `standard-${group.id}`,
|
id: `standard-${group.id}`,
|
||||||
text: this.$t(`emoji.unicode_groups.${group.id}`),
|
text: this.$t(`emoji.unicode_groups.${group.id}`),
|
||||||
icon: UNICODE_EMOJI_GROUP_ICON[group.id],
|
icon: UNICODE_EMOJI_GROUP_ICON[group.id],
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import Gallery from 'src/components/gallery/gallery.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
import { pollFormToMasto } from 'src/services/poll/poll.service.js'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
||||||
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
|
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
|
||||||
|
|
@ -259,8 +260,8 @@ const PostStatusForm = {
|
||||||
emojiUserSuggestor() {
|
emojiUserSuggestor() {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...useEmojiStore().standardEmojiList,
|
||||||
...useInstanceStore().customEmoji,
|
...useEmojiStore().customEmoji,
|
||||||
],
|
],
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
})
|
})
|
||||||
|
|
@ -268,16 +269,16 @@ const PostStatusForm = {
|
||||||
emojiSuggestor() {
|
emojiSuggestor() {
|
||||||
return suggestor({
|
return suggestor({
|
||||||
emoji: [
|
emoji: [
|
||||||
...this.$store.getters.standardEmojiList,
|
...useEmojiStore().standardEmojiList,
|
||||||
...useInstanceStore().customEmoji,
|
...useEmojiStore().customEmoji,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
emoji() {
|
emoji() {
|
||||||
return this.$store.getters.standardEmojiList || []
|
return useEmojiStore().standardEmojiList || []
|
||||||
},
|
},
|
||||||
customEmoji() {
|
customEmoji() {
|
||||||
return useInstanceStore().customEmoji || []
|
return useEmojiStore().customEmoji || []
|
||||||
},
|
},
|
||||||
statusLength() {
|
statusLength() {
|
||||||
return this.newStatus.status.length
|
return this.newStatus.status.length
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import { set } from 'lodash'
|
||||||
|
|
||||||
import { useI18nStore } from 'src/stores/i18n.js'
|
import { useI18nStore } from 'src/stores/i18n.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
||||||
import messages from '../i18n/messages'
|
import messages from '../i18n/messages'
|
||||||
import localeService from '../services/locale/locale.service.js'
|
import localeService from '../services/locale/locale.service.js'
|
||||||
import { applyConfig } from '../services/style_setter/style_setter.js'
|
import { applyConfig } from '../services/style_setter/style_setter.js'
|
||||||
|
|
@ -43,24 +45,23 @@ export const instanceDefaultProperties = Object.keys(instanceDefaultConfig)
|
||||||
const config = {
|
const config = {
|
||||||
state: { ...defaultState },
|
state: { ...defaultState },
|
||||||
getters: {
|
getters: {
|
||||||
defaultConfig(state, getters, rootState) {
|
defaultConfig() {
|
||||||
const { instance } = rootState
|
|
||||||
return {
|
return {
|
||||||
...defaultState,
|
...defaultState,
|
||||||
...Object.fromEntries(
|
...Object.fromEntries(
|
||||||
instanceDefaultProperties.map((key) => [key, instance[key]]),
|
instanceDefaultProperties.map((key) => [key, useInstanceStore()[key]]),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mergedConfig(state, getters, rootState, rootGetters) {
|
mergedConfig(state) {
|
||||||
const { defaultConfig } = rootGetters
|
const instancePrefs = useInstanceStore().prefsStorage
|
||||||
return {
|
const result = Object.fromEntries(
|
||||||
...defaultConfig,
|
Object.entries(defaultState).map(([k, v]) => [
|
||||||
// Do not override with undefined
|
k,
|
||||||
...Object.fromEntries(
|
v ?? instancePrefs[k],
|
||||||
Object.entries(state).filter(([, v]) => v !== undefined),
|
]),
|
||||||
),
|
)
|
||||||
}
|
return result
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
|
@ -177,7 +178,7 @@ const config = {
|
||||||
}
|
}
|
||||||
case 'interfaceLanguage':
|
case 'interfaceLanguage':
|
||||||
messages.setLanguage(useI18nStore().i18n, value)
|
messages.setLanguage(useI18nStore().i18n, value)
|
||||||
dispatch('loadUnicodeEmojiData', value)
|
useEmojiStore().loadUnicodeEmojiData(value)
|
||||||
Cookies.set(
|
Cookies.set(
|
||||||
BACKEND_LANGUAGE_COOKIE_NAME,
|
BACKEND_LANGUAGE_COOKIE_NAME,
|
||||||
localeService.internalToBackendLocaleMulti(value),
|
localeService.internalToBackendLocaleMulti(value),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export const staticOrApiConfigDefault = {
|
||||||
redirectRootLogin: '/main/friends',
|
redirectRootLogin: '/main/friends',
|
||||||
redirectRootNoLogin: '/main/all',
|
redirectRootNoLogin: '/main/all',
|
||||||
hideSitename: false,
|
hideSitename: false,
|
||||||
nsfwCensorImage: undefined,
|
nsfwCensorImage: null,
|
||||||
showFeaturesPanel: true,
|
showFeaturesPanel: true,
|
||||||
showInstanceSpecificPanel: false,
|
showInstanceSpecificPanel: false,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ import api from './api.js'
|
||||||
import chats from './chats.js'
|
import chats from './chats.js'
|
||||||
import config from './config.js'
|
import config from './config.js'
|
||||||
import drafts from './drafts.js'
|
import drafts from './drafts.js'
|
||||||
import instance from './instance.js'
|
|
||||||
import notifications from './notifications.js'
|
import notifications from './notifications.js'
|
||||||
import profileConfig from './profileConfig.js'
|
import profileConfig from './profileConfig.js'
|
||||||
import statuses from './statuses.js'
|
import statuses from './statuses.js'
|
||||||
import users from './users.js'
|
import users from './users.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
instance,
|
|
||||||
statuses,
|
statuses,
|
||||||
notifications,
|
notifications,
|
||||||
users,
|
users,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import {
|
||||||
import { declarations } from 'src/modules/config_declaration'
|
import { declarations } from 'src/modules/config_declaration'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
||||||
import apiService from '../services/api/api.service.js'
|
import apiService from '../services/api/api.service.js'
|
||||||
|
|
@ -702,7 +703,7 @@ const users = {
|
||||||
useServerSideStorageStore().setServerSideStorage(user)
|
useServerSideStorageStore().setServerSideStorage(user)
|
||||||
commit('addNewUsers', [user])
|
commit('addNewUsers', [user])
|
||||||
|
|
||||||
dispatch('fetchEmoji')
|
useEmojiStore().fetchEmoji()
|
||||||
|
|
||||||
getNotificationPermission().then((permission) =>
|
getNotificationPermission().then((permission) =>
|
||||||
useInterfaceStore().setNotificationPermission(permission),
|
useInterfaceStore().setNotificationPermission(permission),
|
||||||
|
|
|
||||||
246
src/stores/emoji.js
Normal file
246
src/stores/emoji.js
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
|
||||||
|
import { ensureFinalFallback } from 'src/i18n/languages.js'
|
||||||
|
|
||||||
|
import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations'
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
// Custom emoji from server
|
||||||
|
customEmoji: [],
|
||||||
|
customEmojiFetched: false,
|
||||||
|
|
||||||
|
// Unicode emoji from bundle
|
||||||
|
emoji: {},
|
||||||
|
emojiFetched: false,
|
||||||
|
unicodeEmojiAnnotations: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
const SORTED_EMOJI_GROUP_IDS = [
|
||||||
|
'smileys-and-emotion',
|
||||||
|
'people-and-body',
|
||||||
|
'animals-and-nature',
|
||||||
|
'food-and-drink',
|
||||||
|
'travel-and-places',
|
||||||
|
'activities',
|
||||||
|
'objects',
|
||||||
|
'symbols',
|
||||||
|
'flags',
|
||||||
|
]
|
||||||
|
|
||||||
|
const REGIONAL_INDICATORS = (() => {
|
||||||
|
const start = 0x1f1e6
|
||||||
|
const end = 0x1f1ff
|
||||||
|
const A = 'A'.codePointAt(0)
|
||||||
|
const res = new Array(end - start + 1)
|
||||||
|
for (let i = start; i <= end; ++i) {
|
||||||
|
const letter = String.fromCodePoint(A + i - start)
|
||||||
|
res[i - start] = {
|
||||||
|
replacement: String.fromCodePoint(i),
|
||||||
|
imageUrl: false,
|
||||||
|
displayText: 'regional_indicator_' + letter,
|
||||||
|
displayTextI18n: {
|
||||||
|
key: 'emoji.regional_indicator',
|
||||||
|
args: { letter },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})()
|
||||||
|
|
||||||
|
const loadAnnotations = (lang) => {
|
||||||
|
return annotationsLoader[lang]().then((k) => k.default)
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectAnnotations = (emoji, annotations) => {
|
||||||
|
const availableLangs = Object.keys(annotations)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...emoji,
|
||||||
|
annotations: availableLangs.reduce((acc, cur) => {
|
||||||
|
acc[cur] = annotations[cur][emoji.replacement]
|
||||||
|
return acc
|
||||||
|
}, {}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectRegionalIndicators = (groups) => {
|
||||||
|
groups.symbols.push(...REGIONAL_INDICATORS)
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEmojiStore = defineStore('emoji', {
|
||||||
|
state: () => ({ ...defaultState }),
|
||||||
|
getters: {
|
||||||
|
groupedCustomEmojis(state) {
|
||||||
|
const packsOf = (emoji) => {
|
||||||
|
const packs = emoji.tags
|
||||||
|
.filter((k) => k.startsWith('pack:'))
|
||||||
|
.map((k) => {
|
||||||
|
const packName = k.slice(5) // remove 'pack:' prefix
|
||||||
|
return {
|
||||||
|
id: `custom-${packName}`,
|
||||||
|
text: packName,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!packs.length) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 'unpacked',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
return packs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.customEmoji.reduce((res, emoji) => {
|
||||||
|
packsOf(emoji).forEach(({ id: packId, text: packName }) => {
|
||||||
|
if (!res[packId]) {
|
||||||
|
res[packId] = {
|
||||||
|
id: packId,
|
||||||
|
text: packName,
|
||||||
|
image: emoji.imageUrl,
|
||||||
|
emojis: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res[packId].emojis.push(emoji)
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
standardEmojiList(state) {
|
||||||
|
return SORTED_EMOJI_GROUP_IDS.map((groupId) =>
|
||||||
|
(this.emoji[groupId] || []).map((k) =>
|
||||||
|
injectAnnotations(k, this.unicodeEmojiAnnotations),
|
||||||
|
),
|
||||||
|
).reduce((a, b) => a.concat(b), [])
|
||||||
|
},
|
||||||
|
standardEmojiGroupList(state) {
|
||||||
|
return SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
|
||||||
|
id: groupId,
|
||||||
|
emojis: (this.emoji[groupId] || []).map((k) =>
|
||||||
|
injectAnnotations(k, this.unicodeEmojiAnnotations),
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
async getStaticEmoji() {
|
||||||
|
try {
|
||||||
|
// See build/emojis_plugin for more details
|
||||||
|
const values = (await import('/src/assets/emoji.json')).default
|
||||||
|
|
||||||
|
const emoji = Object.keys(values).reduce((res, groupId) => {
|
||||||
|
res[groupId] = values[groupId].map((e) => ({
|
||||||
|
displayText: e.slug,
|
||||||
|
imageUrl: false,
|
||||||
|
replacement: e.emoji,
|
||||||
|
}))
|
||||||
|
return res
|
||||||
|
}, {})
|
||||||
|
this.emoji = injectRegionalIndicators(emoji)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Can't load static emoji\n", e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadUnicodeEmojiData(language) {
|
||||||
|
const langList = ensureFinalFallback(language)
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
langList.map(async (lang) => {
|
||||||
|
if (!this.unicodeEmojiAnnotations[lang]) {
|
||||||
|
try {
|
||||||
|
const annotations = await loadAnnotations(lang)
|
||||||
|
this.unicodeEmojiAnnotations[lang] = annotations
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(
|
||||||
|
`Error loading unicode emoji annotations for ${lang}: `,
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
async getCustomEmoji() {
|
||||||
|
try {
|
||||||
|
let res = await window.fetch('/api/v1/pleroma/emoji')
|
||||||
|
if (!res.ok) {
|
||||||
|
res = await window.fetch('/api/pleroma/emoji.json')
|
||||||
|
}
|
||||||
|
if (res.ok) {
|
||||||
|
const result = await res.json()
|
||||||
|
const values = Array.isArray(result)
|
||||||
|
? Object.assign({}, ...result)
|
||||||
|
: result
|
||||||
|
const caseInsensitiveStrCmp = (a, b) => {
|
||||||
|
const la = a.toLowerCase()
|
||||||
|
const lb = b.toLowerCase()
|
||||||
|
return la > lb ? 1 : la < lb ? -1 : 0
|
||||||
|
}
|
||||||
|
const noPackLast = (a, b) => {
|
||||||
|
const aNull = a === ''
|
||||||
|
const bNull = b === ''
|
||||||
|
if (aNull === bNull) {
|
||||||
|
return 0
|
||||||
|
} else if (aNull && !bNull) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const byPackThenByName = (a, b) => {
|
||||||
|
const packOf = (emoji) =>
|
||||||
|
(emoji.tags.filter((k) => k.startsWith('pack:'))[0] || '').slice(
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
const packOfA = packOf(a)
|
||||||
|
const packOfB = packOf(b)
|
||||||
|
return (
|
||||||
|
noPackLast(packOfA, packOfB) ||
|
||||||
|
caseInsensitiveStrCmp(packOfA, packOfB) ||
|
||||||
|
caseInsensitiveStrCmp(a.displayText, b.displayText)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const emoji = Object.entries(values)
|
||||||
|
.map(([key, value]) => {
|
||||||
|
const imageUrl = value.image_url
|
||||||
|
return {
|
||||||
|
displayText: key,
|
||||||
|
imageUrl: imageUrl
|
||||||
|
? useInstanceStore().server + imageUrl
|
||||||
|
: value,
|
||||||
|
tags: imageUrl
|
||||||
|
? value.tags.sort((a, b) => (a > b ? 1 : 0))
|
||||||
|
: ['utf'],
|
||||||
|
replacement: `:${key}: `,
|
||||||
|
}
|
||||||
|
// Technically could use tags but those are kinda useless right now,
|
||||||
|
// should have been "pack" field, that would be more useful
|
||||||
|
})
|
||||||
|
.sort(byPackThenByName)
|
||||||
|
this.customEmoji = emoji
|
||||||
|
} else {
|
||||||
|
throw res
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Can't load custom emojis\n", e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchEmoji() {
|
||||||
|
if (!this.customEmojiFetched) {
|
||||||
|
this.getCustomEmoji().then(() => (this.customEmojiFetched = true))
|
||||||
|
}
|
||||||
|
if (!this.emojiFetched) {
|
||||||
|
this.getStaticEmoji().then(() => (this.emojiFetched = true))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -129,10 +129,10 @@ export const useInstanceStore = defineStore('instance', {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
set({ path, value }) {
|
set({ path, name, value }) {
|
||||||
if (get(defaultState, path) === undefined)
|
if (get(defaultState, path ?? name) === undefined)
|
||||||
console.error(`Unknown instance option ${path}, value: ${value}`)
|
console.error(`Unknown instance option ${path ?? name}, value: ${value}`)
|
||||||
set(this, path, value)
|
set(this, path ?? name, value)
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'name':
|
case 'name':
|
||||||
useInterfaceStore().setPageTitle()
|
useInterfaceStore().setPageTitle()
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
},
|
},
|
||||||
setPageTitle(option = '') {
|
setPageTitle(option = '') {
|
||||||
try {
|
try {
|
||||||
document.title = `${option} ${window.vuex.useInstanceStore().name}`
|
document.title = `${option} ${useInstanceStore().name}`
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`${error}`)
|
console.error(`${error}`)
|
||||||
}
|
}
|
||||||
|
|
@ -222,14 +222,14 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
async fetchPalettesIndex() {
|
async fetchPalettesIndex() {
|
||||||
try {
|
try {
|
||||||
const value = await getResourcesIndex('/static/palettes/index.json')
|
const value = await getResourcesIndex('/static/palettes/index.json')
|
||||||
window.vuex.commit('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'palettesIndex',
|
name: 'palettesIndex',
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
return value
|
return value
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Could not fetch palettes index', e)
|
console.error('Could not fetch palettes index', e)
|
||||||
window.vuex.commit('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'palettesIndex',
|
name: 'palettesIndex',
|
||||||
value: { _error: e },
|
value: { _error: e },
|
||||||
})
|
})
|
||||||
|
|
@ -258,11 +258,11 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
'/static/styles/index.json',
|
'/static/styles/index.json',
|
||||||
deserialize,
|
deserialize,
|
||||||
)
|
)
|
||||||
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value })
|
useInstanceStore().set({ name: 'stylesIndex', value })
|
||||||
return value
|
return value
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Could not fetch styles index', e)
|
console.error('Could not fetch styles index', e)
|
||||||
window.vuex.commit('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'stylesIndex',
|
name: 'stylesIndex',
|
||||||
value: { _error: e },
|
value: { _error: e },
|
||||||
})
|
})
|
||||||
|
|
@ -296,11 +296,11 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
async fetchThemesIndex() {
|
async fetchThemesIndex() {
|
||||||
try {
|
try {
|
||||||
const value = await getResourcesIndex('/static/styles.json')
|
const value = await getResourcesIndex('/static/styles.json')
|
||||||
window.vuex.commit('setInstanceOption', { name: 'themesIndex', value })
|
useInstanceStore().set({ name: 'themesIndex', value })
|
||||||
return value
|
return value
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Could not fetch themes index', e)
|
console.error('Could not fetch themes index', e)
|
||||||
window.vuex.commit('setInstanceOption', {
|
useInstanceStore().set({
|
||||||
name: 'themesIndex',
|
name: 'themesIndex',
|
||||||
value: { _error: e },
|
value: { _error: e },
|
||||||
})
|
})
|
||||||
|
|
@ -386,14 +386,14 @@ export const useInterfaceStore = defineStore('interface', {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { style: instanceStyleName, palette: instancePaletteName } =
|
const { style: instanceStyleName, palette: instancePaletteName } =
|
||||||
window.vuex.useInstanceStore()
|
useInstanceStore()
|
||||||
|
|
||||||
let {
|
let {
|
||||||
theme: instanceThemeV2Name,
|
theme: instanceThemeV2Name,
|
||||||
themesIndex,
|
themesIndex,
|
||||||
stylesIndex,
|
stylesIndex,
|
||||||
palettesIndex,
|
palettesIndex,
|
||||||
} = window.vuex.useInstanceStore()
|
} = useInstanceStore()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
style: userStyleName,
|
style: userStyleName,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue