Merge branch 'develop' into setttingssync

This commit is contained in:
Henry Jameson 2026-02-12 17:16:18 +02:00
commit 3530830b07
134 changed files with 1411 additions and 1299 deletions

View file

@ -1,36 +1,31 @@
import { throttle } from 'lodash' import { throttle } from 'lodash'
import { mapActions, mapState } from 'pinia' import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapGetters } from 'vuex'
import DesktopNav from 'src/components/desktop_nav/desktop_nav.vue' import DesktopNav from './components/desktop_nav/desktop_nav.vue'
import EditStatusModal from 'src/components/edit_status_modal/edit_status_modal.vue' import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
import FeaturesPanel from 'src/components/features_panel/features_panel.vue' import FeaturesPanel from './components/features_panel/features_panel.vue'
import GlobalNoticeList from 'src/components/global_notice_list/global_notice_list.vue' import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue'
import InstanceSpecificPanel from 'src/components/instance_specific_panel/instance_specific_panel.vue' import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import MediaModal from 'src/components/media_modal/media_modal.vue' import MediaModal from './components/media_modal/media_modal.vue'
import MobileNav from 'src/components/mobile_nav/mobile_nav.vue' import MobileNav from './components/mobile_nav/mobile_nav.vue'
import MobilePostStatusButton from 'src/components/mobile_post_status_button/mobile_post_status_button.vue' import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue' import NavPanel from './components/nav_panel/nav_panel.vue'
import PostStatusModal from 'src/components/post_status_modal/post_status_modal.vue' import PostStatusModal from './components/post_status_modal/post_status_modal.vue'
import ShoutPanel from 'src/components/shout_panel/shout_panel.vue' import ShoutPanel from './components/shout_panel/shout_panel.vue'
import SideDrawer from 'src/components/side_drawer/side_drawer.vue' import SideDrawer from './components/side_drawer/side_drawer.vue'
import StatusHistoryModal from 'src/components/status_history_modal/status_history_modal.vue' import StatusHistoryModal from './components/status_history_modal/status_history_modal.vue'
import UserPanel from 'src/components/user_panel/user_panel.vue' import UserPanel from './components/user_panel/user_panel.vue'
import UserReportingModal from 'src/components/user_reporting_modal/user_reporting_modal.vue' import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
import WhoToFollowPanel from 'src/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 { windowHeight, windowWidth } from './services/window_utils/window_utils'
import { useI18nStore } from 'src/stores/i18n.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useShoutStore } from 'src/stores/shout.js' import { useShoutStore } from 'src/stores/shout.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { applyStyleConfig } from 'src/services/style_setter/style_setter.js'
import { getOrCreateServiceWorker } from 'src/services/sw/sw'
import {
windowHeight,
windowWidth,
} from 'src/services/window_utils/window_utils'
export default { export default {
name: 'app', name: 'app',
@ -76,11 +71,11 @@ 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]
useI18nStore().setLanguage()
applyStyleConfig(useSyncConfigStore().mergedConfig)
// Create bound handlers // Create bound handlers
this.updateScrollState = throttle(this.scrollHandler, 200) this.updateScrollState = throttle(this.scrollHandler, 200)
this.updateMobileState = throttle(this.resizeHandler, 200) this.updateMobileState = throttle(this.resizeHandler, 200)
@ -89,7 +84,7 @@ export default {
window.addEventListener('resize', this.updateMobileState) window.addEventListener('resize', this.updateMobileState)
this.scrollParent.addEventListener('scroll', this.updateScrollState) this.scrollParent.addEventListener('scroll', this.updateScrollState)
if (useInterfaceStore().themeApplied) { if (this.themeApplied) {
this.setThemeBodyClass() this.setThemeBodyClass()
this.removeSplash() this.removeSplash()
} }
@ -100,12 +95,9 @@ export default {
this.scrollParent.removeEventListener('scroll', this.updateScrollState) this.scrollParent.removeEventListener('scroll', this.updateScrollState)
}, },
computed: { computed: {
themeApplied() {
return useInterfaceStore().themeApplied
},
currentTheme() { currentTheme() {
if (useInterfaceStore().styleDataUsed) { if (this.styleDataUsed) {
const styleMeta = useInterfaceStore().styleDataUsed.find( const styleMeta = this.styleDataUsed.find(
(x) => x.component === '@meta', (x) => x.component === '@meta',
) )
@ -130,7 +122,7 @@ export default {
] ]
}, },
navClasses() { navClasses() {
const { navbarColumnStretch } = useSyncConfigStore().mergedConfig const { navbarColumnStretch } = this.$store.getters.mergedConfig
return [ return [
'-' + this.layoutType, '-' + this.layoutType,
...(navbarColumnStretch ? ['-column-stretch'] : []), ...(navbarColumnStretch ? ['-column-stretch'] : []),
@ -142,6 +134,9 @@ export default {
userBackground() { userBackground() {
return this.currentUser.background_image return this.currentUser.background_image
}, },
instanceBackground() {
return this.mergedConfig.hideInstanceWallpaper ? null : this.background
},
background() { background() {
return this.userBackground || this.instanceBackground return this.userBackground || this.instanceBackground
}, },
@ -164,11 +159,20 @@ export default {
newPostButtonShown() { newPostButtonShown() {
if (this.isChats) return false if (this.isChats) return false
if (this.isListEdit) return false if (this.isListEdit) return false
return this.alwaysShowNewPostButton || this.layoutType === 'mobile' return (
this.$store.getters.mergedConfig.alwaysShowNewPostButton ||
this.layoutType === 'mobile'
)
},
shoutboxPosition() {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false
},
hideShoutbox() {
return this.$store.getters.mergedConfig.hideShoutbox
}, },
reverseLayout() { reverseLayout() {
const { thirdColumnMode, sidebarRight: reverseSetting } = const { thirdColumnMode, sidebarRight: reverseSetting } =
useSyncConfigStore().mergedConfig this.$store.getters.mergedConfig
if (this.layoutType !== 'wide') { if (this.layoutType !== 'wide') {
return reverseSetting return reverseSetting
} else { } else {
@ -177,46 +181,44 @@ export default {
: !reverseSetting : !reverseSetting
} }
}, },
noSticky() {
return this.$store.getters.mergedConfig.disableStickyHeaders
},
showScrollbars() {
return this.$store.getters.mergedConfig.showScrollbars
},
scrollParent() { scrollParent() {
return window /* this.$refs.appContentRef */ return window /* this.$refs.appContentRef */
}, },
showInstanceSpecificPanel() {
...mapState(useSyncConfigStore, { return (
shoutboxPosition: (store) => this.instanceSpecificPanelPresent &&
store.mergedConfig.alwaysShowSubjectInput || false, !this.$store.getters.mergedConfig.hideISP
alwaysShowSubjectInput: (store) => )
store.mergedConfig.alwaysShowSubjectInput, },
}), ...mapGetters(['mergedConfig']),
...mapState(useInterfaceStore, [
...mapState(useInterfaceStore, ['layoutType']), 'themeApplied',
'styleDataUsed',
...mapState(useSyncConfigStore, { 'layoutType',
hideShoutbox: (store) => store.mergedConfig.hideShoutbox,
noSticky: (store) => store.mergedConfig.disableStickyHeaders,
showScrollbars: (store) => store.mergedConfig.showScrollbars,
}),
...mapState(useInstanceStore, {
instanceBackground: (store) =>
useSyncConfigStore().mergedConfig.hideInstanceWallpaper
? null
: store.background,
showInstanceSpecificPanel: (store) =>
store.showInstanceSpecificPanel &&
!useSyncConfigStore().mergedConfig.hideISP &&
store.instanceSpecificPanelContent,
}),
...mapState(useInstanceStore, [
'editingAvailable',
'showFeaturesPanel',
'private',
'suggestionsEnabled',
]), ]),
...mapState(useInstanceStore, ['styleDataUsed']),
...mapState(useInstanceCapabilitiesStore, [
'suggestionsEnabled',
'editingAvailable',
]),
...mapState(useInstanceStore, {
background: (store) => store.instanceIdentity.background,
showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel,
instanceSpecificPanelPresent: (store) =>
store.instanceIdentity.showInstanceSpecificPanel &&
store.instanceIdentity.instanceSpecificPanelContent,
}),
}, },
methods: { methods: {
resizeHandler() { resizeHandler() {
this.setLayoutWidth(windowWidth()) useInterfaceStore().setLayoutWidth(windowWidth())
this.setLayoutHeight(windowHeight()) useInterfaceStore().setLayoutHeight(windowHeight())
}, },
scrollHandler() { scrollHandler() {
const scrollPosition = const scrollPosition =
@ -263,6 +265,5 @@ export default {
splashscreenRoot.classList.add('hidden') splashscreenRoot.classList.add('hidden')
document.querySelector('#app').classList.remove('hidden') document.querySelector('#app').classList.remove('hidden')
}, },
...mapActions(useInterfaceStore, ['setLayoutWidth', 'setLayoutHeight']),
}, },
} }

View file

@ -1,7 +1,6 @@
/* global process */ /* global process */
import vClickOutside from 'click-outside-vue3' import vClickOutside from 'click-outside-vue3'
import { get, set } from 'lodash'
import { createApp } from 'vue' import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import VueVirtualScroller from 'vue-virtual-scroller' import VueVirtualScroller from 'vue-virtual-scroller'
@ -18,7 +17,7 @@ config.autoAddCss = false
import App from '../App.vue' import App from '../App.vue'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import FaviconService from '../services/favicon_service/favicon_service.js' import FaviconService from '../services/favicon_service/favicon_service.js'
import { applyStyleConfig } from '../services/style_setter/style_setter.js' import { applyConfig } from '../services/style_setter/style_setter.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js' import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
import { import {
windowHeight, windowHeight,
@ -26,13 +25,14 @@ import {
} from '../services/window_utils/window_utils' } from '../services/window_utils/window_utils'
import routes from './routes' import routes from './routes'
import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useAuthFlowStore } from 'src/stores/auth_flow.js' import { useAuthFlowStore } from 'src/stores/auth_flow'
import { useI18nStore } from 'src/stores/i18n.js' import { useEmojiStore } from 'src/stores/emoji.js'
import { useI18nStore } from 'src/stores/i18n'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.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'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import VBodyScrollLock from 'src/directives/body_scroll_lock' import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { import {
@ -83,30 +83,30 @@ const getInstanceConfig = async ({ store }) => {
const textlimit = data.max_toot_chars const textlimit = data.max_toot_chars
const vapidPublicKey = data.pleroma.vapid_public_key const vapidPublicKey = data.pleroma.vapid_public_key
useInstanceCapabilitiesStore().set(
'pleromaExtensionsAvailable',
data.pleroma,
)
useInstanceStore().set({ useInstanceStore().set({
path: 'featureSet.pleromaExtensionsAvailable', name: 'textlimit',
value: data.pleroma,
})
useInstanceStore().set({
path: 'textlimit',
value: textlimit, value: textlimit,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'accountApprovalRequired', name: 'accountApprovalRequired',
value: data.approval_required, value: data.approval_required,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'birthdayRequired', name: 'birthdayRequired',
value: !!data.pleroma?.metadata.birthday_required, value: !!data.pleroma?.metadata.birthday_required,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'birthdayMinAge', name: 'birthdayMinAge',
value: data.pleroma?.metadata.birthday_min_age || 0, value: data.pleroma?.metadata.birthday_min_age || 0,
}) })
if (vapidPublicKey) { if (vapidPublicKey) {
useInstanceStore().set({ useInstanceStore().set({
path: 'vapidPublicKey', name: 'vapidPublicKey',
value: vapidPublicKey, value: vapidPublicKey,
}) })
} }
@ -161,31 +161,23 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
let config = {} let config = {}
if (overrides.staticConfigPreference && env === 'development') { if (overrides.staticConfigPreference && env === 'development') {
console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG') console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG')
config = { ...apiConfig, ...staticConfig } config = Object.assign({}, apiConfig, staticConfig)
} else { } else {
config = { ...staticConfig, ...apiConfig } config = Object.assign({}, staticConfig, apiConfig)
} }
const copyInstanceIdentityOption = (path) => { const copyInstanceOption = ({ source, destination }) => {
if (get(config, path) !== undefined) { if (typeof config[source] !== 'undefined') {
useInstanceStore().set({ useInstanceStore().set({ path: destination, value: config[source] })
path: `instanceIdentity.${path}`,
value: get(config, path),
})
} }
} }
const copyInstancePrefOption = (path) => { Object.keys(staticOrApiConfigDefault)
if (get(config, path) !== undefined) { .map((k) => ({ source: k, destination: `instanceIdentity.${k}` }))
useInstanceStore().set({ .forEach(copyInstanceOption)
path: `prefsStorage.${path}`, Object.keys(instanceDefaultConfig)
value: get(config, path), .map((k) => ({ source: k, destination: `prefsStorage.${k}` }))
}) .forEach(copyInstanceOption)
}
}
Object.keys(staticOrApiConfigDefault).forEach(copyInstanceIdentityOption)
Object.keys(instanceDefaultConfig).forEach(copyInstancePrefOption)
useAuthFlowStore().setInitialStrategy(config.loginMethod) useAuthFlowStore().setInitialStrategy(config.loginMethod)
} }
@ -195,7 +187,7 @@ const getTOS = async ({ store }) => {
const res = await window.fetch('/static/terms-of-service.html') const res = await window.fetch('/static/terms-of-service.html')
if (res.ok) { if (res.ok) {
const html = await res.text() const html = await res.text()
useInstanceStore().set({ path: 'tos', value: html }) useInstanceStore().set({ name: 'instanceIdentity.tos', value: html })
} else { } else {
throw res throw res
} }
@ -210,7 +202,7 @@ const getInstancePanel = async ({ store }) => {
if (res.ok) { if (res.ok) {
const html = await res.text() const html = await res.text()
useInstanceStore().set({ useInstanceStore().set({
path: 'instanceSpecificPanelContent', path: 'instanceIdentity.instanceSpecificPanelContent',
value: html, value: html,
}) })
} else { } else {
@ -244,7 +236,7 @@ const getStickers = async ({ store }) => {
).sort((a, b) => { ).sort((a, b) => {
return a.meta.title.localeCompare(b.meta.title) return a.meta.title.localeCompare(b.meta.title)
}) })
useInstanceStore().set({ path: 'stickers', value: stickers }) useEmojiStore().setStickers(stickers)
} else { } else {
throw res throw res
} }
@ -266,7 +258,7 @@ const getAppSecret = async ({ store }) => {
const resolveStaffAccounts = ({ store, accounts }) => { const resolveStaffAccounts = ({ store, accounts }) => {
const nicknames = accounts.map((uri) => uri.split('/').pop()) const nicknames = accounts.map((uri) => uri.split('/').pop())
useInstanceStore().set({ useInstanceStore().set({
path: 'staffAccounts', name: 'staffAccounts',
value: nicknames, value: nicknames,
}) })
} }
@ -279,85 +271,81 @@ const getNodeInfo = async ({ store }) => {
const data = await res.json() const data = await res.json()
const metadata = data.metadata const metadata = data.metadata
const features = metadata.features const features = metadata.features
useInstanceStore().set({ useInstanceStore().set({
path: 'localBubbleInstances', path: 'name',
value: metadata.localBubbleInstances ?? [],
})
useInstanceStore().set({
path: 'instanceIdentity.name',
value: metadata.nodeName, value: metadata.nodeName,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'registrationOpen', path: 'registrationOpen',
value: data.openRegistrations, value: data.openRegistrations,
}) })
useInstanceStore().set({ useInstanceCapabilitiesStore().set(
path: 'restrictedNicknames', 'mediaProxyAvailable',
value: metadata.restrictedNicknames, features.includes('media_proxy'),
}) )
useInstanceCapabilitiesStore().set(
'safeDM',
features.includes('safe_dm_mentions'),
)
useInstanceCapabilitiesStore().set(
'shoutAvailable',
features.includes('chat'),
)
useInstanceCapabilitiesStore().set(
'pleromaChatMessagesAvailable',
features.includes('pleroma_chat_messages'),
)
useInstanceCapabilitiesStore().set(
'pleromaCustomEmojiReactionsAvailable',
useInstanceStore().set({ features.includes('pleroma_custom_emoji_reactions') ||
path: 'featureSet.mediaProxyAvailable',
value: features.includes('media_proxy'),
})
useInstanceStore().set({
path: 'featureSet.safeDM',
value: features.includes('safe_dm_mentions'),
})
useInstanceStore().set({
path: 'featureSet.shoutAvailable',
value: features.includes('chat'),
})
useInstanceStore().set({
path: 'featureSet.pleromaChatMessagesAvailable',
value: features.includes('pleroma_chat_messages'),
})
useInstanceStore().set({
path: 'featureSet.pleromaCustomEmojiReactionsAvailable',
value:
features.includes('pleroma_custom_emoji_reactions') ||
features.includes('custom_emoji_reactions'), features.includes('custom_emoji_reactions'),
}) )
useInstanceCapabilitiesStore().set(
'pleromaBookmarkFoldersAvailable',
features.includes('pleroma:bookmark_folders'),
)
useInstanceCapabilitiesStore().set(
'gopherAvailable',
features.includes('gopher'),
)
useInstanceCapabilitiesStore().set(
'pollsAvailable',
features.includes('polls'),
)
useInstanceCapabilitiesStore().set(
'editingAvailable',
features.includes('editing'),
)
useInstanceCapabilitiesStore().set(
'mailerEnabled',
metadata.mailerEnabled,
)
useInstanceCapabilitiesStore().set(
'quotingAvailable',
features.includes('quote_posting'),
)
useInstanceCapabilitiesStore().set(
'groupActorAvailable',
features.includes('pleroma:group_actors'),
)
useInstanceCapabilitiesStore().set(
'blockExpiration',
features.includes('pleroma:block_expiration'),
)
useInstanceStore().set({ useInstanceStore().set({
path: 'featureSet.pleromaBookmarkFoldersAvailable', path: 'localBubbleInstances',
value: features.includes('pleroma:bookmark_folders'), value: metadata.localBubbleInstances ?? [],
})
useInstanceStore().set({
path: 'featureSet.gopherAvailable',
value: features.includes('gopher'),
})
useInstanceStore().set({
path: 'featureSet.pollsAvailable',
value: features.includes('polls'),
})
useInstanceStore().set({
path: 'featureSet.editingAvailable',
value: features.includes('editing'),
})
useInstanceStore().set({
path: 'featureSet.mailerEnabled',
value: metadata.mailerEnabled,
})
useInstanceStore().set({
path: 'featureSet.quotingAvailable',
value: features.includes('quote_posting'),
})
useInstanceStore().set({
path: 'featureSet.groupActorAvailable',
value: features.includes('pleroma:group_actors'),
})
useInstanceStore().set({
path: 'featureSet.blockExpiration',
value: features.includes('pleroma:block_expiration'),
})
useInstanceStore().set({
path: 'featureSet.localBubble',
value: Array.isArray(metadata.localBubbleInstances),
}) })
useInstanceCapabilitiesStore().set(
'localBubble',
(metadata.localBubbleInstances ?? []).length > 0,
)
useInstanceStore().set({
path: 'limits.pollLimits',
value: metadata.pollLimits,
})
const uploadLimits = metadata.uploadLimits const uploadLimits = metadata.uploadLimits
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.uploadlimit', path: 'limits.uploadlimit',
@ -379,60 +367,53 @@ const getNodeInfo = async ({ store }) => {
path: 'limits.fieldsLimits', path: 'limits.fieldsLimits',
value: metadata.fieldsLimits, value: metadata.fieldsLimits,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.pollLimits', path: 'restrictedNicknames',
value: metadata.pollLimits, value: metadata.restrictedNicknames,
})
useInstanceStore().set({
path: 'featureSet.postFormats',
value: metadata.postFormats,
}) })
useInstanceCapabilitiesStore().set('postFormats', metadata.postFormats)
const suggestions = metadata.suggestions const suggestions = metadata.suggestions
useInstanceStore().set({ useInstanceCapabilitiesStore().set(
path: 'featureSet.suggestionsEnabled', 'suggestionsEnabled',
value: suggestions.enabled, suggestions.enabled,
}) )
useInstanceStore().set({ // this is unused, why?
path: 'featureSet.suggestionsWeb', useInstanceCapabilitiesStore().set('suggestionsWeb', suggestions.web)
value: suggestions.web,
})
//
const software = data.software const software = data.software
useInstanceStore().set({ useInstanceStore().set({
path: 'backendVersion', name: 'backendVersion',
value: software.version, value: software.version,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'backendRepository', name: 'backendRepository',
value: software.repository, value: software.repository,
}) })
useInstanceStore().set({ path: 'private', value: metadata.private }) const priv = metadata.private
useInstanceStore().set({ name: 'privateMode', value: priv })
const frontendVersion = window.___pleromafe_commit_hash const frontendVersion = window.___pleromafe_commit_hash
useInstanceStore().set({ useInstanceStore().set({
path: 'frontendVersion', name: 'frontendVersion',
value: frontendVersion, value: frontendVersion,
}) })
const federation = metadata.federation const federation = metadata.federation
useInstanceStore().set({ useInstanceCapabilitiesStore().set(
path: 'featureSet.tagPolicyAvailable', 'tagPolicyAvailable',
value: typeof federation.mrf_policies === 'undefined'
typeof federation.mrf_policies === 'undefined' ? false
? false : metadata.federation.mrf_policies.includes('TagPolicy'),
: metadata.federation.mrf_policies.includes('TagPolicy'), )
})
useInstanceStore().set({ useInstanceStore().set({
path: 'federationPolicy', path: 'federationPolicy',
value: federation, value: federation,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'federating', path: 'federating',
value: value:
@ -471,8 +452,8 @@ const setConfig = async ({ store }) => {
const checkOAuthToken = async ({ store }) => { const checkOAuthToken = async ({ store }) => {
const oauth = useOAuthStore() const oauth = useOAuthStore()
if (oauth.userToken) { if (oauth.getUserToken) {
return store.dispatch('loginUser', oauth.userToken) return store.dispatch('loginUser', oauth.getUserToken)
} }
return Promise.resolve() return Promise.resolve()
} }
@ -552,7 +533,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
typeof overrides.target !== 'undefined' typeof overrides.target !== 'undefined'
? overrides.target ? overrides.target
: window.location.origin : window.location.origin
useInstanceStore().set({ path: 'server', value: server }) useInstanceStore().set({ name: 'server', value: server })
await setConfig({ store }) await setConfig({ store })
try { try {
@ -566,7 +547,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
return Promise.reject(e) return Promise.reject(e)
} }
applyStyleConfig(useSyncConfigStore().mergedConfig) applyConfig(store.state.config, i18n.global)
// Now we can try getting the server settings and logging in // Now we can try getting the server settings and logging in
// Most of these are preloaded into the index.html so blocking is minimized // Most of these are preloaded into the index.html so blocking is minimized

View file

@ -33,13 +33,16 @@ 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' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.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) {
next() next()
} else { } else {
next(useInstanceStore().redirectRootNoLogin || '/main/all') next(
useInstanceStore().instanceIdentity.redirectRootNoLogin || '/main/all',
)
} }
} }
@ -50,8 +53,9 @@ export default (store) => {
redirect: () => { redirect: () => {
return ( return (
(store.state.users.currentUser (store.state.users.currentUser
? useInstanceStore().redirectRootLogin ? useInstanceStore().instanceIdentity.redirectRootLogin
: useInstanceStore().redirectRootNoLogin) || '/main/all' : useInstanceStore().instanceIdentity.redirectRootNoLogin) ||
'/main/all'
) )
}, },
}, },
@ -202,7 +206,7 @@ export default (store) => {
}, },
] ]
if (useInstanceStore().featureSet.pleromaChatMessagesAvailable) { if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
routes = routes.concat([ routes = routes.concat([
{ {
name: 'chat', name: 'chat',

View file

@ -5,7 +5,6 @@ import StaffPanel from '../staff_panel/staff_panel.vue'
import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue' import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const About = { const About = {
components: { components: {
@ -17,13 +16,13 @@ const About = {
}, },
computed: { computed: {
showFeaturesPanel() { showFeaturesPanel() {
return useInstanceStore().showFeaturesPanel return useInstanceStore().instanceIdentity.showFeaturesPanel
}, },
showInstanceSpecificPanel() { showInstanceSpecificPanel() {
return ( return (
useInstanceStore().showInstanceSpecificPanel && useInstanceStore().instanceIdentity.showInstanceSpecificPanel &&
!useSyncConfigStore().mergedConfig.hideISP && !this.$store.getters.mergedConfig.hideISP &&
useInstanceStore().instanceSpecificPanelContent useInstanceStore().instanceIdentity.instanceSpecificPanelContent
) )
}, },
}, },

View file

@ -1,5 +1,4 @@
import { mapState as mapPiniaState } from 'pinia' import { mapState } from 'pinia'
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'
@ -7,9 +6,8 @@ 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'
import { useInstanceStore } from 'src/stores/instance' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useReportsStore } from 'src/stores/reports' import { useReportsStore } from 'src/stores/reports'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
@ -91,18 +89,15 @@ const AccountActions = {
}, },
computed: { computed: {
shouldConfirmBlock() { shouldConfirmBlock() {
return useSyncConfigStore().mergedConfig.modalOnBlock return this.$store.getters.mergedConfig.modalOnBlock
}, },
shouldConfirmRemoveUserFromFollowers() { shouldConfirmRemoveUserFromFollowers() {
return useSyncConfigStore().mergedConfig.modalOnRemoveUserFromFollowers return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
}, },
...mapPiniaState(useInstanceStore, (store) => ({ ...mapState(useInstanceCapabilitiesStore, [
blockExpirationSupported: (store) => store.featureSet.blockExpiration, 'blockExpiration',
})), 'pleromaChatMessagesAvailable',
...mapState({ ]),
pleromaChatMessagesAvailable: (state) =>
state.instance.pleromaChatMessagesAvailable,
}),
}, },
} }

View file

@ -95,7 +95,7 @@
</Popover> </Popover>
<teleport to="#modal"> <teleport to="#modal">
<confirm-modal <confirm-modal
v-if="showingConfirmBlock && !blockExpirationSupported" v-if="showingConfirmBlock && !blockExpiration"
ref="blockDialog" ref="blockDialog"
:title="$t('user_card.block_confirm_title')" :title="$t('user_card.block_confirm_title')"
:confirm-text="$t('user_card.block_confirm_accept_button')" :confirm-text="$t('user_card.block_confirm_accept_button')"
@ -138,7 +138,7 @@
</i18n-t> </i18n-t>
</confirm-modal> </confirm-modal>
<UserTimedFilterModal <UserTimedFilterModal
v-if="blockExpirationSupported" v-if="blockExpiration"
ref="timedBlockDialog" ref="timedBlockDialog"
:is-mute="false" :is-mute="false"
:user="user" :user="user"

View file

@ -4,7 +4,7 @@ import localeService from '../../services/locale/locale.service.js'
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
import RichContent from '../rich_content/rich_content.jsx' import RichContent from '../rich_content/rich_content.jsx'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
const Announcement = { const Announcement = {
components: { components: {

View file

@ -3,7 +3,7 @@ import { mapState } from 'vuex'
import Announcement from '../announcement/announcement.vue' import Announcement from '../announcement/announcement.vue'
import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
const AnnouncementsPage = { const AnnouncementsPage = {
components: { components: {

View file

@ -1,4 +1,3 @@
import { mapState } from 'pinia'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import nsfwImage from '../../assets/nsfw.png' import nsfwImage from '../../assets/nsfw.png'
@ -8,8 +7,8 @@ import StillImage from '../still-image/still-image.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue' import VideoAttachment from '../video_attachment/video_attachment.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -59,8 +58,8 @@ const Attachment = {
localDescription: this.description || this.attachment.description, localDescription: this.description || this.attachment.description,
nsfwImage: nsfwImage:
useInstanceStore().instanceIdentity.nsfwCensorImage || nsfwImage, useInstanceStore().instanceIdentity.nsfwCensorImage || nsfwImage,
hideNsfwLocal: useSyncConfigStore().mergedConfig.hideNsfw, hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
preloadImage: useSyncConfigStore().mergedConfig.preloadImage, preloadImage: this.$store.getters.mergedConfig.preloadImage,
loading: false, loading: false,
img: img:
fileTypeService.fileType(this.attachment.mimetype) === 'image' && fileTypeService.fileType(this.attachment.mimetype) === 'image' &&
@ -93,6 +92,9 @@ const Attachment = {
usePlaceholder() { usePlaceholder() {
return this.size === 'hide' return this.size === 'hide'
}, },
useContainFit() {
return this.$store.getters.mergedConfig.useContainFit
},
placeholderName() { placeholderName() {
if (this.attachment.description === '' || !this.attachment.description) { if (this.attachment.description === '' || !this.attachment.description) {
return this.type.toUpperCase() return this.type.toUpperCase()
@ -106,7 +108,9 @@ const Attachment = {
return 'file' return 'file'
}, },
referrerpolicy() { referrerpolicy() {
return useInstanceStore().mediaProxyAvailable ? '' : 'no-referrer' return useInstanceCapabilitiesStore().mediaProxyAvailable
? ''
: 'no-referrer'
}, },
type() { type() {
return fileTypeService.fileType(this.attachment.mimetype) return fileTypeService.fileType(this.attachment.mimetype)
@ -125,7 +129,7 @@ const Attachment = {
modalTypes = ['image', 'video', 'audio', 'flash'] modalTypes = ['image', 'video', 'audio', 'flash']
break break
default: default:
modalTypes = this.playVideosInModal modalTypes = this.mergedConfig.playVideosInModal
? ['image', 'video', 'flash'] ? ['image', 'video', 'flash']
: ['image'] : ['image']
break break
@ -135,11 +139,7 @@ const Attachment = {
videoTag() { videoTag() {
return this.useModal ? 'button' : 'span' return this.useModal ? 'button' : 'span'
}, },
...mapState(useSyncConfigStore, { ...mapGetters(['mergedConfig']),
useContainFit: (state) => state.mergedConfig.useContainFit,
playVideosInModal: (state) => state.mergedConfig.playVideosInModal,
useOneClickNsfw: (state) => state.mergedConfig.useOneClickNsfw,
}),
}, },
watch: { watch: {
'attachment.description'(newVal) { 'attachment.description'(newVal) {
@ -190,9 +190,9 @@ const Attachment = {
}, },
toggleHidden(event) { toggleHidden(event) {
if ( if (
this.useOneClickNsfw && this.mergedConfig.useOneClickNsfw &&
!this.showHidden && !this.showHidden &&
(this.type !== 'video' || this.playVideosInModal) (this.type !== 'video' || this.mergedConfig.playVideosInModal)
) { ) {
this.openModal(event) this.openModal(event)
return return

View file

@ -5,7 +5,7 @@ import LoginForm from '../login_form/login_form.vue'
import MFARecoveryForm from '../mfa_form/recovery_form.vue' import MFARecoveryForm from '../mfa_form/recovery_form.vue'
import MFATOTPForm from '../mfa_form/totp_form.vue' import MFATOTPForm from '../mfa_form/totp_form.vue'
import { useAuthFlowStore } from 'src/stores/auth_flow' import { useAuthFlowStore } from 'src/stores/auth_flow.js'
const AuthForm = { const AuthForm = {
name: 'AuthForm', name: 'AuthForm',

View file

@ -1,7 +1,10 @@
import { mapState } from 'vuex' import { mapState } from 'pinia'
import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue'
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
const BlockCard = { const BlockCard = {
props: ['userId'], props: ['userId'],
computed: { computed: {
@ -24,19 +27,18 @@ const BlockCard = {
new Date(this.user.mute_expires_at).toLocaleString(), new Date(this.user.mute_expires_at).toLocaleString(),
]) ])
}, },
...mapState({ ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
blockExpirationSupported: (state) => state.instance.blockExpiration,
}),
}, },
components: { components: {
BasicUserCard, BasicUserCard,
UserTimedFilterModal,
}, },
methods: { methods: {
unblockUser() { unblockUser() {
this.$store.dispatch('unblockUser', this.user.id) this.$store.dispatch('unblockUser', this.user.id)
}, },
blockUser() { blockUser() {
if (this.blockExpirationSupported) { if (this.blockExpiration) {
this.$refs.timedBlockDialog.optionallyPrompt() this.$refs.timedBlockDialog.optionallyPrompt()
} else { } else {
this.$store.dispatch('blockUser', { id: this.user.id }) this.$store.dispatch('blockUser', { id: this.user.id })

View file

@ -1,8 +1,8 @@
import apiService from '../../services/api/api.service' import apiService from '../../services/api/api.service'
import EmojiPicker from '../emoji_picker/emoji_picker.vue' import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
const BookmarkFolderEdit = { const BookmarkFolderEdit = {
data() { data() {

View file

@ -1,6 +1,6 @@
import BookmarkFolderCard from '../bookmark_folder_card/bookmark_folder_card.vue' import BookmarkFolderCard from '../bookmark_folder_card/bookmark_folder_card.vue'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
const BookmarkFolders = { const BookmarkFolders = {
data() { data() {

View file

@ -3,7 +3,7 @@ import { mapState } from 'pinia'
import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js'
import NavigationEntry from 'src/components/navigation/navigation_entry.vue' import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
export const BookmarkFoldersMenuContent = { export const BookmarkFoldersMenuContent = {
props: ['showPin'], props: ['showPin'],

View file

@ -17,7 +17,6 @@ import {
} from './chat_layout_utils.js' } from './chat_layout_utils.js'
import { useInterfaceStore } from 'src/stores/interface.js' 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 { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons' import { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons'
@ -110,11 +109,11 @@ const Chat = {
'currentChat', 'currentChat',
'currentChatMessageService', 'currentChatMessageService',
'findOpenedChatByRecipientId', 'findOpenedChatByRecipientId',
'mergedConfig',
]), ]),
...mapPiniaState(useInterfaceStore, { ...mapPiniaState(useInterfaceStore, {
mobileLayout: (store) => store.layoutType === 'mobile', mobileLayout: (store) => store.layoutType === 'mobile',
}), }),
...mapPiniaState(useSyncConfigStore, ['mergedConfig']),
...mapState({ ...mapState({
backendInteractor: (state) => state.api.backendInteractor, backendInteractor: (state) => state.api.backendInteractor,
mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus,

View file

@ -10,8 +10,8 @@ import Popover from '../popover/popover.vue'
import StatusContent from '../status_content/status_content.vue' import StatusContent from '../status_content/status_content.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInterfaceStore } from 'src/stores/interface'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons' import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons'
@ -76,7 +76,7 @@ const ChatMessage = {
}), }),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
restrictedNicknames: (state) => state.instance.restrictedNicknames, restrictedNicknames: (state) => useInstanceStore().restrictedNicknames,
}), }),
popoverMarginStyle() { popoverMarginStyle() {
if (this.isCurrentUser) { if (this.isCurrentUser) {
@ -85,8 +85,7 @@ const ChatMessage = {
return { left: 50 } return { left: 50 }
} }
}, },
...mapGetters(['findUser']), ...mapGetters(['mergedConfig', 'findUser']),
...mapPiniaState(useSyncConfigStore, ['mergedConfig']),
}, },
data() { data() {
return { return {

View file

@ -8,9 +8,7 @@ import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue'
import Status from '../status/status.vue' import Status from '../status/status.vue'
import ThreadTree from '../thread_tree/thread_tree.vue' import ThreadTree from '../thread_tree/thread_tree.vue'
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 { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -79,12 +77,37 @@ const conversation = {
} }
}, },
computed: { computed: {
maxDepthToShowByDefault() {
// maxDepthInThread = max number of depths that is *visible*
// since our depth starts with 0 and "showing" means "showing children"
// there is a -2 here
const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2
return maxDepth >= 1 ? maxDepth : 1
},
streamingEnabled() {
return (
this.mergedConfig.useStreamingApi &&
this.mastoUserSocketStatus === WSConnectionStatus.JOINED
)
},
displayStyle() {
return this.$store.getters.mergedConfig.conversationDisplay
},
isTreeView() { isTreeView() {
return !this.isLinearView return !this.isLinearView
}, },
treeViewIsSimple() {
return !this.$store.getters.mergedConfig.conversationTreeAdvanced
},
isLinearView() { isLinearView() {
return this.displayStyle === 'linear' return this.displayStyle === 'linear'
}, },
shouldFadeAncestors() {
return this.$store.getters.mergedConfig.conversationTreeFadeAncestors
},
otherRepliesButtonPosition() {
return this.$store.getters.mergedConfig.conversationOtherRepliesButton
},
showOtherRepliesButtonBelowStatus() { showOtherRepliesButtonBelowStatus() {
return this.otherRepliesButtonPosition === 'below' return this.otherRepliesButtonPosition === 'below'
}, },
@ -369,28 +392,7 @@ const conversation = {
maybeHighlight() { maybeHighlight() {
return this.isExpanded ? this.highlight : null return this.isExpanded ? this.highlight : null
}, },
...mapPiniaState(useSyncConfigStore, ['mergedConfig']), ...mapGetters(['mergedConfig']),
...mapPiniaState(useSyncConfigStore, {
maxDepthToShowByDefault: (store) => {
// maxDepthInThread = max number of depths that is *visible*
// since our depth starts with 0 and "showing" means "showing children"
// there is a -2 here
const maxDepth = store.mergedConfig.maxDepthInThread - 2
return maxDepth >= 1 ? maxDepth : 1
},
streamingEnabled: (store) => {
return (
store.mergedConfig.useStreamingApi &&
this.mastoUserSocketStatus === WSConnectionStatus.JOINED
)
},
displayStyle: (store) => store.mergedConfig.conversationDisplay,
treeViewIsSimple: (store) => !store.mergedConfig.conversationTreeAdvanced,
shouldFadeAncestors: (store) =>
store.mergedConfig.conversationTreeFadeAncestors,
otherRepliesButtonPosition: (store) =>
store.mergedConfig.conversationOtherRepliesButton,
}),
...mapState({ ...mapState({
mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus,
}), }),

View file

@ -1,11 +1,10 @@
import SearchBar from 'components/search_bar/search_bar.vue' import SearchBar from 'components/search_bar/search_bar.vue'
import { mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -35,14 +34,6 @@ 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: {
@ -51,21 +42,32 @@ 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.logoMask
},
logoStyle() { logoStyle() {
return { return {
visibility: this.logoMask ? 'hidden' : 'visible', visibility: this.enableMask ? 'hidden' : 'visible',
} }
}, },
logoMaskStyle() { logoMaskStyle() {
return this.logoMask return this.enableMask
? { ? {
'mask-image': `url(${this.logo})`, 'mask-image': `url(${this.logo})`,
} }
: { : {
'background-color': this.logoMask ? '' : 'transparent', 'background-color': this.enableMask ? '' : 'transparent',
} }
}, },
logoBgStyle() { logoBgStyle() {
@ -74,28 +76,28 @@ export default {
margin: `${this.logoMargin} 0`, margin: `${this.logoMargin} 0`,
opacity: this.searchBarHidden ? 1 : 0, opacity: this.searchBarHidden ? 1 : 0,
}, },
this.logoMask this.enableMask
? {} ? {}
: { : {
'background-color': this.logoMask ? '' : 'transparent', 'background-color': this.enableMask ? '' : 'transparent',
}, },
) )
}, },
...mapState(useInstanceStore, ['privateMode']),
...mapState(useInstanceStore, {
logoMask: (store) => store.instanceIdentity.logoMask,
logo: (store) => store.instanceIdentity.logo,
logoLeft: (store) => store.instanceIdentity.logoLeft,
logoMargin: (store) => store.instanceIdentity.logoMargin,
sitename: (store) => store.instanceIdentity.name,
hideSitename: (store) => store.instanceIdentity.hideSitename,
}),
currentUser() { currentUser() {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
shouldConfirmLogout() { shouldConfirmLogout() {
return useSyncConfigStore().mergedConfig.modalOnLogout return this.$store.getters.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() {
@ -122,11 +124,6 @@ export default {
onSearchBarToggled(hidden) { onSearchBarToggled(hidden) {
this.searchBarHidden = hidden this.searchBarHidden = hidden
}, },
openSettingsModal() { ...mapActions(useInterfaceStore, ['openSettingsModal']),
useInterfaceStore().openSettingsModal('user')
},
openAdminModal() {
useInterfaceStore().openSettingsModal('admin')
},
}, },
} }

View file

@ -40,7 +40,7 @@
<button <button
class="button-unstyled nav-icon" class="button-unstyled nav-icon"
:title="$t('nav.preferences')" :title="$t('nav.preferences')"
@click.stop="openSettingsModal" @click.stop="openSettingsModal('user')"
> >
<FAIcon <FAIcon
fixed-width fixed-width
@ -53,7 +53,7 @@
class="button-unstyled nav-icon" class="button-unstyled nav-icon"
target="_blank" target="_blank"
:title="$t('nav.administration')" :title="$t('nav.administration')"
@click.stop="openAdminModal" @click.stop="openSettingsModal('admin')"
> >
<FAIcon <FAIcon
fixed-width fixed-width

View file

@ -3,7 +3,7 @@ import get from 'lodash/get'
import EditStatusForm from '../edit_status_form/edit_status_form.vue' import EditStatusForm from '../edit_status_form/edit_status_form.vue'
import Modal from '../modal/modal.vue' import Modal from '../modal/modal.vue'
import { useEditStatusStore } from 'src/stores/editStatus' import { useEditStatusStore } from 'src/stores/editStatus.js'
const EditStatusModal = { const EditStatusModal = {
components: { components: {

View file

@ -2,14 +2,12 @@ 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 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'
import { useEmojiStore } from 'src/stores/emoji.js' import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { ensureFinalFallback } from 'src/i18n/languages.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -342,7 +340,7 @@ const EmojiPicker = {
this.$nextTick(() => { this.$nextTick(() => {
this.updateEmojiSize() this.updateEmojiSize()
}) })
return useSyncConfigStore().mergedConfig.fontSize return this.$store.getters.mergedConfig.fontSize
}, },
emojiHeight() { emojiHeight() {
return this.emojiSize return this.emojiSize
@ -354,8 +352,8 @@ const EmojiPicker = {
return this.showingStickers ? '' : this.activeGroup return this.showingStickers ? '' : this.activeGroup
}, },
stickersAvailable() { stickersAvailable() {
if (useInstanceStore().stickers) { if (useEmojiStore().stickers) {
return useInstanceStore().stickers.length > 0 return useEmojiStore().stickers.length > 0
} }
return 0 return 0
}, },
@ -386,7 +384,7 @@ const EmojiPicker = {
.concat(this.unicodeEmojiGroups) .concat(this.unicodeEmojiGroups)
}, },
stickerPickerEnabled() { stickerPickerEnabled() {
return (useInstanceStore().stickers || []).length !== 0 return (useEmojiStore().stickers || []).length !== 0
}, },
debouncedHandleKeywordChange() { debouncedHandleKeywordChange() {
return debounce(() => { return debounce(() => {
@ -407,7 +405,7 @@ const EmojiPicker = {
}, },
languages() { languages() {
return ensureFinalFallback( return ensureFinalFallback(
useSyncConfigStore().mergedConfig.interfaceLanguage, this.$store.getters.mergedConfig.interfaceLanguage,
) )
}, },
maybeLocalizedEmojiName() { maybeLocalizedEmojiName() {

View file

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

View file

@ -1,35 +1,24 @@
import { mapState } from 'pinia'
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
const FeaturesPanel = { const FeaturesPanel = {
computed: { computed: {
shout: function () { ...mapState(useInstanceCapabilitiesStore, [
return useInstanceStore().shoutAvailable 'shoutAvailable',
}, 'pleromaChatMessagesAvailable',
pleromaChatMessages: function () { 'gopherAvailable',
return useInstanceStore().pleromaChatMessagesAvailable 'suggestionsEnabled',
}, 'mediaProxyAvailable',
gopher: function () { ]),
return useInstanceStore().gopherAvailable ...mapState(useInstanceStore, {
}, textlimit: (store) => store.limits.textlimit,
whoToFollow: function () { uploadlimit: (store) =>
return useInstanceStore().suggestionsEnabled fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit),
}, }),
mediaProxy: function () {
return useInstanceStore().mediaProxyAvailable
},
minimalScopesMode: function () {
return useInstanceStore().minimalScopesMode
},
textlimit: function () {
return useInstanceStore().textlimit
},
uploadlimit: function () {
return fileSizeFormatService.fileSizeFormat(
useInstanceStore().uploadlimit,
)
},
}, },
} }

View file

@ -8,19 +8,19 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<ul> <ul>
<li v-if="shout"> <li v-if="shoutAvailable">
{{ $t('features_panel.shout') }} {{ $t('features_panel.shout') }}
</li> </li>
<li v-if="pleromaChatMessages"> <li v-if="pleromaChatMessagesAvailable">
{{ $t('features_panel.pleroma_chat_messages') }} {{ $t('features_panel.pleroma_chat_messages') }}
</li> </li>
<li v-if="gopher"> <li v-if="gopherAvailable">
{{ $t('features_panel.gopher') }} {{ $t('features_panel.gopher') }}
</li> </li>
<li v-if="whoToFollow"> <li v-if="suggestionsEnabled">
{{ $t('features_panel.who_to_follow') }} {{ $t('features_panel.who_to_follow') }}
</li> </li>
<li v-if="mediaProxy"> <li v-if="mediaProxyAvailable">
{{ $t('features_panel.media_proxy') }} {{ $t('features_panel.media_proxy') }}
</li> </li>
<li>{{ $t('features_panel.scope_options') }}</li> <li>{{ $t('features_panel.scope_options') }}</li>

View file

@ -2,7 +2,7 @@ import Checkbox from 'src/components/checkbox/checkbox.vue'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {

View file

@ -2,7 +2,7 @@ import { set, sumBy } from 'lodash'
import Attachment from '../attachment/attachment.vue' import Attachment from '../attachment/attachment.vue'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer.js'
const Gallery = { const Gallery = {
props: [ props: [

View file

@ -1,4 +1,4 @@
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.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'

View file

@ -3,7 +3,7 @@ import { useInstanceStore } from 'src/stores/instance.js'
const InstanceSpecificPanel = { const InstanceSpecificPanel = {
computed: { computed: {
instanceSpecificPanelContent() { instanceSpecificPanelContent() {
return useInstanceStore().instanceSpecificPanelContent return useInstanceStore().instanceIdentity.instanceSpecificPanelContent
}, },
}, },
} }

View file

@ -1,6 +1,6 @@
import ListsCard from '../lists_card/lists_card.vue' import ListsCard from '../lists_card/lists_card.vue'
import { useListsStore } from 'src/stores/lists' import { useListsStore } from 'src/stores/lists.js'
const Lists = { const Lists = {
data() { data() {

View file

@ -7,8 +7,8 @@ import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import ListsUserSearch from '../lists_user_search/lists_user_search.vue' import ListsUserSearch from '../lists_user_search/lists_user_search.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { useListsStore } from 'src/stores/lists' import { useListsStore } from 'src/stores/lists.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons'

View file

@ -4,7 +4,8 @@ import { mapState } from 'vuex'
import { getListEntries } from 'src/components/navigation/filter.js' import { getListEntries } from 'src/components/navigation/filter.js'
import NavigationEntry from 'src/components/navigation/navigation_entry.vue' import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
import { useListsStore } from 'src/stores/lists' import { useInstanceStore } from 'src/stores/instance.js'
import { useListsStore } from 'src/stores/lists.js'
export const ListsMenuContent = { export const ListsMenuContent = {
props: ['showPin'], props: ['showPin'],
@ -17,8 +18,6 @@ export const ListsMenuContent = {
}), }),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
privateMode: (state) => state.instance.private,
federating: (state) => state.instance.federating,
}), }),
}, },
} }

View file

@ -1,6 +1,6 @@
import Timeline from '../timeline/timeline.vue' import Timeline from '../timeline/timeline.vue'
import { useListsStore } from 'src/stores/lists' import { useListsStore } from 'src/stores/lists.js'
const ListsTimeline = { const ListsTimeline = {
data() { data() {

View file

@ -18,25 +18,19 @@ const LoginForm = {
error: false, error: false,
}), }),
computed: { computed: {
isPasswordAuth() {
return this.requiredPassword
},
isTokenAuth() {
return this.requiredToken
},
...mapStores(useOAuthStore),
...mapState({ ...mapState({
loggingIn: (state) => state.users.loggingIn, loggingIn: (state) => state.users.loggingIn,
}), }),
...mapPiniaState(useAuthFlowStore, [ ...mapPiniaState(useOAuthStore, ['clientId', 'clientSecret']),
'requiredPassword', ...mapPiniaState(useInstanceStore, ['server', 'registrationOpen']),
'requiredToken', ...mapPiniaState(useAuthFlowStore, {
'requiredMFA', isTokenAuth: (store) => store.requiredToken,
]), isPasswordAuth: (store) => !store.requiredToken,
...mapPiniaState(useInstanceStore, ['registrationOpen', 'server']), }),
}, },
methods: { methods: {
...mapActions(useAuthFlowStore, ['requireMFA', 'login']), ...mapActions(useAuthFlowStore, ['requireMFA', 'login']),
...mapActions(useOAuthStore, ['ensureAppToken']),
submit() { submit() {
this.isTokenAuth ? this.submitToken() : this.submitPassword() this.isTokenAuth ? this.submitToken() : this.submitPassword()
}, },
@ -48,10 +42,10 @@ const LoginForm = {
// NOTE: we do not really need the app token, but obtaining a token and // NOTE: we do not really need the app token, but obtaining a token and
// calling verify_credentials is the only way to ensure the app still works. // calling verify_credentials is the only way to ensure the app still works.
this.oauthStore.ensureAppToken().then(() => { this.ensureAppToken().then(() => {
const app = { const app = {
clientId: this.oauthStore.clientId, clientId: this.clientId,
clientSecret: this.oauthStore.clientSecret, clientSecret: this.clientSecret,
} }
oauthApi.login({ ...app, ...data }) oauthApi.login({ ...app, ...data })
}) })
@ -61,10 +55,10 @@ const LoginForm = {
// NOTE: we do not really need the app token, but obtaining a token and // NOTE: we do not really need the app token, but obtaining a token and
// calling verify_credentials is the only way to ensure the app still works. // calling verify_credentials is the only way to ensure the app still works.
this.oauthStore.ensureAppToken().then(() => { this.ensureAppToken().then(() => {
const app = { const app = {
clientId: this.oauthStore.clientId, clientId: this.clientId,
clientSecret: this.oauthStore.clientSecret, clientSecret: this.clientSecret,
} }
oauthApi oauthApi

View file

@ -7,7 +7,7 @@ import StillImage from '../still-image/still-image.vue'
import SwipeClick from '../swipe_click/swipe_click.vue' import SwipeClick from '../swipe_click/swipe_click.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue' import VideoAttachment from '../video_attachment/video_attachment.vue'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {

View file

@ -1,7 +1,7 @@
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'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInstanceStore } from 'src/stores/instance.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch, faUpload } from '@fortawesome/free-solid-svg-icons' import { faCircleNotch, faUpload } from '@fortawesome/free-solid-svg-icons'
@ -33,7 +33,7 @@ const mediaUpload = {
} }
// Skip if image compression is disabled // Skip if image compression is disabled
if (!useSyncConfigStore().mergedConfig.imageCompression) { if (!this.$store.getters.mergedConfig.imageCompression) {
return file return file
} }
@ -78,7 +78,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 =
!useSyncConfigStore().mergedConfig.alwaysUseJpeg && supportsWebP !this.$store.getters.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'
@ -122,10 +122,10 @@ const mediaUpload = {
async uploadFile(file) { async uploadFile(file) {
const self = this const self = this
const store = this.$store const store = this.$store
if (file.size > store.state.instance.uploadlimit) { if (file.size > useInstanceStore().uploadlimit) {
const filesize = fileSizeFormatService.fileSizeFormat(file.size) const filesize = fileSizeFormatService.fileSizeFormat(file.size)
const allowedsize = fileSizeFormatService.fileSizeFormat( const allowedsize = fileSizeFormatService.fileSizeFormat(
store.state.instance.uploadlimit, useInstanceStore().uploadlimit,
) )
self.$emit('upload-failed', 'file_too_big', { self.$emit('upload-failed', 'file_too_big', {
filesize: filesize.num, filesize: filesize.num,

View file

@ -1,6 +1,5 @@
import { mapState as mapPiniaState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import { import {
highlightClass, highlightClass,
@ -9,8 +8,6 @@ import {
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
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 { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -101,10 +98,7 @@ const MentionLink = {
return this.user && this.user.screen_name_ui return this.user && this.user.screen_name_ui
}, },
highlight() { highlight() {
return ( return this.user && this.mergedConfig.highlight[this.user.screen_name]
this.user &&
useSyncConfigStore().mergedConfig.highlight[this.user.screen_name]
)
}, },
highlightType() { highlightType() {
return this.highlight && '-' + this.highlight.type return this.highlight && '-' + this.highlight.type
@ -137,7 +131,7 @@ const MentionLink = {
return this.userName !== this.userNameFull return this.userName !== this.userNameFull
}, },
shouldShowFullUserName() { shouldShowFullUserName() {
const conf = useSyncConfigStore().mergedConfig.mentionLinkDisplay const conf = this.mergedConfig.mentionLinkDisplay
if (conf === 'short') { if (conf === 'short') {
return false return false
} else if (conf === 'full') { } else if (conf === 'full') {
@ -147,16 +141,25 @@ 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

@ -1,9 +1,11 @@
import { mapActions, mapState as mapPiniaState, mapStores } from 'pinia' import { mapActions, mapState, mapStores } from 'pinia'
import { mapState } from 'vuex'
import mfaApi from '../../services/new_api/mfa.js'
import mfaApi from '../../services/new_api/mfa.js' import mfaApi from '../../services/new_api/mfa.js'
import { useAuthFlowStore } from 'src/stores/auth_flow.js' import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -17,13 +19,10 @@ export default {
error: false, error: false,
}), }),
computed: { computed: {
...mapPiniaState(useAuthFlowStore, {
authSettings: (store) => store.settings,
}),
...mapStores(useOAuthStore), ...mapStores(useOAuthStore),
...mapState({ ...mapState(useOAuthStore, ['clientId', 'clientSecret']),
instance: 'instance', ...mapState(useAuthFlowStore, ['settings']),
}), ...mapState(useInstanceStore, ['server']),
}, },
methods: { methods: {
...mapActions(useAuthFlowStore, ['requireTOTP', 'abortMFA', 'login']), ...mapActions(useAuthFlowStore, ['requireTOTP', 'abortMFA', 'login']),
@ -38,13 +37,11 @@ export default {
}, },
submit() { submit() {
const { clientId, clientSecret } = this.oauthStore
const data = { const data = {
clientId, clientId: this.clientId,
clientSecret, clientSecret: this.clientSecret,
instance: this.instance.server, instance: this.server,
mfaToken: this.authSettings.mfa_token, mfaToken: this.settings.mfa_token,
code: this.code, code: this.code,
} }

View file

@ -11,9 +11,9 @@ import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import Notifications from '../notifications/notifications.vue' import Notifications from '../notifications/notifications.vue'
import SideDrawer from '../side_drawer/side_drawer.vue' import SideDrawer from '../side_drawer/side_drawer.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useServerSideStorageStore } from 'src/stores/serverSideStorage.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -75,15 +75,15 @@ const MobileNav = {
return this.$route.name === 'chat' return this.$route.name === 'chat'
}, },
...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
...mapState(useSyncConfigStore, { ...mapState(useServerSideStorageStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'), new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
}), }),
shouldConfirmLogout() { shouldConfirmLogout() {
return useSyncConfigStore().mergedConfig.modalOnLogout return this.$store.getters.mergedConfig.modalOnLogout
}, },
closingDrawerMarksAsSeen() { closingDrawerMarksAsSeen() {
return useSyncConfigStore().mergedConfig.closingDrawerMarksAsSeen return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen
}, },
...mapGetters(['unreadChatCount']), ...mapGetters(['unreadChatCount']),
}, },

View file

@ -1,7 +1,6 @@
import { debounce } from 'lodash' import { debounce } from 'lodash'
import { usePostStatusStore } from 'src/stores/post_status' import { usePostStatusStore } from 'src/stores/post_status.js'
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'
@ -46,10 +45,10 @@ const MobilePostStatusButton = {
) )
}, },
isPersistent() { isPersistent() {
return !!useSyncConfigStore().mergedConfig.alwaysShowNewPostButton return !!this.$store.getters.mergedConfig.alwaysShowNewPostButton
}, },
autohideFloatingPostButton() { autohideFloatingPostButton() {
return !!useSyncConfigStore().mergedConfig.autohideFloatingPostButton return !!this.$store.getters.mergedConfig.autohideFloatingPostButton
}, },
}, },
watch: { watch: {

View file

@ -2,6 +2,7 @@ import DialogModal from '../dialog_modal/dialog_modal.vue'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faChevronDown } from '@fortawesome/free-solid-svg-icons' import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
@ -56,7 +57,7 @@ const ModerationTools = {
}, },
canUseTagPolicy() { canUseTagPolicy() {
return ( return (
useInstanceStore().tagPolicyAvailable && useInstanceCapabilitiesStore().tagPolicyAvailable &&
this.privileged('users_manage_tags') this.privileged('users_manage_tags')
) )
}, },

View file

@ -9,9 +9,10 @@ import { ROOT_ITEMS, TIMELINES } from 'src/components/navigation/navigation.js'
import NavigationEntry from 'src/components/navigation/navigation_entry.vue' 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'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -83,28 +84,28 @@ const NavPanel = {
this.editMode = !this.editMode this.editMode = !this.editMode
}, },
toggleCollapse() { toggleCollapse() {
useSyncConfigStore().setPreference({ useServerSideStorageStore().setPreference({
path: 'simple.collapseNav', path: 'simple.collapseNav',
value: !this.collapsed, value: !this.collapsed,
}) })
useSyncConfigStore().pushSyncConfig() useServerSideStorageStore().pushServerSideStorage()
}, },
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)) {
useSyncConfigStore().removeCollectionPreference({ useServerSideStorageStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} else { } else {
useSyncConfigStore().addCollectionPreference({ useServerSideStorageStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} }
useSyncConfigStore().pushSyncConfig() useServerSideStorageStore().pushServerSideStorage()
}, },
}, },
computed: { computed: {
@ -112,20 +113,20 @@ const NavPanel = {
unreadAnnouncementCount: 'unreadAnnouncementCount', unreadAnnouncementCount: 'unreadAnnouncementCount',
supportsAnnouncements: (store) => store.supportsAnnouncements, supportsAnnouncements: (store) => store.supportsAnnouncements,
}), }),
...mapPiniaState(useSyncConfigStore, { ...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'pleromaBookmarkFoldersAvailable',
'localBubble',
]),
...mapPiniaState(useInstanceStore, ['federating']),
...mapPiniaState(useInstanceStore, {
privateMode: (store) => store.private,
}),
...mapPiniaState(useServerSideStorageStore, {
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),
}), }),
...mapPiniaState(useInstanceStore, {
bubbleTimeline: (store) => store.featureSet.localBubble,
pleromaChatMessagesAvailable: (store) =>
store.featureSet.pleromaChatMessagesAvailable,
bookmarkFolders: (store) =>
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,
@ -142,8 +143,8 @@ const NavPanel = {
isFederating: this.federating, isFederating: this.federating,
isPrivate: this.privateMode, isPrivate: this.privateMode,
currentUser: this.currentUser, currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimeline, supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarkFolders, supportsBookmarkFolders: this.pleromaBookmarkFoldersAvailable,
}, },
) )
}, },
@ -156,8 +157,8 @@ const NavPanel = {
isFederating: this.federating, isFederating: this.federating,
isPrivate: this.privateMode, isPrivate: this.privateMode,
currentUser: this.currentUser, currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimeline, supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarkFolders, supportsBookmarkFolders: this.pleromaBookmarkFoldersAvailable,
}, },
) )
}, },

View file

@ -84,7 +84,7 @@
/> />
</div> </div>
<NavigationEntry <NavigationEntry
v-if="currentUser && bookmarkFolders" v-if="currentUser && pleromaBookmarkFoldersAvailable"
:show-pin="false" :show-pin="false"
:item="{ icon: 'bookmark', label: 'nav.bookmarks' }" :item="{ icon: 'bookmark', label: 'nav.bookmarks' }"
:aria-expanded="showBookmarkFolders ? 'true' : 'false'" :aria-expanded="showBookmarkFolders ? 'true' : 'false'"

View file

@ -4,8 +4,8 @@ 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.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useServerSideStorageStore } from 'src/stores/serverSideStorage.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'
@ -23,17 +23,17 @@ const NavigationEntry = {
}, },
togglePin(value) { togglePin(value) {
if (this.isPinned(value)) { if (this.isPinned(value)) {
useSyncConfigStore().removeCollectionPreference({ useServerSideStorageStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} else { } else {
useSyncConfigStore().addCollectionPreference({ useServerSideStorageStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} }
useSyncConfigStore().pushSyncConfig() useServerSideStorageStore().pushServerSideStorage()
}, },
}, },
computed: { computed: {
@ -47,7 +47,7 @@ const NavigationEntry = {
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useSyncConfigStore, { ...mapPiniaState(useServerSideStorageStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),

View file

@ -15,9 +15,10 @@ 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 { useInstanceStore } from 'src/stores/instance' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useListsStore } from 'src/stores/lists' import { useListsStore } from 'src/stores/lists'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -69,17 +70,15 @@ const NavPanel = {
...mapPiniaState(useBookmarkFoldersStore, { ...mapPiniaState(useBookmarkFoldersStore, {
bookmarks: getBookmarkFolderEntries, bookmarks: getBookmarkFolderEntries,
}), }),
...mapPiniaState(useSyncConfigStore, { ...mapPiniaState(useServerSideStorageStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),
...mapPiniaState(useInstanceStore, { ...mapPiniaState(useInstanceStore, ['privateMode', 'federating']),
privateMode: (store) => store.featureSet.private, ...mapPiniaState(useInstanceCapabilitiesStore, [
federating: (store) => store.featureSet.federating, 'pleromaChatMessagesAvailable',
pleromaChatMessagesAvailable: (store) => 'localBubble',
store.featureSet.pleromaChatMessagesAvailable, ]),
bubbleTimelinesSupported: (store) => store.featureSet.localBubble,
}),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
followRequestCount: (state) => state.api.followRequests.length, followRequestCount: (state) => state.api.followRequests.length,
@ -98,7 +97,7 @@ const NavPanel = {
isFederating: this.federating, isFederating: this.federating,
isPrivate: this.privateMode, isPrivate: this.privateMode,
currentUser: this.currentUser, currentUser: this.currentUser,
supportsBubbleTimeline: this.bubbleTimelinesSupported, supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarks, supportsBookmarkFolders: this.bookmarks,
}, },
) )
@ -117,7 +116,7 @@ const NavPanel = {
{ {
hasChats: this.pleromaChatMessagesAvailable, hasChats: this.pleromaChatMessagesAvailable,
hasAnnouncements: this.supportsAnnouncements, hasAnnouncements: this.supportsAnnouncements,
supportsBubbleTimeline: this.bubbleTimelinesSupported, supportsBubbleTimeline: this.localBubble,
supportsBookmarkFolders: this.bookmarks, supportsBookmarkFolders: this.bookmarks,
isFederating: this.federating, isFederating: this.federating,
isPrivate: this.privateMode, isPrivate: this.privateMode,

View file

@ -17,7 +17,6 @@ import UserLink from '../user_link/user_link.vue'
import UserPopover from '../user_popover/user_popover.vue' import UserPopover from '../user_popover/user_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
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'
@ -182,7 +181,7 @@ const Notification = {
return highlightClass(this.notification.from_profile) return highlightClass(this.notification.from_profile)
}, },
userStyle() { userStyle() {
const highlight = useSyncConfigStore().mergedConfig.highlight const highlight = this.$store.getters.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])
}, },
@ -210,7 +209,7 @@ const Notification = {
return isStatusNotification(this.notification.type) return isStatusNotification(this.notification.type)
}, },
mergedConfig() { mergedConfig() {
return useSyncConfigStore().mergedConfig return this.$store.getters.mergedConfig
}, },
shouldConfirmApprove() { shouldConfirmApprove() {
return this.mergedConfig.modalOnApproveFollow return this.mergedConfig.modalOnApproveFollow

View file

@ -16,9 +16,7 @@ import Notification from '../notification/notification.vue'
import NotificationFilters from './notification_filters.vue' import NotificationFilters from './notification_filters.vue'
import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useAnnouncementsStore } from 'src/stores/announcements.js'
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 { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -100,7 +98,7 @@ const Notifications = {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
ignoreInactionableSeen() { ignoreInactionableSeen() {
return useSyncConfigStore().mergedConfig.ignoreInactionableSeen return this.$store.getters.mergedConfig.ignoreInactionableSeen
}, },
extraNotificationsCount() { extraNotificationsCount() {
return countExtraNotifications(this.$store) return countExtraNotifications(this.$store)
@ -138,10 +136,10 @@ const Notifications = {
) )
}, },
noSticky() { noSticky() {
return useSyncConfigStore().mergedConfig.disableStickyHeaders return this.$store.getters.mergedConfig.disableStickyHeaders
}, },
unseenAtTop() { unseenAtTop() {
return useSyncConfigStore().mergedConfig.unseenAtTop return this.$store.getters.mergedConfig.unseenAtTop
}, },
showExtraNotifications() { showExtraNotifications() {
return !this.noExtra return !this.noExtra

View file

@ -49,7 +49,7 @@ import { computed } from 'vue'
import ColorInput from 'src/components/color_input/color_input.vue' import ColorInput from 'src/components/color_input/color_input.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { import {
newExporter, newExporter,

View file

@ -1,7 +1,10 @@
import { mapState as mapPiniaState } from 'pinia'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import passwordResetApi from '../../services/new_api/password_reset.js' import passwordResetApi from '../../services/new_api/password_reset.js'
import { useInstanceStore } from 'src/stores/instance.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'
@ -20,11 +23,8 @@ const passwordReset = {
computed: { computed: {
...mapState({ ...mapState({
signedIn: (state) => !!state.users.currentUser, signedIn: (state) => !!state.users.currentUser,
instance: (state) => state.instance,
}), }),
mailerEnabled() { ...mapPiniaState(useInstanceStore, ['server', 'mailerEnabled']),
return this.instance.mailerEnabled
},
}, },
created() { created() {
if (this.signedIn) { if (this.signedIn) {
@ -44,9 +44,9 @@ const passwordReset = {
submit() { submit() {
this.isPending = true this.isPending = true
const email = this.user.email const email = this.user.email
const instance = this.instance.server const server = this.server
passwordResetApi({ instance, email }) passwordResetApi({ server, email })
.then(({ status }) => { .then(({ status }) => {
this.isPending = false this.isPending = false
this.user.email = '' this.user.email = ''

View file

@ -4,8 +4,7 @@ import Timeago from 'components/timeago/timeago.vue'
import genRandomSeed from '../../services/random_seed/random_seed.service.js' import genRandomSeed from '../../services/random_seed/random_seed.service.js'
import { usePollsStore } from 'src/stores/polls' import { usePollsStore } from 'src/stores/polls.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
export default { export default {
name: 'Poll', name: 'Poll',
@ -49,7 +48,7 @@ export default {
return (this.poll && this.poll.expired) || false return (this.poll && this.poll.expired) || false
}, },
expirationLabel() { expirationLabel() {
if (useSyncConfigStore().mergedConfig.useAbsoluteTimeFormat) { if (this.$store.getters.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

@ -55,7 +55,7 @@ export default {
}, },
}, },
pollLimits() { pollLimits() {
return useInstanceStore().pollLimits return useInstanceStore().limits.pollLimits
}, },
maxOptions() { maxOptions() {
return this.pollLimits.max_options return this.pollLimits.max_options

View file

@ -22,9 +22,9 @@ import StatusContent from '../status_content/status_content.vue'
import { useEmojiStore } from 'src/stores/emoji.js' import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.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 { useSyncConfigStore } from 'src/stores/sync_config.js'
import { pollFormToMasto } from 'src/services/poll/poll.service.js' import { pollFormToMasto } from 'src/services/poll/poll.service.js'
@ -163,6 +163,8 @@ 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,
@ -185,34 +187,37 @@ const PostStatusForm = {
} }
const scope = const scope =
(this.copyMessageScope && this.scopeCopy) || (this.copyMessageScope && 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: !!this.sensitiveByDefault, nsfw: !!sensitiveByDefault,
files: [], files: [],
poll: {}, poll: {},
hasPoll: false, hasPoll: false,
mediaDescriptions: {}, mediaDescriptions: {},
visibility: scope, visibility: scope,
contentType: this.contentType, contentType,
quoting: false, quoting: false,
} }
if (statusType === 'edit') { if (statusType === 'edit') {
const statusContentType = this.statusContentType || this.contentType const statusContentType = this.statusContentType || contentType
statusParams = { statusParams = {
type: statusType, type: statusType,
refId, refId,
spoilerText: this.subject || '', spoilerText: this.subject || '',
status: this.statusText || '', status: this.statusText || '',
nsfw: this.statusIsSensitive || !!this.sensitiveByDefault, nsfw: this.statusIsSensitive || !!sensitiveByDefault,
files: this.statusFiles || [], files: this.statusFiles || [],
poll: this.statusPoll || {}, poll: this.statusPoll || {},
hasPoll: false, hasPoll: false,
@ -249,6 +254,9 @@ 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
}, },
@ -295,22 +303,28 @@ const PostStatusForm = {
isOverLengthLimit() { isOverLengthLimit() {
return this.hasStatusLengthLimit && this.charactersLeft < 0 return this.hasStatusLengthLimit && this.charactersLeft < 0
}, },
minimalScopesMode() {
return useInstanceStore().minimalScopesMode
},
alwaysShowSubject() {
return this.mergedConfig.alwaysShowSubjectInput
},
postFormats() { postFormats() {
return useInstanceStore().postFormats || [] return useInstanceCapabilitiesStore().postFormats || []
}, },
safeDMEnabled() { safeDMEnabled() {
return useInstanceStore().safeDM return useInstanceCapabilitiesStore().safeDM
}, },
pollsAvailable() { pollsAvailable() {
return ( return (
useInstanceStore().pollsAvailable && useInstanceCapabilitiesStore().pollsAvailable &&
useInstanceStore().pollLimits.max_options >= 2 && useInstanceStore().limits.pollLimits.max_options >= 2 &&
this.disablePolls !== true this.disablePolls !== true
) )
}, },
hideScopeNotice() { hideScopeNotice() {
return ( return (
this.disableNotice || useSyncConfigStore().mergedConfig.hideScopeNotice this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice
) )
}, },
pollContentError() { pollContentError() {
@ -333,7 +347,7 @@ const PostStatusForm = {
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== '' return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
}, },
quotable() { quotable() {
if (!useInstanceStore().quotingAvailable) { if (!useInstanceCapabilitiesStore().quotingAvailable) {
return false return false
} }
@ -365,6 +379,9 @@ 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')
@ -394,17 +411,10 @@ const PostStatusForm = {
) )
) )
}, },
...mapGetters(['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (store) => store.mobileLayout, mobileLayout: (store) => store.mobileLayout,
}), }),
...mapState(useSyncConfigStore, {
scopeCopy: (store) => store.mergedConfig.scopeCopy,
shouldAutoSaveDraft: (store) => store.mergedConfig.autoSaveDraft,
showAllScopes: (store) => !store.mergedConfig.minimalScopesMode,
alwaysShowSubject: (store) => store.mergedConfig.alwaysShowSubjectInput,
contentType: (store) => store.mergedConfig.postContentType,
sensitiveByDefaultType: (store) => store.mergedConfig.sensitiveByDefault,
}),
}, },
watch: { watch: {
newStatus: { newStatus: {

View file

@ -3,7 +3,7 @@ import get from 'lodash/get'
import Modal from '../modal/modal.vue' import Modal from '../modal/modal.vue'
import PostStatusForm from '../post_status_form/post_status_form.vue' import PostStatusForm from '../post_status_form/post_status_form.vue'
import { usePostStatusStore } from 'src/stores/post_status' import { usePostStatusStore } from 'src/stores/post_status.js'
const PostStatusModal = { const PostStatusModal = {
components: { components: {

View file

@ -1,9 +1,9 @@
import { mapState } from 'pinia' import { mapState } from 'pinia'
import { mapGetters } from 'vuex'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
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 { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons' import { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons'
@ -31,7 +31,7 @@ const QuickFilterSettings = {
}, },
}, },
computed: { computed: {
...mapState(useSyncConfigStore, ['mergedConfig']), ...mapGetters(['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (state) => state.layoutType === 'mobile', mobileLayout: (state) => state.layoutType === 'mobile',
}), }),

View file

@ -4,8 +4,7 @@ import { mapGetters } from 'vuex'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import QuickFilterSettings from 'src/components/quick_filter_settings/quick_filter_settings.vue' import QuickFilterSettings from 'src/components/quick_filter_settings/quick_filter_settings.vue'
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 {
@ -37,7 +36,7 @@ const QuickViewSettings = {
}, },
}, },
computed: { computed: {
...mapState(useSyncConfigStore, ['mergedConfig']), ...mapGetters(['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (state) => state.layoutType === 'mobile', mobileLayout: (state) => state.layoutType === 'mobile',
}), }),

View file

@ -1,11 +1,14 @@
import useVuelidate from '@vuelidate/core' import useVuelidate from '@vuelidate/core'
import { required, requiredIf, sameAs } from '@vuelidate/validators' import { required, requiredIf, sameAs } from '@vuelidate/validators'
import { mapState as mapPiniaState } from 'pinia'
import { mapActions, mapState } from 'vuex' import { mapActions, mapState } from 'vuex'
import localeService from '../../services/locale/locale.service.js' import localeService from '../../services/locale/locale.service.js'
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue' import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue' import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { DAY } from 'src/services/date_utils/date_utils.js' import { DAY } from 'src/services/date_utils/date_utils.js'
const registration = { const registration = {
@ -97,21 +100,21 @@ const registration = {
) )
) )
}, },
...mapPiniaState(useInstanceStore, {
registrationOpen: (store) => store.registrationOpen,
embeddedToS: (store) => store.embeddedToS,
termsOfService: (store) => store.tos,
accountActivationRequired: (store) => store.accountActivationRequired,
accountApprovalRequired: (store) => store.accountApprovalRequired,
birthdayRequired: (store) => store.birthdayRequired,
birthdayMinAge: (store) => store.birthdayMinAge,
}),
...mapState({ ...mapState({
registrationOpen: (state) => state.instance.registrationOpen,
signedIn: (state) => !!state.users.currentUser, signedIn: (state) => !!state.users.currentUser,
isPending: (state) => state.users.signUpPending, isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors, serverValidationErrors: (state) => state.users.signUpErrors,
signUpNotice: (state) => state.users.signUpNotice, signUpNotice: (state) => state.users.signUpNotice,
hasSignUpNotice: (state) => !!state.users.signUpNotice.message, hasSignUpNotice: (state) => !!state.users.signUpNotice.message,
termsOfService: (state) => state.instance.tos,
embeddedToS: (state) => state.instance.embeddedToS,
accountActivationRequired: (state) =>
state.instance.accountActivationRequired,
accountApprovalRequired: (state) =>
state.instance.accountApprovalRequired,
birthdayRequired: (state) => state.instance.birthdayRequired,
birthdayMinAge: (state) => state.instance.birthdayMinAge,
}), }),
}, },
methods: { methods: {

View file

@ -4,7 +4,7 @@ import StatusContent from '../status_content/status_content.vue'
import Timeago from '../timeago/timeago.vue' import Timeago from '../timeago/timeago.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useReportsStore } from 'src/stores/reports' import { useReportsStore } from 'src/stores/reports.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'

View file

@ -12,7 +12,7 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import StringSetting from '../helpers/string_setting.vue' import StringSetting from '../helpers/string_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {

View file

@ -7,7 +7,7 @@ import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import StringSetting from '../helpers/string_setting.vue' import StringSetting from '../helpers/string_setting.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faGlobe } from '@fortawesome/free-solid-svg-icons' import { faGlobe } from '@fortawesome/free-solid-svg-icons'

View file

@ -19,6 +19,10 @@ export default {
type: String, type: String,
default: null, default: null,
}, },
description: {
type: String,
default: null,
},
path: { path: {
type: [String, Array], type: [String, Array],
required: false, required: false,

View file

@ -8,7 +8,7 @@ import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
import './vertical_tab_switcher.scss' import './vertical_tab_switcher.scss'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
const findFirstUsable = (slots) => slots.findIndex((_) => _.props) const findFirstUsable = (slots) => slots.findIndex((_) => _.props)
@ -35,11 +35,6 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
parentCollapsed: {
required: false,
type: Boolean,
default: null,
},
}, },
data() { data() {
return { return {
@ -202,7 +197,7 @@ export default {
</div> </div>
<div <div
role="tabpanel" role="tabpanel"
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} class="contents"
v-body-scroll-lock={this.bodyScrollLock} v-body-scroll-lock={this.bodyScrollLock}
ref="contents" ref="contents"
> >

View file

@ -63,10 +63,8 @@
} }
.tab-content-wrapper { .tab-content-wrapper {
display: flex;
flex-direction: column;
height: 100%;
flex: 1 1 auto; flex: 1 1 auto;
height: 100%;
&.-hidden { &.-hidden {
display: none; display: none;

View file

@ -8,7 +8,7 @@ import Modal from 'src/components/modal/modal.vue'
import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import PanelLoading from 'src/components/panel_loading/panel_loading.vue'
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { import {
newExporter, newExporter,

View file

@ -17,7 +17,7 @@ import RegistrationsTab from './admin_tabs/registrations_tab.vue'
import UploadsTab from './admin_tabs/uploads_tab.vue' import UploadsTab from './admin_tabs/uploads_tab.vue'
import VerticalTabSwitcher from './helpers/vertical_tab_switcher.jsx' import VerticalTabSwitcher from './helpers/vertical_tab_switcher.jsx'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {

View file

@ -15,7 +15,7 @@ import ProfileTab from './tabs/profile_tab.vue'
import SecurityTab from './tabs/security_tab/security_tab.vue' import SecurityTab from './tabs/security_tab/security_tab.vue'
import StyleTab from './tabs/style_tab/style_tab.vue' import StyleTab from './tabs/style_tab/style_tab.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {

View file

@ -3,7 +3,6 @@
ref="tabSwitcher" ref="tabSwitcher"
class="settings_tab-switcher" class="settings_tab-switcher"
:scrollable-tabs="true" :scrollable-tabs="true"
:child-collapsed="childCollapsed"
:body-scroll-lock="bodyLock" :body-scroll-lock="bodyLock"
:hide-header="navHideHeader" :hide-header="navHideHeader"
> >

View file

@ -12,8 +12,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
import Preview from './old_theme_tab/theme_preview.vue' import Preview from './old_theme_tab/theme_preview.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface' import { normalizeThemeData, useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { newImporter } from 'src/services/export_import/export_import.js' import { newImporter } from 'src/services/export_import/export_import.js'
import { import {
@ -277,11 +276,11 @@ const AppearanceTab = {
return !window.IntersectionObserver return !window.IntersectionObserver
}, },
instanceWallpaper() { instanceWallpaper() {
useInstanceStore().background useInstanceStore().instanceIdentity.background
}, },
instanceWallpaperUsed() { instanceWallpaperUsed() {
return ( return (
this.instanceWallpaper && useInstanceStore().instanceIdentity.background &&
!this.$store.state.users.currentUser.background_image !this.$store.state.users.currentUser.background_image
) )
}, },
@ -312,9 +311,9 @@ const AppearanceTab = {
}, },
onImport(parsed, filename) { onImport(parsed, filename) {
if (filename.endsWith('.json')) { if (filename.endsWith('.json')) {
this.setThemeCustom(parsed.source || parsed.theme) useInterfaceStore().setThemeCustom(parsed.source || parsed.theme)
} else if (filename.endsWith('.iss')) { } else if (filename.endsWith('.iss')) {
this.setStyleCustom(parsed) useInterfaceStore().setStyleCustom(parsed)
} }
}, },
onImportFailure(result) { onImportFailure(result) {
@ -336,36 +335,35 @@ const AppearanceTab = {
} }
}, },
isThemeActive(key) { isThemeActive(key) {
return key === useSyncConfigStore().mergedConfig.theme return (
key ===
(this.mergedConfig.theme || useInstanceStore().instanceIdentity.theme)
)
}, },
isStyleActive(key) { isStyleActive(key) {
return key === useSyncConfigStore().mergedConfig.style return (
key ===
(this.mergedConfig.style || useInstanceStore().instanceIdentity.style)
)
}, },
isPaletteActive(key) { isPaletteActive(key) {
return ( return (
key === key ===
(useSyncConfigStore().mergedConfig.palette || (this.mergedConfig.palette ||
useInstanceStore().palette) useInstanceStore().instanceIdentity.palette)
) )
}, },
...mapActions(useInterfaceStore, [ ...mapActions(useInterfaceStore, ['setStyle', 'setTheme']),
'setStyle', setPalette(name, data) {
'setStyleCustom', useInterfaceStore().setPalette(name)
'setPalette',
'setPaletteCustom',
'setTheme',
'setThemeCustom',
]),
setLocalPalette(name, data) {
this.setPalette(name)
this.userPalette = data this.userPalette = data
}, },
setLocalPaletteCustom(data) { setPaletteCustom(data) {
this.setPaletteCustom(data) useInterfaceStore().setPaletteCustom(data)
this.userPalette = data this.userPalette = data
}, },
resetTheming() { resetTheming() {
this.setStyle('stock') useInterfaceStore().setStyle('stock')
}, },
previewTheme(key, version, input) { previewTheme(key, version, input) {
let theme3 let theme3

View file

@ -1,6 +1,5 @@
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
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'
@ -12,7 +11,8 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
const ClutterTab = { const ClutterTab = {
components: { components: {
@ -25,18 +25,19 @@ const ClutterTab = {
HelpIndicator, HelpIndicator,
}, },
computed: { computed: {
instanceSpecificPanelPresent() {
return useInstanceStore().showInstanceSpecificPanel
},
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useSyncConfigStore, { ...mapState(useInstanceCapabilitiesStore, ['shoutAvailable']),
...mapState(useInstanceStore, {
showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel,
instanceSpecificPanelPresent: (store) =>
store.instanceIdentity.showInstanceSpecificPanel &&
store.instanceIdentity.instanceSpecificPanelContent,
}),
...mapState(useServerSideStorageStore, {
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,
}), }),
...mapVuexState({
blockExpirationSupported: (state) => state.instance.blockExpiration,
}),
onMuteDefaultActionLv1: { onMuteDefaultActionLv1: {
get() { get() {
const value = this.$store.state.config.onMuteDefaultAction const value = this.$store.state.config.onMuteDefaultAction
@ -88,10 +89,10 @@ const ClutterTab = {
}, },
}, },
methods: { methods: {
...mapActions(useSyncConfigStore, [ ...mapActions(useServerSideStorageStore, [
'setPreference', 'setPreference',
'unsetPreference', 'unsetPreference',
'pushSyncConfig', 'pushServerSideStorage',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -138,7 +139,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.pushSyncConfig() this.pushServerSideStorage()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -154,19 +155,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.pushSyncConfig() this.pushServerSideStorage()
}, },
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.pushSyncConfig() this.pushServerSideStorage()
}, },
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.pushSyncConfig() this.pushServerSideStorage()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -192,7 +193,7 @@ const ClutterTab = {
path: 'simple.muteFilters.' + id, path: 'simple.muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushSyncConfig() this.pushServerSideStorage()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },

View file

@ -43,6 +43,11 @@
{{ $t('settings.hide_scrobbles_after') }} {{ $t('settings.hide_scrobbles_after') }}
</UnitSetting> </UnitSetting>
</li> </li>
<li v-if="instanceSpecificPanelPresent">
<BooleanSetting path="hideISP">
{{ $t('settings.hide_isp') }}
</BooleanSetting>
</li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -71,7 +76,7 @@
{{ $t('settings.user_card_hide_personal_marks') }} {{ $t('settings.user_card_hide_personal_marks') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li v-if="instanceShoutboxPresent"> <li v-if="shoutAvailable">
<BooleanSetting <BooleanSetting
path="hideShoutbox" path="hideShoutbox"
> >

View file

@ -1,4 +1,4 @@
import { mapState } from 'vuex' import { mapState } from 'pinia'
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'
@ -13,7 +13,6 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
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'
@ -30,12 +29,6 @@ import {
library.add(faGlobe, faMessage, faPenAlt, faDatabase, faSliders) library.add(faGlobe, faMessage, faPenAlt, faDatabase, faSliders)
const ComposingTab = { const ComposingTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() { data() {
return { return {
subjectLineOptions: ['email', 'noop', 'masto'].map((mode) => ({ subjectLineOptions: ['email', 'noop', 'masto'].map((mode) => ({
@ -123,7 +116,7 @@ const ComposingTab = {
}, },
language: { language: {
get: function () { get: function () {
return useSyncConfigStore().mergedConfig.interfaceLanguage return this.$store.getters.mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
this.$store.dispatch('setOption', { this.$store.dispatch('setOption', {
@ -133,9 +126,7 @@ const ComposingTab = {
}, },
}, },
...SharedComputedObject(), ...SharedComputedObject(),
...mapState({ ...mapState(useInstanceStore, ['blockExpiration']),
blockExpirationSupported: (state) => state.instance.blockExpiration,
}),
}, },
methods: { methods: {
changeDefaultScope(value) { changeDefaultScope(value) {

View file

@ -4,7 +4,7 @@ import Checkbox from 'src/components/checkbox/checkbox.vue'
import Exporter from 'src/components/exporter/exporter.vue' import Exporter from 'src/components/exporter/exporter.vue'
import Importer from 'src/components/importer/importer.vue' import Importer from 'src/components/importer/importer.vue'
import { useOAuthTokensStore } from 'src/stores/oauth_tokens' import { useOAuthTokensStore } from 'src/stores/oauth_tokens.js'
const DataImportExportTab = { const DataImportExportTab = {
data() { data() {

View file

@ -1,5 +1,3 @@
import { mapState } from 'pinia'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
@ -11,6 +9,14 @@ const pleromaFeCommitUrl =
'https://git.pleroma.social/pleroma/pleroma-fe/commit/' 'https://git.pleroma.social/pleroma/pleroma-fe/commit/'
const VersionTab = { const VersionTab = {
data() {
const instance = useInstanceStore()
return {
backendVersion: instance.backendVersion,
backendRepository: instance.backendRepository,
frontendVersion: instance.frontendVersion,
}
},
components: { components: {
BooleanSetting, BooleanSetting,
}, },
@ -19,11 +25,6 @@ const VersionTab = {
return pleromaFeCommitUrl + this.frontendVersion return pleromaFeCommitUrl + this.frontendVersion
}, },
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useInstanceStore, [
'backendVersion',
'backendRepository',
'frontendVersion',
]),
}, },
methods: { methods: {
clearAssetCache() { clearAssetCache() {

View file

@ -11,9 +11,9 @@ import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
import { import {
newExporter, newExporter,
@ -36,11 +36,11 @@ const FilteringTab = {
label: this.$t(`user_card.mute_block_${mode}`), label: this.$t(`user_card.mute_block_${mode}`),
})), })),
muteFiltersDraftObject: cloneDeep( muteFiltersDraftObject: cloneDeep(
useSyncConfigStore().prefsStorage.simple.muteFilters, useServerSideStorageStore().prefsStorage.simple.muteFilters,
), ),
muteFiltersDraftDirty: Object.fromEntries( muteFiltersDraftDirty: Object.fromEntries(
Object.entries( Object.entries(
useSyncConfigStore().prefsStorage.simple.muteFilters, useServerSideStorageStore().prefsStorage.simple.muteFilters,
).map(([k]) => [k, false]), ).map(([k]) => [k, false]),
), ),
exportedFilter: null, exportedFilter: null,
@ -91,6 +91,13 @@ const FilteringTab = {
HelpIndicator, HelpIndicator,
}, },
computed: { computed: {
...SharedComputedObject(),
...mapState(useServerSideStorageStore, {
muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
onMuteDefaultActionLv1: { onMuteDefaultActionLv1: {
get() { get() {
const value = this.$store.state.config.onMuteDefaultAction const value = this.$store.state.config.onMuteDefaultAction
@ -140,22 +147,12 @@ const FilteringTab = {
([, { expires }]) => expires != null && expires <= now, ([, { expires }]) => expires != null && expires <= now,
) )
}, },
...mapState(useInstanceStore, {
instanceSpecificPanelPresent: (store) => store.showInstanceSpecificPanel,
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
...SharedComputedObject(),
...mapState(useSyncConfigStore, {
muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}),
}, },
methods: { methods: {
...mapActions(useSyncConfigStore, [ ...mapActions(useServerSideStorageStore, [
'setPreference', 'setPreference',
'unsetPreference', 'unsetPreference',
'pushSyncConfig', 'pushServerSideStorage',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -202,7 +199,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.pushSyncConfig() this.pushServerSideStorage()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -218,19 +215,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.pushSyncConfig() this.pushServerSideStorage()
}, },
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.pushSyncConfig() this.pushServerSideStorage()
}, },
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.pushSyncConfig() this.pushServerSideStorage()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -256,7 +253,7 @@ const FilteringTab = {
path: 'simple.muteFilters.' + id, path: 'simple.muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushSyncConfig() this.pushServerSideStorage()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },

View file

@ -47,7 +47,7 @@
</li> </li>
</ul> </ul>
</li> </li>
<li v-if="blockExpirationSupported"> <li v-if="blockExpiration">
<span class="setting-item"> <span class="setting-item">
<span class="setting-label"> <span class="setting-label">
{{ $t('user_card.default_block_expiration') }} {{ $t('user_card.default_block_expiration') }}

View file

@ -10,17 +10,11 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import localeService from 'src/services/locale/locale.service.js' import localeService from 'src/services/locale/locale.service.js'
const GeneralTab = { const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() { data() {
return { return {
absoluteTime12hOptions: ['24h', '12h'].map((mode) => ({ absoluteTime12hOptions: ['24h', '12h'].map((mode) => ({
@ -43,23 +37,17 @@ const GeneralTab = {
computed: { computed: {
language: { language: {
get: function () { get: function () {
return useSyncConfigStore().mergedConfig.interfaceLanguage return this.$store.getters.mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
useSyncConfigStore().setPreference({ this.$store.dispatch('setOption', {
path: 'simple.interfaceLanguage', name: 'interfaceLanguage',
value: val, value: val,
}) })
useSyncConfigStore().pushSyncConfig()
}, },
}, },
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useSyncConfigStore, { ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
theme3hacks: (store) => store.mergedConfig.theme3hacks,
}),
...mapState(useInstanceStore, {
blockExpirationSupported: (store) => store.featureSet.blockExpiration,
}),
}, },
methods: { methods: {
updateProfile() { updateProfile() {
@ -77,9 +65,15 @@ const GeneralTab = {
}) })
}, },
updateFont(key, value) { updateFont(key, value) {
useSyncConfigStore().setPreference({ this.$store.dispatch('setOption', {
path: `simple.theme3hacks.fonts.${key}`, name: 'theme3hacks',
value, value: {
...this.mergedConfig.theme3hacks,
fonts: {
...this.mergedConfig.theme3hacks.fonts,
[key]: value,
},
},
}) })
}, },
}, },

View file

@ -157,7 +157,7 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
<li <li
v-if="!blockExpirationSupported" v-if="!blockExpiration"
> >
<BooleanSetting <BooleanSetting
path="modalOnBlock" path="modalOnBlock"

View file

@ -1,19 +1,14 @@
import { mapState } from 'pinia'
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'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import UnitSetting from '../helpers/unit_setting.vue' import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const GeneralTab = { const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() { data() {
return { return {
thirdColumnModeOptions: ['none', 'notifications', 'postform'].map( thirdColumnModeOptions: ['none', 'notifications', 'postform'].map(
@ -32,19 +27,17 @@ const GeneralTab = {
ProfileSettingIndicator, ProfileSettingIndicator,
}, },
computed: { computed: {
postFormats() { ...mapState(useInstanceCapabilitiesStore, [
return useInstanceStore().postFormats || [] 'postFormats',
}, 'suggestionsEnabled',
instanceShoutboxPresent() { ]),
return useInstanceStore().shoutAvailable
},
columns() { columns() {
const mode = useSyncConfigStore().mergedConfig.thirdColumnMode const mode = this.$store.getters.mergedConfig.thirdColumnMode
const notif = mode === 'none' ? [] : ['notifs'] const notif = mode === 'none' ? [] : ['notifs']
if ( if (
useSyncConfigStore().mergedConfig.sidebarRight || this.$store.getters.mergedConfig.sidebarRight ||
mode === 'postform' mode === 'postform'
) { ) {
return [...notif, 'content', 'sidebar'] return [...notif, 'content', 'sidebar']

View file

@ -69,11 +69,6 @@
{{ $t('settings.show_scrollbars') }} {{ $t('settings.show_scrollbars') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li v-if="instanceSpecificPanelPresent">
<BooleanSetting path="hideISP">
{{ $t('settings.hide_isp') }}
</BooleanSetting>
</li>
<li> <li>
<UnitSetting <UnitSetting
path="panelHeaderSize" path="panelHeaderSize"

View file

@ -14,8 +14,7 @@ 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 { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthTokensStore } from 'src/stores/oauth_tokens' import { useOAuthTokensStore } from 'src/stores/oauth_tokens.js'
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'),

View file

@ -10,8 +10,7 @@ import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import Preview from './theme_preview.vue' import Preview from './theme_preview.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { import {
getContrastRatioLayers, getContrastRatioLayers,
@ -82,7 +81,7 @@ export default {
}), }),
availableStyles: [], availableStyles: [],
selected: '', selected: '',
selectedTheme: useSyncConfigStore().mergedConfig.theme, selectedTheme: this.$store.getters.mergedConfig.theme,
themeWarning: undefined, themeWarning: undefined,
tempImportFile: undefined, tempImportFile: undefined,
engineVersion: 0, engineVersion: 0,
@ -129,7 +128,7 @@ export default {
} }
}, },
created() { created() {
const currentIndex = useInstanceStore().instanceThemesIndex const currentIndex = useInstanceStore().themesIndex
let promise let promise
if (currentIndex) { if (currentIndex) {
@ -138,8 +137,8 @@ export default {
promise = useInterfaceStore().fetchThemesIndex() promise = useInterfaceStore().fetchThemesIndex()
} }
promise.then((instanceThemesIndex) => { promise.then((themesIndex) => {
Object.values(instanceThemesIndex).forEach((themeFunc) => { Object.values(themesIndex).forEach((themeFunc) => {
themeFunc().then( themeFunc().then(
(themeData) => themeData && this.availableStyles.push(themeData), (themeData) => themeData && this.availableStyles.push(themeData),
) )

View file

@ -6,12 +6,6 @@ import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
const GeneralTab = { const GeneralTab = {
props: {
parentCollapsed: {
required: true,
type: Boolean,
},
},
data() { data() {
return { return {
conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({ conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({

View file

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

View file

@ -25,7 +25,6 @@ import Preview from '../old_theme_tab/theme_preview.vue'
import VirtualDirectivesTab from './virtual_directives_tab.vue' import VirtualDirectivesTab from './virtual_directives_tab.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config'
import { import {
getContrastRatio, getContrastRatio,

View file

@ -1,5 +1,5 @@
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useShoutStore } from 'src/stores/shout' import { useShoutStore } from 'src/stores/shout.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'

View file

@ -1,5 +1,5 @@
import { mapState as mapPiniaState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { mapGetters, mapState } from 'vuex' import { mapGetters } from 'vuex'
import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js' import { USERNAME_ROUTES } from 'src/components/navigation/navigation.js'
import GestureService from '../../services/gesture_service/gesture_service' import GestureService from '../../services/gesture_service/gesture_service'
@ -8,6 +8,7 @@ import UserCard from '../user_card/user_card.vue'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.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'
@ -76,27 +77,9 @@ const SideDrawer = {
unseenNotificationsCount() { unseenNotificationsCount() {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
suggestionsEnabled() {
return useInstanceStore().suggestionsEnabled
},
logo() {
return useInstanceStore().logo
},
hideSitename() {
return useInstanceStore().hideSitename
},
sitename() {
return useInstanceStore().name
},
followRequestCount() { followRequestCount() {
return this.$store.state.api.followRequests.length return this.$store.state.api.followRequests.length
}, },
privateMode() {
return useInstanceStore().private
},
federating() {
return useInstanceStore().federating
},
timelinesRoute() { timelinesRoute() {
let name let name
if (useInterfaceStore().lastTimeline) { if (useInterfaceStore().lastTimeline) {
@ -109,13 +92,19 @@ const SideDrawer = {
return { name } return { name }
} }
}, },
...mapPiniaState(useAnnouncementsStore, { ...mapState(useAnnouncementsStore, [
supportsAnnouncements: (store) => store.supportsAnnouncements, 'supportsAnnouncements',
unreadAnnouncementCount: 'unreadAnnouncementCount', 'unreadAnnouncementCount',
}), ]),
...mapState({ ...mapState(useInstanceCapabilitiesStore, [
pleromaChatMessagesAvailable: (state) => 'pleromaChatMessagesAvailable',
state.instance.pleromaChatMessagesAvailable, 'suggestionsEnabled',
]),
...mapState(useInstanceStore, ['privateMode', 'federating']),
...mapState(useInstanceStore, {
logo: (store) => store.instanceIdentity.logo,
sitename: (store) => store.instanceIdentity.name,
hideSitename: (store) => store.instanceIdentity.hideSitename,
}), }),
...mapGetters(['unreadChatCount', 'draftCount']), ...mapGetters(['unreadChatCount', 'draftCount']),
}, },
@ -133,12 +122,7 @@ const SideDrawer = {
touchMove(e) { touchMove(e) {
GestureService.updateSwipe(e, this.closeGesture) GestureService.updateSwipe(e, this.closeGesture)
}, },
openSettingsModal() { ...mapActions(useInterfaceStore, ['openSettingsModal']),
useInterfaceStore().openSettingsModal('user')
},
openAdminModal() {
useInterfaceStore().openSettingsModal('admin')
},
}, },
} }

View file

@ -198,7 +198,7 @@
<li @click="toggleDrawer"> <li @click="toggleDrawer">
<button <button
class="menu-item" class="menu-item"
@click="openSettingsModal" @click="openSettingsModal('user')"
> >
<FAIcon <FAIcon
fixed-width fixed-width
@ -225,7 +225,7 @@
> >
<button <button
class="menu-item" class="menu-item"
@click.stop="openAdminModal" @click.stop="openSettingsModal('admin')"
> >
<FAIcon <FAIcon
fixed-width fixed-width

View file

@ -30,7 +30,7 @@ const StaffPanel = {
}, },
...mapGetters(['findUserByName']), ...mapGetters(['findUserByName']),
...mapState({ ...mapState({
staffAccounts: (state) => state.instance.staffAccounts, staffAccounts: (state) => useInstanceStore().staffAccounts,
}), }),
}, },
} }

View file

@ -1,5 +1,4 @@
import { unescape as ldUnescape, uniqBy } from 'lodash' import { unescape as ldUnescape, uniqBy } from 'lodash'
import { mapState } from 'pinia'
import MentionLink from 'src/components/mention_link/mention_link.vue' import MentionLink from 'src/components/mention_link/mention_link.vue'
import MentionsLine from 'src/components/mentions_line/mentions_line.vue' import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
@ -22,7 +21,8 @@ import UserListPopover from '../user_list_popover/user_list_popover.vue'
import UserPopover from '../user_popover/user_popover.vue' import UserPopover from '../user_popover/user_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
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'
@ -258,7 +258,12 @@ const Status = {
return !!this.currentUser return !!this.currentUser
}, },
muteFilterHits() { muteFilterHits() {
return muteFilterHits(Object.values(this.muteFilters), this.status) return muteFilterHits(
Object.values(
useServerSideStorageStore().prefsStorage.simple.muteFilters,
),
this.status,
)
}, },
botStatus() { botStatus() {
return this.status.user.actor_type === 'Service' return this.status.user.actor_type === 'Service'
@ -451,6 +456,9 @@ const Status = {
.map((tagObj) => tagObj.name) .map((tagObj) => tagObj.name)
.join(' ') .join(' ')
}, },
hidePostStats() {
return this.mergedConfig.hidePostStats
},
shouldDisplayFavsAndRepeats() { shouldDisplayFavsAndRepeats() {
return ( return (
!this.hidePostStats && !this.hidePostStats &&
@ -472,7 +480,7 @@ const Status = {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
mergedConfig() { mergedConfig() {
return useSyncConfigStore().mergedConfig return this.$store.getters.mergedConfig
}, },
isSuspendable() { isSuspendable() {
return !this.replying && this.mediaPlaying.length === 0 return !this.replying && this.mediaPlaying.length === 0
@ -490,7 +498,7 @@ const Status = {
return this.status.edited_at !== null return this.status.edited_at !== null
}, },
editingAvailable() { editingAvailable() {
return useInstanceStore().editingAvailable return useInstanceCapabilitiesStore().editingAvailable
}, },
hasVisibleQuote() { hasVisibleQuote() {
return this.status.quote_url && this.status.quote_visible return this.status.quote_url && this.status.quote_visible
@ -507,10 +515,10 @@ const Status = {
return this.quotedStatus && this.displayQuote return this.quotedStatus && this.displayQuote
}, },
scrobblePresent() { scrobblePresent() {
if (this.hideScrobbles) return false if (this.mergedConfig.hideScrobbles) return false
if (!this.status.user?.latestScrobble) return false if (!this.status.user?.latestScrobble) return false
const value = this.hideScrobblesAfter.match(/\d+/gs)[0] const value = this.mergedConfig.hideScrobblesAfter.match(/\d+/gs)[0]
const unit = this.hideScrobblesAfter.match(/\D+/gs)[0] const unit = this.mergedConfig.hideScrobblesAfter.match(/\D+/gs)[0]
let multiplier = 60 * 1000 // minutes is smallest unit let multiplier = 60 * 1000 // minutes is smallest unit
switch (unit) { switch (unit) {
case 'm': case 'm':
@ -532,13 +540,6 @@ const Status = {
scrobble() { scrobble() {
return this.status.user?.latestScrobble return this.status.user?.latestScrobble
}, },
...mapState(useSyncConfigStore, {
muteFilters: (store) => store.prefsStorage.simple.muteFilters,
hideBotIndicatior: (store) => store.prefsStorage.simple.hideBotIndicator,
hidePostStats: (store) => store.mergedConfig.hidePostStats,
hideScrobbles: (store) => store.mergedConfig.hideScrobbles,
hideScrobblesAfter: (store) => store.mergedConfig.hideScrobblesAfter,
}),
}, },
methods: { methods: {
visibilityIcon(visibility) { visibilityIcon(visibility) {

View file

@ -3,6 +3,7 @@ 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 { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -93,7 +94,8 @@ export default {
return this.status.thread_muted return this.status.thread_muted
}, },
hideCustomEmoji() { hideCustomEmoji() {
return !useInstanceStore().pleromaCustomEmojiReactionsAvailable return !useInstanceCapabilitiesStore()
.pleromaCustomEmojiReactionsAvailable
}, },
buttonInnerClass() { buttonInnerClass() {
return [ return [
@ -109,7 +111,7 @@ export default {
] ]
}, },
remoteInteractionLink() { remoteInteractionLink() {
return this.$store.getters.remoteInteractionLink({ return useInstanceStore().getRemoteInteractionLink({
statusId: this.status.id, statusId: this.status.id,
}) })
}, },

View file

@ -1,4 +1,6 @@
import { useEditStatusStore } from 'src/stores/editStatus.js' import { useEditStatusStore } from 'src/stores/editStatus.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useReportsStore } from 'src/stores/reports.js' import { useReportsStore } from 'src/stores/reports.js'
import { useStatusHistoryStore } from 'src/stores/statusHistory.js' import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
@ -49,8 +51,8 @@ export const BUTTONS = [
(currentUser.id === status.user.id || (currentUser.id === status.user.id ||
!PRIVATE_SCOPES.has(status.visibility)), !PRIVATE_SCOPES.has(status.visibility)),
toggleable: true, toggleable: true,
confirm: ({ status, mergedConfig }) => confirm: ({ status, getters }) =>
!status.repeated && mergedConfig.modalOnRepeat, !status.repeated && getters.mergedConfig.modalOnRepeat,
confirmStrings: { confirmStrings: {
title: 'status.repeat_confirm_title', title: 'status.repeat_confirm_title',
body: 'status.repeat_confirm', body: 'status.repeat_confirm',
@ -158,8 +160,11 @@ export const BUTTONS = [
name: 'editHistory', name: 'editHistory',
icon: 'history', icon: 'history',
label: 'status.status_history', label: 'status.status_history',
if({ status, instance }) { if({ status, state }) {
return instance.featureSet.editingAvailable && status.edited_at !== null return (
useInstanceCapabilitiesStore().editingAvailable &&
status.edited_at !== null
)
}, },
action({ status }) { action({ status }) {
const originalStatus = { ...status } const originalStatus = { ...status }
@ -186,10 +191,10 @@ export const BUTTONS = [
name: 'edit', name: 'edit',
icon: 'pen', icon: 'pen',
label: 'status.edit', label: 'status.edit',
if({ status, loggedIn, currentUser, instance }) { if({ status, loggedIn, currentUser, state }) {
return ( return (
loggedIn && loggedIn &&
instance.featureSet.editingAvailable && useInstanceCapabilitiesStore().editingAvailable &&
status.user.id === currentUser.id status.user.id === currentUser.id
) )
}, },
@ -222,7 +227,7 @@ export const BUTTONS = [
currentUser.privileges.includes('messages_delete')) currentUser.privileges.includes('messages_delete'))
) )
}, },
confirm: ({ mergedConfig }) => mergedConfig.modalOnDelete, confirm: ({ getters }) => getters.mergedConfig.modalOnDelete,
confirmStrings: { confirmStrings: {
title: 'status.delete_confirm_title', title: 'status.delete_confirm_title',
body: 'status.delete_confirm', body: 'status.delete_confirm',
@ -240,10 +245,10 @@ export const BUTTONS = [
name: 'share', name: 'share',
icon: 'share-alt', icon: 'share-alt',
label: 'status.copy_link', label: 'status.copy_link',
action({ instance, status, router }) { action({ state, status, router }) {
navigator.clipboard.writeText( navigator.clipboard.writeText(
[ [
instance.server, useInstanceStore().server,
router.resolve({ name: 'conversation', params: { id: status.id } }) router.resolve({ name: 'conversation', params: { id: status.id } })
.href, .href,
].join(''), ].join(''),

View file

@ -5,8 +5,7 @@ import Popover from 'src/components/popover/popover.vue'
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'
import { useInstanceStore } from 'src/stores/instance.js' import { useServerSideStorageStore } from 'src/stores/serverSideStorage.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import genRandomSeed from 'src/services/random_seed/random_seed.service.js' import genRandomSeed from 'src/services/random_seed/random_seed.service.js'
@ -37,7 +36,7 @@ const StatusActionButtons = {
ActionButtonContainer, ActionButtonContainer,
}, },
computed: { computed: {
...mapState(useSyncConfigStore, { ...mapState(useServerSideStorageStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedStatusActions), new Set(store.prefsStorage.collections.pinnedStatusActions),
}), }),
@ -59,8 +58,8 @@ const StatusActionButtons = {
replying: this.replying, replying: this.replying,
emit: this.$emit, emit: this.$emit,
dispatch: this.$store.dispatch, dispatch: this.$store.dispatch,
instance: useInstanceStore(), state: this.$store.state,
mergedConfig: useSyncConfigStore().mergedConfig, getters: this.$store.getters,
router: this.$router, router: this.$router,
currentUser: this.currentUser, currentUser: this.currentUser,
loggedIn: !!this.currentUser, loggedIn: !!this.currentUser,
@ -112,18 +111,18 @@ const StatusActionButtons = {
return this.pinnedItems.has(button.name) return this.pinnedItems.has(button.name)
}, },
unpin(button) { unpin(button) {
useSyncConfigStore().removeCollectionPreference({ useServerSideStorageStore().removeCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useSyncConfigStore().pushSyncConfig() useServerSideStorageStore().pushServerSideStorage()
}, },
pin(button) { pin(button) {
useSyncConfigStore().addCollectionPreference({ useServerSideStorageStore().addCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useSyncConfigStore().pushSyncConfig() useServerSideStorageStore().pushServerSideStorage()
}, },
getComponent(button) { getComponent(button) {
if (!this.$store.state.users.currentUser && button.anonLink) { if (!this.$store.state.users.currentUser && button.anonLink) {

View file

@ -1,9 +1,7 @@
import { mapState } from 'pinia' 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 { useSyncConfigStore } from 'src/stores/sync_config.js'
import fileType from 'src/services/file_type/file_type.service' import fileType from 'src/services/file_type/file_type.service'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -112,7 +110,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, ' ')
}, },
...mapState(useSyncConfigStore, ['mergedConfig']), ...mapGetters(['mergedConfig']),
}, },
components: { components: {
RichContent, RichContent,

View file

@ -3,7 +3,7 @@ import { mapState } from 'pinia'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import StillImage from 'src/components/still-image/still-image.vue' import StillImage from 'src/components/still-image/still-image.vue'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faChevronRight, faFolder } from '@fortawesome/free-solid-svg-icons' import { faChevronRight, faFolder } from '@fortawesome/free-solid-svg-icons'

View file

@ -1,4 +1,3 @@
import { mapState as mapPiniaState } from 'pinia'
import { mapGetters, mapState } from 'vuex' 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'
@ -7,8 +6,7 @@ import Gallery from '../gallery/gallery.vue'
import LinkPreview from '../link-preview/link-preview.vue' import LinkPreview from '../link-preview/link-preview.vue'
import Poll from '../poll/poll.vue' import Poll from '../poll/poll.vue'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer.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 {
@ -76,7 +74,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:
!useSyncConfigStore().mergedConfig.collapseMessageWithSubject, !this.$store.getters.mergedConfig.collapseMessageWithSubject,
} }
}, },
computed: { computed: {
@ -93,8 +91,8 @@ const StatusContent = {
}, },
hideAttachments() { hideAttachments() {
return ( return (
(this.hideAttachments && !this.inConversation) || (this.mergedConfig.hideAttachments && !this.inConversation) ||
(this.hideAttachmentsInConv && this.inConversation) (this.mergedConfig.hideAttachmentsInConv && this.inConversation)
) )
}, },
nsfwClickthrough() { nsfwClickthrough() {
@ -106,29 +104,28 @@ const StatusContent = {
} }
return true return true
}, },
localCollapseSubjectDefault() {
return this.mergedConfig.collapseMessageWithSubject
},
attachmentSize() { attachmentSize() {
if (this.compact) { if (this.compact) {
return 'small' return 'small'
} else if ( } else if (
(this.hideAttachments && !this.inConversation) || (this.mergedConfig.hideAttachments && !this.inConversation) ||
(this.hideAttachmentsInConv && this.inConversation) || (this.mergedConfig.hideAttachmentsInConv && this.inConversation) ||
this.status.attachments.length > this.maxThumbnails this.status.attachments.length > this.maxThumbnails
) { ) {
return 'hide' return 'hide'
} }
return 'normal' return 'normal'
}, },
maxThumbnails() {
return this.mergedConfig.maxThumbnails
},
...mapGetters(['mergedConfig']),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useSyncConfigStore, {
localCollapseSubjectDefault: (store) =>
store.mergedConfig.collapseMessageWithSubject,
maxThumbnails: (store) => store.mergedConfig.maxThumbnails,
hideAttachments: (store) => store.mergedConfig.hideAttachments,
hideAttachmentsInConv: (store) =>
store.prefsStorage.simple.hideAttachmentsInConv,
}),
}, },
components: { components: {
Attachment, Attachment,

View file

@ -3,7 +3,7 @@ import { get } from 'lodash'
import Modal from '../modal/modal.vue' import Modal from '../modal/modal.vue'
import Status from '../status/status.vue' import Status from '../status/status.vue'
import { useStatusHistoryStore } from 'src/stores/statusHistory' import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
const StatusHistoryModal = { const StatusHistoryModal = {
components: { components: {

View file

@ -3,6 +3,7 @@
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'
import { useEmojiStore } from 'src/stores/emoji.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
const StickerPicker = { const StickerPicker = {
@ -19,7 +20,7 @@ const StickerPicker = {
}, },
computed: { computed: {
pack() { pack() {
return useInstanceStore().stickers || [] return useEmojiStore().stickers || []
}, },
}, },
methods: { methods: {

View file

@ -55,7 +55,135 @@
</Popover> </Popover>
</template> </template>
<script src="./still-image-emoji-popover.js" /> <script>
import Popover from 'components/popover/popover.vue'
import SelectComponent from 'components/select/select.vue'
import { assign } from 'lodash'
import StillImage from './still-image.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface'
export default {
components: { StillImage, Popover, SelectComponent },
props: {
shortcode: {
type: String,
required: true,
},
isLocal: {
type: Boolean,
required: true,
},
},
data() {
return {
knownLocalPacks: {},
packName: '',
}
},
computed: {
isUserAdmin() {
return this.$store.state.users.currentUser.rights.admin
},
},
methods: {
displayError(msg) {
useInterfaceStore().pushGlobalNotice({
messageKey: 'admin_dash.emoji.error',
messageArgs: [msg],
level: 'error',
})
},
copyToLocalPack() {
this.$store.state.api.backendInteractor
.addNewEmojiFile({
packName: this.packName,
file: this.$attrs.src,
shortcode: this.shortcode,
filename: '',
})
.then((resp) => resp.json())
.then((resp) => {
if (resp.error !== undefined) {
this.displayError(resp.error)
return
}
useInterfaceStore().pushGlobalNotice({
messageKey: 'admin_dash.emoji.copied_successfully',
messageArgs: [this.shortcode, this.packName],
level: 'success',
})
this.$refs.emojiPopover.hidePopover()
this.packName = ''
})
},
// Copied from emoji_tab.js
loadPacksPaginated(listFunction) {
const pageSize = 25
const allPacks = {}
return listFunction({
instance: useInstanceStore().server,
page: 1,
pageSize: 0,
})
.then((data) => data.json())
.then((data) => {
if (data.error !== undefined) {
return Promise.reject(data.error)
}
let resultingPromise = Promise.resolve({})
for (let i = 0; i < Math.ceil(data.count / pageSize); i++) {
resultingPromise = resultingPromise
.then(() =>
listFunction({
instance: useInstanceStore().server,
page: i,
pageSize,
}),
)
.then((data) => data.json())
.then((pageData) => {
if (pageData.error !== undefined) {
return Promise.reject(pageData.error)
}
assign(allPacks, pageData.packs)
})
}
return resultingPromise
})
.then(() => allPacks)
.catch((data) => {
this.displayError(data)
})
},
fetchEmojiPacksIfAdmin() {
if (!this.isUserAdmin) return
this.loadPacksPaginated(
this.$store.state.api.backendInteractor.listEmojiPacks,
).then((allPacks) => {
// Sort by key
const sorted = Object.keys(allPacks)
.sort()
.reduce((acc, key) => {
if (key.length === 0) return acc
acc[key] = allPacks[key]
return acc
}, {})
this.knownLocalPacks = sorted
})
},
},
}
</script>
<style> <style>
.emoji-popover { .emoji-popover {

View file

@ -7,7 +7,7 @@ import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
import './tab_switcher.scss' import './tab_switcher.scss'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
const findFirstUsable = (slots) => slots.findIndex((_) => _.props) const findFirstUsable = (slots) => slots.findIndex((_) => _.props)

View file

@ -4,8 +4,8 @@ import { useInstanceStore } from 'src/stores/instance.js'
const TermsOfServicePanel = { const TermsOfServicePanel = {
computed: mapState(useInstanceStore, { computed: mapState(useInstanceStore, {
content: (state) => state.tos, content: (store) => store.instanceIdentity.tos,
embedded: (state) => state.embeddedToS, embedded: (store) => store.instanceIdentity.embeddedToS,
}), }),
} }

View file

@ -8,9 +8,7 @@ import ScrollTopButton from '../scroll_top_button/scroll_top_button.vue'
import Status from '../status/status.vue' import Status from '../status/status.vue'
import TimelineMenu from '../timeline_menu/timeline_menu.vue' import TimelineMenu from '../timeline_menu/timeline_menu.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.js'
@ -127,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 useSyncConfigStore().mergedConfig.virtualScrolling return this.$store.getters.mergedConfig.virtualScrolling
}, },
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (store) => store.layoutType === 'mobile', mobileLayout: (store) => store.layoutType === 'mobile',
@ -315,7 +313,7 @@ const Timeline = {
}, },
watch: { watch: {
newStatusCount(count) { newStatusCount(count) {
if (!useSyncConfigStore().mergedConfig.streaming) { if (!this.$store.getters.mergedConfig.streaming) {
return return
} }
if (count > 0) { if (count > 0) {
@ -325,9 +323,7 @@ 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 {

Some files were not shown because too many files have changed in this diff Show more