diff --git a/build/emojis_plugin.js b/build/emojis_plugin.js index 7979086dd..9872f5331 100644 --- a/build/emojis_plugin.js +++ b/build/emojis_plugin.js @@ -25,7 +25,11 @@ const getAllAccessibleAnnotations = async (projectRoot) => { await access(importFile) return `'${lang}': () => import('${importModule}')` } catch (e) { - console.error(e) + if (e.message.match(/ENOENT/)) { + console.warn(`Missing emoji annotations locale: ${destLang}`) + } else { + console.error('test', e.message) + } return } }), diff --git a/public/static/config.json b/public/static/config.json index 6df21bb9e..8a78284a3 100644 --- a/public/static/config.json +++ b/public/static/config.json @@ -25,7 +25,7 @@ "sidebarRight": false, "subjectLineBehavior": "email", "theme": null, - "style": "BreezyDX", - "palette": "sigsegv2", + "style": null, + "palette": null, "webPushNotifications": false } diff --git a/src/App.js b/src/App.js index 174d91da4..c7862a8fb 100644 --- a/src/App.js +++ b/src/App.js @@ -135,13 +135,11 @@ export default { userBackground() { return this.currentUser.background_image }, + instanceBackground() { + return this.mergedConfig.hideInstanceWallpaper ? null : this.background + }, background() { - return ( - this.userBackground || - (this.mergedConfig.hideInstanceWallpaper - ? null - : this.instanceBackground) - ) + return this.userBackground || this.instanceBackground }, bgStyle() { if (this.background) { @@ -211,7 +209,7 @@ export default { 'editingAvailable', ]), ...mapState(useInstanceStore, { - instanceBackground: (store) => store.instanceIdentity.background, + background: (store) => store.instanceIdentity.background, showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel, instanceSpecificPanelPresent: (store) => store.instanceIdentity.showInstanceSpecificPanel && diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 97f9b8a42..b87ff8924 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -33,6 +33,7 @@ import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInterfaceStore } from 'src/stores/interface.js' import { useOAuthStore } from 'src/stores/oauth' +import { useSyncConfigStore } from 'src/stores/sync_config.js' import VBodyScrollLock from 'src/directives/body_scroll_lock' import { @@ -547,7 +548,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { return Promise.reject(e) } - applyStyleConfig(store.state.config, i18n.global) + applyStyleConfig(useSyncConfigStore().mergedConfig, i18n.global) // Now we can try getting the server settings and logging in // Most of these are preloaded into the index.html so blocking is minimized diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 4917a11fb..23de501de 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -2,6 +2,7 @@ import { take } from 'lodash' import Popover from 'src/components/popover/popover.vue' import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue' +import { ensureFinalFallback } from '../../i18n/languages.js' import Completion from '../../services/completion/completion.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import genRandomSeed from '../../services/random_seed/random_seed.service.js' @@ -10,8 +11,6 @@ import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_i import { useSyncConfigStore } from 'src/stores/sync_config.js' -import { ensureFinalFallback } from 'src/i18n/languages.js' - import { library } from '@fortawesome/fontawesome-svg-core' import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' @@ -137,7 +136,7 @@ const EmojiInput = { return useSyncConfigStore().mergedConfig.padEmoji }, defaultCandidateIndex() { - return useSyncConfigStore().mergedConfig.autocompleteSelect ? 0 : -1 + return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1 }, preText() { return this.modelValue.slice(0, this.caret) @@ -166,7 +165,7 @@ const EmojiInput = { }, languages() { return ensureFinalFallback( - useSyncConfigStore().mergedConfig.interfaceLanguage, + this.$store.getters.mergedConfig.interfaceLanguage, ) }, maybeLocalizedEmojiNamesAndKeywords() { @@ -334,6 +333,7 @@ const EmojiInput = { if (!this.pickerShown) { this.scrollIntoView() this.$refs.picker.showPicker() + this.$refs.picker.startEmojiLoad() } else { this.$refs.picker.hidePicker() } diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index cebabc812..544901ebf 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -81,15 +81,21 @@ const Notifications = { filteredNotifications() { if (this.unseenAtTop) { return [ - ...filteredNotificationsFromStore(this.$store).filter((n) => - this.shouldShowUnseen(n), - ), - ...filteredNotificationsFromStore(this.$store).filter( - (n) => !this.shouldShowUnseen(n), - ), + ...filteredNotificationsFromStore( + this.$store, + useSyncConfigStore().mergedConfig.notificationVisibility, + ).filter((n) => this.shouldShowUnseen(n)), + ...filteredNotificationsFromStore( + this.$store, + useSyncConfigStore().mergedConfig.notificationVisibility, + ).filter((n) => !this.shouldShowUnseen(n)), ] } else { - return filteredNotificationsFromStore(this.$store, this.filterMode) + return filteredNotificationsFromStore( + this.$store, + useSyncConfigStore().mergedConfig.notificationVisibility, + this.filterMode, + ) } }, unseenCountBadgeText() { diff --git a/src/components/still-image/still-image-emoji-popover.js b/src/components/still-image/still-image-emoji-popover.js deleted file mode 100644 index 0d382d357..000000000 --- a/src/components/still-image/still-image-emoji-popover.js +++ /dev/null @@ -1,127 +0,0 @@ -import Popover from 'components/popover/popover.vue' -import SelectComponent from 'components/select/select.vue' -import { assign } from 'lodash' - -import StillImage from './still-image.vue' - -import { useInstanceStore } from 'src/stores/instance.js' -import { useInterfaceStore } from 'src/stores/interface' - -export default { - components: { StillImage, Popover, SelectComponent }, - props: { - shortcode: { - type: String, - required: true, - }, - isLocal: { - type: Boolean, - required: true, - }, - }, - data() { - return { - knownLocalPacks: {}, - packName: '', - } - }, - computed: { - isUserAdmin() { - return this.$store.state.users.currentUser.rights.admin - }, - }, - methods: { - displayError(msg) { - useInterfaceStore().pushGlobalNotice({ - messageKey: 'admin_dash.emoji.error', - messageArgs: [msg], - level: 'error', - }) - }, - copyToLocalPack() { - this.$store.state.api.backendInteractor - .addNewEmojiFile({ - packName: this.packName, - file: this.$attrs.src, - shortcode: this.shortcode, - filename: '', - }) - .then((resp) => resp.json()) - .then((resp) => { - if (resp.error !== undefined) { - this.displayError(resp.error) - return - } - useInterfaceStore().pushGlobalNotice({ - messageKey: 'admin_dash.emoji.copied_successfully', - messageArgs: [this.shortcode, this.packName], - level: 'success', - }) - - this.$refs.emojiPopover.hidePopover() - this.packName = '' - }) - }, - - // Copied from emoji_tab.js - loadPacksPaginated(listFunction) { - const pageSize = 25 - const allPacks = {} - - return listFunction({ - instance: useInstanceStore().server, - page: 1, - pageSize: 0, - }) - .then((data) => data.json()) - .then((data) => { - if (data.error !== undefined) { - return Promise.reject(data.error) - } - - let resultingPromise = Promise.resolve({}) - for (let i = 0; i < Math.ceil(data.count / pageSize); i++) { - resultingPromise = resultingPromise - .then(() => - listFunction({ - instance: useInstanceStore().server, - page: i, - pageSize, - }), - ) - .then((data) => data.json()) - .then((pageData) => { - if (pageData.error !== undefined) { - return Promise.reject(pageData.error) - } - - assign(allPacks, pageData.packs) - }) - } - - return resultingPromise - }) - .then(() => allPacks) - .catch((data) => { - this.displayError(data) - }) - }, - fetchEmojiPacksIfAdmin() { - if (!this.isUserAdmin) return - - this.loadPacksPaginated( - this.$store.state.api.backendInteractor.listEmojiPacks, - ).then((allPacks) => { - // Sort by key - const sorted = Object.keys(allPacks) - .sort() - .reduce((acc, key) => { - if (key.length === 0) return acc - acc[key] = allPacks[key] - return acc - }, {}) - this.knownLocalPacks = sorted - }) - }, - }, -} diff --git a/src/components/timeago/timeago.js b/src/components/timeago/timeago.js index a9e874862..efb92d4cd 100644 --- a/src/components/timeago/timeago.js +++ b/src/components/timeago/timeago.js @@ -1,5 +1,3 @@ -import { useSyncConfigStore } from 'src/stores/sync_config.js' - import * as DateUtils from 'src/services/date_utils/date_utils.js' import localeService from 'src/services/locale/locale.service.js' @@ -15,17 +13,17 @@ export default { }, computed: { shouldUseAbsoluteTimeFormat() { - if (!useSyncConfigStore().mergedConfig.useAbsoluteTimeFormat) { + if (!this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { return false } return ( DateUtils.durationStrToMs( - useSyncConfigStore().mergedConfig.absoluteTimeFormatMinAge, + this.$store.getters.mergedConfig.absoluteTimeFormatMinAge, ) <= this.relativeTimeMs ) }, time12hFormat() { - return useSyncConfigStore().mergedConfig.absoluteTimeFormat12h === '12h' + return this.$store.getters.mergedConfig.absoluteTimeFormat12h === '12h' }, browserLocale() { return localeService.internalToBrowserLocale(this.$i18n.locale) diff --git a/src/lib/language.js b/src/lib/language.js index f8904dd07..68e3a0989 100644 --- a/src/lib/language.js +++ b/src/lib/language.js @@ -1,4 +1,13 @@ +import Cookies from 'js-cookie' + +import { useEmojiStore } from 'src/stores/emoji.js' import { useI18nStore } from 'src/stores/i18n.js' +import { useSyncConfigStore } from 'src/stores/sync_config.js' + +import messages from 'src/i18n/messages' +import localeService from 'src/services/locale/locale.service.js' + +const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage' export const piniaLanguagePlugin = ({ store, options }) => { if (store.$id === 'sync_config') { @@ -7,6 +16,12 @@ export const piniaLanguagePlugin = ({ store, options }) => { const { path, value } = args[0] if (path === 'simple.interfaceLanguage') { useI18nStore().setLanguage(value) + messages.setLanguage(this.i18n, value) + useEmojiStore().loadUnicodeEmojiData(value) + Cookies.set( + BACKEND_LANGUAGE_COOKIE_NAME, + localeService.internalToBackendLocaleMulti(value), + ) } } }) diff --git a/src/lib/push_notifications_plugin.js b/src/lib/push_notifications_plugin.js index 0dfe9588b..7d44625c2 100644 --- a/src/lib/push_notifications_plugin.js +++ b/src/lib/push_notifications_plugin.js @@ -59,10 +59,8 @@ export const piniaPushNotificationsPlugin = ({ store }) => { } if (permissionGranted && enabled && user) { - console.log('piniaReg') return window.vuex.dispatch('registerPushNotifications') } else { - console.log('piniaUnreg') return window.vuex.dispatch('unregisterPushNotifications') } }) @@ -87,10 +85,8 @@ export const vuexPushNotificationsPlugin = (store) => { ) { console.log(!!user, permissionGranted, enabled) if (user && permissionGranted && enabled) { - console.log('vuexReg') return store.dispatch('registerPushNotifications') } else { - console.log('vuexUnreg') return store.dispatch('unregisterPushNotifications') } } diff --git a/src/modules/config_declaration.js b/src/modules/config_declaration.js index 5c0d7ac0e..bf6a5cd7b 100644 --- a/src/modules/config_declaration.js +++ b/src/modules/config_declaration.js @@ -1,3 +1,5 @@ +import { useSyncConfigStore } from 'src/stores/sync_config.js' + export const CONFIG_MIGRATION = 1 import { v4 as uuidv4 } from 'uuid' @@ -22,7 +24,7 @@ export const declarations = [ description: 'Mute filters, wordfilter/regexp/etc', valueType: 'complex', migration(serverside, rootState) { - rootState.config.muteWords.forEach((word, order) => { + useSyncConfigStore().mergedConfig.muteWords.forEach((word, order) => { const uniqueId = uuidv4() serverside.setPreference({ diff --git a/src/modules/users.js b/src/modules/users.js index ea2a0ccb4..a22c157ed 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -553,9 +553,9 @@ const users = { registerPushNotifications(store) { const token = store.state.currentUser.credentials const vapidPublicKey = useInstanceStore().vapidPublicKey - const isEnabled = store.rootState.config.webPushNotifications + const isEnabled = useSyncConfigStore().mergedConfig.webPushNotifications const notificationVisibility = - store.rootState.config.notificationVisibility + useSyncConfigStore().mergedConfig.notificationVisibility registerPushNotifications( isEnabled, diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js index 14785a685..e5baa9a20 100644 --- a/src/services/notification_utils/notification_utils.js +++ b/src/services/notification_utils/notification_utils.js @@ -16,12 +16,7 @@ let cachedBadgeUrl = null export const notificationsFromStore = (store) => store.state.notifications.data -export const visibleTypes = (store) => { - // When called from within a module we need rootGetters to access wider scope - // however when called from a component (i.e. this.$store) we already have wider scope - const rootGetters = store.rootGetters || store.getters - const { notificationVisibility } = rootGetters.mergedConfig - +const visibleTypes = (notificationVisibility) => { return [ notificationVisibility.likes && 'like', notificationVisibility.mentions && 'mention', @@ -76,11 +71,15 @@ const isMutedNotification = (notification) => { return muteFilterHits(notification.status).length > 0 } -export const maybeShowNotification = (store, notification) => { +export const maybeShowNotification = ( + store, + notificationVisibility, + notification, +) => { const rootState = store.rootState || store.state if (notification.seen) return - if (!visibleTypes(store).includes(notification.type)) return + if (!visibleTypes(notificationVisibility).includes(notification.type)) return if (notification.type === 'mention' && isMutedNotification(notification)) return @@ -91,14 +90,18 @@ export const maybeShowNotification = (store, notification) => { showDesktopNotification(rootState, notificationObject) } -export const filteredNotificationsFromStore = (store, types) => { +export const filteredNotificationsFromStore = ( + store, + notificationVisibility, + types, +) => { // map is just to clone the array since sort mutates it and it causes some issues const sortedNotifications = notificationsFromStore(store) .map((_) => _) .sort(sortById) // TODO implement sorting elsewhere and make it optional return sortedNotifications.filter((notification) => - (types || visibleTypes(store)).includes(notification.type), + (types || visibleTypes(notificationVisibility)).includes(notification.type), ) } diff --git a/src/stores/i18n.js b/src/stores/i18n.js index a18b1d4d2..fee09f4bd 100644 --- a/src/stores/i18n.js +++ b/src/stores/i18n.js @@ -1,14 +1,6 @@ import Cookies from 'js-cookie' import { defineStore } from 'pinia' -import { useEmojiStore } from 'src/stores/emoji.js' -import { useSyncConfigStore } from 'src/stores/sync_config.js' - -import messages from 'src/i18n/messages' -import localeService from 'src/services/locale/locale.service.js' - -const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage' - export const useI18nStore = defineStore('i18n', { state: () => ({ i18n: null, @@ -19,16 +11,5 @@ export const useI18nStore = defineStore('i18n', { i18n: newI18n.global, }) }, - setLanguage(originalValue) { - const value = - originalValue || useSyncConfigStore().mergedConfig.interfaceLanguage - - messages.setLanguage(this.i18n, value) - useEmojiStore().loadUnicodeEmojiData(value) - Cookies.set( - BACKEND_LANGUAGE_COOKIE_NAME, - localeService.internalToBackendLocaleMulti(value), - ) - }, }, }) diff --git a/src/stores/interface.js b/src/stores/interface.js index 8d05ce44b..dfe788262 100644 --- a/src/stores/interface.js +++ b/src/stores/interface.js @@ -8,6 +8,7 @@ import { import { deserialize } from '../services/theme_data/iss_deserializer.js' import { useInstanceStore } from 'src/stores/instance.js' +import { useSyncConfigStore } from 'src/stores/sync_config.js' import { CURRENT_VERSION, @@ -402,13 +403,13 @@ export const useInterfaceStore = defineStore('interface', { styleCustomData: userStyleCustomData, palette: userPaletteName, paletteCustomData: userPaletteCustomData, - } = window.vuex.state.config + } = useSyncConfigStore().mergedConfig let { theme: userThemeV2Name, customTheme: userThemeV2Snapshot, customThemeSource: userThemeV2Source, - } = window.vuex.state.config + } = useSyncConfigStore().mergedConfig let majorVersionUsed @@ -573,7 +574,7 @@ export const useInterfaceStore = defineStore('interface', { }, async applyTheme({ recompile = false } = {}) { const { forceThemeRecompilation, themeDebug, theme3hacks } = - window.vuex.state.config + useSyncConfigStore().mergedConfig this.themeChangeInProgress = true // If we're not forced to recompile try using // cache (tryLoadCache return true if load successful) diff --git a/src/sw.js b/src/sw.js index 3e22cca68..e3225c91d 100644 --- a/src/sw.js +++ b/src/sw.js @@ -4,11 +4,10 @@ import 'virtual:pleroma-fe/service_worker_env' import { createI18n } from 'vue-i18n' -import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js' -import { prepareNotificationObject } from './services/notification_utils/notification_utils.js' -import { cacheKey, emojiCacheKey, shouldCache } from './services/sw/sw.js' - import { storage } from 'src/lib/storage.js' +import { parseNotification } from 'src/services/entity_normalizer/entity_normalizer.service.js' +import { prepareNotificationObject } from 'src/services/notification_utils/notification_utils.js' +import { cacheKey, emojiCacheKey, shouldCache } from 'src/services/sw/sw.js' // Collects all messages for service workers // Needed because service workers cannot use dynamic imports @@ -39,7 +38,7 @@ const setSettings = async () => { const locale = vuexState.config.interfaceLanguage || 'en' i18n.locale = locale const notificationsNativeArray = Object.entries( - vuexState.config.notificationNative || {}, + vuexState.config.notificationNative, ) state.webPushAlwaysShowNotifications = vuexState.config.webPushAlwaysShowNotifications diff --git a/test/unit/specs/components/draft.spec.js b/test/unit/specs/components/draft.spec.js index 7bc053f52..386b2a761 100644 --- a/test/unit/specs/components/draft.spec.js +++ b/test/unit/specs/components/draft.spec.js @@ -1,10 +1,13 @@ import { createTestingPinia } from '@pinia/testing' import { flushPromises, mount } from '@vue/test-utils' +import { setActivePinia } from 'pinia' import { nextTick } from 'vue' import PostStatusForm from 'src/components/post_status_form/post_status_form.vue' import { $t, mountOpts, waitForEvent } from '../../../fixtures/setup_test' +import { useSyncConfigStore } from 'src/stores/sync_config.js' + const autoSaveOrNot = (caseFn, caseTitle, runFn) => { caseFn(`${caseTitle} with auto-save`, function () { return runFn.bind(this)(true) @@ -36,17 +39,19 @@ afterEach(() => { }) describe('Draft saving', () => { - createTestingPinia() + beforeEach(() => { + setActivePinia(createTestingPinia()) + }) autoSaveOrNot( it, 'should save when the button is clicked', async (autoSave) => { const wrapper = mount(PostStatusForm, mountOpts()) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: autoSave, - }) + const store = useSyncConfigStore() + store.mergedConfig = { + autoSaveDraft: autoSave, + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') @@ -63,10 +68,10 @@ describe('Draft saving', () => { it('should auto-save if it is enabled', async function () { vi.useFakeTimers() const wrapper = mount(PostStatusForm, mountOpts()) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: true, - }) + const store = useSyncConfigStore() + store.mergedConfig = { + autoSaveDraft: true, + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') await textarea.setValue('mew mew') @@ -86,10 +91,10 @@ describe('Draft saving', () => { }, }), ) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: true, - }) + const store = useSyncConfigStore() + store.mergedConfig = { + autoSaveDraft: true, + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') await textarea.setValue('mew mew') @@ -107,14 +112,11 @@ describe('Draft saving', () => { }, }), ) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: false, - }) - await wrapper.vm.$store.dispatch('setOption', { - name: 'unsavedPostAction', - value: 'save', - }) + const store = useSyncConfigStore() + store.mergedConfig = { + autoSaveDraft: false, + unsavedPostAction: 'save', + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') await textarea.setValue('mew mew') @@ -132,14 +134,11 @@ describe('Draft saving', () => { }, }), ) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: false, - }) - await wrapper.vm.$store.dispatch('setOption', { - name: 'unsavedPostAction', - value: 'discard', - }) + const store = useSyncConfigStore() + store.mergedConfig = { + autoSaveDraft: false, + unsavedPostAction: 'discard', + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') await textarea.setValue('mew mew') @@ -157,14 +156,11 @@ describe('Draft saving', () => { }, }), ) - await wrapper.vm.$store.dispatch('setOption', { - name: 'autoSaveDraft', - value: false, - }) - await wrapper.vm.$store.dispatch('setOption', { - name: 'unsavedPostAction', - value: 'confirm', - }) + const store = useSyncConfigStore(createTestingPinia()) + store.mergedConfig = { + autoSaveDraft: false, + unsavedPostAction: 'confirm', + } expect(wrapper.vm.$store.getters.draftCount).to.equal(0) const textarea = wrapper.get('textarea') await textarea.setValue('mew mew') diff --git a/test/unit/specs/services/notification_utils/notification_utils.spec.js b/test/unit/specs/services/notification_utils/notification_utils.spec.js index 2bfd3c4a1..0db318e3c 100644 --- a/test/unit/specs/services/notification_utils/notification_utils.spec.js +++ b/test/unit/specs/services/notification_utils/notification_utils.spec.js @@ -40,9 +40,6 @@ describe('NotificationUtils', () => { ], }, }, - getters: { - mergedConfig: {}, - }, } const expected = [ {