MASSIVE refactor, replacing instance module with store, separating emoji stuff into its own store, making sure everything refers to new stores (WIP)

This commit is contained in:
Henry Jameson 2026-01-22 17:16:51 +02:00
commit 5bdf341560
95 changed files with 801 additions and 833 deletions

View file

@ -3,7 +3,7 @@ import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import DesktopNav from './components/desktop_nav/desktop_nav.vue' import DesktopNav from './components/desktop_nav/desktop_nav.vue'
import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
import FeaturesPanel from './components/features_panel/features_panel.vue' import FeaturesPanel from './components/features_panel/features_panel.vue'
@ -22,9 +22,9 @@ import UserReportingModal from './components/user_reporting_modal/user_reporting
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import { getOrCreateServiceWorker } from './services/sw/sw' import { getOrCreateServiceWorker } from './services/sw/sw'
import { windowHeight, windowWidth } from './services/window_utils/window_utils' import { windowHeight, windowWidth } from './services/window_utils/window_utils'
import { useInstanceStore } from './stores/instance' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from './stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { useShoutStore } from './stores/shout' import { useShoutStore } from 'src/stores/shout.js'
export default { export default {
name: 'app', name: 'app',
@ -70,9 +70,6 @@ export default {
}, },
}, },
created() { created() {
// Load the locale from the storage
const val = this.$store.getters.mergedConfig.interfaceLanguage
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
document.getElementById('modal').classList = ['-' + this.layoutType] document.getElementById('modal').classList = ['-' + this.layoutType]
// Create bound handlers // Create bound handlers
@ -124,7 +121,7 @@ export default {
] ]
}, },
navClasses() { navClasses() {
const { navbarColumnStretch } = this.$store.getters.mergedConfig const { navbarColumnStretch } = useSyncConfigStore().mergedConfig
return [ return [
'-' + this.layoutType, '-' + this.layoutType,
...(navbarColumnStretch ? ['-column-stretch'] : []), ...(navbarColumnStretch ? ['-column-stretch'] : []),
@ -159,19 +156,19 @@ export default {
if (this.isChats) return false if (this.isChats) return false
if (this.isListEdit) return false if (this.isListEdit) return false
return ( return (
this.$store.getters.mergedConfig.alwaysShowNewPostButton || useSyncConfigStore().mergedConfig.alwaysShowNewPostButton ||
this.layoutType === 'mobile' this.layoutType === 'mobile'
) )
}, },
shoutboxPosition() { shoutboxPosition() {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false return useSyncConfigStore().mergedConfig.alwaysShowNewPostButton || false
}, },
layoutType() { layoutType() {
return useInterfaceStore().layoutType return useInterfaceStore().layoutType
}, },
reverseLayout() { reverseLayout() {
const { thirdColumnMode, sidebarRight: reverseSetting } = const { thirdColumnMode, sidebarRight: reverseSetting } =
this.$store.getters.mergedConfig useSyncConfigStore().mergedConfig
if (this.layoutType !== 'wide') { if (this.layoutType !== 'wide') {
return reverseSetting return reverseSetting
} else { } else {
@ -181,16 +178,16 @@ export default {
} }
}, },
noSticky() { noSticky() {
return this.$store.getters.mergedConfig.disableStickyHeaders return useSyncConfigStore().mergedConfig.disableStickyHeaders
}, },
showScrollbars() { showScrollbars() {
return this.$store.getters.mergedConfig.showScrollbars return useSyncConfigStore().mergedConfig.showScrollbars
}, },
scrollParent() { scrollParent() {
return window /* this.$refs.appContentRef */ return window /* this.$refs.appContentRef */
}, },
...mapGetters(['mergedConfig']), ...mapGetters(['mergedConfig']),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
hideShoutbox: (store) => store.mergedConfig.hideShoutbox, hideShoutbox: (store) => store.mergedConfig.hideShoutbox,
}), }),
...mapState(useInstanceStore, { ...mapState(useInstanceStore, {
@ -198,7 +195,7 @@ export default {
this.mergedConfig.hideInstanceWallpaper ? null : store.background, this.mergedConfig.hideInstanceWallpaper ? null : store.background,
showInstanceSpecificPanel: (store) => showInstanceSpecificPanel: (store) =>
store.showInstanceSpecificPanel && store.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP && !useSyncConfigStore().mergedConfig.hideISP &&
store.instanceSpecificPanelContent, store.instanceSpecificPanelContent,
}), }),
...mapState(useInstanceStore, [ ...mapState(useInstanceStore, [

View file

@ -542,6 +542,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
? overrides.target ? overrides.target
: window.location.origin : window.location.origin
useInstanceStore().set({ path: 'server', value: server }) useInstanceStore().set({ path: 'server', value: server })
console.log('AFTER', useInstanceStore().server, server)
await setConfig({ store }) await setConfig({ store })
try { try {

View file

@ -28,12 +28,11 @@ import UserProfile from 'components/user_profile/user_profile.vue'
import WhoToFollow from 'components/who_to_follow/who_to_follow.vue' import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue' import NavPanel from 'src/components/nav_panel/nav_panel.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue' import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue'
import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue' import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue'
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue' import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
import { useInstanceStore } from 'src/stores/instance.js'
export default (store) => { export default (store) => {
const validateAuthenticatedRoute = (to, from, next) => { const validateAuthenticatedRoute = (to, from, next) => {
if (store.state.users.currentUser) { if (store.state.users.currentUser) {

View file

@ -1,3 +1,5 @@
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import FeaturesPanel from '../features_panel/features_panel.vue' import FeaturesPanel from '../features_panel/features_panel.vue'
import InstanceSpecificPanel from '../instance_specific_panel/instance_specific_panel.vue' import InstanceSpecificPanel from '../instance_specific_panel/instance_specific_panel.vue'
import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue' import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue'
@ -14,13 +16,13 @@ const About = {
}, },
computed: { computed: {
showFeaturesPanel() { showFeaturesPanel() {
return this.$store.state.instance.showFeaturesPanel return useInstanceStore().showFeaturesPanel
}, },
showInstanceSpecificPanel() { showInstanceSpecificPanel() {
return ( return (
this.$store.state.instance.showInstanceSpecificPanel && useInstanceStore().showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP && !useSyncConfigStore().mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent useInstanceStore().instanceSpecificPanelContent
) )
}, },
}, },

View file

@ -3,6 +3,7 @@ import { mapState } from 'vuex'
import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue' import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue'
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
import { useReportsStore } from 'src/stores/reports' import { useReportsStore } from 'src/stores/reports'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import ProgressButton from '../progress_button/progress_button.vue' import ProgressButton from '../progress_button/progress_button.vue'
@ -87,10 +88,10 @@ const AccountActions = {
}, },
computed: { computed: {
shouldConfirmBlock() { shouldConfirmBlock() {
return this.$store.getters.mergedConfig.modalOnBlock return useSyncConfigStore().mergedConfig.modalOnBlock
}, },
shouldConfirmRemoveUserFromFollowers() { shouldConfirmRemoveUserFromFollowers() {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers return useSyncConfigStore().mergedConfig.modalOnRemoveUserFromFollowers
}, },
...mapState({ ...mapState({
blockExpirationSupported: (state) => state.instance.blockExpiration, blockExpirationSupported: (state) => state.instance.blockExpiration,

View file

@ -1,6 +1,8 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { useInstanceStore } from 'src/stores/instance.js'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import nsfwImage from '../../assets/nsfw.png' import nsfwImage from '../../assets/nsfw.png'
import fileTypeService from '../../services/file_type/file_type.service.js' import fileTypeService from '../../services/file_type/file_type.service.js'
import Flash from '../flash/flash.vue' import Flash from '../flash/flash.vue'
@ -53,9 +55,9 @@ const Attachment = {
data() { data() {
return { return {
localDescription: this.description || this.attachment.description, localDescription: this.description || this.attachment.description,
nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage, nsfwImage: useInstanceStore().nsfwCensorImage || nsfwImage,
hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw, hideNsfwLocal: useSyncConfigStore().mergedConfig.hideNsfw,
preloadImage: this.$store.getters.mergedConfig.preloadImage, preloadImage: useSyncConfigStore().mergedConfig.preloadImage,
loading: false, loading: false,
img: img:
fileTypeService.fileType(this.attachment.mimetype) === 'image' && fileTypeService.fileType(this.attachment.mimetype) === 'image' &&
@ -89,7 +91,7 @@ const Attachment = {
return this.size === 'hide' return this.size === 'hide'
}, },
useContainFit() { useContainFit() {
return this.$store.getters.mergedConfig.useContainFit return useSyncConfigStore().mergedConfig.useContainFit
}, },
placeholderName() { placeholderName() {
if (this.attachment.description === '' || !this.attachment.description) { if (this.attachment.description === '' || !this.attachment.description) {
@ -104,7 +106,7 @@ const Attachment = {
return 'file' return 'file'
}, },
referrerpolicy() { referrerpolicy() {
return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer' return useInstanceStore().mediaProxyAvailable ? '' : 'no-referrer'
}, },
type() { type() {
return fileTypeService.fileType(this.attachment.mimetype) return fileTypeService.fileType(this.attachment.mimetype)

View file

@ -1,4 +1,5 @@
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
const AvatarList = { const AvatarList = {
@ -16,7 +17,7 @@ const AvatarList = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
}, },

View file

@ -1,5 +1,6 @@
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import UserLink from '../user_link/user_link.vue' import UserLink from '../user_link/user_link.vue'
import UserPopover from '../user_popover/user_popover.vue' import UserPopover from '../user_popover/user_popover.vue'
@ -17,7 +18,7 @@ const BasicUserCard = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
}, },

View file

@ -2,7 +2,9 @@ import { clone, filter, findIndex, get, reduce } from 'lodash'
import { mapState as mapPiniaState } from 'pinia' import { mapState as mapPiniaState } from 'pinia'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { WSConnectionStatus } from '../../services/api/api.service.js' import { WSConnectionStatus } from '../../services/api/api.service.js'
import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue'
import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue' import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue'
@ -80,7 +82,7 @@ const conversation = {
// maxDepthInThread = max number of depths that is *visible* // maxDepthInThread = max number of depths that is *visible*
// since our depth starts with 0 and "showing" means "showing children" // since our depth starts with 0 and "showing" means "showing children"
// there is a -2 here // there is a -2 here
const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2 const maxDepth = useSyncConfigStore().mergedConfig.maxDepthInThread - 2
return maxDepth >= 1 ? maxDepth : 1 return maxDepth >= 1 ? maxDepth : 1
}, },
streamingEnabled() { streamingEnabled() {
@ -90,22 +92,22 @@ const conversation = {
) )
}, },
displayStyle() { displayStyle() {
return this.$store.getters.mergedConfig.conversationDisplay return useSyncConfigStore().mergedConfig.conversationDisplay
}, },
isTreeView() { isTreeView() {
return !this.isLinearView return !this.isLinearView
}, },
treeViewIsSimple() { treeViewIsSimple() {
return !this.$store.getters.mergedConfig.conversationTreeAdvanced return !useSyncConfigStore().mergedConfig.conversationTreeAdvanced
}, },
isLinearView() { isLinearView() {
return this.displayStyle === 'linear' return this.displayStyle === 'linear'
}, },
shouldFadeAncestors() { shouldFadeAncestors() {
return this.$store.getters.mergedConfig.conversationTreeFadeAncestors return useSyncConfigStore().mergedConfig.conversationTreeFadeAncestors
}, },
otherRepliesButtonPosition() { otherRepliesButtonPosition() {
return this.$store.getters.mergedConfig.conversationOtherRepliesButton return useSyncConfigStore().mergedConfig.conversationOtherRepliesButton
}, },
showOtherRepliesButtonBelowStatus() { showOtherRepliesButtonBelowStatus() {
return this.otherRepliesButtonPosition === 'below' return this.otherRepliesButtonPosition === 'below'

View file

@ -1,6 +1,9 @@
import SearchBar from 'components/search_bar/search_bar.vue' import SearchBar from 'components/search_bar/search_bar.vue'
import { mapState } from 'pinia'
import { useInterfaceStore } from 'src/stores/interface' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -31,6 +34,14 @@ library.add(
faCog, faCog,
faInfoCircle, faInfoCircle,
) )
const supportsMask =
window.CSS &&
window.CSS.supports &&
(window.CSS.supports('mask-size', 'contain') ||
window.CSS.supports('-webkit-mask-size', 'contain') ||
window.CSS.supports('-moz-mask-size', 'contain') ||
window.CSS.supports('-ms-mask-size', 'contain') ||
window.CSS.supports('-o-mask-size', 'contain'))
export default { export default {
components: { components: {
@ -39,68 +50,51 @@ export default {
}, },
data: () => ({ data: () => ({
searchBarHidden: true, searchBarHidden: true,
supportsMask:
window.CSS &&
window.CSS.supports &&
(window.CSS.supports('mask-size', 'contain') ||
window.CSS.supports('-webkit-mask-size', 'contain') ||
window.CSS.supports('-moz-mask-size', 'contain') ||
window.CSS.supports('-ms-mask-size', 'contain') ||
window.CSS.supports('-o-mask-size', 'contain')),
showingConfirmLogout: false, showingConfirmLogout: false,
}), }),
computed: { computed: {
enableMask() {
return this.supportsMask && this.$store.state.instance.logoMask
},
logoStyle() { logoStyle() {
return { return {
visibility: this.enableMask ? 'hidden' : 'visible', visibility: this.logoMask ? 'hidden' : 'visible',
} }
}, },
logoMaskStyle() { logoMaskStyle() {
return this.enableMask return this.logoMask
? { ? {
'mask-image': `url(${this.$store.state.instance.logo})`, 'mask-image': `url(${this.logo})`,
} }
: { : {
'background-color': this.enableMask ? '' : 'transparent', 'background-color': this.logoMask ? '' : 'transparent',
} }
}, },
logoBgStyle() { logoBgStyle() {
return Object.assign( return Object.assign(
{ {
margin: `${this.$store.state.instance.logoMargin} 0`, margin: `${this.logoMargin} 0`,
opacity: this.searchBarHidden ? 1 : 0, opacity: this.searchBarHidden ? 1 : 0,
}, },
this.enableMask this.logoMask
? {} ? {}
: { : {
'background-color': this.enableMask ? '' : 'transparent', 'background-color': this.logoMask ? '' : 'transparent',
}, },
) )
}, },
logo() {
return this.$store.state.instance.logo
},
sitename() {
return this.$store.state.instance.name
},
hideSitename() {
return this.$store.state.instance.hideSitename
},
logoLeft() {
return this.$store.state.instance.logoLeft
},
currentUser() { currentUser() {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
privateMode() {
return this.$store.state.instance.private
},
shouldConfirmLogout() { shouldConfirmLogout() {
return this.$store.getters.mergedConfig.modalOnLogout return useSyncConfigStore().mergedConfig.modalOnLogout
}, },
...mapState(useInstanceStore, {
logo: (state) => state.instanceIdentity.logo,
logoMask: (state) => supportsMask && state.instanceIdentity.logoMask,
logoLeft: (state) => state.instanceIdentity.logoLeft,
logoMargin: (state) => state.instanceIdentity.logoMargin,
sitename: (state) => state.instanceIdentity.name,
privateMode: (state) => state.private,
hideSitename: (state) => state.instanceIdentity.hideSitename,
}),
}, },
methods: { methods: {
scrollToTop() { scrollToTop() {

View file

@ -1,3 +1,5 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const DialogModal = { const DialogModal = {
props: { props: {
darkOverlay: { darkOverlay: {
@ -13,7 +15,7 @@ const DialogModal = {
}, },
computed: { computed: {
mobileCenter() { mobileCenter() {
return this.$store.getters.mergedConfig.modalMobileCenter return useSyncConfigStore().mergedConfig.modalMobileCenter
}, },
}, },
} }

View file

@ -5,6 +5,7 @@ import EditStatusForm from 'src/components/edit_status_form/edit_status_form.vue
import Gallery from 'src/components/gallery/gallery.vue' import Gallery from 'src/components/gallery/gallery.vue'
import PostStatusForm from 'src/components/post_status_form/post_status_form.vue' import PostStatusForm from 'src/components/post_status_form/post_status_form.vue'
import StatusContent from 'src/components/status_content/status_content.vue' import StatusContent from 'src/components/status_content/status_content.vue'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faPollH } from '@fortawesome/free-solid-svg-icons' import { faPollH } from '@fortawesome/free-solid-svg-icons'
@ -57,7 +58,7 @@ const Draft = {
: undefined : undefined
}, },
localCollapseSubjectDefault() { localCollapseSubjectDefault() {
return this.$store.getters.mergedConfig.collapseMessageWithSubject return useSyncConfigStore().mergedConfig.collapseMessageWithSubject
}, },
nsfwClickthrough() { nsfwClickthrough() {
if (!this.draft.nsfw) { if (!this.draft.nsfw) {

View file

@ -1,4 +1,5 @@
import DialogModal from 'src/components/dialog_modal/dialog_modal.vue' import DialogModal from 'src/components/dialog_modal/dialog_modal.vue'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const DraftCloser = { const DraftCloser = {
data() { data() {
@ -12,10 +13,10 @@ const DraftCloser = {
emits: ['save', 'discard'], emits: ['save', 'discard'],
computed: { computed: {
action() { action() {
if (this.$store.getters.mergedConfig.autoSaveDraft) { if (useSyncConfigStore().mergedConfig.autoSaveDraft) {
return 'save' return 'save'
} else { } else {
return this.$store.getters.mergedConfig.unsavedPostAction return useSyncConfigStore().mergedConfig.unsavedPostAction
} }
}, },
shouldConfirm() { shouldConfirm() {

View file

@ -2,7 +2,8 @@ import { take } from 'lodash'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue' import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue'
import { ensureFinalFallback } from '../../i18n/languages.js' import { ensureFinalFallback } from 'src/i18n/languages.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import Completion from '../../services/completion/completion.js' import Completion from '../../services/completion/completion.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
import genRandomSeed from '../../services/random_seed/random_seed.service.js' import genRandomSeed from '../../services/random_seed/random_seed.service.js'
@ -131,10 +132,10 @@ const EmojiInput = {
}, },
computed: { computed: {
padEmoji() { padEmoji() {
return this.$store.getters.mergedConfig.padEmoji return useSyncConfigStore().mergedConfig.padEmoji
}, },
defaultCandidateIndex() { defaultCandidateIndex() {
return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1 return useSyncConfigStore().mergedConfig.autocompleteSelect ? 0 : -1
}, },
preText() { preText() {
return this.modelValue.slice(0, this.caret) return this.modelValue.slice(0, this.caret)
@ -163,7 +164,7 @@ const EmojiInput = {
}, },
languages() { languages() {
return ensureFinalFallback( return ensureFinalFallback(
this.$store.getters.mergedConfig.interfaceLanguage, useSyncConfigStore().mergedConfig.interfaceLanguage,
) )
}, },
maybeLocalizedEmojiNamesAndKeywords() { maybeLocalizedEmojiNamesAndKeywords() {
@ -331,7 +332,6 @@ const EmojiInput = {
if (!this.pickerShown) { if (!this.pickerShown) {
this.scrollIntoView() this.scrollIntoView()
this.$refs.picker.showPicker() this.$refs.picker.showPicker()
this.$refs.picker.startEmojiLoad()
} else { } else {
this.$refs.picker.hidePicker() this.$refs.picker.hidePicker()
} }

View file

@ -1,8 +1,10 @@
import { useEmojiStore } from 'src/stores/emoji.js'
/** /**
* 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
* *

View file

@ -2,7 +2,10 @@ import { chunk, debounce, trim } from 'lodash'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import { ensureFinalFallback } from '../../i18n/languages.js' import { ensureFinalFallback } from 'src/i18n/languages.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useSyncConfigStore } from 'src/stores/sync_config.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'
@ -337,7 +340,7 @@ const EmojiPicker = {
this.$nextTick(() => { this.$nextTick(() => {
this.updateEmojiSize() this.updateEmojiSize()
}) })
return this.$store.getters.mergedConfig.fontSize return useSyncConfigStore().mergedConfig.fontSize
}, },
emojiHeight() { emojiHeight() {
return this.emojiSize return this.emojiSize
@ -349,8 +352,8 @@ const EmojiPicker = {
return this.showingStickers ? '' : this.activeGroup return this.showingStickers ? '' : this.activeGroup
}, },
stickersAvailable() { stickersAvailable() {
if (this.$store.state.instance.stickers) { if (useInstanceStore().stickers) {
return this.$store.state.instance.stickers.length > 0 return useInstanceStore().stickers.length > 0
} }
return 0 return 0
}, },
@ -358,7 +361,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')
} }
@ -368,7 +371,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],
@ -381,7 +384,7 @@ const EmojiPicker = {
.concat(this.unicodeEmojiGroups) .concat(this.unicodeEmojiGroups)
}, },
stickerPickerEnabled() { stickerPickerEnabled() {
return (this.$store.state.instance.stickers || []).length !== 0 return (useInstanceStore().stickers || []).length !== 0
}, },
debouncedHandleKeywordChange() { debouncedHandleKeywordChange() {
return debounce(() => { return debounce(() => {
@ -402,7 +405,7 @@ const EmojiPicker = {
}, },
languages() { languages() {
return ensureFinalFallback( return ensureFinalFallback(
this.$store.getters.mergedConfig.interfaceLanguage, useSyncConfigStore().mergedConfig.interfaceLanguage,
) )
}, },
maybeLocalizedEmojiName() { maybeLocalizedEmojiName() {

View file

@ -1,8 +1,9 @@
import { mapState as mapPiniaState } from 'pinia' import { mapState } from 'pinia'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -51,10 +52,11 @@ const ExtraNotifications = {
currentUser() { currentUser() {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
...mapGetters(['unreadChatCount', 'followRequestCount', 'mergedConfig']), ...mapGetters(['unreadChatCount', 'followRequestCount']),
...mapPiniaState(useAnnouncementsStore, { ...mapState(useAnnouncementsStore, {
unreadAnnouncementCount: 'unreadAnnouncementCount', unreadAnnouncementCount: 'unreadAnnouncementCount',
}), }),
...mapState(useSyncConfigStore, ['mergedConfig']),
}, },
methods: { methods: {
openNotificationSettings() { openNotificationSettings() {

View file

@ -1,31 +1,32 @@
import { useInstanceStore } from 'src/stores/instance.js'
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
const FeaturesPanel = { const FeaturesPanel = {
computed: { computed: {
shout: function () { shout: function () {
return this.$store.state.instance.shoutAvailable return useInstanceStore().shoutAvailable
}, },
pleromaChatMessages: function () { pleromaChatMessages: function () {
return this.$store.state.instance.pleromaChatMessagesAvailable return useInstanceStore().pleromaChatMessagesAvailable
}, },
gopher: function () { gopher: function () {
return this.$store.state.instance.gopherAvailable return useInstanceStore().gopherAvailable
}, },
whoToFollow: function () { whoToFollow: function () {
return this.$store.state.instance.suggestionsEnabled return useInstanceStore().suggestionsEnabled
}, },
mediaProxy: function () { mediaProxy: function () {
return this.$store.state.instance.mediaProxyAvailable return useInstanceStore().mediaProxyAvailable
}, },
minimalScopesMode: function () { minimalScopesMode: function () {
return this.$store.state.instance.minimalScopesMode return useInstanceStore().minimalScopesMode
}, },
textlimit: function () { textlimit: function () {
return this.$store.state.instance.textlimit return useInstanceStore().textlimit
}, },
uploadlimit: function () { uploadlimit: function () {
return fileSizeFormatService.fileSizeFormat( return fileSizeFormatService.fileSizeFormat(
this.$store.state.instance.uploadlimit, useInstanceStore().uploadlimit,
) )
}, },
}, },

View file

@ -1,3 +1,4 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { import {
requestFollow, requestFollow,
requestUnfollow, requestUnfollow,
@ -16,7 +17,7 @@ export default {
}, },
computed: { computed: {
shouldConfirmUnfollow() { shouldConfirmUnfollow() {
return this.$store.getters.mergedConfig.modalOnUnfollow return useSyncConfigStore().mergedConfig.modalOnUnfollow
}, },
isPressed() { isPressed() {
return this.inProgress || this.relationship.following return this.inProgress || this.relationship.following

View file

@ -1,3 +1,4 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js' import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
@ -76,7 +77,7 @@ const FollowRequestCard = {
}, },
computed: { computed: {
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useSyncConfigStore().mergedConfig
}, },
shouldConfirmApprove() { shouldConfirmApprove() {
return this.mergedConfig.modalOnApproveFollow return this.mergedConfig.modalOnApproveFollow

View file

@ -1,7 +1,9 @@
import { useInstanceStore } from 'src/stores/instance.js'
const InstanceSpecificPanel = { const InstanceSpecificPanel = {
computed: { computed: {
instanceSpecificPanelContent() { instanceSpecificPanelContent() {
return this.$store.state.instance.instanceSpecificPanelContent return useInstanceStore().instanceSpecificPanelContent
}, },
}, },
} }

View file

@ -1,5 +1,4 @@
/* eslint-env browser */ import { useSyncConfigStore } from 'src/stores/sync_config.js'
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
import statusPosterService from '../../services/status_poster/status_poster.service.js' import statusPosterService from '../../services/status_poster/status_poster.service.js'
@ -33,7 +32,7 @@ const mediaUpload = {
} }
// Skip if image compression is disabled // Skip if image compression is disabled
if (!this.$store.getters.mergedConfig.imageCompression) { if (!useSyncConfigStore().mergedConfig.imageCompression) {
return file return file
} }
@ -78,7 +77,7 @@ const mediaUpload = {
// Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG // Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG
const type = const type =
!this.$store.getters.mergedConfig.alwaysUseJpeg && supportsWebP !useSyncConfigStore().mergedConfig.alwaysUseJpeg && supportsWebP
? 'image/webp' ? 'image/webp'
: 'image/jpeg' : 'image/jpeg'
const extension = type === 'image/webp' ? '.webp' : '.jpg' const extension = type === 'image/webp' ? '.webp' : '.jpg'

View file

@ -1,6 +1,8 @@
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { mapState as mapPiniaState } from 'pinia'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { import {
highlightClass, highlightClass,
@ -97,7 +99,7 @@ const MentionLink = {
return this.user && this.user.screen_name_ui return this.user && this.user.screen_name_ui
}, },
highlight() { highlight() {
return this.user && this.mergedConfig.highlight[this.user.screen_name] return this.user && useSyncConfigStore().mergedConfig.highlight[this.user.screen_name]
}, },
highlightType() { highlightType() {
return this.highlight && '-' + this.highlight.type return this.highlight && '-' + this.highlight.type
@ -130,7 +132,7 @@ const MentionLink = {
return this.userName !== this.userNameFull return this.userName !== this.userNameFull
}, },
shouldShowFullUserName() { shouldShowFullUserName() {
const conf = this.mergedConfig.mentionLinkDisplay const conf = useSyncConfigStore().mergedConfig.mentionLinkDisplay
if (conf === 'short') { if (conf === 'short') {
return false return false
} else if (conf === 'full') { } else if (conf === 'full') {
@ -140,25 +142,16 @@ const MentionLink = {
return this.isRemote return this.isRemote
} }
}, },
shouldShowTooltip() {
return this.mergedConfig.mentionLinkShowTooltip
},
shouldShowAvatar() {
return this.mergedConfig.mentionLinkShowAvatar
},
shouldShowYous() {
return this.mergedConfig.mentionLinkShowYous
},
shouldBoldenYou() {
return this.mergedConfig.mentionLinkBoldenYou
},
shouldFadeDomain() {
return this.mergedConfig.mentionLinkFadeDomain
},
...mapGetters(['mergedConfig']),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useSyncConfigStore, {
shouldShowTooltip: (state) => state.mergedConfig.mentionLinkShowTooltip,
shouldShowAvatar: (state) => state.mergedConfig.mentionLinkShowAvatar,
shouldShowYous: (state) => state.mergedConfig.mentionLinkShowYous,
shouldBoldenYou: (state) => state.mergedConfig.mentionLinkBoldenYou,
shouldFadeDomain: (state) => state.mergedConfig.mentionLinkFadeDomain,
}),
}, },
} }

View file

@ -3,7 +3,8 @@ import { mapGetters } from 'vuex'
import NavigationPins from 'src/components/navigation/navigation_pins.vue' import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import GestureService from '../../services/gesture_service/gesture_service' import GestureService from '../../services/gesture_service/gesture_service'
import { import {
countExtraNotifications, countExtraNotifications,
@ -64,24 +65,24 @@ const MobileNav = {
return `${this.unseenCount ? this.unseenCount : ''}` return `${this.unseenCount ? this.unseenCount : ''}`
}, },
hideSitename() { hideSitename() {
return this.$store.state.instance.hideSitename return useInstanceStore().hideSitename
}, },
sitename() { sitename() {
return this.$store.state.instance.name return useInstanceStore().name
}, },
isChat() { isChat() {
return this.$route.name === 'chat' return this.$route.name === 'chat'
}, },
...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'), new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
}), }),
shouldConfirmLogout() { shouldConfirmLogout() {
return this.$store.getters.mergedConfig.modalOnLogout return useSyncConfigStore().mergedConfig.modalOnLogout
}, },
closingDrawerMarksAsSeen() { closingDrawerMarksAsSeen() {
return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen return useSyncConfigStore().mergedConfig.closingDrawerMarksAsSeen
}, },
...mapGetters(['unreadChatCount']), ...mapGetters(['unreadChatCount']),
}, },

View file

@ -1,6 +1,7 @@
import { debounce } from 'lodash' import { debounce } from 'lodash'
import { usePostStatusStore } from 'src/stores/post_status' import { usePostStatusStore } from 'src/stores/post_status'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faPen } from '@fortawesome/free-solid-svg-icons' import { faPen } from '@fortawesome/free-solid-svg-icons'
@ -45,10 +46,10 @@ const MobilePostStatusButton = {
) )
}, },
isPersistent() { isPersistent() {
return !!this.$store.getters.mergedConfig.alwaysShowNewPostButton return !!useSyncConfigStore().mergedConfig.alwaysShowNewPostButton
}, },
autohideFloatingPostButton() { autohideFloatingPostButton() {
return !!this.$store.getters.mergedConfig.autohideFloatingPostButton return !!useSyncConfigStore().mergedConfig.autohideFloatingPostButton
}, },
}, },
watch: { watch: {

View file

@ -1,3 +1,4 @@
import { useInstanceStore } from 'src/stores/instance.js'
import DialogModal from '../dialog_modal/dialog_modal.vue' import DialogModal from '../dialog_modal/dialog_modal.vue'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
@ -54,7 +55,7 @@ const ModerationTools = {
}, },
canUseTagPolicy() { canUseTagPolicy() {
return ( return (
this.$store.state.instance.tagPolicyAvailable && useInstanceStore().tagPolicyAvailable &&
this.privileged('users_manage_tags') this.privileged('users_manage_tags')
) )
}, },

View file

@ -10,7 +10,7 @@ import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
import NavigationPins from 'src/components/navigation/navigation_pins.vue' import NavigationPins from 'src/components/navigation/navigation_pins.vue'
import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -82,28 +82,28 @@ const NavPanel = {
this.editMode = !this.editMode this.editMode = !this.editMode
}, },
toggleCollapse() { toggleCollapse() {
useServerSideStorageStore().setPreference({ useSyncConfigStore().setPreference({
path: 'simple.collapseNav', path: 'simple.collapseNav',
value: !this.collapsed, value: !this.collapsed,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
isPinned(item) { isPinned(item) {
return this.pinnedItems.has(item) return this.pinnedItems.has(item)
}, },
togglePin(item) { togglePin(item) {
if (this.isPinned(item)) { if (this.isPinned(item)) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} else { } else {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} }
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
}, },
computed: { computed: {
@ -111,7 +111,7 @@ const NavPanel = {
unreadAnnouncementCount: 'unreadAnnouncementCount', unreadAnnouncementCount: 'unreadAnnouncementCount',
supportsAnnouncements: (store) => store.supportsAnnouncements, supportsAnnouncements: (store) => store.supportsAnnouncements,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
collapsed: (store) => store.prefsStorage.simple.collapseNav, collapsed: (store) => store.prefsStorage.simple.collapseNav,
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
@ -123,12 +123,12 @@ const NavPanel = {
store.featureSet.pleromaChatMessagesAvailable, store.featureSet.pleromaChatMessagesAvailable,
bookmarkFolders: (store) => bookmarkFolders: (store) =>
store.featureSet.pleromaBookmarkFoldersAvailable, store.featureSet.pleromaBookmarkFoldersAvailable,
privateMode: (state) => state.private,
federating: (state) => state.federating,
}), }),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
followRequestCount: (state) => state.api.followRequests.length, followRequestCount: (state) => state.api.followRequests.length,
privateMode: (state) => state.instance.private,
federating: (state) => state.instance.federating,
}), }),
timelinesItems() { timelinesItems() {
return filterNavigation( return filterNavigation(

View file

@ -4,7 +4,7 @@ import { mapState } from 'vuex'
import { routeTo } 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 OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faThumbtack } from '@fortawesome/free-solid-svg-icons' import { faThumbtack } from '@fortawesome/free-solid-svg-icons'
@ -22,17 +22,17 @@ const NavigationEntry = {
}, },
togglePin(value) { togglePin(value) {
if (this.isPinned(value)) { if (this.isPinned(value)) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} else { } else {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} }
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
}, },
computed: { computed: {
@ -46,7 +46,7 @@ const NavigationEntry = {
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),

View file

@ -14,9 +14,9 @@ import {
import StillImage from 'src/components/still-image/still-image.vue' import StillImage from 'src/components/still-image/still-image.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
import { useListsStore } from 'src/stores/lists'
import { useInstanceStore } from 'src/stores/instance' import { useInstanceStore } from 'src/stores/instance'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useListsStore } from 'src/stores/lists'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -68,15 +68,17 @@ const NavPanel = {
...mapPiniaState(useBookmarkFoldersStore, { ...mapPiniaState(useBookmarkFoldersStore, {
bookmarks: getBookmarkFolderEntries, bookmarks: getBookmarkFolderEntries,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),
...mapPiniaState(useInstanceStore, { ...mapPiniaState(useInstanceStore, {
privateMode: (store) => store.featureSet.private, privateMode: (store) => store.featureSet.private,
federating: (store) => store.featureSet.federating, federating: (store) => store.featureSet.federating,
pleromaChatMessagesAvailable: (store) => store.featureSet.pleromaChatMessagesAvailable, pleromaChatMessagesAvailable: (store) =>
bubbleTimelinesSupported: (store) => store.featureSet.localBubbleInstances.length > 0, store.featureSet.pleromaChatMessagesAvailable,
bubbleTimelinesSupported: (store) =>
store.featureSet.localBubbleInstances.length > 0,
}), }),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,

View file

@ -2,6 +2,8 @@ import { mapState } from 'vuex'
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { import {
highlightClass, highlightClass,
@ -107,7 +109,7 @@ const Notification = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
getUser(notification) { getUser(notification) {
@ -178,7 +180,7 @@ const Notification = {
return highlightClass(this.notification.from_profile) return highlightClass(this.notification.from_profile)
}, },
userStyle() { userStyle() {
const highlight = this.$store.getters.mergedConfig.highlight const highlight = useSyncConfigStore().mergedConfig.highlight
const user = this.notification.from_profile const user = this.notification.from_profile
return highlightStyle(highlight[user.screen_name]) return highlightStyle(highlight[user.screen_name])
}, },
@ -206,7 +208,7 @@ const Notification = {
return isStatusNotification(this.notification.type) return isStatusNotification(this.notification.type)
}, },
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useSyncConfigStore().mergedConfig
}, },
shouldConfirmApprove() { shouldConfirmApprove() {
return this.mergedConfig.modalOnApproveFollow return this.mergedConfig.modalOnApproveFollow

View file

@ -106,6 +106,7 @@
</template> </template>
<script> <script>
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -117,7 +118,7 @@ export default {
components: { Popover }, components: { Popover },
computed: { computed: {
filters() { filters() {
return this.$store.getters.mergedConfig.notificationVisibility return useSyncConfigStore().mergedConfig.notificationVisibility
}, },
}, },
methods: { methods: {

View file

@ -2,8 +2,10 @@ import { mapState } from 'pinia'
import { computed } from 'vue' import { computed } from 'vue'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import FaviconService from '../../services/favicon_service/favicon_service.js' import FaviconService from '../../services/favicon_service/favicon_service.js'
import { import {
ACTIONABLE_NOTIFICATION_TYPES, ACTIONABLE_NOTIFICATION_TYPES,
@ -97,7 +99,7 @@ const Notifications = {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
ignoreInactionableSeen() { ignoreInactionableSeen() {
return this.$store.getters.mergedConfig.ignoreInactionableSeen return useSyncConfigStore().mergedConfig.ignoreInactionableSeen
}, },
extraNotificationsCount() { extraNotificationsCount() {
return countExtraNotifications(this.$store) return countExtraNotifications(this.$store)
@ -135,10 +137,10 @@ const Notifications = {
) )
}, },
noSticky() { noSticky() {
return this.$store.getters.mergedConfig.disableStickyHeaders return useSyncConfigStore().mergedConfig.disableStickyHeaders
}, },
unseenAtTop() { unseenAtTop() {
return this.$store.getters.mergedConfig.unseenAtTop return useSyncConfigStore().mergedConfig.unseenAtTop
}, },
showExtraNotifications() { showExtraNotifications() {
return !this.noExtra return !this.noExtra

View file

@ -1,3 +1,4 @@
import { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
import oauth from '../../services/new_api/oauth.js' import oauth from '../../services/new_api/oauth.js'
@ -12,7 +13,7 @@ const oac = {
.getToken({ .getToken({
clientId, clientId,
clientSecret, clientSecret,
instance: this.$store.state.instance.server, instance: useInstanceStore().server,
code: this.code, code: this.code,
}) })
.then((result) => { .then((result) => {

View file

@ -3,6 +3,7 @@ import RichContent from 'components/rich_content/rich_content.jsx'
import Timeago from 'components/timeago/timeago.vue' import Timeago from 'components/timeago/timeago.vue'
import { usePollsStore } from 'src/stores/polls' import { usePollsStore } from 'src/stores/polls'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import genRandomSeed from '../../services/random_seed/random_seed.service.js' import genRandomSeed from '../../services/random_seed/random_seed.service.js'
export default { export default {
@ -47,7 +48,7 @@ export default {
return (this.poll && this.poll.expired) || false return (this.poll && this.poll.expired) || false
}, },
expirationLabel() { expirationLabel() {
if (this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { if (useSyncConfigStore().mergedConfig.useAbsoluteTimeFormat) {
return this.expired ? 'polls.expired_at' : 'polls.expires_at' return this.expired ? 'polls.expired_at' : 'polls.expires_at'
} else { } else {
return this.expired ? 'polls.expired' : 'polls.expires_in' return this.expired ? 'polls.expired' : 'polls.expires_in'

View file

@ -1,5 +1,6 @@
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
import { pollFallback } from 'src/services/poll/poll.service.js' import { pollFallback } from 'src/services/poll/poll.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -52,7 +53,7 @@ export default {
}, },
}, },
pollLimits() { pollLimits() {
return this.$store.state.instance.pollLimits return useInstanceStore().pollLimits
}, },
maxOptions() { maxOptions() {
return this.pollLimits.max_options return this.pollLimits.max_options

View file

@ -6,9 +6,11 @@ import DraftCloser from 'src/components/draft_closer/draft_closer.vue'
import Gallery from 'src/components/gallery/gallery.vue' 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 { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.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 { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js' import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
import fileTypeService from '../../services/file_type/file_type.service.js' import fileTypeService from '../../services/file_type/file_type.service.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
@ -159,8 +161,6 @@ const PostStatusForm = {
const preset = this.$route.query.message const preset = this.$route.query.message
let statusText = preset || '' let statusText = preset || ''
const { scopeCopy } = this.$store.getters.mergedConfig
const [statusType, refId] = typeAndRefId({ const [statusType, refId] = typeAndRefId({
replyTo: this.replyTo, replyTo: this.replyTo,
profileMention: this.profileMention && this.repliedUser?.id, profileMention: this.profileMention && this.repliedUser?.id,
@ -183,26 +183,23 @@ const PostStatusForm = {
} }
const scope = const scope =
(this.copyMessageScope && scopeCopy) || (this.copyMessageScope && this.scopeCopy) ||
this.copyMessageScope === 'direct' this.copyMessageScope === 'direct'
? this.copyMessageScope ? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope : this.$store.state.users.currentUser.default_scope
const { postContentType: contentType, sensitiveByDefault } =
this.$store.getters.mergedConfig
statusParams = { statusParams = {
type: statusType, type: statusType,
refId, refId,
spoilerText: this.subject || '', spoilerText: this.subject || '',
status: statusText, status: statusText,
nsfw: !!sensitiveByDefault, nsfw: !!this.sensitiveByDefault,
files: [], files: [],
poll: {}, poll: {},
hasPoll: false, hasPoll: false,
mediaDescriptions: {}, mediaDescriptions: {},
visibility: scope, visibility: scope,
contentType, contentType: this.contentType,
quoting: false, quoting: false,
} }
@ -250,17 +247,14 @@ const PostStatusForm = {
userDefaultScope() { userDefaultScope() {
return this.$store.state.users.currentUser.default_scope return this.$store.state.users.currentUser.default_scope
}, },
showAllScopes() {
return !this.mergedConfig.minimalScopesMode
},
hideExtraActions() { hideExtraActions() {
return this.disableDraft || this.hideDraft return this.disableDraft || this.hideDraft
}, },
emojiUserSuggestor() { emojiUserSuggestor() {
return suggestor({ return suggestor({
emoji: [ emoji: [
...this.$store.getters.standardEmojiList, ...useEmojiStore().standardEmojiList,
...this.$store.state.instance.customEmoji, ...useEmojiStore().customEmoji,
], ],
store: this.$store, store: this.$store,
}) })
@ -268,16 +262,16 @@ const PostStatusForm = {
emojiSuggestor() { emojiSuggestor() {
return suggestor({ return suggestor({
emoji: [ emoji: [
...this.$store.getters.standardEmojiList, ...useEmojiStore().standardEmojiList,
...this.$store.state.instance.customEmoji, ...useEmojiStore().customEmoji,
], ],
}) })
}, },
emoji() { emoji() {
return this.$store.getters.standardEmojiList || [] return useEmojiStore().standardEmojiList || []
}, },
customEmoji() { customEmoji() {
return this.$store.state.instance.customEmoji || [] return useEmojiStore().customEmoji || []
}, },
statusLength() { statusLength() {
return this.newStatus.status.length return this.newStatus.status.length
@ -286,7 +280,7 @@ const PostStatusForm = {
return this.newStatus.spoilerText.length return this.newStatus.spoilerText.length
}, },
statusLengthLimit() { statusLengthLimit() {
return this.$store.state.instance.textlimit return useInstanceStore().textlimit
}, },
hasStatusLengthLimit() { hasStatusLengthLimit() {
return this.statusLengthLimit > 0 return this.statusLengthLimit > 0
@ -300,21 +294,21 @@ const PostStatusForm = {
return this.hasStatusLengthLimit && this.charactersLeft < 0 return this.hasStatusLengthLimit && this.charactersLeft < 0
}, },
postFormats() { postFormats() {
return this.$store.state.instance.postFormats || [] return useInstanceStore().postFormats || []
}, },
safeDMEnabled() { safeDMEnabled() {
return this.$store.state.instance.safeDM return useInstanceStore().safeDM
}, },
pollsAvailable() { pollsAvailable() {
return ( return (
this.$store.state.instance.pollsAvailable && useInstanceStore().pollsAvailable &&
this.$store.state.instance.pollLimits.max_options >= 2 && useInstanceStore().pollLimits.max_options >= 2 &&
this.disablePolls !== true this.disablePolls !== true
) )
}, },
hideScopeNotice() { hideScopeNotice() {
return ( return (
this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice this.disableNotice || useSyncConfigStore().mergedConfig.hideScopeNotice
) )
}, },
pollContentError() { pollContentError() {
@ -337,7 +331,7 @@ const PostStatusForm = {
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== '' return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
}, },
quotable() { quotable() {
if (!this.$store.state.instance.quotingAvailable) { if (!useInstanceStore().quotingAvailable) {
return false return false
} }
@ -369,9 +363,6 @@ const PostStatusForm = {
pollFormVisible() { pollFormVisible() {
return this.newStatus.hasPoll return this.newStatus.hasPoll
}, },
shouldAutoSaveDraft() {
return this.$store.getters.mergedConfig.autoSaveDraft
},
autoSaveState() { autoSaveState() {
if (this.saveable) { if (this.saveable) {
return this.$t('post_status.auto_save_saving') return this.$t('post_status.auto_save_saving')
@ -401,13 +392,16 @@ const PostStatusForm = {
) )
) )
}, },
...mapGetters(['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (store) => store.mobileLayout, mobileLayout: (store) => store.mobileLayout,
}), }),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
minimalScopesMode: (store) => store.mergedConfig.minimalScopesMode, scopeCopy: (store) => store.mergedConfig.scopeCopy,
shouldAutoSaveDraft: (store) => store.mergedConfig.autoSaveDraft,
showAllScopes: (store) => !store.mergedConfig.minimalScopesMode,
alwaysShowSubject: (store) => store.mergedConfig.alwaysShowSubjectInput, alwaysShowSubject: (store) => store.mergedConfig.alwaysShowSubjectInput,
contentType: (store) => store.mergedConfig.postContentType,
sensitiveByDefaultType: (store) => store.mergedConfig.sensitiveByDefault,
}), }),
}, },
watch: { watch: {

View file

@ -1,3 +1,4 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
export default { export default {
@ -20,7 +21,7 @@ export default {
} }
}, },
shouldConfirmRemoveUserFromFollowers() { shouldConfirmRemoveUserFromFollowers() {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers return useSyncConfigStore().mergedConfig.modalOnRemoveUserFromFollowers
}, },
}, },
methods: { methods: {

View file

@ -1,5 +1,6 @@
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import { useReportsStore } from 'src/stores/reports' import { useReportsStore } from 'src/stores/reports'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import StatusContent from '../status_content/status_content.vue' import StatusContent from '../status_content/status_content.vue'
@ -31,7 +32,7 @@ const Report = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
setReportState(state) { setReportState(state) {

View file

@ -6,6 +6,7 @@ import StillImage from 'components/still-image/still-image.vue'
import { assign, clone } from 'lodash' import { assign, clone } from 'lodash'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue' import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue'
import ModifiedIndicator from '../helpers/modified_indicator.vue' import ModifiedIndicator from '../helpers/modified_indicator.vue'
@ -102,7 +103,7 @@ const EmojiTab = {
// Remote pack // Remote pack
return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}` return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}`
} else { } else {
return `${this.$store.state.instance.server}/emoji/${encodeURIComponent(this.packName)}/${name}` return `${useInstanceStore().server}/emoji/${encodeURIComponent(this.packName)}/${name}`
} }
}, },

View file

@ -1,6 +1,7 @@
import Attachment from 'src/components/attachment/attachment.vue' import Attachment from 'src/components/attachment/attachment.vue'
import MediaUpload from 'src/components/media_upload/media_upload.vue' import MediaUpload from 'src/components/media_upload/media_upload.vue'
import { fileTypeExt } from 'src/services/file_type/file_type.service.js' import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import Setting from './setting.js' import Setting from './setting.js'
export default { export default {
@ -24,9 +25,7 @@ export default {
attachment() { attachment() {
const path = this.realDraftMode ? this.draft : this.state const path = this.realDraftMode ? this.draft : this.state
// The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage. // The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage.
const url = path.includes('://') const url = path.includes('://') ? path : useInstanceStore().server + path
? path
: this.$store.state.instance.server + path
return { return {
mimetype: fileTypeExt(url), mimetype: fileTypeExt(url),
url, url,

View file

@ -4,6 +4,7 @@ import Attachment from 'src/components/attachment/attachment.vue'
import MediaUpload from 'src/components/media_upload/media_upload.vue' import MediaUpload from 'src/components/media_upload/media_upload.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import { fileTypeExt } from 'src/services/file_type/file_type.service.js' import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import Setting from './setting.js' import Setting from './setting.js'
export default { export default {
@ -34,9 +35,7 @@ export default {
url: '', url: '',
} }
} }
const url = path.includes('://') const url = path.includes('://') ? path : useInstanceStore().server + path
? path
: this.$store.state.instance.server + path
return { return {
mimetype: fileTypeExt(url), mimetype: fileTypeExt(url),

View file

@ -1,7 +1,7 @@
import { cloneDeep, get, isEqual, set } from 'lodash' import { cloneDeep, get, isEqual, set } from 'lodash'
import { useInstanceStore } from 'src/stores/instance' import { useInstanceStore } from 'src/stores/instance'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import DraftButtons from './draft_buttons.vue' import DraftButtons from './draft_buttons.vue'
import ModifiedIndicator from './modified_indicator.vue' import ModifiedIndicator from './modified_indicator.vue'
import ProfileSettingIndicator from './profile_setting_indicator.vue' import ProfileSettingIndicator from './profile_setting_indicator.vue'
@ -229,13 +229,13 @@ export default {
configSource() { configSource() {
switch (this.realSource) { switch (this.realSource) {
case 'server-side': case 'server-side':
return useServerSideStorageStore().mergedConfig return useSyncConfigStore().mergedConfig
case 'profile': case 'profile':
return this.$store.state.profileConfig return this.$store.state.profileConfig
case 'admin': case 'admin':
return this.$store.state.adminSettings.config return this.$store.state.adminSettings.config
default: default:
return this.$store.getters.mergedConfig return useSyncConfigStore().mergedConfig
} }
}, },
configSink() { configSink() {
@ -246,8 +246,8 @@ export default {
case 'server-side': { case 'server-side': {
return (originalPath, value, operator) => { return (originalPath, value, operator) => {
const path = `simple.${originalPath}` const path = `simple.${originalPath}`
useServerSideStorageStore().setPreference({ path, value }) useSyncConfigStore().setPreference({ path, value })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
} }
} }
case 'profile': case 'profile':
@ -353,7 +353,7 @@ export default {
this.draft = cloneDeep(this.state) this.draft = cloneDeep(this.state)
} else { } else {
set( set(
this.$store.getters.mergedConfig, useSyncConfigStore().mergedConfig,
this.path, this.path,
cloneDeep(this.defaultState), cloneDeep(this.defaultState),
) )

View file

@ -1,10 +1,10 @@
import { mapState as mapPiniaState } from 'pinia' import { mapState as mapPiniaState } from 'pinia'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
const SharedComputedObject = () => ({ const SharedComputedObject = () => ({
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
serverSide: (store) => store.state.prefsStorage, serverSide: (store) => store.state.prefsStorage,
}), }),
...mapGetters(['mergedConfig']), ...mapGetters(['mergedConfig']),

View file

@ -11,7 +11,9 @@ import { getCssRules } from 'src/services/theme_data/css_utils.js'
import { deserialize } from 'src/services/theme_data/iss_deserializer.js' import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
import { init } from 'src/services/theme_data/theme_data_3.service.js' import { init } from 'src/services/theme_data/theme_data_3.service.js'
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface' import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
@ -83,7 +85,7 @@ const AppearanceTab = {
const updateIndex = (resource) => { const updateIndex = (resource) => {
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1) const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
const currentIndex = this.$store.state.instance[`${resource}sIndex`] const currentIndex = useInstanceStore()[`${resource}sIndex`]
let promise let promise
if (currentIndex) { if (currentIndex) {
@ -273,11 +275,11 @@ const AppearanceTab = {
return !window.IntersectionObserver return !window.IntersectionObserver
}, },
instanceWallpaper() { instanceWallpaper() {
this.$store.state.instance.background useInstanceStore().background
}, },
instanceWallpaperUsed() { instanceWallpaperUsed() {
return ( return (
this.$store.state.instance.background && useInstanceStore().background &&
!this.$store.state.users.currentUser.background_image !this.$store.state.users.currentUser.background_image
) )
}, },
@ -332,20 +334,13 @@ const AppearanceTab = {
} }
}, },
isThemeActive(key) { isThemeActive(key) {
return ( return key === (this.mergedConfig.theme || useInstanceStore().theme)
key === (this.mergedConfig.theme || this.$store.state.instance.theme)
)
}, },
isStyleActive(key) { isStyleActive(key) {
return ( return key === (this.mergedConfig.style || useInstanceStore().style)
key === (this.mergedConfig.style || this.$store.state.instance.style)
)
}, },
isPaletteActive(key) { isPaletteActive(key) {
return ( return key === (this.mergedConfig.palette || useInstanceStore().palette)
key ===
(this.mergedConfig.palette || this.$store.state.instance.palette)
)
}, },
...mapActions(useInterfaceStore, ['setStyle', 'setTheme']), ...mapActions(useInterfaceStore, ['setStyle', 'setTheme']),
setPalette(name, data) { setPalette(name, data) {
@ -431,10 +426,10 @@ const AppearanceTab = {
if (!file) { if (!file) {
return return
} }
if (file.size > this.$store.state.instance[slot + 'limit']) { if (file.size > useInstanceStore()[slot + 'limit']) {
const filesize = fileSizeFormatService.fileSizeFormat(file.size) const filesize = fileSizeFormatService.fileSizeFormat(file.size)
const allowedsize = fileSizeFormatService.fileSizeFormat( const allowedsize = fileSizeFormatService.fileSizeFormat(
this.$store.state.instance[slot + 'limit'], useInstanceStore()[slot + 'limit'],
) )
useInterfaceStore().pushGlobalNotice({ useInterfaceStore().pushGlobalNotice({
messageKey: 'upload.error.message', messageKey: 'upload.error.message',

View file

@ -4,7 +4,8 @@ import { mapState as mapVuexState } from 'vuex'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import HelpIndicator from '../helpers/help_indicator.vue' import HelpIndicator from '../helpers/help_indicator.vue'
@ -24,10 +25,10 @@ const ClutterTab = {
}, },
computed: { computed: {
instanceSpecificPanelPresent() { instanceSpecificPanelPresent() {
return this.$store.state.instance.showInstanceSpecificPanel return useInstanceStore().showInstanceSpecificPanel
}, },
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
muteFilters: (store) => muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters), Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
@ -86,10 +87,10 @@ const ClutterTab = {
}, },
}, },
methods: { methods: {
...mapActions(useServerSideStorageStore, [ ...mapActions(useSyncConfigStore, [
'setPreference', 'setPreference',
'unsetPreference', 'unsetPreference',
'pushServerSideStorage', 'pushSyncConfig',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -136,7 +137,7 @@ const ClutterTab = {
filter.order = this.muteFilters.length + 2 filter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -152,19 +153,19 @@ const ClutterTab = {
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
deleteFilter(id) { deleteFilter(id) {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
purgeExpiredFilters() { purgeExpiredFilters() {
this.muteFiltersExpired.forEach(([id]) => { this.muteFiltersExpired.forEach(([id]) => {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null })
}) })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -190,7 +191,7 @@ const ClutterTab = {
path: 'simple.muteFilters.' + id, path: 'simple.muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushServerSideStorage() this.pushSyncConfig()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },

View file

@ -6,6 +6,8 @@ import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js' import { cacheKey, clearCache, emojiCacheKey } from 'src/services/sw/sw.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
@ -108,7 +110,7 @@ const ComposingTab = {
}, },
computed: { computed: {
postFormats() { postFormats() {
return this.$store.state.instance.postFormats || [] return useInstanceStore().postFormats || []
}, },
postContentOptions() { postContentOptions() {
return this.postFormats.map((format) => ({ return this.postFormats.map((format) => ({
@ -119,7 +121,7 @@ const ComposingTab = {
}, },
language: { language: {
get: function () { get: function () {
return this.$store.getters.mergedConfig.interfaceLanguage return useSyncConfigStore().mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
this.$store.dispatch('setOption', { this.$store.dispatch('setOption', {

View file

@ -9,8 +9,9 @@ import {
newExporter, newExporter,
newImporter, newImporter,
} from 'src/services/export_import/export_import.js' } from 'src/services/export_import/export_import.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import HelpIndicator from '../helpers/help_indicator.vue' import HelpIndicator from '../helpers/help_indicator.vue'
@ -34,11 +35,11 @@ const FilteringTab = {
label: this.$t(`user_card.mute_block_${mode}`), label: this.$t(`user_card.mute_block_${mode}`),
})), })),
muteFiltersDraftObject: cloneDeep( muteFiltersDraftObject: cloneDeep(
useServerSideStorageStore().prefsStorage.simple.muteFilters, useSyncConfigStore().prefsStorage.simple.muteFilters,
), ),
muteFiltersDraftDirty: Object.fromEntries( muteFiltersDraftDirty: Object.fromEntries(
Object.entries( Object.entries(
useServerSideStorageStore().prefsStorage.simple.muteFilters, useSyncConfigStore().prefsStorage.simple.muteFilters,
).map(([k]) => [k, false]), ).map(([k]) => [k, false]),
), ),
exportedFilter: null, exportedFilter: null,
@ -90,10 +91,10 @@ const FilteringTab = {
}, },
computed: { computed: {
instanceSpecificPanelPresent() { instanceSpecificPanelPresent() {
return this.$store.state.instance.showInstanceSpecificPanel return useInstanceStore().showInstanceSpecificPanel
}, },
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
muteFilters: (store) => muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters), Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
@ -152,10 +153,10 @@ const FilteringTab = {
}, },
}, },
methods: { methods: {
...mapActions(useServerSideStorageStore, [ ...mapActions(useSyncConfigStore, [
'setPreference', 'setPreference',
'unsetPreference', 'unsetPreference',
'pushServerSideStorage', 'pushSyncConfig',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -202,7 +203,7 @@ const FilteringTab = {
filter.order = this.muteFilters.length + 2 filter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -218,19 +219,19 @@ const FilteringTab = {
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
deleteFilter(id) { deleteFilter(id) {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
purgeExpiredFilters() { purgeExpiredFilters() {
this.muteFiltersExpired.forEach(([id]) => { this.muteFiltersExpired.forEach(([id]) => {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null })
}) })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -256,7 +257,7 @@ const FilteringTab = {
path: 'simple.muteFilters.' + id, path: 'simple.muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushServerSideStorage() this.pushSyncConfig()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },

View file

@ -3,6 +3,8 @@ import { mapState } from 'vuex'
import FontControl from 'src/components/font_control/font_control.vue' import FontControl from 'src/components/font_control/font_control.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
@ -39,7 +41,7 @@ const GeneralTab = {
computed: { computed: {
language: { language: {
get: function () { get: function () {
return this.$store.getters.mergedConfig.interfaceLanguage return useSyncConfigStore().mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
this.$store.dispatch('setOption', { this.$store.dispatch('setOption', {

View file

@ -1,3 +1,5 @@
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue' import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
@ -30,18 +32,18 @@ const GeneralTab = {
}, },
computed: { computed: {
postFormats() { postFormats() {
return this.$store.state.instance.postFormats || [] return useInstanceStore().postFormats || []
}, },
instanceShoutboxPresent() { instanceShoutboxPresent() {
return this.$store.state.instance.shoutAvailable return useInstanceStore().shoutAvailable
}, },
columns() { columns() {
const mode = this.$store.getters.mergedConfig.thirdColumnMode const mode = useSyncConfigStore().mergedConfig.thirdColumnMode
const notif = mode === 'none' ? [] : ['notifs'] const notif = mode === 'none' ? [] : ['notifs']
if ( if (
this.$store.getters.mergedConfig.sidebarRight || useSyncConfigStore().mergedConfig.sidebarRight ||
mode === 'postform' mode === 'postform'
) { ) {
return [...notif, 'content', 'sidebar'] return [...notif, 'content', 'sidebar']

View file

@ -12,7 +12,9 @@ import MuteCard from 'src/components/mute_card/mute_card.vue'
import ProgressButton from 'src/components/progress_button/progress_button.vue' import ProgressButton from 'src/components/progress_button/progress_button.vue'
import SelectableList from 'src/components/selectable_list/selectable_list.vue' import SelectableList from 'src/components/selectable_list/selectable_list.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthTokensStore } from 'src/stores/oauth_tokens' import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const BlockList = withLoadMore({ const BlockList = withLoadMore({
fetch: (props, $store) => $store.dispatch('fetchBlocks'), fetch: (props, $store) => $store.dispatch('fetchBlocks'),
@ -64,7 +66,7 @@ const MutesAndBlocks = {
}, },
computed: { computed: {
knownDomains() { knownDomains() {
return this.$store.state.instance.knownDomains return useInstanceStore().knownDomains
}, },
user() { user() {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser

View file

@ -41,7 +41,9 @@ import {
} from 'src/services/theme_data/theme_data.service.js' } from 'src/services/theme_data/theme_data.service.js'
import { init } from 'src/services/theme_data/theme_data_3.service.js' import { init } from 'src/services/theme_data/theme_data_3.service.js'
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import Preview from './theme_preview.vue' import Preview from './theme_preview.vue'
// List of color values used in v1 // List of color values used in v1
@ -78,7 +80,7 @@ export default {
}), }),
availableStyles: [], availableStyles: [],
selected: '', selected: '',
selectedTheme: this.$store.getters.mergedConfig.theme, selectedTheme: useSyncConfigStore().mergedConfig.theme,
themeWarning: undefined, themeWarning: undefined,
tempImportFile: undefined, tempImportFile: undefined,
engineVersion: 0, engineVersion: 0,
@ -125,7 +127,7 @@ export default {
} }
}, },
created() { created() {
const currentIndex = this.$store.state.instance.instanceThemesIndex const currentIndex = useInstanceStore().instanceThemesIndex
let promise let promise
if (currentIndex) { if (currentIndex) {

View file

@ -1,6 +1,7 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import ProgressButton from 'src/components/progress_button/progress_button.vue' import ProgressButton from 'src/components/progress_button/progress_button.vue'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthTokensStore } from 'src/stores/oauth_tokens' import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
import Mfa from './mfa.vue' import Mfa from './mfa.vue'
@ -42,7 +43,7 @@ const SecurityTab = {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
pleromaExtensionsAvailable() { pleromaExtensionsAvailable() {
return this.$store.state.instance.pleromaExtensionsAvailable return useInstanceStore().pleromaExtensionsAvailable
}, },
oauthTokens() { oauthTokens() {
return useOAuthTokensStore().tokens.map((oauthToken) => { return useOAuthTokensStore().tokens.map((oauthToken) => {

View file

@ -1,4 +1,5 @@
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import { useShoutStore } from 'src/stores/shout' import { useShoutStore } from 'src/stores/shout'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -32,7 +33,7 @@ const shoutPanel = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.username, user.username,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
}, },

View file

@ -3,6 +3,7 @@ import { mapGetters, mapState } from 'vuex'
import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js' import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useShoutStore } from 'src/stores/shout' import { useShoutStore } from 'src/stores/shout'
import GestureService from '../../services/gesture_service/gesture_service' import GestureService from '../../services/gesture_service/gesture_service'
@ -75,25 +76,25 @@ const SideDrawer = {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
suggestionsEnabled() { suggestionsEnabled() {
return this.$store.state.instance.suggestionsEnabled return useInstanceStore().suggestionsEnabled
}, },
logo() { logo() {
return this.$store.state.instance.logo return useInstanceStore().logo
}, },
hideSitename() { hideSitename() {
return this.$store.state.instance.hideSitename return useInstanceStore().hideSitename
}, },
sitename() { sitename() {
return this.$store.state.instance.name return useInstanceStore().name
}, },
followRequestCount() { followRequestCount() {
return this.$store.state.api.followRequests.length return this.$store.state.api.followRequests.length
}, },
privateMode() { privateMode() {
return this.$store.state.instance.private return useInstanceStore().private
}, },
federating() { federating() {
return this.$store.state.instance.federating return useInstanceStore().federating
}, },
timelinesRoute() { timelinesRoute() {
let name let name

View file

@ -2,11 +2,12 @@ import groupBy from 'lodash/groupBy'
import map from 'lodash/map' import map from 'lodash/map'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { useInstanceStore } from 'src/stores/instance.js'
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
const StaffPanel = { const StaffPanel = {
created() { created() {
const nicknames = this.$store.state.instance.staffAccounts const nicknames = useInstanceStore().staffAccounts
nicknames.forEach((nickname) => nicknames.forEach((nickname) =>
this.$store.dispatch('fetchUserIfMissing', nickname), this.$store.dispatch('fetchUserIfMissing', nickname),
) )

View file

@ -6,7 +6,8 @@ import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import StatusActionButtons from 'src/components/status_action_buttons/status_action_buttons.vue' import StatusActionButtons from 'src/components/status_action_buttons/status_action_buttons.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { muteFilterHits } from '../../services/status_parser/status_parser.js' import { muteFilterHits } from '../../services/status_parser/status_parser.js'
import { import {
highlightClass, highlightClass,
@ -469,7 +470,7 @@ const Status = {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useSyncConfigStore().mergedConfig
}, },
isSuspendable() { isSuspendable() {
return !this.replying && this.mediaPlaying.length === 0 return !this.replying && this.mediaPlaying.length === 0
@ -487,7 +488,7 @@ const Status = {
return this.status.edited_at !== null return this.status.edited_at !== null
}, },
editingAvailable() { editingAvailable() {
return this.$store.state.instance.editingAvailable return useInstanceStore().editingAvailable
}, },
hasVisibleQuote() { hasVisibleQuote() {
return this.status.quote_url && this.status.quote_visible return this.status.quote_url && this.status.quote_visible
@ -529,7 +530,7 @@ const Status = {
scrobble() { scrobble() {
return this.status.user?.latestScrobble return this.status.user?.latestScrobble
}, },
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
muteFilters: (store) => store.prefsStorage.simple.muteFilters, muteFilters: (store) => store.prefsStorage.simple.muteFilters,
hideBotIndicatior: (store) => store.prefsStorage.simple.hideBotIndicator, hideBotIndicatior: (store) => store.prefsStorage.simple.hideBotIndicator,
hidePostStats: (store) => store.mergedConfig.hidePostStats, hidePostStats: (store) => store.mergedConfig.hidePostStats,
@ -588,7 +589,7 @@ const Status = {
return generateProfileLink( return generateProfileLink(
id, id,
name, name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
addMediaPlaying(id) { addMediaPlaying(id) {

View file

@ -1,6 +1,7 @@
import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue' import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue' import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -91,7 +92,7 @@ export default {
return this.status.thread_muted return this.status.thread_muted
}, },
hideCustomEmoji() { hideCustomEmoji() {
return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable return !useInstanceStore().pleromaCustomEmojiReactionsAvailable
}, },
buttonInnerClass() { buttonInnerClass() {
return [ return [

View file

@ -3,7 +3,7 @@ import { mapState } from 'pinia'
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue' import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import genRandomSeed from 'src/services/random_seed/random_seed.service.js' import genRandomSeed from 'src/services/random_seed/random_seed.service.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import ActionButtonContainer from './action_button_container.vue' import ActionButtonContainer from './action_button_container.vue'
import { BUTTONS } from './buttons_definitions.js' import { BUTTONS } from './buttons_definitions.js'
@ -34,7 +34,7 @@ const StatusActionButtons = {
ActionButtonContainer, ActionButtonContainer,
}, },
computed: { computed: {
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedStatusActions), new Set(store.prefsStorage.collections.pinnedStatusActions),
}), }),
@ -109,18 +109,18 @@ const StatusActionButtons = {
return this.pinnedItems.has(button.name) return this.pinnedItems.has(button.name)
}, },
unpin(button) { unpin(button) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
pin(button) { pin(button) {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
getComponent(button) { getComponent(button) {
if (!this.$store.state.users.currentUser && button.anonLink) { if (!this.$store.state.users.currentUser && button.anonLink) {

View file

@ -1,7 +1,9 @@
import { mapState } from 'pinia'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import fileType from 'src/services/file_type/file_type.service' import fileType from 'src/services/file_type/file_type.service'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -109,7 +111,7 @@ const StatusBody = {
collapsedStatus() { collapsedStatus() {
return this.status.raw_html.replace(/(\n|<br\s?\/?>)/g, ' ') return this.status.raw_html.replace(/(\n|<br\s?\/?>)/g, ' ')
}, },
...mapGetters(['mergedConfig']), ...mapState(useSyncConfigStore, ['mergedConfig']),
}, },
components: { components: {
RichContent, RichContent,

View file

@ -3,7 +3,7 @@ import { mapGetters, mapState } from 'vuex'
import StatusBody from 'src/components/status_body/status_body.vue' import StatusBody from 'src/components/status_body/status_body.vue'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import Attachment from '../attachment/attachment.vue' import Attachment from '../attachment/attachment.vue'
import Gallery from '../gallery/gallery.vue' import Gallery from '../gallery/gallery.vue'
import LinkPreview from '../link-preview/link-preview.vue' import LinkPreview from '../link-preview/link-preview.vue'
@ -75,7 +75,7 @@ const StatusContent = {
uncontrolledShowingLongSubject: false, uncontrolledShowingLongSubject: false,
// not as computed because it sets the initial state which will be changed later // not as computed because it sets the initial state which will be changed later
uncontrolledExpandingSubject: uncontrolledExpandingSubject:
!this.$store.getters.mergedConfig.collapseMessageWithSubject, !useSyncConfigStore().mergedConfig.collapseMessageWithSubject,
} }
}, },
computed: { computed: {
@ -124,7 +124,7 @@ const StatusContent = {
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
maxThumbnails: (store) => store.prefsStorage.simple.maxThumbnails, maxThumbnails: (store) => store.prefsStorage.simple.maxThumbnails,
hideAttachments: (store) => store.prefsStorage.simple.hideAttachments, hideAttachments: (store) => store.prefsStorage.simple.hideAttachments,
hideAttachmentsInConv: (store) => hideAttachmentsInConv: (store) =>

View file

@ -1,4 +1,6 @@
/* eslint-env browser */ /* eslint-env browser */
import { useInstanceStore } from 'src/stores/instance.js'
import statusPosterService from '../../services/status_poster/status_poster.service.js' import statusPosterService from '../../services/status_poster/status_poster.service.js'
import TabSwitcher from '../tab_switcher/tab_switcher.jsx' import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
@ -16,7 +18,7 @@ const StickerPicker = {
}, },
computed: { computed: {
pack() { pack() {
return this.$store.state.instance.stickers || [] return useInstanceStore().stickers || []
}, },
}, },
methods: { methods: {

View file

@ -60,6 +60,7 @@ import Popover from 'components/popover/popover.vue'
import SelectComponent from 'components/select/select.vue' import SelectComponent from 'components/select/select.vue'
import { assign } from 'lodash' import { assign } from 'lodash'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import StillImage from './still-image.vue' import StillImage from './still-image.vue'
@ -125,7 +126,7 @@ export default {
const allPacks = {} const allPacks = {}
return listFunction({ return listFunction({
instance: this.$store.state.instance.server, instance: useInstanceStore().server,
page: 1, page: 1,
pageSize: 0, pageSize: 0,
}) })
@ -140,7 +141,7 @@ export default {
resultingPromise = resultingPromise resultingPromise = resultingPromise
.then(() => .then(() =>
listFunction({ listFunction({
instance: this.$store.state.instance.server, instance: useInstanceStore().server,
page: i, page: i,
pageSize, pageSize,
}), }),

View file

@ -1,3 +1,5 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const StillImage = { const StillImage = {
props: [ props: [
'src', 'src',
@ -15,7 +17,7 @@ const StillImage = {
return { return {
// for lazy loading, see loadLazy() // for lazy loading, see loadLazy()
realSrc: this.src, realSrc: this.src,
stopGifs: this.$store.getters.mergedConfig.stopGifs, stopGifs: useSyncConfigStore().mergedConfig.stopGifs,
} }
}, },
computed: { computed: {

View file

@ -1,12 +1,12 @@
import { mapState } from 'pinia'
import { useInstanceStore } from 'src/stores/instance.js'
const TermsOfServicePanel = { const TermsOfServicePanel = {
computed: { computed: mapState(useInstanceStore, {
content() { content: (state) => state.tos,
return this.$store.state.instance.tos embedded: (state) => state.embeddedToS,
}, }),
embedded() {
return this.$store.state.instance.embeddedToS
},
},
} }
export default TermsOfServicePanel export default TermsOfServicePanel

View file

@ -10,6 +10,7 @@
<script> <script>
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
export default { export default {
name: 'Timeago', name: 'Timeago',
@ -23,17 +24,17 @@ export default {
}, },
computed: { computed: {
shouldUseAbsoluteTimeFormat() { shouldUseAbsoluteTimeFormat() {
if (!this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { if (!useSyncConfigStore().mergedConfig.useAbsoluteTimeFormat) {
return false return false
} }
return ( return (
DateUtils.durationStrToMs( DateUtils.durationStrToMs(
this.$store.getters.mergedConfig.absoluteTimeFormatMinAge, useSyncConfigStore().mergedConfig.absoluteTimeFormatMinAge,
) <= this.relativeTimeMs ) <= this.relativeTimeMs
) )
}, },
time12hFormat() { time12hFormat() {
return this.$store.getters.mergedConfig.absoluteTimeFormat12h === '12h' return useSyncConfigStore().mergedConfig.absoluteTimeFormat12h === '12h'
}, },
browserLocale() { browserLocale() {
return localeService.internalToBrowserLocale(this.$i18n.locale) return localeService.internalToBrowserLocale(this.$i18n.locale)

View file

@ -2,7 +2,9 @@ import { debounce, keyBy, throttle } from 'lodash'
import { mapState } from 'pinia' import { mapState } from 'pinia'
import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import Conversation from '../conversation/conversation.vue' import Conversation from '../conversation/conversation.vue'
import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue'
import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue' import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue'
@ -123,7 +125,7 @@ const Timeline = {
return this.timeline.visibleStatuses.slice(min, max).map((_) => _.id) return this.timeline.visibleStatuses.slice(min, max).map((_) => _.id)
}, },
virtualScrollingEnabled() { virtualScrollingEnabled() {
return this.$store.getters.mergedConfig.virtualScrolling return useSyncConfigStore().mergedConfig.virtualScrolling
}, },
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (store) => store.layoutType === 'mobile', mobileLayout: (store) => store.layoutType === 'mobile',
@ -311,7 +313,7 @@ const Timeline = {
}, },
watch: { watch: {
newStatusCount(count) { newStatusCount(count) {
if (!this.$store.getters.mergedConfig.streaming) { if (!useSyncConfigStore().mergedConfig.streaming) {
return return
} }
if (count > 0) { if (count > 0) {
@ -321,7 +323,9 @@ const Timeline = {
if ( if (
top < 15 && top < 15 &&
!this.paused && !this.paused &&
!(this.unfocused && this.$store.getters.mergedConfig.pauseOnUnfocused) !(
this.unfocused && useSyncConfigStore().mergedConfig.pauseOnUnfocused
)
) { ) {
this.showNewStatuses() this.showNewStatuses()
} else { } else {

View file

@ -64,10 +64,12 @@ const TimelineMenu = {
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useInstanceStore, { ...mapPiniaState(useInstanceStore, {
bookmarkFolders: (store) => store.featureSet.pleromaBookmarkFoldersAvailable, bookmarkFolders: (state) =>
bubbleTimeline: (state) => store.featureSet.localBubbleInstances.length > 0, state.featureSet.pleromaBookmarkFoldersAvailable,
privateMode: (state) => store.private, bubbleTimeline: (state) =>
federating: (state) => store.federating, state.featureSet.localBubbleInstances.length > 0,
privateMode: (state) => state.private,
federating: (state) => state.federating,
}), }),
timelinesList() { timelinesList() {
return filterNavigation( return filterNavigation(

View file

@ -1,7 +1,8 @@
import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png' import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png'
import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png' import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png'
import Modal from 'src/components/modal/modal.vue' import Modal from 'src/components/modal/modal.vue'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faTimes } from '@fortawesome/free-solid-svg-icons' import { faTimes } from '@fortawesome/free-solid-svg-icons'
@ -36,11 +37,11 @@ const UpdateNotification = {
}, },
shouldShow() { shouldShow() {
return ( return (
!this.$store.state.instance.disableUpdateNotification && !useInstanceStore().disableUpdateNotification &&
this.$store.state.users.currentUser && this.$store.state.users.currentUser &&
useServerSideStorageStore().flagStorage.updateCounter < useSyncConfigStore().flagStorage.updateCounter <
CURRENT_UPDATE_COUNTER && CURRENT_UPDATE_COUNTER &&
!useServerSideStorageStore().prefsStorage.simple.dontShowUpdateNotifs !useSyncConfigStore().prefsStorage.simple.dontShowUpdateNotifs
) )
}, },
}, },
@ -50,22 +51,22 @@ const UpdateNotification = {
}, },
neverShowAgain() { neverShowAgain() {
this.toggleShow() this.toggleShow()
useServerSideStorageStore().setFlag({ useSyncConfigStore().setFlag({
flag: 'updateCounter', flag: 'updateCounter',
value: CURRENT_UPDATE_COUNTER, value: CURRENT_UPDATE_COUNTER,
}) })
useServerSideStorageStore().setPreference({ useSyncConfigStore().setPreference({
path: 'simple.dontShowUpdateNotifs', path: 'simple.dontShowUpdateNotifs',
value: true, value: true,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
dismiss() { dismiss() {
useServerSideStorageStore().setFlag({ useSyncConfigStore().setFlag({
flag: 'updateCounter', flag: 'updateCounter',
value: CURRENT_UPDATE_COUNTER, value: CURRENT_UPDATE_COUNTER,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
}, },
mounted() { mounted() {

View file

@ -1,3 +1,4 @@
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import StillImage from '../still-image/still-image.vue' import StillImage from '../still-image/still-image.vue'
@ -35,7 +36,7 @@ const UserAvatar = {
data() { data() {
return { return {
showPlaceholder: false, showPlaceholder: false,
defaultAvatar: `${this.$store.state.instance.server + this.$store.state.instance.defaultAvatar}`, defaultAvatar: `${useInstanceStore().server + useInstanceStore().defaultAvatar}`,
betterShadow: useInterfaceStore().browserSupport.cssFilter, betterShadow: useInterfaceStore().browserSupport.cssFilter,
} }
}, },

View file

@ -16,7 +16,8 @@ import { propsToNative } from 'src/services/attributes_helper/attributes_helper.
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { usePostStatusStore } from 'src/stores/post_status' import { usePostStatusStore } from 'src/stores/post_status'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from '../../stores/interface' import { useInterfaceStore } from '../../stores/interface'
import { useMediaViewerStore } from '../../stores/media_viewer' import { useMediaViewerStore } from '../../stores/media_viewer'
import AccountActions from '../account_actions/account_actions.vue' import AccountActions from '../account_actions/account_actions.vue'
@ -178,7 +179,7 @@ export default {
return false return false
}, },
groupActorAvailable() { groupActorAvailable() {
return this.$store.state.instance.groupActorAvailable return useInstanceStore().groupActorAvailable
}, },
availableActorTypes() { availableActorTypes() {
return this.groupActorAvailable return this.groupActorAvailable
@ -211,7 +212,7 @@ export default {
return Math.round(this.user.statuses_count / days) return Math.round(this.user.statuses_count / days)
}, },
emoji() { emoji() {
return this.$store.state.instance.customEmoji.map((e) => ({ return useEmojiStore().customEmoji.map((e) => ({
shortcode: e.displayText, shortcode: e.displayText,
static_url: e.imageUrl, static_url: e.imageUrl,
url: e.imageUrl, url: e.imageUrl,
@ -334,18 +335,18 @@ export default {
}, },
defaultAvatar() { defaultAvatar() {
return ( return (
this.$store.state.instance.server + useInstanceStore().server +
this.$store.state.instance.defaultAvatar useInstanceStore().defaultAvatar
) )
}, },
defaultBanner() { defaultBanner() {
return ( return (
this.$store.state.instance.server + useInstanceStore().server +
this.$store.state.instance.defaultBanner useInstanceStore().defaultBanner
) )
}, },
isDefaultAvatar() { isDefaultAvatar() {
const baseAvatar = this.$store.state.instance.defaultAvatar const baseAvatar = useInstanceStore().defaultAvatar
return ( return (
!this.$store.state.users.currentUser.profile_image_url || !this.$store.state.users.currentUser.profile_image_url ||
this.$store.state.users.currentUser.profile_image_url.includes( this.$store.state.users.currentUser.profile_image_url.includes(
@ -354,14 +355,14 @@ export default {
) )
}, },
isDefaultBanner() { isDefaultBanner() {
const baseBanner = this.$store.state.instance.defaultBanner const baseBanner = useInstanceStore().defaultBanner
return ( return (
!this.$store.state.users.currentUser.cover_photo || !this.$store.state.users.currentUser.cover_photo ||
this.$store.state.users.currentUser.cover_photo.includes(baseBanner) this.$store.state.users.currentUser.cover_photo.includes(baseBanner)
) )
}, },
fieldsLimits() { fieldsLimits() {
return this.$store.state.instance.fieldsLimits return useInstanceStore().fieldsLimits
}, },
maxFields() { maxFields() {
return this.fieldsLimits ? this.fieldsLimits.maxFields : 0 return this.fieldsLimits ? this.fieldsLimits.maxFields : 0
@ -370,7 +371,7 @@ export default {
return suggestor({ return suggestor({
emoji: [ emoji: [
...this.$store.getters.standardEmojiList, ...this.$store.getters.standardEmojiList,
...this.$store.state.instance.customEmoji, ...useEmojiStore().customEmoji,
], ],
store: this.$store, store: this.$store,
}) })
@ -379,12 +380,12 @@ export default {
return suggestor({ return suggestor({
emoji: [ emoji: [
...this.$store.getters.standardEmojiList, ...this.$store.getters.standardEmojiList,
...this.$store.state.instance.customEmoji, ...useEmojiStore().customEmoji,
], ],
}) })
}, },
...mapGetters(['mergedConfig']), ...mapGetters(['mergedConfig']),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
hideUserStats: (store) => store.prefsStorage.simple.hideUserStats, hideUserStats: (store) => store.prefsStorage.simple.hideUserStats,
userCardHidePersonalMarks: (store) => userCardHidePersonalMarks: (store) =>
store.prefsStorage.simple.userCardHidePersonalMarks, store.prefsStorage.simple.userCardHidePersonalMarks,
@ -415,7 +416,7 @@ export default {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
openProfileTab() { openProfileTab() {

View file

@ -15,6 +15,7 @@
<script> <script>
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
const UserLink = { const UserLink = {
@ -33,7 +34,7 @@ const UserLink = {
return generateProfileLink( return generateProfileLink(
user.id, user.id,
user.screen_name, user.screen_name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
}, },

View file

@ -1,5 +1,7 @@
import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import UserCard from '../user_card/user_card.vue' import UserCard from '../user_card/user_card.vue'
const UserPopover = { const UserPopover = {
@ -9,14 +11,11 @@ const UserPopover = {
UserCard, UserCard,
Popover: defineAsyncComponent(() => import('../popover/popover.vue')), Popover: defineAsyncComponent(() => import('../popover/popover.vue')),
}, },
computed: { computed: mapState(useSyncConfigStore, {
userPopoverAvatarAction() { userPopoverAvatarAction: (state) =>
return this.$store.getters.mergedConfig.userPopoverAvatarAction state.mergedConfig.userPopoverAvatarAction,
}, userPopoverOverlay: (state) => state.mergedConfig.userPopoverOverlay,
userPopoverOverlay() { }),
return this.$store.getters.mergedConfig.userPopoverOverlay
},
},
} }
export default UserPopover export default UserPopover

View file

@ -2,6 +2,8 @@ import get from 'lodash/get'
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import withLoadMore from '../../hocs/with_load_more/with_load_more' import withLoadMore from '../../hocs/with_load_more/with_load_more'
import Conversation from '../conversation/conversation.vue' import Conversation from '../conversation/conversation.vue'
import FollowCard from '../follow_card/follow_card.vue' import FollowCard from '../follow_card/follow_card.vue'
@ -87,7 +89,7 @@ const UserProfile = {
favoritesTabVisible() { favoritesTabVisible() {
return ( return (
this.isUs || this.isUs ||
(this.$store.state.instance.pleromaPublicFavouritesAvailable && (useInstanceStore().pleromaPublicFavouritesAvailable &&
!this.user.hide_favorites) !this.user.hide_favorites)
) )
}, },

View file

@ -2,12 +2,13 @@ import Checkbox from 'src/components/checkbox/checkbox.vue'
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue' import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import { durationStrToMs } from 'src/services/date_utils/date_utils.js' import { durationStrToMs } from 'src/services/date_utils/date_utils.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const UserTimedFilterModal = { const UserTimedFilterModal = {
data() { data() {
const action = this.isMute const action = this.isMute
? this.$store.getters.mergedConfig.onMuteDefaultAction ? useSyncConfigStore().mergedConfig.onMuteDefaultAction
: this.$store.getters.mergedConfig.onBlockDefaultAction : useSyncConfigStore().mergedConfig.onBlockDefaultAction
const doAsk = action === 'ask' const doAsk = action === 'ask'
const defaultValues = {} const defaultValues = {}
@ -43,9 +44,9 @@ const UserTimedFilterModal = {
computed: { computed: {
shouldConfirm() { shouldConfirm() {
if (this.isMute) { if (this.isMute) {
return this.$store.getters.mergedConfig.onMuteDefaultAction === 'ask' return useSyncConfigStore().mergedConfig.onMuteDefaultAction === 'ask'
} else { } else {
return this.$store.getters.mergedConfig.onBlockDefaultAction === 'ask' return useSyncConfigStore().mergedConfig.onBlockDefaultAction === 'ask'
} }
}, },
expiryString() { expiryString() {

View file

@ -1,3 +1,5 @@
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const VideoAttachment = { const VideoAttachment = {
props: ['attachment', 'controls'], props: ['attachment', 'controls'],
data() { data() {
@ -9,10 +11,10 @@ const VideoAttachment = {
}, },
computed: { computed: {
loopVideo() { loopVideo() {
if (this.$store.getters.mergedConfig.loopVideoSilentOnly) { if (useSyncConfigStore().mergedConfig.loopVideoSilentOnly) {
return !this.hasAudio return !this.hasAudio
} }
return this.$store.getters.mergedConfig.loopVideo return useSyncConfigStore().mergedConfig.loopVideo
}, },
}, },
methods: { methods: {

View file

@ -1,3 +1,4 @@
import { useInstanceStore } from 'src/stores/instance.js'
import apiService from '../../services/api/api.service.js' import apiService from '../../services/api/api.service.js'
import FollowCard from '../follow_card/follow_card.vue' import FollowCard from '../follow_card/follow_card.vue'

View file

@ -1,6 +1,7 @@
import { shuffle } from 'lodash' import { shuffle } from 'lodash'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { useInstanceStore } from 'src/stores/instance.js'
import apiService from '../../services/api/api.service.js' import apiService from '../../services/api/api.service.js'
function showWhoToFollow(panel, reply) { function showWhoToFollow(panel, reply) {
@ -8,7 +9,7 @@ function showWhoToFollow(panel, reply) {
panel.usersToFollow.forEach((toFollow, index) => { panel.usersToFollow.forEach((toFollow, index) => {
const user = shuffled[index] const user = shuffled[index]
const img = user.avatar || this.$store.state.instance.defaultAvatar const img = user.avatar || useInstanceStore().defaultAvatar
const name = user.acct const name = user.acct
toFollow.img = img toFollow.img = img
@ -46,7 +47,7 @@ const WhoToFollowPanel = {
return this.$store.state.users.currentUser.screen_name return this.$store.state.users.currentUser.screen_name
}, },
suggestionsEnabled() { suggestionsEnabled() {
return this.$store.state.instance.suggestionsEnabled return useInstanceStore().suggestionsEnabled
}, },
}, },
methods: { methods: {
@ -54,7 +55,7 @@ const WhoToFollowPanel = {
return generateProfileLink( return generateProfileLink(
id, id,
name, name,
this.$store.state.instance.restrictedNicknames, useInstanceStore().restrictedNicknames,
) )
}, },
}, },
@ -67,7 +68,7 @@ const WhoToFollowPanel = {
}, },
mounted: function () { mounted: function () {
this.usersToFollow = new Array(3).fill().map(() => ({ this.usersToFollow = new Array(3).fill().map(() => ({
img: this.$store.state.instance.defaultAvatar, img: useInstanceStore().defaultAvatar,
name: '', name: '',
id: 0, id: 0,
})) }))

View file

@ -0,0 +1,7 @@
export const piniaLanguagePlugin = ({ store, options }) => {
if (store.$id === 'serverSideStorage') {
store.$onAction(({ store }) => {
console.log(store)
})
}
}

View file

@ -1,38 +1,53 @@
import { useInterfaceStore } from 'src/stores/interface' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import {
registerPushNotifications,
unregisterPushNotifications,
} from '../services/sw/sw.js'
export default (store) => { export const vuexPushNotificationsPlugin = (store) => {
store.subscribe((mutation, state) => { store.subscribe((mutation, state) => {
const vapidPublicKey = state.instance.vapidPublicKey
const webPushNotification = state.config.webPushNotifications
const permission = useInterfaceStore().notificationPermission === 'granted'
const user = state.users.currentUser const user = state.users.currentUser
const webPushNotifications =
useSyncConfigStore().mergedConfig.webPushNotifications
const vapidPublicKey = useInstanceStore().vapidPublicKey
const permission = useInterfaceStore().notificationPermission === 'granted'
const isUserMutation = mutation.type === 'setCurrentUser' const isUserMutation = mutation.type === 'setCurrentUser'
const isVapidMutation =
mutation.type === 'setInstanceOption' &&
mutation.payload.name === 'vapidPublicKey'
const isPermMutation = const isPermMutation =
mutation.type === 'setNotificationPermission' && mutation.type === 'setNotificationPermission' &&
mutation.payload === 'granted' mutation.payload === 'granted'
const isUserConfigMutation =
mutation.type === 'setOption' &&
mutation.payload.name === 'webPushNotifications'
const isVisibilityMutation =
mutation.type === 'setOption' &&
mutation.payload.name === 'notificationVisibility'
if ( if (isUserMutation || isPermMutation) {
isUserMutation || if (user && vapidPublicKey && permission && webPushNotifications) {
isVapidMutation ||
isPermMutation ||
isUserConfigMutation ||
isVisibilityMutation
) {
if (user && vapidPublicKey && permission && webPushNotification) {
return store.dispatch('registerPushNotifications') return store.dispatch('registerPushNotifications')
} else if (isUserConfigMutation && !webPushNotification) { } else {
return store.dispatch('unregisterPushNotifications') return store.dispatch('unregisterPushNotifications')
} }
} }
}) })
} }
export const piniaPushNotificationsPlugin = ({ store, options }) => {
if (store.$id === 'syncConfigStore') {
store.$onAction(({ name, args }) => {
const { path } = args[0]
if (name === 'setPreference' && path === 'webPushNotifications') {
console.log('ACTION', args)
const user = window.vuex.state.users.currentUser
const webPushNotifications =
useSyncConfigStore().mergedConfig.webPushNotifications
const vapidPublicKey = useInstanceStore().vapidPublicKey
const permission =
useInterfaceStore().notificationPermission === 'granted'
if (user && vapidPublicKey && permission && webPushNotifications) {
return window.vuex.dispatch('registerPushNotifications')
} else {
return window.vuex.dispatch('unregisterPushNotifications')
}
}
})
}
}

View file

@ -20,7 +20,10 @@ import messages from './i18n/messages.js'
import createPersistedState, { import createPersistedState, {
piniaPersistPlugin, piniaPersistPlugin,
} from './lib/persisted_state.js' } from './lib/persisted_state.js'
import pushNotifications from './lib/push_notifications_plugin.js' import {
piniaPushNotificationsPlugin,
vuexPushNotificationsPlugin,
} from './lib/push_notifications_plugin.js'
import vuexModules from './modules/index.js' import vuexModules from './modules/index.js'
const currentLocale = (window.navigator.language || 'en').split('-')[0] const currentLocale = (window.navigator.language || 'en').split('-')[0]
@ -35,7 +38,7 @@ const i18n = createI18n({
messages.setLanguage(i18n.global, currentLocale) messages.setLanguage(i18n.global, currentLocale)
const persistedStateOptions = { const persistedStateOptions = {
paths: ['serverSideStorage.cache', 'config', 'users.lastLoginName', 'oauth'], paths: ['syncConfig.cache', 'config', 'users.lastLoginName', 'oauth'],
} }
;(async () => { ;(async () => {
@ -66,9 +69,10 @@ const persistedStateOptions = {
try { try {
let storageError let storageError
const plugins = [pushNotifications] const plugins = [vuexPushNotificationsPlugin]
const pinia = createPinia() const pinia = createPinia()
pinia.use(piniaPersistPlugin()) pinia.use(piniaPersistPlugin())
pinia.use(piniaPushNotificationsPlugin)
try { try {
const persistedState = await createPersistedState(persistedStateOptions) const persistedState = await createPersistedState(persistedStateOptions)

View file

@ -342,7 +342,7 @@ const api = {
// Set up websocket connection // Set up websocket connection
const token = state.wsToken const token = state.wsToken
if ( if (
rootState.instance.shoutAvailable && useInstanceStore().featureSet.shoutAvailable &&
typeof token !== 'undefined' && typeof token !== 'undefined' &&
state.socket === null state.socket === null
) { ) {

View file

@ -42,27 +42,6 @@ export const instanceDefaultProperties = Object.keys(instanceDefaultConfig)
const config = { const config = {
state: { ...defaultState }, state: { ...defaultState },
getters: {
defaultConfig(state, getters, rootState) {
const { instance } = rootState
return {
...defaultState,
...Object.fromEntries(
instanceDefaultProperties.map((key) => [key, instance[key]]),
),
}
},
mergedConfig(state, getters, rootState, rootGetters) {
const { defaultConfig } = rootGetters
return {
...defaultConfig,
// Do not override with undefined
...Object.fromEntries(
Object.entries(state).filter(([, v]) => v !== undefined),
),
}
},
},
mutations: { mutations: {
setOptionTemporarily(state, { name, value }) { setOptionTemporarily(state, { name, value }) {
set(state, name, value) set(state, name, value)
@ -84,47 +63,6 @@ const config = {
}, },
}, },
actions: { actions: {
loadSettings({ dispatch }, data) {
const knownKeys = new Set(Object.keys(defaultState))
const presentKeys = new Set(Object.keys(data))
const intersection = new Set()
for (const elem of presentKeys) {
if (knownKeys.has(elem)) {
intersection.add(elem)
}
}
intersection.forEach((name) =>
dispatch('setOption', { name, value: data[name] }),
)
},
setHighlight({ commit }, { user, color, type }) {
commit('setHighlight', { user, color, type })
},
setOptionTemporarily({ commit, dispatch, state }, { name, value }) {
if (useInterfaceStore().temporaryChangesTimeoutId !== null) {
console.warn("Can't track more than one temporary change")
return
}
const oldValue = state[name]
commit('setOptionTemporarily', { name, value })
const confirm = () => {
dispatch('setOption', { name, value })
useInterfaceStore().clearTemporaryChanges()
}
const revert = () => {
commit('setOptionTemporarily', { name, value: oldValue })
useInterfaceStore().clearTemporaryChanges()
}
useInterfaceStore().setTemporaryChanges({
confirm,
revert,
})
},
setThemeV2({ commit, dispatch }, { customTheme, customThemeSource }) { setThemeV2({ commit, dispatch }, { customTheme, customThemeSource }) {
commit('setOption', { name: 'theme', value: 'custom' }) commit('setOption', { name: 'theme', value: 'custom' })
commit('setOption', { name: 'customTheme', value: customTheme }) commit('setOption', { name: 'customTheme', value: customTheme })

View file

@ -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,

View file

@ -1,7 +1,7 @@
// See build/emojis_plugin for more details // See build/emojis_plugin for more details
import { ensureFinalFallback } from 'src/i18n/languages.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { ensureFinalFallback } from '../i18n/languages.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
import { instanceDefaultProperties } from './config.js' import { instanceDefaultProperties } from './config.js'
import { import {
@ -158,59 +158,6 @@ const instance = {
.map((key) => [key, state[key]]) .map((key) => [key, state[key]])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
}, },
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 state.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) =>
(state.emoji[groupId] || []).map((k) =>
injectAnnotations(k, state.unicodeEmojiAnnotations),
),
).reduce((a, b) => a.concat(b), [])
},
standardEmojiGroupList(state) {
return SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
id: groupId,
emojis: (state.emoji[groupId] || []).map((k) =>
injectAnnotations(k, state.unicodeEmojiAnnotations),
),
}))
},
instanceDomain(state) { instanceDomain(state) {
return new URL(state.server).hostname return new URL(state.server).hostname
}, },
@ -349,17 +296,6 @@ const instance = {
console.warn("Can't load custom emojis\n", e) console.warn("Can't load custom emojis\n", e)
} }
}, },
fetchEmoji({ dispatch, state }) {
if (!state.customEmojiFetched) {
state.customEmojiFetched = true
dispatch('getCustomEmoji')
}
if (!state.emojiFetched) {
state.emojiFetched = true
dispatch('getStaticEmoji')
}
},
async getKnownDomains({ commit, rootState }) { async getKnownDomains({ commit, rootState }) {
try { try {
const result = await apiService.fetchKnownDomains({ const result = await apiService.fetchKnownDomains({

View file

@ -1,5 +1,5 @@
import { useReportsStore } from 'src/stores/reports.js' import { useReportsStore } from 'src/stores/reports.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
import { import {
closeAllDesktopNotifications, closeAllDesktopNotifications,
@ -118,9 +118,7 @@ export const notifications = {
maybeShowNotification( maybeShowNotification(
store, store,
Object.values( Object.values(useSyncConfigStore().prefsStorage.simple.muteFilters),
useServerSideStorageStore().prefsStorage.simple.muteFilters,
),
notification, notification,
) )
} else if (notification.seen) { } else if (notification.seen) {

View file

@ -10,9 +10,11 @@ import {
} from 'lodash' } from 'lodash'
import { declarations } from 'src/modules/config_declaration' import { declarations } from 'src/modules/config_declaration'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useEmojiStore } from 'src/stores/emoji.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import oauthApi from '../services/new_api/oauth.js' import oauthApi from '../services/new_api/oauth.js'
@ -678,14 +680,14 @@ const users = {
useInterfaceStore().setLastTimeline('public-timeline') useInterfaceStore().setLastTimeline('public-timeline')
useInterfaceStore().setLayoutWidth(windowWidth()) useInterfaceStore().setLayoutWidth(windowWidth())
useInterfaceStore().setLayoutHeight(windowHeight()) useInterfaceStore().setLayoutHeight(windowHeight())
store.commit('clearServerSideStorage') store.commit('clearSyncConfig')
}) })
}, },
loginUser(store, accessToken) { loginUser(store, accessToken) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const commit = store.commit const commit = store.commit
const dispatch = store.dispatch const dispatch = store.dispatch
const rootState = store.rootState
commit('beginLogin') commit('beginLogin')
store.rootState.api.backendInteractor store.rootState.api.backendInteractor
.verifyCredentials(accessToken) .verifyCredentials(accessToken)
@ -699,10 +701,10 @@ const users = {
user.domainMutes = [] user.domainMutes = []
commit('setCurrentUser', user) commit('setCurrentUser', user)
useServerSideStorageStore().setServerSideStorage(user) useSyncConfigStore().setSyncConfig(user)
commit('addNewUsers', [user]) commit('addNewUsers', [user])
dispatch('fetchEmoji') useEmojiStore().fetchEmoji()
getNotificationPermission().then((permission) => getNotificationPermission().then((permission) =>
useInterfaceStore().setNotificationPermission(permission), useInterfaceStore().setNotificationPermission(permission),
@ -720,17 +722,16 @@ const users = {
/* /*
// Reset wordfilter // Reset wordfilter
Object.keys( Object.keys(
useServerSideStorageStore().prefsStorage.simple.muteFilters useSyncConfigStore().prefsStorage.simple.muteFilters
).forEach(key => { ).forEach(key => {
useServerSideStorageStore().unsetPreference({ path: 'simple.muteFilters.' + key, value: null }) useSyncConfigStore().unsetPreference({ path: 'simple.muteFilters.' + key, value: null })
}) })
// Reset flag to 0 to re-run migrations // Reset flag to 0 to re-run migrations
useServerSideStorageStore().setFlag({ flag: 'configMigration', value: 0 }) useSyncConfigStore().setFlag({ flag: 'configMigration', value: 0 })
/**/ /**/
const { configMigration } = const { configMigration } = useSyncConfigStore().flagStorage
useServerSideStorageStore().flagStorage
declarations declarations
.filter((x) => { .filter((x) => {
return ( return (
@ -741,12 +742,12 @@ const users = {
}) })
.toSorted((a, b) => a.configMigration - b.configMigration) .toSorted((a, b) => a.configMigration - b.configMigration)
.forEach((value) => { .forEach((value) => {
value.migration(useServerSideStorageStore(), store.rootState) value.migration(useSyncConfigStore(), store.rootState)
useServerSideStorageStore().setFlag({ useSyncConfigStore().setFlag({
flag: 'configMigration', flag: 'configMigration',
value: value.migrationNum, value: value.migrationNum,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}) })
if (user.token) { if (user.token) {
@ -763,7 +764,9 @@ const users = {
// Start fetching notifications // Start fetching notifications
dispatch('startFetchingNotifications') dispatch('startFetchingNotifications')
if (rootState.instance.pleromaChatMessagesAvailable) { if (
useInstanceStore().featureSet.pleromaChatMessagesAvailable
) {
// Start fetching chats // Start fetching chats
dispatch('startFetchingChats') dispatch('startFetchingChats')
} }
@ -776,7 +779,7 @@ const users = {
dispatch('startFetchingFollowRequests') dispatch('startFetchingFollowRequests')
} }
if (store.getters.mergedConfig.useStreamingApi) { if (useSyncConfigStore().mergedConfig.useStreamingApi) {
dispatch('fetchTimeline', { timeline: 'friends', since: null }) dispatch('fetchTimeline', { timeline: 'friends', since: null })
dispatch('fetchNotifications', { since: null }) dispatch('fetchNotifications', { since: null })
dispatch('enableMastoSockets', true) dispatch('enableMastoSockets', true)

View file

@ -1,6 +1,7 @@
import FaviconService from 'src/services/favicon_service/favicon_service.js' import FaviconService from 'src/services/favicon_service/favicon_service.js'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useI18nStore } from 'src/stores/i18n.js' import { useI18nStore } from 'src/stores/i18n.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js' import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
import { muteFilterHits } from '../status_parser/status_parser.js' import { muteFilterHits } from '../status_parser/status_parser.js'
@ -15,10 +16,7 @@ let cachedBadgeUrl = null
export const notificationsFromStore = (store) => store.state.notifications.data export const notificationsFromStore = (store) => store.state.notifications.data
export const visibleTypes = (store) => { export const visibleTypes = (store) => {
// When called from within a module we need rootGetters to access wider scope const { notificationVisibility } = useSyncConfigStore().mergedConfig
// 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
return [ return [
notificationVisibility.likes && 'like', notificationVisibility.likes && 'like',
@ -101,8 +99,8 @@ export const filteredNotificationsFromStore = (store, types) => {
} }
export const unseenNotificationsFromStore = (store) => { export const unseenNotificationsFromStore = (store) => {
const rootGetters = store.rootGetters || store.getters const ignoreInactionableSeen =
const ignoreInactionableSeen = rootGetters.mergedConfig.ignoreInactionableSeen useSyncConfigStore().mergedConfig.ignoreInactionableSeen
return filteredNotificationsFromStore(store).filter(({ seen, type }) => { return filteredNotificationsFromStore(store).filter(({ seen, type }) => {
if (!ignoreInactionableSeen) return !seen if (!ignoreInactionableSeen) return !seen
@ -183,7 +181,7 @@ export const prepareNotificationObject = (notification, i18n) => {
export const countExtraNotifications = (store) => { export const countExtraNotifications = (store) => {
const rootGetters = store.rootGetters || store.getters const rootGetters = store.rootGetters || store.getters
const mergedConfig = rootGetters.mergedConfig const mergedConfig = useSyncConfigStore().mergedConfig
if (!mergedConfig.showExtraNotifications) { if (!mergedConfig.showExtraNotifications) {
return 0 return 0

View file

@ -1,4 +1,6 @@
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import apiService from '../api/api.service.js' import apiService from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
@ -23,12 +25,11 @@ const mastoApiNotificationTypes = new Set([
const fetchAndUpdate = ({ store, credentials, older = false, since }) => { const fetchAndUpdate = ({ store, credentials, older = false, since }) => {
const args = { credentials } const args = { credentials }
const { getters } = store
const rootState = store.rootState || store.state const rootState = store.rootState || store.state
const timelineData = rootState.notifications const timelineData = rootState.notifications
const hideMutedPosts = getters.mergedConfig.hideMutedPosts const { hideMutedPosts } = useSyncConfigStore().mergedConfig
if (rootState.instance.pleromaChatMessagesAvailable) { if (useInstanceStore().featureSet.pleromaChatMessagesAvailable) {
mastoApiNotificationTypes.add('pleroma:chat_mention') mastoApiNotificationTypes.add('pleroma:chat_mention')
} }

View file

@ -1,6 +1,7 @@
import { camelCase } from 'lodash' import { camelCase } from 'lodash'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import apiService from '../api/api.service.js' import apiService from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
@ -41,9 +42,8 @@ const fetchAndUpdate = ({
}) => { }) => {
const args = { timeline, credentials } const args = { timeline, credentials }
const rootState = store.rootState || store.state const rootState = store.rootState || store.state
const { getters } = store
const timelineData = rootState.statuses.timelines[camelCase(timeline)] const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const { hideMutedPosts, replyVisibility } = getters.mergedConfig const { hideMutedPosts, replyVisibility } = useSyncConfigStore().mergedConfig
const loggedIn = !!rootState.users.currentUser const loggedIn = !!rootState.users.currentUser
if (older) { if (older) {

243
src/stores/emoji.js Normal file
View file

@ -0,0 +1,243 @@
import { defineStore } from 'pinia'
import { ensureFinalFallback } from 'src/i18n/languages.js'
import { useInstanceStore } from 'src/stores/instance.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))
}
},
},
})

View file

@ -1,8 +1,8 @@
import { get, set } from 'lodash' import { get, set } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ensureFinalFallback } from 'src/i18n/languages.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { ensureFinalFallback } from '../i18n/languages.js'
import { instanceDefaultProperties } from '../modules/config.js' import { instanceDefaultProperties } from '../modules/config.js'
import { import {
instanceDefaultConfig, instanceDefaultConfig,
@ -10,40 +10,6 @@ import {
} from '../modules/default_config_state.js' } from '../modules/default_config_state.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations'
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 REMOTE_INTERACTION_URL = '/main/ostatus' const REMOTE_INTERACTION_URL = '/main/ostatus'
const defaultState = { const defaultState = {
@ -80,15 +46,6 @@ const defaultState = {
...instanceDefaultConfig, ...instanceDefaultConfig,
}, },
// Custom emoji from server
customEmoji: [],
customEmojiFetched: false,
// Unicode emoji from bundle
emoji: {},
emojiFetched: false,
unicodeEmojiAnnotations: {},
// Known domains list for user's domain-muting // Known domains list for user's domain-muting
knownDomains: [], knownDomains: [],
@ -143,27 +100,6 @@ const defaultState = {
}, },
} }
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 useInstanceStore = defineStore('instance', { export const useInstanceStore = defineStore('instance', {
state: () => ({ ...defaultState }), state: () => ({ ...defaultState }),
getters: { getters: {
@ -172,59 +108,6 @@ export const useInstanceStore = defineStore('instance', {
.map((key) => [key, state[key]]) .map((key) => [key, state[key]])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
}, },
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),
),
}))
},
instanceDomain(state) { instanceDomain(state) {
return new URL(this.server).hostname return new URL(this.server).hostname
}, },
@ -259,121 +142,6 @@ export const useInstanceStore = defineStore('instance', {
break break
} }
}, },
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 ? this.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.customEmojiFetched = true
window.vuex.dispatch('getCustomEmoji')
}
if (!this.emojiFetched) {
this.emojiFetched = true
window.vuex.dispatch('getStaticEmoji')
}
},
async getKnownDomains() { async getKnownDomains() {
try { try {
this.knownDomains = await apiService.fetchKnownDomains({ this.knownDomains = await apiService.fetchKnownDomains({

View file

@ -5,6 +5,8 @@ import {
generatePreset, generatePreset,
} from 'src/services/theme_data/theme_data.service.js' } from 'src/services/theme_data/theme_data.service.js'
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { import {
applyTheme, applyTheme,
getResourcesIndex, getResourcesIndex,
@ -86,7 +88,7 @@ export const useInterfaceStore = defineStore('interface', {
}, },
setPageTitle(option = '') { setPageTitle(option = '') {
try { try {
document.title = `${option} ${window.vuex.state.instance.name}` document.title = `${option} ${useInstanceStore().name}`
} catch (error) { } catch (error) {
console.error(`${error}`) console.error(`${error}`)
} }
@ -182,7 +184,7 @@ export const useInterfaceStore = defineStore('interface', {
const mobileLayout = width <= 800 const mobileLayout = width <= 800
const normalOrMobile = mobileLayout ? 'mobile' : 'normal' const normalOrMobile = mobileLayout ? 'mobile' : 'normal'
const { thirdColumnMode } = window.vuex.getters.mergedConfig const { thirdColumnMode } = useSyncConfigStore().mergedConfig
if (thirdColumnMode === 'none' || !window.vuex.state.users.currentUser) { if (thirdColumnMode === 'none' || !window.vuex.state.users.currentUser) {
this.layoutType = normalOrMobile this.layoutType = normalOrMobile
} else { } else {
@ -221,15 +223,15 @@ 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', path: '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', path: 'palettesIndex',
value: { _error: e }, value: { _error: e },
}) })
return Promise.resolve({}) return Promise.resolve({})
@ -239,7 +241,7 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
window.vuex.commit('setOption', { name: 'palette', value }) useSyncConfigStore().setPreference({ path: 'palette', value })
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -247,7 +249,7 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
window.vuex.commit('setOption', { name: 'paletteCustomData', value }) useSyncConfigStore().setPreference({ path: 'paletteCustomData', value })
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -257,12 +259,12 @@ export const useInterfaceStore = defineStore('interface', {
'/static/styles/index.json', '/static/styles/index.json',
deserialize, deserialize,
) )
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value }) useInstanceStore().set({ path: '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', path: 'stylesIndex',
value: { _error: e }, value: { _error: e },
}) })
return Promise.resolve({}) return Promise.resolve({})
@ -273,7 +275,7 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV2() this.resetThemeV2()
this.resetThemeV3Palette() this.resetThemeV3Palette()
window.vuex.commit('setOption', { name: 'style', value }) useSyncConfigStore().setPreference({ path: 'style', value })
this.useStylePalette = true this.useStylePalette = true
this.applyTheme({ recompile: true }).then(() => { this.applyTheme({ recompile: true }).then(() => {
@ -285,7 +287,7 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV2() this.resetThemeV2()
this.resetThemeV3Palette() this.resetThemeV3Palette()
window.vuex.commit('setOption', { name: 'styleCustomData', value }) useSyncConfigStore().setPreference({ path: 'styleCustomData', value })
this.useStylePalette = true this.useStylePalette = true
this.applyTheme({ recompile: true }).then(() => { this.applyTheme({ recompile: true }).then(() => {
@ -295,12 +297,12 @@ 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({ path: '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', path: 'themesIndex',
value: { _error: e }, value: { _error: e },
}) })
return Promise.resolve({}) return Promise.resolve({})
@ -311,7 +313,7 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
window.vuex.commit('setOption', { name: 'theme', value }) useSyncConfigStore().setPreference({ name: 'theme', value })
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -320,27 +322,30 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
window.vuex.commit('setOption', { name: 'customTheme', value }) useSyncConfigStore().setPreference({ path: 'customTheme', value })
window.vuex.commit('setOption', { name: 'customThemeSource', value }) useSyncConfigStore().setPreference({ path: 'customThemeSource', value })
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
resetThemeV3() { resetThemeV3() {
window.vuex.commit('setOption', { name: 'style', value: null }) useSyncConfigStore().setPreference({ path: 'style', value: null })
window.vuex.commit('setOption', { name: 'styleCustomData', value: null }) useSyncConfigStore().setPreference({
path: 'styleCustomData',
value: null,
})
}, },
resetThemeV3Palette() { resetThemeV3Palette() {
window.vuex.commit('setOption', { name: 'palette', value: null }) useSyncConfigStore().setPreference({ path: 'palette', value: null })
window.vuex.commit('setOption', { useSyncConfigStore().setPreference({
name: 'paletteCustomData', name: 'paletteCustomData',
value: null, value: null,
}) })
}, },
resetThemeV2() { resetThemeV2() {
window.vuex.commit('setOption', { name: 'theme', value: null }) useSyncConfigStore().setPreference({ path: 'theme', value: null })
window.vuex.commit('setOption', { name: 'customTheme', value: null }) useSyncConfigStore().setPreference({ path: 'customTheme', value: null })
window.vuex.commit('setOption', { useSyncConfigStore().setPreference({
name: 'customThemeSource', path: 'customThemeSource',
value: null, value: null,
}) })
}, },
@ -385,14 +390,14 @@ export const useInterfaceStore = defineStore('interface', {
} }
const { style: instanceStyleName, palette: instancePaletteName } = const { style: instanceStyleName, palette: instancePaletteName } =
window.vuex.state.instance useInstanceStore()
let { let {
theme: instanceThemeV2Name, theme: instanceThemeV2Name,
themesIndex, themesIndex,
stylesIndex, stylesIndex,
palettesIndex, palettesIndex,
} = window.vuex.state.instance } = useInstanceStore()
const { const {
style: userStyleName, style: userStyleName,
@ -508,8 +513,8 @@ export const useInterfaceStore = defineStore('interface', {
) )
if (this.useStylePalette) { if (this.useStylePalette) {
window.vuex.commit('setOption', { useSyncConfigStore().setPreference({
name: 'palette', path: 'palette',
value: firstStylePaletteName, value: firstStylePaletteName,
}) })
} }

View file

@ -397,7 +397,7 @@ export const _doMigrations = (cache, live) => {
console.debug('Found hotpatch migration, applying') console.debug('Found hotpatch migration, applying')
return window._PLEROMA_HOTPATCH.reverseMigrations.call( return window._PLEROMA_HOTPATCH.reverseMigrations.call(
{}, {},
'serverSideStorage', 'syncConfigStore',
{ from: data._version, to: VERSION }, { from: data._version, to: VERSION },
data, data,
) )
@ -408,7 +408,7 @@ export const _doMigrations = (cache, live) => {
return cache return cache
} }
export const useServerSideStorageStore = defineStore('serverSideStorage', { export const useSyncConfigStore = defineStore('syncConfigStore', {
state() { state() {
return cloneDeep(defaultState) return cloneDeep(defaultState)
}, },
@ -560,13 +560,13 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
username, username,
) )
}, },
clearServerSideStorage() { clearSyncConfig() {
const blankState = { ...cloneDeep(defaultState) } const blankState = { ...cloneDeep(defaultState) }
Object.keys(this).forEach((k) => { Object.keys(this).forEach((k) => {
this[k] = blankState[k] this[k] = blankState[k]
}) })
}, },
setServerSideStorage(userData) { setSyncConfig(userData) {
const live = userData.storage const live = userData.storage
this.raw = live this.raw = live
let cache = this.cache let cache = this.cache
@ -633,7 +633,7 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
this.flagStorage = this.cache.flagStorage this.flagStorage = this.cache.flagStorage
this.prefsStorage = this.cache.prefsStorage this.prefsStorage = this.cache.prefsStorage
}, },
pushServerSideStorage({ force = false } = {}) { pushSyncConfig({ force = false } = {}) {
const needPush = this.dirty || force const needPush = this.dirty || force
if (!needPush) return if (!needPush) return
this.updateCache({ username: window.vuex.state.users.currentUser.fqn }) this.updateCache({ username: window.vuex.state.users.currentUser.fqn })
@ -641,7 +641,7 @@ export const useServerSideStorageStore = defineStore('serverSideStorage', {
window.vuex.state.api.backendInteractor window.vuex.state.api.backendInteractor
.updateProfileJSON({ params }) .updateProfileJSON({ params })
.then((user) => { .then((user) => {
this.setServerSideStorage(user) this.setSyncConfig(user)
this.dirty = false this.dirty = false
}) })
}, },

View file

@ -5,9 +5,10 @@ import 'virtual:pleroma-fe/service_worker_env'
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import { storage } from 'src/lib/storage.js' import { storage } from 'src/lib/storage.js'
import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js' import { parseNotification } from 'src/services/entity_normalizer/entity_normalizer.service.js'
import { prepareNotificationObject } from './services/notification_utils/notification_utils.js' import { prepareNotificationObject } from 'src/services/notification_utils/notification_utils.js'
import { cacheKey, emojiCacheKey, shouldCache } from './services/sw/sw.js' import { cacheKey, emojiCacheKey, shouldCache } from 'src/services/sw/sw.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
// Collects all messages for service workers // Collects all messages for service workers
// Needed because service workers cannot use dynamic imports // Needed because service workers cannot use dynamic imports
@ -35,7 +36,7 @@ function getWindowClients() {
const setSettings = async () => { const setSettings = async () => {
const vuexState = await storage.getItem('vuex-lz') const vuexState = await storage.getItem('vuex-lz')
const locale = vuexState.config.interfaceLanguage || 'en' const locale = useSyncConfigStore().mergedConfig.interfaceLanguage || 'en'
i18n.locale = locale i18n.locale = locale
const notificationsNativeArray = Object.entries( const notificationsNativeArray = Object.entries(
vuexState.config.notificationNative, vuexState.config.notificationNative,

View file

@ -12,25 +12,25 @@ import {
COMMAND_TRIM_FLAGS_AND_RESET, COMMAND_TRIM_FLAGS_AND_RESET,
defaultState, defaultState,
newUserFlags, newUserFlags,
useServerSideStorageStore, useSyncConfigStore,
VERSION, VERSION,
} from 'src/stores/serverSideStorage.js' } from 'src/stores/sync_config.js'
describe('The serverSideStorage module', () => { describe('The SyncConfig module', () => {
beforeEach(() => { beforeEach(() => {
setActivePinia(createPinia()) setActivePinia(createPinia())
}) })
describe('mutations', () => { describe('mutations', () => {
describe('setServerSideStorage', () => { describe('setSyncConfig', () => {
const user = { const user = {
created_at: new Date('1999-02-09'), created_at: new Date('1999-02-09'),
storage: {}, storage: {},
} }
it('should initialize storage if none present', () => { it('should initialize storage if none present', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setServerSideStorage(store, user) store.setSyncConfig(store, user)
expect(store.cache._version).to.eql(VERSION) expect(store.cache._version).to.eql(VERSION)
expect(store.cache._timestamp).to.be.a('number') expect(store.cache._timestamp).to.be.a('number')
expect(store.cache.flagStorage).to.eql(defaultState.flagStorage) expect(store.cache.flagStorage).to.eql(defaultState.flagStorage)
@ -38,8 +38,8 @@ describe('The serverSideStorage module', () => {
}) })
it('should initialize storage with proper flags for new users if none present', () => { it('should initialize storage with proper flags for new users if none present', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setServerSideStorage({ ...user, created_at: new Date() }) store.setSyncConfig({ ...user, created_at: new Date() })
expect(store.cache._version).to.eql(VERSION) expect(store.cache._version).to.eql(VERSION)
expect(store.cache._timestamp).to.be.a('number') expect(store.cache._timestamp).to.be.a('number')
expect(store.cache.flagStorage).to.eql(newUserFlags) expect(store.cache.flagStorage).to.eql(newUserFlags)
@ -47,14 +47,14 @@ describe('The serverSideStorage module', () => {
}) })
it('should merge flags even if remote timestamp is older', () => { it('should merge flags even if remote timestamp is older', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.cache = { store.cache = {
_timestamp: Date.now(), _timestamp: Date.now(),
_version: VERSION, _version: VERSION,
...cloneDeep(defaultState), ...cloneDeep(defaultState),
} }
store.setServerSideStorage({ store.setSyncConfig({
...user, ...user,
storage: { storage: {
_timestamp: 123, _timestamp: 123,
@ -76,10 +76,10 @@ describe('The serverSideStorage module', () => {
}) })
it('should reset local timestamp to remote if contents are the same', () => { it('should reset local timestamp to remote if contents are the same', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.cache = null store.cache = null
store.setServerSideStorage({ store.setSyncConfig({
...user, ...user,
storage: { storage: {
_timestamp: 123, _timestamp: 123,
@ -96,8 +96,8 @@ describe('The serverSideStorage module', () => {
}) })
it('should remote version if local missing', () => { it('should remote version if local missing', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setServerSideStorage(store, user) store.setSyncConfig(store, user)
expect(store.cache._version).to.eql(VERSION) expect(store.cache._version).to.eql(VERSION)
expect(store.cache._timestamp).to.be.a('number') expect(store.cache._timestamp).to.be.a('number')
expect(store.cache.flagStorage).to.eql(defaultState.flagStorage) expect(store.cache.flagStorage).to.eql(defaultState.flagStorage)
@ -105,7 +105,7 @@ describe('The serverSideStorage module', () => {
}) })
describe('setPreference', () => { describe('setPreference', () => {
it('should set preference and update journal log accordingly', () => { it('should set preference and update journal log accordingly', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.testing', value: 1 }) store.setPreference({ path: 'simple.testing', value: 1 })
expect(store.prefsStorage.simple.testing).to.eql(1) expect(store.prefsStorage.simple.testing).to.eql(1)
expect(store.prefsStorage._journal.length).to.eql(1) expect(store.prefsStorage._journal.length).to.eql(1)
@ -119,7 +119,7 @@ describe('The serverSideStorage module', () => {
}) })
it('should keep journal to a minimum', () => { it('should keep journal to a minimum', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.testing', value: 1 }) store.setPreference({ path: 'simple.testing', value: 1 })
store.setPreference({ path: 'simple.testing', value: 2 }) store.setPreference({ path: 'simple.testing', value: 2 })
store.addCollectionPreference({ path: 'collections.testing', value: 2 }) store.addCollectionPreference({ path: 'collections.testing', value: 2 })
@ -148,7 +148,7 @@ describe('The serverSideStorage module', () => {
}) })
it('should remove duplicate entries from journal', () => { it('should remove duplicate entries from journal', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.testing', value: 1 }) store.setPreference({ path: 'simple.testing', value: 1 })
store.setPreference({ path: 'simple.testing', value: 1 }) store.setPreference({ path: 'simple.testing', value: 1 })
store.addCollectionPreference({ path: 'collections.testing', value: 2 }) store.addCollectionPreference({ path: 'collections.testing', value: 2 })
@ -160,7 +160,7 @@ describe('The serverSideStorage module', () => {
}) })
it('should remove depth = 3 set/unset entries from journal', () => { it('should remove depth = 3 set/unset entries from journal', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.object.foo', value: 1 }) store.setPreference({ path: 'simple.object.foo', value: 1 })
store.unsetPreference({ path: 'simple.object.foo' }) store.unsetPreference({ path: 'simple.object.foo' })
store.updateCache(store, { username: 'test' }) store.updateCache(store, { username: 'test' })
@ -169,7 +169,7 @@ describe('The serverSideStorage module', () => {
}) })
it('should not allow unsetting depth <= 2', () => { it('should not allow unsetting depth <= 2', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.object.foo', value: 1 }) store.setPreference({ path: 'simple.object.foo', value: 1 })
expect(() => store.unsetPreference({ path: 'simple' })).to.throw() expect(() => store.unsetPreference({ path: 'simple' })).to.throw()
expect(() => expect(() =>
@ -178,7 +178,7 @@ describe('The serverSideStorage module', () => {
}) })
it('should not allow (un)setting depth > 3', () => { it('should not allow (un)setting depth > 3', () => {
const store = useServerSideStorageStore() const store = useSyncConfigStore()
store.setPreference({ path: 'simple.object', value: {} }) store.setPreference({ path: 'simple.object', value: {} })
expect(() => expect(() =>
store.setPreference({ path: 'simple.object.lv3', value: 1 }), store.setPreference({ path: 'simple.object.lv3', value: 1 }),