Merge pull request 'Synchronized Settings' (#3473) from setttingssync into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma-fe/pulls/3473
This commit is contained in:
HJ 2026-04-23 18:56:01 +00:00
commit 9f3c0ec60b
150 changed files with 3942 additions and 1810 deletions

View file

@ -25,7 +25,11 @@ const getAllAccessibleAnnotations = async (projectRoot) => {
await access(importFile) await access(importFile)
return `'${lang}': () => import('${importModule}')` return `'${lang}': () => import('${importModule}')`
} catch (e) { } catch (e) {
console.error(e) if (e.message.match(/ENOENT/)) {
console.warn(`Missing emoji annotations locale: ${destLang}`)
} else {
console.error('test', e.message)
}
return return
} }
}), }),

View file

@ -1,7 +1,6 @@
import { throttle } from 'lodash' import { throttle } from 'lodash'
import { mapState } from 'pinia' import { mapState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapGetters } from 'vuex'
import DesktopNav from './components/desktop_nav/desktop_nav.vue' import DesktopNav from './components/desktop_nav/desktop_nav.vue'
import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue'
@ -22,11 +21,20 @@ import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_pan
import { getOrCreateServiceWorker } from './services/sw/sw' import { getOrCreateServiceWorker } from './services/sw/sw'
import { windowHeight, windowWidth } from './services/window_utils/window_utils' import { windowHeight, windowWidth } from './services/window_utils/window_utils'
import { useEmojiStore } from 'src/stores/emoji.js'
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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useShoutStore } from 'src/stores/shout.js' import { useShoutStore } from 'src/stores/shout.js'
import messages from 'src/i18n/messages'
import localeService from 'src/services/locale/locale.service.js'
// Helper to unwrap reactive proxies
window.toValue = (x) => JSON.parse(JSON.stringify(x))
export default { export default {
name: 'app', name: 'app',
components: { components: {
@ -72,8 +80,10 @@ export default {
}, },
created() { created() {
// Load the locale from the storage // Load the locale from the storage
const val = this.$store.getters.mergedConfig.interfaceLanguage const value = useMergedConfigStore().mergedConfig.interfaceLanguage
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) useI18nStore().setLanguage(value)
useEmojiStore().loadUnicodeEmojiData(value)
document.getElementById('modal').classList = ['-' + this.layoutType] document.getElementById('modal').classList = ['-' + this.layoutType]
// Create bound handlers // Create bound handlers
@ -122,7 +132,7 @@ export default {
] ]
}, },
navClasses() { navClasses() {
const { navbarColumnStretch } = this.$store.getters.mergedConfig const { navbarColumnStretch } = useMergedConfigStore().mergedConfig
return [ return [
'-' + this.layoutType, '-' + this.layoutType,
...(navbarColumnStretch ? ['-column-stretch'] : []), ...(navbarColumnStretch ? ['-column-stretch'] : []),
@ -135,7 +145,9 @@ export default {
return this.currentUser.background_image return this.currentUser.background_image
}, },
instanceBackground() { instanceBackground() {
return this.mergedConfig.hideInstanceWallpaper ? null : this.background return useMergedConfigStore().mergedConfig.hideInstanceWallpaper
? null
: this.instanceBackgroundUrl
}, },
background() { background() {
return this.userBackground || this.instanceBackground return this.userBackground || this.instanceBackground
@ -160,19 +172,21 @@ export default {
if (this.isChats) return false if (this.isChats) return false
if (this.isListEdit) return false if (this.isListEdit) return false
return ( return (
this.$store.getters.mergedConfig.alwaysShowNewPostButton || useMergedConfigStore().mergedConfig.alwaysShowNewPostButton ||
this.layoutType === 'mobile' this.layoutType === 'mobile'
) )
}, },
shoutboxPosition() { shoutboxPosition() {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false return (
useMergedConfigStore().mergedConfig.alwaysShowNewPostButton || false
)
}, },
hideShoutbox() { hideShoutbox() {
return this.$store.getters.mergedConfig.hideShoutbox return useMergedConfigStore().mergedConfig.hideShoutbox
}, },
reverseLayout() { reverseLayout() {
const { thirdColumnMode, sidebarRight: reverseSetting } = const { thirdColumnMode, sidebarRight: reverseSetting } =
this.$store.getters.mergedConfig useMergedConfigStore().mergedConfig
if (this.layoutType !== 'wide') { if (this.layoutType !== 'wide') {
return reverseSetting return reverseSetting
} else { } else {
@ -182,10 +196,10 @@ export default {
} }
}, },
noSticky() { noSticky() {
return this.$store.getters.mergedConfig.disableStickyHeaders return useMergedConfigStore().mergedConfig.disableStickyHeaders
}, },
showScrollbars() { showScrollbars() {
return this.$store.getters.mergedConfig.showScrollbars return useMergedConfigStore().mergedConfig.showScrollbars
}, },
scrollParent() { scrollParent() {
return window /* this.$refs.appContentRef */ return window /* this.$refs.appContentRef */
@ -193,10 +207,10 @@ export default {
showInstanceSpecificPanel() { showInstanceSpecificPanel() {
return ( return (
this.instanceSpecificPanelPresent && this.instanceSpecificPanelPresent &&
!this.$store.getters.mergedConfig.hideISP !useMergedConfigStore().mergedConfig.hideISP
) )
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
...mapState(useInterfaceStore, [ ...mapState(useInterfaceStore, [
'themeApplied', 'themeApplied',
'styleDataUsed', 'styleDataUsed',
@ -208,7 +222,7 @@ export default {
'editingAvailable', 'editingAvailable',
]), ]),
...mapState(useInstanceStore, { ...mapState(useInstanceStore, {
background: (store) => store.instanceIdentity.background, instanceBackgroundUrl: (store) => store.instanceIdentity.background,
showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel, showFeaturesPanel: (store) => store.instanceIdentity.showFeaturesPanel,
instanceSpecificPanelPresent: (store) => instanceSpecificPanelPresent: (store) =>
store.instanceIdentity.showInstanceSpecificPanel && store.instanceIdentity.showInstanceSpecificPanel &&

View file

@ -797,14 +797,17 @@ option {
} }
.notice-dismissible { .notice-dismissible {
padding-right: 4rem; display: flex;
position: relative; padding: 0.75em 1em;
align-items: baseline;
line-height: 1.5;
span {
display: block;
flex: 1 1 auto;
}
.dismiss { .dismiss {
position: absolute;
top: 0;
right: 0;
padding: 0.5em;
color: inherit; color: inherit;
} }
} }

View file

@ -32,12 +32,17 @@ 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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth' import { useOAuthStore } from 'src/stores/oauth'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
import VBodyScrollLock from 'src/directives/body_scroll_lock' import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { import {
instanceDefaultConfig, INSTANCE_DEFAULT_CONFIG_DEFINITIONS,
staticOrApiConfigDefault, INSTANCE_IDENTITY_DEFAULT_DEFINITIONS,
INSTANCE_IDENTIY_EXTERNAL,
} from 'src/modules/default_config_state.js' } from 'src/modules/default_config_state.js'
let staticInitialResults = null let staticInitialResults = null
@ -80,7 +85,7 @@ const getInstanceConfig = async ({ store }) => {
const res = await preloadFetch('/api/v1/instance') const res = await preloadFetch('/api/v1/instance')
if (res.ok) { if (res.ok) {
const data = await res.json() const data = await res.json()
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( useInstanceCapabilitiesStore().set(
@ -88,8 +93,8 @@ const getInstanceConfig = async ({ store }) => {
data.pleroma, data.pleroma,
) )
useInstanceStore().set({ useInstanceStore().set({
path: 'textlimit', path: 'limits.textLimit',
value: textlimit, value: textLimit,
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'accountApprovalRequired', path: 'accountApprovalRequired',
@ -166,18 +171,21 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
config = Object.assign({}, staticConfig, apiConfig) config = Object.assign({}, staticConfig, apiConfig)
} }
const copyInstanceOption = ({ source, destination }) => { Object.keys(INSTANCE_IDENTITY_DEFAULT_DEFINITIONS).forEach((source) => {
if (typeof config[source] !== 'undefined') { if (source === 'name') return
useInstanceStore().set({ path: destination, value: config[source] }) if (INSTANCE_IDENTIY_EXTERNAL.has(source)) return
} useInstanceStore().set({
} value: config[source],
path: `instanceIdentity.${source}`,
})
})
Object.keys(staticOrApiConfigDefault) Object.keys(INSTANCE_DEFAULT_CONFIG_DEFINITIONS).forEach((source) =>
.map((k) => ({ source: k, destination: `instanceIdentity.${k}` })) useInstanceStore().set({
.forEach(copyInstanceOption) value: config[source],
Object.keys(instanceDefaultConfig) path: `prefsStorage.${source}`,
.map((k) => ({ source: k, destination: `prefsStorage.${k}` })) }),
.forEach(copyInstanceOption) )
useAuthFlowStore().setInitialStrategy(config.loginMethod) useAuthFlowStore().setInitialStrategy(config.loginMethod)
} }
@ -187,7 +195,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({ name: 'instanceIdentity.tos', value: html }) useInstanceStore().set({ path: 'instanceIdentity.tos', value: html })
} else { } else {
throw res throw res
} }
@ -272,7 +280,7 @@ const getNodeInfo = async ({ store }) => {
const metadata = data.metadata const metadata = data.metadata
const features = metadata.features const features = metadata.features
useInstanceStore().set({ useInstanceStore().set({
path: 'name', path: 'instanceIdentity.name',
value: metadata.nodeName, value: metadata.nodeName,
}) })
useInstanceStore().set({ useInstanceStore().set({
@ -523,6 +531,11 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
useInterfaceStore().setLayoutWidth(windowWidth()) useInterfaceStore().setLayoutWidth(windowWidth())
useInterfaceStore().setLayoutHeight(windowHeight()) useInterfaceStore().setLayoutHeight(windowHeight())
window.syncConfig = useSyncConfigStore()
window.mergedConfig = useMergedConfigStore()
window.localConfig = useLocalConfigStore()
window.highlightConfig = useUserHighlightStore()
FaviconService.initFaviconService() FaviconService.initFaviconService()
initServiceWorker(store) initServiceWorker(store)
@ -533,7 +546,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({ name: 'server', value: server }) useInstanceStore().set({ path: 'server', value: server })
await setConfig({ store }) await setConfig({ store })
try { try {
@ -547,7 +560,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
return Promise.reject(e) return Promise.reject(e)
} }
applyStyleConfig(store.state.config, i18n.global) applyStyleConfig(useMergedConfigStore().mergedConfig, 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

@ -5,6 +5,7 @@ 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
const About = { const About = {
components: { components: {
@ -21,7 +22,7 @@ const About = {
showInstanceSpecificPanel() { showInstanceSpecificPanel() {
return ( return (
useInstanceStore().instanceIdentity.showInstanceSpecificPanel && useInstanceStore().instanceIdentity.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP && !useMergedConfigStore().mergedConfig.hideISP &&
useInstanceStore().instanceIdentity.instanceSpecificPanelContent useInstanceStore().instanceIdentity.instanceSpecificPanelContent
) )
}, },

View file

@ -7,6 +7,7 @@ import Popover from '../popover/popover.vue'
import ProgressButton from '../progress_button/progress_button.vue' import ProgressButton from '../progress_button/progress_button.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useReportsStore } from 'src/stores/reports' import { useReportsStore } from 'src/stores/reports'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -89,10 +90,10 @@ const AccountActions = {
}, },
computed: { computed: {
shouldConfirmBlock() { shouldConfirmBlock() {
return this.$store.getters.mergedConfig.modalOnBlock return useMergedConfigStore().mergedConfig.modalOnBlock
}, },
shouldConfirmRemoveUserFromFollowers() { shouldConfirmRemoveUserFromFollowers() {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers return useMergedConfigStore().mergedConfig.modalOnRemoveUserFromFollowers
}, },
...mapState(useInstanceCapabilitiesStore, [ ...mapState(useInstanceCapabilitiesStore, [
'blockExpiration', 'blockExpiration',

View file

@ -1,4 +1,4 @@
import { mapGetters } from 'vuex' import { mapState } from 'pinia'
import nsfwImage from '../../assets/nsfw.png' import nsfwImage from '../../assets/nsfw.png'
import Flash from '../flash/flash.vue' import Flash from '../flash/flash.vue'
@ -8,6 +8,7 @@ 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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMediaViewerStore } from 'src/stores/media_viewer' import { useMediaViewerStore } from 'src/stores/media_viewer'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -57,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: this.$store.getters.mergedConfig.hideNsfw, hideNsfwLocal: useMergedConfigStore().mergedConfig.hideNsfw,
preloadImage: this.$store.getters.mergedConfig.preloadImage, preloadImage: useMergedConfigStore().mergedConfig.preloadImage,
loading: false, loading: false,
img: this.attachment.type === 'image' && document.createElement('img'), img: this.attachment.type === 'image' && document.createElement('img'),
modalOpen: false, modalOpen: false,
@ -90,7 +91,7 @@ const Attachment = {
return this.size === 'hide' return this.size === 'hide'
}, },
useContainFit() { useContainFit() {
return this.$store.getters.mergedConfig.useContainFit return this.mergedConfig.useContainFit
}, },
placeholderName() { placeholderName() {
if (this.attachment.description === '' || !this.attachment.description) { if (this.attachment.description === '' || !this.attachment.description) {
@ -133,7 +134,7 @@ const Attachment = {
videoTag() { videoTag() {
return this.useModal ? 'button' : 'span' return this.useModal ? 'button' : 'span'
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
}, },
watch: { watch: {
'attachment.description'(newVal) { 'attachment.description'(newVal) {
@ -186,7 +187,8 @@ const Attachment = {
if ( if (
this.mergedConfig.useOneClickNsfw && this.mergedConfig.useOneClickNsfw &&
!this.showHidden && !this.showHidden &&
(this.attachment.type !== 'video' || this.mergedConfig.playVideosInModal) (this.attachment.type !== 'video' ||
this.mergedConfig.playVideosInModal)
) { ) {
this.openModal(event) this.openModal(event)
return return

View file

@ -25,9 +25,7 @@ const ChatListItem = {
return return
} }
const types = this.chat.lastMessage.attachments.map((file) => const types = this.chat.lastMessage.attachments.map((file) => file.type)
file.type,
)
if (types.includes('video')) { if (types.includes('video')) {
return this.$t('file_type.video') return this.$t('file_type.video')
} else if (types.includes('audio')) { } else if (types.includes('audio')) {

View file

@ -12,6 +12,7 @@ import UserAvatar from '../user_avatar/user_avatar.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'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
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'
@ -85,7 +86,7 @@ const ChatMessage = {
return { left: 50 } return { left: 50 }
} }
}, },
...mapGetters(['mergedConfig', 'findUser']), ...mapPiniaState(useMergedConfigStore, ['mergedConfig', 'findUser']),
}, },
data() { data() {
return { return {

View file

@ -1,8 +1,10 @@
import { mapGetters } from 'vuex' import { mapState } from 'pinia'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
import ConfirmModal from './confirm_modal.vue' import ConfirmModal from './confirm_modal.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
export default { export default {
props: ['type', 'user', 'status'], props: ['type', 'user', 'status'],
emits: ['hide', 'show', 'muted'], emits: ['hide', 'show', 'muted'],
@ -43,7 +45,7 @@ export default {
} }
} }
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
}, },
methods: { methods: {
optionallyPrompt() { optionallyPrompt() {

View file

@ -1,6 +1,6 @@
import { clone, filter, findIndex, get, reduce } from 'lodash' import { clone, filter, findIndex, get, reduce } from 'lodash'
import { mapState as mapPiniaState } from 'pinia' import { mapState as mapPiniaState } from 'pinia'
import { mapGetters, mapState } from 'vuex' import { mapState } from 'vuex'
import { WSConnectionStatus } from '../../services/api/api.service.js' import { WSConnectionStatus } from '../../services/api/api.service.js'
import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue'
@ -9,6 +9,7 @@ import Status from '../status/status.vue'
import ThreadTree from '../thread_tree/thread_tree.vue' import ThreadTree from '../thread_tree/thread_tree.vue'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -81,7 +82,7 @@ const conversation = {
// maxDepthInThread = max number of depths that is *visible* // maxDepthInThread = max number of depths that is *visible*
// since our depth starts with 0 and "showing" means "showing children" // since our depth starts with 0 and "showing" means "showing children"
// there is a -2 here // there is a -2 here
const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2 const maxDepth = this.mergedConfig.maxDepthInThread - 2
return maxDepth >= 1 ? maxDepth : 1 return maxDepth >= 1 ? maxDepth : 1
}, },
streamingEnabled() { streamingEnabled() {
@ -91,22 +92,22 @@ const conversation = {
) )
}, },
displayStyle() { displayStyle() {
return this.$store.getters.mergedConfig.conversationDisplay return this.mergedConfig.conversationDisplay
}, },
isTreeView() { isTreeView() {
return !this.isLinearView return !this.isLinearView
}, },
treeViewIsSimple() { treeViewIsSimple() {
return !this.$store.getters.mergedConfig.conversationTreeAdvanced return !this.mergedConfig.conversationTreeAdvanced
}, },
isLinearView() { isLinearView() {
return this.displayStyle === 'linear' return this.displayStyle === 'linear'
}, },
shouldFadeAncestors() { shouldFadeAncestors() {
return this.$store.getters.mergedConfig.conversationTreeFadeAncestors return this.mergedConfig.conversationTreeFadeAncestors
}, },
otherRepliesButtonPosition() { otherRepliesButtonPosition() {
return this.$store.getters.mergedConfig.conversationOtherRepliesButton return this.mergedConfig.conversationOtherRepliesButton
}, },
showOtherRepliesButtonBelowStatus() { showOtherRepliesButtonBelowStatus() {
return this.otherRepliesButtonPosition === 'below' return this.otherRepliesButtonPosition === 'below'
@ -392,7 +393,7 @@ const conversation = {
maybeHighlight() { maybeHighlight() {
return this.isExpanded ? this.highlight : null return this.isExpanded ? this.highlight : null
}, },
...mapGetters(['mergedConfig']), ...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
...mapState({ ...mapState({
mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus,
}), }),

View file

@ -88,38 +88,34 @@
class="thread-ancestor" class="thread-ancestor"
:class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}" :class="{'thread-ancestor-has-other-replies': getReplies(status.id).length > 1, '-faded': shouldFadeAncestors}"
> >
<status <Status
ref="statusComponent" ref="statusComponent"
:inline-expanded="collapsable && isExpanded"
:statusoid="status"
:expandable="!isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:focused="isFocused(status.id)"
:in-conversation="isExpanded"
:highlight="getHighlight()"
:replies="getReplies(status.id)"
:in-profile="inProfile"
:profile-user-id="profileUserId"
class="conversation-status status-fadein panel-body" class="conversation-status status-fadein panel-body"
:statusoid="status"
:replies="getReplies(status.id)"
:expandable="!isExpanded"
:focused="isFocused(status.id)"
:highlight="getHighlight()"
:inline-expanded="collapsable && isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:in-profile="inProfile"
:in-conversation="isExpanded"
:profile-user-id="profileUserId"
:simple-tree="treeViewIsSimple" :simple-tree="treeViewIsSimple"
:toggle-thread-display="toggleThreadDisplay"
:thread-display-status="threadDisplayStatus"
:show-thread-recursively="showThreadRecursively"
:total-reply-count="totalReplyCount"
:total-reply-depth="totalReplyDepth"
:show-other-replies-as-button="showOtherRepliesButtonInsideStatus" :show-other-replies-as-button="showOtherRepliesButtonInsideStatus"
:dive="() => diveIntoStatus(status.id)" :dive="() => diveIntoStatus(status.id)"
:controlled-showing-tall="statusContentProperties[status.id].showingTall" :controlled-showing-tall="statusContentProperties[status.id].showingTall"
:controlled-expanding-subject="statusContentProperties[status.id].expandingSubject"
:controlled-showing-long-subject="statusContentProperties[status.id].showingLongSubject"
:controlled-replying="statusContentProperties[status.id].replying"
:controlled-media-playing="statusContentProperties[status.id].mediaPlaying"
:controlled-toggle-showing-tall="() => toggleStatusContentProperty(status.id, 'showingTall')" :controlled-toggle-showing-tall="() => toggleStatusContentProperty(status.id, 'showingTall')"
:controlled-expanding-subject="statusContentProperties[status.id].expandingSubject"
:controlled-toggle-expanding-subject="() => toggleStatusContentProperty(status.id, 'expandingSubject')" :controlled-toggle-expanding-subject="() => toggleStatusContentProperty(status.id, 'expandingSubject')"
:controlled-showing-long-subject="statusContentProperties[status.id].showingLongSubject"
:controlled-toggle-showing-long-subject="() => toggleStatusContentProperty(status.id, 'showingLongSubject')" :controlled-toggle-showing-long-subject="() => toggleStatusContentProperty(status.id, 'showingLongSubject')"
:controlled-replying="statusContentProperties[status.id].replying"
:controlled-toggle-replying="() => toggleStatusContentProperty(status.id, 'replying')" :controlled-toggle-replying="() => toggleStatusContentProperty(status.id, 'replying')"
:controlled-media-playing="statusContentProperties[status.id].mediaPlaying"
:controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)" :controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)"
@goto="setHighlight" @goto="setHighlight"
@ -195,26 +191,18 @@
v-for="status in conversation" v-for="status in conversation"
:key="status.id" :key="status.id"
ref="statusComponent" ref="statusComponent"
:inline-expanded="collapsable && isExpanded"
:statusoid="status"
:expandable="!isExpanded"
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:focused="isFocused(status.id)"
:in-conversation="isExpanded"
:highlight="getHighlight()"
:replies="getReplies(status.id)"
:in-profile="inProfile"
:profile-user-id="profileUserId"
class="conversation-status status-fadein panel-body" class="conversation-status status-fadein panel-body"
:statusoid="status"
:replies="getReplies(status.id)"
:toggle-thread-display="toggleThreadDisplay" :expandable="!isExpanded"
:thread-display-status="threadDisplayStatus" :focused="isFocused(status.id)"
:show-thread-recursively="showThreadRecursively" :highlight="getHighlight()"
:total-reply-count="totalReplyCount" :inline-expanded="collapsable && isExpanded"
:total-reply-depth="totalReplyDepth" :show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
:status-content-properties="statusContentProperties" :in-profile="inProfile"
:set-status-content-property="setStatusContentProperty" :in-conversation="isExpanded"
:toggle-status-content-property="toggleStatusContentProperty" :profile-user-id="profileUserId"
@goto="setHighlight" @goto="setHighlight"
@toggle-expanded="toggleExpanded" @toggle-expanded="toggleExpanded"

View file

@ -5,6 +5,7 @@ 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' import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -96,7 +97,7 @@ export default {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
shouldConfirmLogout() { shouldConfirmLogout() {
return this.$store.getters.mergedConfig.modalOnLogout return useMergedConfigStore().mergedConfig.modalOnLogout
}, },
}, },
methods: { methods: {

View file

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

View file

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

View file

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

View file

@ -9,6 +9,8 @@ import genRandomSeed from '../../services/random_seed/random_seed.service.js'
import EmojiPicker from '../emoji_picker/emoji_picker.vue' import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
@ -131,10 +133,10 @@ const EmojiInput = {
}, },
computed: { computed: {
padEmoji() { padEmoji() {
return this.$store.getters.mergedConfig.padEmoji return useMergedConfigStore().mergedConfig.padEmoji
}, },
defaultCandidateIndex() { defaultCandidateIndex() {
return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1 return useMergedConfigStore().mergedConfig.autocompleteSelect ? 0 : -1
}, },
preText() { preText() {
return this.modelValue.slice(0, this.caret) return this.modelValue.slice(0, this.caret)
@ -163,7 +165,7 @@ const EmojiInput = {
}, },
languages() { languages() {
return ensureFinalFallback( return ensureFinalFallback(
this.$store.getters.mergedConfig.interfaceLanguage, useMergedConfigStore().mergedConfig.interfaceLanguage,
) )
}, },
maybeLocalizedEmojiNamesAndKeywords() { maybeLocalizedEmojiNamesAndKeywords() {

View file

@ -1,3 +1,5 @@
import { useEmojiStore } from 'src/stores/emoji.js'
/** /**
* suggest - generates a suggestor function to be used by emoji-input * suggest - generates a suggestor function to be used by emoji-input
* data: object providing source information for specific types of suggestions: * data: object providing source information for specific types of suggestions:

View file

@ -8,6 +8,7 @@ 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -340,7 +341,7 @@ const EmojiPicker = {
this.$nextTick(() => { this.$nextTick(() => {
this.updateEmojiSize() this.updateEmojiSize()
}) })
return this.$store.getters.mergedConfig.fontSize return useMergedConfigStore().mergedConfig.fontSize
}, },
emojiHeight() { emojiHeight() {
return this.emojiSize return this.emojiSize
@ -405,7 +406,7 @@ const EmojiPicker = {
}, },
languages() { languages() {
return ensureFinalFallback( return ensureFinalFallback(
this.$store.getters.mergedConfig.interfaceLanguage, useMergedConfigStore().mergedConfig.interfaceLanguage,
) )
}, },
maybeLocalizedEmojiName() { maybeLocalizedEmojiName() {

View file

@ -2,6 +2,8 @@ import StillImage from 'src/components/still-image/still-image.vue'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import UserListPopover from '../user_list_popover/user_list_popover.vue' import UserListPopover from '../user_list_popover/user_list_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons' import { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
@ -42,7 +44,7 @@ const EmojiReactions = {
return !!this.$store.state.users.currentUser return !!this.$store.state.users.currentUser
}, },
remoteInteractionLink() { remoteInteractionLink() {
return this.$store.getters.remoteInteractionLink({ return useInstanceStore().getRemoteInteractionLink({
statusId: this.status.id, statusId: this.status.id,
}) })
}, },

View file

@ -3,6 +3,8 @@ 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -51,18 +53,19 @@ const ExtraNotifications = {
currentUser() { currentUser() {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
...mapGetters(['unreadChatCount', 'followRequestCount', 'mergedConfig']), ...mapGetters(['unreadChatCount', 'followRequestCount']),
...mapPiniaState(useAnnouncementsStore, { ...mapPiniaState(useAnnouncementsStore, {
unreadAnnouncementCount: 'unreadAnnouncementCount', unreadAnnouncementCount: 'unreadAnnouncementCount',
}), }),
...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
}, },
methods: { methods: {
openNotificationSettings() { openNotificationSettings() {
return useInterfaceStore().openSettingsModalTab('notifications') return useInterfaceStore().openSettingsModalTab('notifications')
}, },
dismissConfigurationTip() { dismissConfigurationTip() {
return this.$store.dispatch('setOption', { return useSyncConfigStore().setSimplePrefAndSave({
name: 'showExtraNotificationsTip', path: 'showExtraNotificationsTip',
value: false, value: false,
}) })
}, },

View file

@ -15,7 +15,7 @@ const FeaturesPanel = {
'mediaProxyAvailable', 'mediaProxyAvailable',
]), ]),
...mapState(useInstanceStore, { ...mapState(useInstanceStore, {
textlimit: (store) => store.limits.textlimit, textLimit: (store) => store.limits.textLimit,
uploadlimit: (store) => uploadlimit: (store) =>
fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit), fileSizeFormatService.fileSizeFormat(store.limits.uploadlimit),
}), }),

View file

@ -24,7 +24,7 @@
{{ $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>
<li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li> <li>{{ $t('features_panel.text_limit') }} = {{ textLimit }}</li>
<li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li> <li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li>
</ul> </ul>
</div> </div>

View file

@ -3,6 +3,8 @@ import {
requestUnfollow, requestUnfollow,
} from '../../services/follow_manipulate/follow_manipulate' } from '../../services/follow_manipulate/follow_manipulate'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
export default { export default {
props: ['relationship', 'user', 'labelFollowing', 'buttonClass'], props: ['relationship', 'user', 'labelFollowing', 'buttonClass'],
components: { components: {
@ -16,7 +18,7 @@ export default {
}, },
computed: { computed: {
shouldConfirmUnfollow() { shouldConfirmUnfollow() {
return this.$store.getters.mergedConfig.modalOnUnfollow return useMergedConfigStore().mergedConfig.modalOnUnfollow
}, },
isPressed() { isPressed() {
return this.inProgress || this.relationship.following return this.inProgress || this.relationship.following

View file

@ -2,6 +2,8 @@ import { notificationsFromStore } from '../../services/notification_utils/notifi
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const FollowRequestCard = { const FollowRequestCard = {
props: ['user'], props: ['user'],
components: { components: {
@ -76,7 +78,7 @@ const FollowRequestCard = {
}, },
computed: { computed: {
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useMergedConfigStore().mergedConfig
}, },
shouldConfirmApprove() { shouldConfirmApprove() {
return this.mergedConfig.modalOnApproveFollow return this.mergedConfig.modalOnApproveFollow

View file

@ -1,5 +1,6 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' 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 LocalSettingIndicator from 'src/components/settings_modal/helpers/local_setting_indicator.vue'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
@ -18,6 +19,7 @@ export default {
Select, Select,
Checkbox, Checkbox,
Popover, Popover,
LocalSettingIndicator,
}, },
props: ['name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'], props: ['name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'],
mounted() { mounted() {
@ -43,7 +45,7 @@ export default {
}, },
computed: { computed: {
present() { present() {
return typeof this.modelValue !== 'undefined' return this.modelValue != null
}, },
localFontsList() { localFontsList() {
return useInterfaceStore().localFonts return useInterfaceStore().localFonts

View file

@ -6,8 +6,10 @@
:id="name + '-o'" :id="name + '-o'"
class="font-checkbox setting-control setting-label" class="font-checkbox setting-control setting-label"
:model-value="present" :model-value="present"
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)" @change="$emit('update:modelValue', modelValue == null ? fallback : null)"
> >
<LocalSettingIndicator />
{{ ' ' }}
<i18n-t <i18n-t
scope="global" scope="global"
keypath="settings.style.fonts.override" keypath="settings.style.fonts.override"

View file

@ -4,7 +4,7 @@ import Attachment from '../attachment/attachment.vue'
import { useMediaViewerStore } from 'src/stores/media_viewer.js' import { useMediaViewerStore } from 'src/stores/media_viewer.js'
const displayTypes = new Set(["image", "video", "flash"]) const displayTypes = new Set(['image', 'video', 'flash'])
const Gallery = { const Gallery = {
props: [ props: [

View file

@ -1,13 +1,11 @@
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue'
import localeService from '../../services/locale/locale.service.js' import localeService from '../../services/locale/locale.service.js'
import Select from '../select/select.vue' import Select from '../select/select.vue'
export default { export default {
components: { components: {
Select, Select,
ProfileSettingIndicator,
}, },
props: { props: {
// List of languages (or just one language) // List of languages (or just one language)

View file

@ -1,4 +1,6 @@
import { mapGetters } from 'vuex' import { mapState } from 'pinia'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const LinkPreview = { const LinkPreview = {
name: 'LinkPreview', name: 'LinkPreview',
@ -24,7 +26,7 @@ const LinkPreview = {
hideNsfwConfig() { hideNsfwConfig() {
return this.mergedConfig.hideNsfw return this.mergedConfig.hideNsfw
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
}, },
created() { created() {
if (this.useImage) { if (this.useImage) {

View file

@ -124,11 +124,10 @@ const ListsNew = {
useListsStore() useListsStore()
.createList({ title: this.titleDraft }) .createList({ title: this.titleDraft })
.then((list) => { .then((list) => {
useListsStore() useListsStore().setListAccounts({
.setListAccounts({ listId: list.id,
listId: list.id, accountIds: [...this.addedUserIds],
accountIds: [...this.addedUserIds], })
})
return list.id return list.id
}) })
.then((listId) => { .then((listId) => {

View file

@ -2,6 +2,7 @@ import fileSizeFormatService from '../../services/file_size_format/file_size_for
import statusPosterService from '../../services/status_poster/status_poster.service.js' import statusPosterService from '../../services/status_poster/status_poster.service.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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 +34,7 @@ const mediaUpload = {
} }
// Skip if image compression is disabled // Skip if image compression is disabled
if (!this.$store.getters.mergedConfig.imageCompression) { if (!useMergedConfigStore().mergedConfig.imageCompression) {
return file return file
} }
@ -78,7 +79,7 @@ const mediaUpload = {
// Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG // Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG
const type = const type =
!this.$store.getters.mergedConfig.alwaysUseJpeg && supportsWebP !useMergedConfigStore().mergedConfig.alwaysUseJpeg && supportsWebP
? 'image/webp' ? 'image/webp'
: 'image/jpeg' : 'image/jpeg'
const extension = type === 'image/webp' ? '.webp' : '.jpg' const extension = type === 'image/webp' ? '.webp' : '.jpg'

View file

@ -1,3 +1,4 @@
import { mapState as mapPiniaState } from 'pinia'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
@ -8,6 +9,9 @@ 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.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'
@ -97,23 +101,23 @@ const MentionLink = {
userNameFullUi() { userNameFullUi() {
return this.user && this.user.screen_name_ui return this.user && this.user.screen_name_ui
}, },
highlight() { highlightData() {
return this.user && this.mergedConfig.highlight[this.user.screen_name] return this.highlight[this.user?.screen_name]
}, },
highlightType() { highlightType() {
return this.highlight && '-' + this.highlight.type return this.highlightData && '-' + this.highlightData.type
}, },
highlightClass() { highlightClass() {
if (this.highlight) return highlightClass(this.user) return this.highlightData && highlightClass(this.user)
}, },
style() { style() {
if (this.highlight) { if (this.highlightData) {
const { const {
backgroundColor, backgroundColor,
backgroundPosition, backgroundPosition,
backgroundImage, backgroundImage,
...rest ...rest
} = highlightStyle(this.highlight) } = highlightStyle(this.highlightData)
return rest return rest
} }
}, },
@ -121,7 +125,7 @@ const MentionLink = {
return [ return [
{ {
'-you': this.isYou && this.shouldBoldenYou, '-you': this.isYou && this.shouldBoldenYou,
'-highlighted': this.highlight, '-highlighted': !!this.highlightData,
'-has-selection': this.hasSelection, '-has-selection': this.hasSelection,
}, },
this.highlightType, this.highlightType,
@ -156,7 +160,8 @@ const MentionLink = {
shouldFadeDomain() { shouldFadeDomain() {
return this.mergedConfig.mentionLinkFadeDomain return this.mergedConfig.mentionLinkFadeDomain
}, },
...mapGetters(['mergedConfig']), ...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
...mapPiniaState(useUserHighlightStore, ['highlight']),
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),

View file

@ -1,7 +1,9 @@
import { mapGetters } from 'vuex' 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
export const MENTIONS_LIMIT = 5 export const MENTIONS_LIMIT = 5
const MentionsLine = { const MentionsLine = {
@ -26,7 +28,7 @@ const MentionsLine = {
manyMentions() { manyMentions() {
return this.extraMentions.length > 0 return this.extraMentions.length > 0
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
}, },
methods: { methods: {
toggleShowMore() { toggleShowMore() {

View file

@ -13,7 +13,7 @@ import SideDrawer from '../side_drawer/side_drawer.vue'
import { useAnnouncementsStore } from 'src/stores/announcements.js' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -52,11 +52,19 @@ const MobileNav = {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore(this.$store) return unseenNotificationsFromStore(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
useMergedConfigStore().mergedConfig.ignoreInactionableSeen,
)
}, },
unseenNotificationsCount() { unseenNotificationsCount() {
return ( return (
this.unseenNotifications.length + countExtraNotifications(this.$store) this.unseenNotifications.length +
countExtraNotifications(
this.$store,
useMergedConfigStore().mergedConfig,
)
) )
}, },
unseenCount() { unseenCount() {
@ -75,15 +83,15 @@ const MobileNav = {
return this.$route.name === 'chat' return this.$route.name === 'chat'
}, },
...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']),
...mapState(useServerSideStorageStore, { ...mapState(useMergedConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'), new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'),
}), }),
shouldConfirmLogout() { shouldConfirmLogout() {
return this.$store.getters.mergedConfig.modalOnLogout return useMergedConfigStore().mergedConfig.modalOnLogout
}, },
closingDrawerMarksAsSeen() { closingDrawerMarksAsSeen() {
return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen return useMergedConfigStore().mergedConfig.closingDrawerMarksAsSeen
}, },
...mapGetters(['unreadChatCount']), ...mapGetters(['unreadChatCount']),
}, },

View file

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

View file

@ -1,5 +1,6 @@
import { get } from 'lodash' import { get } from 'lodash'
import { mapState } from 'vuex' import { mapState } from 'pinia'
import { useInstanceStore } from 'src/stores/instance.js'
/** /**
* This is for backwards compatibility. We originally didn't recieve * This is for backwards compatibility. We originally didn't recieve
@ -18,64 +19,64 @@ const toInstanceReasonObject = (instances, info, key) => {
const MRFTransparencyPanel = { const MRFTransparencyPanel = {
computed: { computed: {
...mapState({ ...mapState(useInstanceStore, {
federationPolicy: (state) => get(state, 'instance.federationPolicy'), federationPolicy: (state) => state.federationPolicy,
mrfPolicies: (state) => mrfPolicies: (state) =>
get(state, 'instance.federationPolicy.mrf_policies', []), get(state, 'federationPolicy.mrf_policies', []),
quarantineInstances: (state) => quarantineInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get(state, 'instance.federationPolicy.quarantined_instances', []), get(state, 'federationPolicy.quarantined_instances', []),
get( get(
state, state,
'instance.federationPolicy.quarantined_instances_info', 'federationPolicy.quarantined_instances_info',
[], [],
), ),
'quarantined_instances', 'quarantined_instances',
), ),
acceptInstances: (state) => acceptInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.accept', []), get(state, 'federationPolicy.mrf_simple.accept', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []), get(state, 'federationPolicy.mrf_simple_info', []),
'accept', 'accept',
), ),
rejectInstances: (state) => rejectInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.reject', []), get(state, 'federationPolicy.mrf_simple.reject', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []), get(state, 'federationPolicy.mrf_simple_info', []),
'reject', 'reject',
), ),
ftlRemovalInstances: (state) => ftlRemovalInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get( get(
state, state,
'instance.federationPolicy.mrf_simple.federated_timeline_removal', 'federationPolicy.mrf_simple.federated_timeline_removal',
[], [],
), ),
get(state, 'instance.federationPolicy.mrf_simple_info', []), get(state, 'federationPolicy.mrf_simple_info', []),
'federated_timeline_removal', 'federated_timeline_removal',
), ),
mediaNsfwInstances: (state) => mediaNsfwInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), get(state, 'federationPolicy.mrf_simple.media_nsfw', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []), get(state, 'federationPolicy.mrf_simple_info', []),
'media_nsfw', 'media_nsfw',
), ),
mediaRemovalInstances: (state) => mediaRemovalInstances: (state) =>
toInstanceReasonObject( toInstanceReasonObject(
get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), get(state, 'federationPolicy.mrf_simple.media_removal', []),
get(state, 'instance.federationPolicy.mrf_simple_info', []), get(state, 'federationPolicy.mrf_simple_info', []),
'media_removal', 'media_removal',
), ),
keywordsFtlRemoval: (state) => keywordsFtlRemoval: (state) =>
get( get(
state, state,
'instance.federationPolicy.mrf_keyword.federated_timeline_removal', 'federationPolicy.mrf_keyword.federated_timeline_removal',
[], [],
), ),
keywordsReject: (state) => keywordsReject: (state) =>
get(state, 'instance.federationPolicy.mrf_keyword.reject', []), get(state, 'federationPolicy.mrf_keyword.reject', []),
keywordsReplace: (state) => keywordsReplace: (state) =>
get(state, 'instance.federationPolicy.mrf_keyword.replace', []), get(state, 'federationPolicy.mrf_keyword.replace', []),
}), }),
hasInstanceSpecificPolicies() { hasInstanceSpecificPolicies() {
return ( return (

View file

@ -12,7 +12,7 @@ import NavigationPins from 'src/components/navigation/navigation_pins.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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -84,28 +84,28 @@ const NavPanel = {
this.editMode = !this.editMode this.editMode = !this.editMode
}, },
toggleCollapse() { toggleCollapse() {
useServerSideStorageStore().setPreference({ useSyncConfigStore().setSimplePrefAndSave({
path: 'simple.collapseNav', path: 'collapseNav',
value: !this.collapsed, value: !this.collapsed,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
isPinned(item) { isPinned(item) {
return this.pinnedItems.has(item) return this.pinnedItems.has(item)
}, },
togglePin(item) { togglePin(item) {
if (this.isPinned(item)) { if (this.isPinned(item)) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} else { } else {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value: item, value: item,
}) })
} }
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
}, },
computed: { computed: {
@ -122,7 +122,7 @@ const NavPanel = {
...mapPiniaState(useInstanceStore, { ...mapPiniaState(useInstanceStore, {
privateMode: (store) => store.private, privateMode: (store) => store.private,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
collapsed: (store) => store.prefsStorage.simple.collapseNav, collapsed: (store) => store.prefsStorage.simple.collapseNav,
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),

View file

@ -5,7 +5,7 @@ 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.js' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { 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)) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} else { } else {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedNavItems', path: 'collections.pinnedNavItems',
value, value,
}) })
} }
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
}, },
computed: { computed: {
@ -47,7 +47,7 @@ const NavigationEntry = {
...mapState({ ...mapState({
currentUser: (state) => state.users.currentUser, currentUser: (state) => state.users.currentUser,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),

View file

@ -18,7 +18,7 @@ import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useListsStore } from 'src/stores/lists' import { useListsStore } from 'src/stores/lists'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -70,7 +70,7 @@ const NavPanel = {
...mapPiniaState(useBookmarkFoldersStore, { ...mapPiniaState(useBookmarkFoldersStore, {
bookmarks: getBookmarkFolderEntries, bookmarks: getBookmarkFolderEntries,
}), }),
...mapPiniaState(useServerSideStorageStore, { ...mapPiniaState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems), new Set(store.prefsStorage.collections.pinnedNavItems),
}), }),

View file

@ -17,6 +17,8 @@ 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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.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'
@ -181,9 +183,8 @@ const Notification = {
return highlightClass(this.notification.from_profile) return highlightClass(this.notification.from_profile)
}, },
userStyle() { userStyle() {
const highlight = this.$store.getters.mergedConfig.highlight const user = this.notification.from_profile.screen_name
const user = this.notification.from_profile return highlightStyle(useUserHighlightStore().get(user))
return highlightStyle(highlight[user.screen_name])
}, },
expandable() { expandable() {
return new Set(['like', 'pleroma:emoji_reaction', 'repeat', 'poll']).has( return new Set(['like', 'pleroma:emoji_reaction', 'repeat', 'poll']).has(
@ -209,7 +210,7 @@ const Notification = {
return isStatusNotification(this.notification.type) return isStatusNotification(this.notification.type)
}, },
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useMergedConfigStore().mergedConfig
}, },
shouldConfirmApprove() { shouldConfirmApprove() {
return this.mergedConfig.modalOnApproveFollow return this.mergedConfig.modalOnApproveFollow

View file

@ -108,6 +108,9 @@
<script> <script>
import Popover from '../popover/popover.vue' import Popover from '../popover/popover.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.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 } from '@fortawesome/free-solid-svg-icons' import { faFilter } from '@fortawesome/free-solid-svg-icons'
@ -117,13 +120,13 @@ export default {
components: { Popover }, components: { Popover },
computed: { computed: {
filters() { filters() {
return this.$store.getters.mergedConfig.notificationVisibility return useMergedConfigStore().mergedConfig.notificationVisibility
}, },
}, },
methods: { methods: {
toggleNotificationFilter(type) { toggleNotificationFilter(type) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'notificationVisibility', path: 'notificationVisibility',
value: { value: {
...this.filters, ...this.filters,
[type]: !this.filters[type], [type]: !this.filters[type],

View file

@ -17,6 +17,7 @@ import NotificationFilters from './notification_filters.vue'
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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -75,20 +76,29 @@ const Notifications = {
return this.$store.state.notifications.error return this.$store.state.notifications.error
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore(this.$store) return unseenNotificationsFromStore(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
)
}, },
filteredNotifications() { filteredNotifications() {
if (this.unseenAtTop) { if (this.unseenAtTop) {
return [ return [
...filteredNotificationsFromStore(this.$store).filter((n) => ...filteredNotificationsFromStore(
this.shouldShowUnseen(n), this.$store,
), useMergedConfigStore().mergedConfig.notificationVisibility,
...filteredNotificationsFromStore(this.$store).filter( ).filter((n) => this.shouldShowUnseen(n)),
(n) => !this.shouldShowUnseen(n), ...filteredNotificationsFromStore(
), this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
).filter((n) => !this.shouldShowUnseen(n)),
] ]
} else { } else {
return filteredNotificationsFromStore(this.$store, this.filterMode) return filteredNotificationsFromStore(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
this.filterMode,
)
} }
}, },
unseenCountBadgeText() { unseenCountBadgeText() {
@ -98,10 +108,13 @@ const Notifications = {
return this.unseenNotifications.length return this.unseenNotifications.length
}, },
ignoreInactionableSeen() { ignoreInactionableSeen() {
return this.$store.getters.mergedConfig.ignoreInactionableSeen return useMergedConfigStore().mergedConfig.ignoreInactionableSeen
}, },
extraNotificationsCount() { extraNotificationsCount() {
return countExtraNotifications(this.$store) return countExtraNotifications(
this.$store,
useMergedConfigStore().mergedConfig,
)
}, },
unseenCountTitle() { unseenCountTitle() {
return ( return (
@ -136,10 +149,10 @@ const Notifications = {
) )
}, },
noSticky() { noSticky() {
return this.$store.getters.mergedConfig.disableStickyHeaders return useMergedConfigStore().mergedConfig.disableStickyHeaders
}, },
unseenAtTop() { unseenAtTop() {
return this.$store.getters.mergedConfig.unseenAtTop return useMergedConfigStore().mergedConfig.unseenAtTop
}, },
showExtraNotifications() { showExtraNotifications() {
return !this.noExtra return !this.noExtra

View file

@ -61,15 +61,16 @@
</div> </div>
<p <p
v-if="error" v-if="error"
class="alert error notice-dismissible" class="alert error"
> >
<span>{{ error }}</span> <span>{{ error }}</span>
<a <button
class="fa-scale-110 fa-old-padding dismiss" class="fa-scale-110 fa-old-padding dismiss"
type="button"
@click.prevent="dismissError()" @click.prevent="dismissError()"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
</a> </button>
</p> </p>
</div> </div>
</form> </form>
@ -117,10 +118,6 @@
margin: 0.3em 0 1em; margin: 0.3em 0 1em;
} }
.notice-dismissible {
padding-right: 2rem;
}
.dismiss { .dismiss {
cursor: pointer; cursor: pointer;
} }

View file

@ -4,6 +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 { useMergedConfigStore } from 'src/stores/merged_config.js'
import { usePollsStore } from 'src/stores/polls.js' import { usePollsStore } from 'src/stores/polls.js'
export default { export default {
@ -48,7 +49,7 @@ export default {
return (this.poll && this.poll.expired) || false return (this.poll && this.poll.expired) || false
}, },
expirationLabel() { expirationLabel() {
if (this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { if (useMergedConfigStore().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

@ -25,6 +25,8 @@ import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.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 { useMergedConfigStore } from 'src/stores/merged_config.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'
@ -170,7 +172,7 @@ 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 { scopeCopy } = useMergedConfigStore().mergedConfig
const [statusType, refId] = typeAndRefId({ const [statusType, refId] = typeAndRefId({
replyTo: this.replyTo, replyTo: this.replyTo,
@ -200,7 +202,7 @@ const PostStatusForm = {
: this.$store.state.users.currentUser.default_scope : this.$store.state.users.currentUser.default_scope
const { postContentType: contentType, sensitiveByDefault } = const { postContentType: contentType, sensitiveByDefault } =
this.$store.getters.mergedConfig useMergedConfigStore().mergedConfig
statusParams = { statusParams = {
type: statusType, type: statusType,
@ -301,7 +303,7 @@ const PostStatusForm = {
return this.newStatus.spoilerText.length return this.newStatus.spoilerText.length
}, },
statusLengthLimit() { statusLengthLimit() {
return useInstanceStore().textlimit return useInstanceStore().limits.textLimit
}, },
hasStatusLengthLimit() { hasStatusLengthLimit() {
return this.statusLengthLimit > 0 return this.statusLengthLimit > 0
@ -335,7 +337,8 @@ const PostStatusForm = {
}, },
hideScopeNotice() { hideScopeNotice() {
return ( return (
this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice this.disableNotice ||
useMergedConfigStore().mergedConfig.hideScopeNotice
) )
}, },
pollContentError() { pollContentError() {
@ -420,7 +423,7 @@ const PostStatusForm = {
return this.newStatus.hasQuote && !this.newStatus.quote.thread return this.newStatus.hasQuote && !this.newStatus.quote.thread
}, },
shouldAutoSaveDraft() { shouldAutoSaveDraft() {
return this.$store.getters.mergedConfig.autoSaveDraft return useMergedConfigStore().mergedConfig.autoSaveDraft
}, },
autoSaveState() { autoSaveState() {
if (this.saveable) { if (this.saveable) {
@ -453,7 +456,7 @@ const PostStatusForm = {
) )
) )
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (store) => store.mobileLayout, mobileLayout: (store) => store.mobileLayout,
}), }),
@ -879,8 +882,8 @@ const PostStatusForm = {
this.newStatus.hasQuote = !this.newStatus.hasQuote this.newStatus.hasQuote = !this.newStatus.hasQuote
}, },
dismissScopeNotice() { dismissScopeNotice() {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'hideScopeNotice', path: 'hideScopeNotice',
value: true, value: true,
}) })
}, },

View file

@ -111,7 +111,6 @@
.visibility-notice { .visibility-notice {
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--roundness); border-radius: var(--roundness);
padding: 0.5em 1em
} }
.visibility-notice.edit-warning { .visibility-notice.edit-warning {

View file

@ -9,20 +9,24 @@
@dragover.prevent="fileDrag" @dragover.prevent="fileDrag"
> >
<div class="form-group"> <div class="form-group">
<i18n-t <div
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning" v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning"
keypath="post_status.account_not_locked_warning" class="visibility-notice notice-dismissible"
tag="p"
class="visibility-notice"
scope="global"
> >
<button <i18n-t
class="button-unstyled -link" keypath="post_status.account_not_locked_warning"
@click="openProfileTab" tag="p"
class=""
scope="global"
> >
{{ $t('post_status.account_not_locked_warning_link') }} <button
</button> class="button-unstyled -link"
</i18n-t> @click="openProfileTab"
>
{{ $t('post_status.account_not_locked_warning_link') }}
</button>
</i18n-t>
</div>
<p <p
v-if="!hideScopeNotice && newStatus.visibility === 'public'" v-if="!hideScopeNotice && newStatus.visibility === 'public'"
class="visibility-notice notice-dismissible" class="visibility-notice notice-dismissible"
@ -70,7 +74,7 @@
</p> </p>
<p <p
v-else-if="newStatus.visibility === 'direct'" v-else-if="newStatus.visibility === 'direct'"
class="visibility-notice" class="visibility-notice notice-dismissible"
> >
<span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span> <span v-if="safeDMEnabled">{{ $t('post_status.direct_warning_to_first_only') }}</span>
<span v-else>{{ $t('post_status.direct_warning_to_all') }}</span> <span v-else>{{ $t('post_status.direct_warning_to_all') }}</span>

View file

@ -1,9 +1,11 @@
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.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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'
@ -20,8 +22,8 @@ const QuickFilterSettings = {
}, },
methods: { methods: {
setReplyVisibility(visibility) { setReplyVisibility(visibility) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'replyVisibility', path: 'replyVisibility',
value: visibility, value: visibility,
}) })
this.$store.dispatch('queueFlushAll') this.$store.dispatch('queueFlushAll')
@ -31,7 +33,7 @@ const QuickFilterSettings = {
}, },
}, },
computed: { computed: {
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (state) => state.layoutType === 'mobile', mobileLayout: (state) => state.layoutType === 'mobile',
}), }),
@ -85,11 +87,13 @@ const QuickFilterSettings = {
this.mergedConfig.hideAttachmentsInConv this.mergedConfig.hideAttachmentsInConv
) )
}, },
set() { set(value) {
const value = !this.hideMedia useLocalConfigStore().set({
this.$store.dispatch('setOption', { name: 'hideAttachments', value }) path: 'hideAttachments',
this.$store.dispatch('setOption', { value,
name: 'hideAttachmentsInConv', })
useLocalConfigStore().set({
path: 'hideAttachmentsInConv',
value, value,
}) })
}, },
@ -98,10 +102,9 @@ const QuickFilterSettings = {
get() { get() {
return this.mergedConfig.hideFilteredStatuses return this.mergedConfig.hideFilteredStatuses
}, },
set() { set(value) {
const value = !this.hideMutedPosts useSyncConfigStore().setSimplePrefAndSave({
this.$store.dispatch('setOption', { path: 'hideFilteredStatuses',
name: 'hideFilteredStatuses',
value, value,
}) })
}, },
@ -110,19 +113,20 @@ const QuickFilterSettings = {
get() { get() {
return this.mergedConfig.muteBotStatuses return this.mergedConfig.muteBotStatuses
}, },
set() { set(value) {
const value = !this.muteBotStatuses useSyncConfigStore().setSimplePrefAndSave({
this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) path: 'muteBotStatuses',
value,
})
}, },
}, },
muteSensitiveStatuses: { muteSensitiveStatuses: {
get() { get() {
return this.mergedConfig.muteSensitiveStatuses return this.mergedConfig.muteSensitiveStatuses
}, },
set() { set(value) {
const value = !this.muteSensitiveStatuses useSyncConfigStore().setSimplePrefAndSave({
this.$store.dispatch('setOption', { path: 'muteSensitiveStatuses',
name: 'muteSensitiveStatuses',
value, value,
}) })
}, },

View file

@ -1,10 +1,11 @@
import { mapState } from 'pinia' import { mapState } from 'pinia'
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.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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 {
@ -25,18 +26,12 @@ const QuickViewSettings = {
QuickFilterSettings, QuickFilterSettings,
}, },
methods: { methods: {
setConversationDisplay(visibility) {
this.$store.dispatch('setOption', {
name: 'conversationDisplay',
value: visibility,
})
},
openTab(tab) { openTab(tab) {
useInterfaceStore().openSettingsModalTab(tab) useInterfaceStore().openSettingsModalTab(tab)
}, },
}, },
computed: { computed: {
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
...mapState(useInterfaceStore, { ...mapState(useInterfaceStore, {
mobileLayout: (state) => state.layoutType === 'mobile', mobileLayout: (state) => state.layoutType === 'mobile',
}), }),
@ -47,8 +42,11 @@ const QuickViewSettings = {
get() { get() {
return this.mergedConfig.conversationDisplay return this.mergedConfig.conversationDisplay
}, },
set(newVal) { set(value) {
this.setConversationDisplay(newVal) useSyncConfigStore().setSimplePrefAndSave({
path: 'conversationDisplay',
value,
})
}, },
}, },
autoUpdate: { autoUpdate: {
@ -57,7 +55,7 @@ const QuickViewSettings = {
}, },
set() { set() {
const value = !this.autoUpdate const value = !this.autoUpdate
this.$store.dispatch('setOption', { name: 'streaming', value }) useSyncConfigStore().setSimplePrefAndSave({ path: 'streaming', value })
}, },
}, },
collapseWithSubjects: { collapseWithSubjects: {
@ -66,8 +64,8 @@ const QuickViewSettings = {
}, },
set() { set() {
const value = !this.collapseWithSubjects const value = !this.collapseWithSubjects
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'collapseMessageWithSubject', path: 'collapseMessageWithSubject',
value, value,
}) })
}, },
@ -78,8 +76,8 @@ const QuickViewSettings = {
}, },
set() { set() {
const value = !this.showUserAvatars const value = !this.showUserAvatars
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'mentionLinkShowAvatar', path: 'mentionLinkShowAvatar',
value, value,
}) })
}, },
@ -90,7 +88,10 @@ const QuickViewSettings = {
}, },
set() { set() {
const value = !this.muteBotStatuses const value = !this.muteBotStatuses
this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) useSyncConfigStore().setSimplePrefAndSave({
path: 'muteBotStatuses',
value,
})
}, },
}, },
muteSensitiveStatuses: { muteSensitiveStatuses: {
@ -99,8 +100,8 @@ const QuickViewSettings = {
}, },
set() { set() {
const value = !this.muteSensitiveStatuses const value = !this.muteSensitiveStatuses
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'muteSensitiveStatuses', path: 'muteSensitiveStatuses',
value, value,
}) })
}, },

View file

@ -1,5 +1,7 @@
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
export default { export default {
props: ['user', 'relationship'], props: ['user', 'relationship'],
data() { data() {
@ -20,7 +22,7 @@ export default {
} }
}, },
shouldConfirmRemoveUserFromFollowers() { shouldConfirmRemoveUserFromFollowers() {
return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers return useMergedConfigStore().mergedConfig.modalOnRemoveUserFromFollowers
}, },
}, },
methods: { methods: {

View file

@ -40,7 +40,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
</div> </div>
<div v-if="!compact">{{ $t('settings.preview') }}</div> <div v-if="!compact">{{ $t('settings.preview') }}</div>
<Attachment <Attachment

View file

@ -18,7 +18,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel }} {{ backendDescriptionLabel }}

View file

@ -9,7 +9,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel }} {{ backendDescriptionLabel }}

View file

@ -33,7 +33,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
<DraftButtons v-if="!hideDraftButtons" /> <DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"

View file

@ -7,7 +7,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
<DraftButtons /> <DraftButtons />
</span> </span>
</template> </template>

View file

@ -1,6 +1,8 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Setting from './setting.js' import Setting from './setting.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
export default { export default {
...Setting, ...Setting,
data() { data() {
@ -43,7 +45,7 @@ export default {
if (this.forceNew) return true if (this.forceNew) return true
if (!this.allowNew) return false if (!this.allowNew) return false
const isExpert = this.$store.state.config.expertLevel > 0 const isExpert = useMergedConfigStore().mergedConfig.expertLevel > 0
const hasBuiltins = this.builtinEntries.length > 0 const hasBuiltins = this.builtinEntries.length > 0
if (hasBuiltins) { if (hasBuiltins) {

View file

@ -75,7 +75,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
<DraftButtons /> <DraftButtons />
</div> </div>
</template> </template>

View file

@ -77,7 +77,6 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons /> <DraftButtons />
</div> </div>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<span <span
v-if="isProfile" v-if="isLocal"
class="ProfileSettingIndicator" class="LocalSettingIndicator"
> >
<Popover <Popover
trigger="hover" trigger="hover"
@ -9,13 +9,13 @@
<template #trigger> <template #trigger>
&nbsp; &nbsp;
<FAIcon <FAIcon
icon="server" icon="desktop"
:aria-label="$t('settings.setting_server_side')" :aria-label="$t('settings.setting_local_side')"
/> />
</template> </template>
<template #content> <template #content>
<div class="profilesetting-tooltip"> <div class="profilesetting-tooltip">
{{ $t('settings.setting_server_side') }} {{ $t('settings.setting_local_side') }}
</div> </div>
</template> </template>
</Popover> </Popover>
@ -26,18 +26,18 @@
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faServer } from '@fortawesome/free-solid-svg-icons' import { faDesktop } from '@fortawesome/free-solid-svg-icons'
library.add(faServer) library.add(faDesktop)
export default { export default {
components: { Popover }, components: { Popover },
props: ['isProfile'], props: ['isLocal'],
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.ProfileSettingIndicator { .LocalSettingIndicator {
display: inline-block; display: inline-block;
position: relative; position: relative;
} }

View file

@ -77,7 +77,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
<DraftButtons /> <DraftButtons />
</div> </div>
</template> </template>

View file

@ -9,6 +9,13 @@
class="setting-label" class="setting-label"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }}
<DraftButtons v-if="!hideDraftButtons" />
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}
</template> </template>
@ -29,13 +36,6 @@
:value="realDraftMode ? draft :state" :value="realDraftMode ? draft :state"
@change="update" @change="update"
> >
{{ ' ' }}
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
class="setting-description" class="setting-description"

View file

@ -44,7 +44,6 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons v-if="!hideDraftButtons" /> <DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"

View file

@ -11,7 +11,6 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}

View file

@ -11,7 +11,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}

View file

@ -1,14 +1,20 @@
import { cloneDeep, get, isEqual, set } from 'lodash' import { cloneDeep, get, isEqual, set } from 'lodash'
import DraftButtons from './draft_buttons.vue' import DraftButtons from './draft_buttons.vue'
import LocalSettingIndicator from './local_setting_indicator.vue'
import ModifiedIndicator from './modified_indicator.vue' import ModifiedIndicator from './modified_indicator.vue'
import ProfileSettingIndicator from './profile_setting_indicator.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
export default { export default {
components: { components: {
ModifiedIndicator, ModifiedIndicator,
DraftButtons, DraftButtons,
ProfileSettingIndicator, LocalSettingIndicator,
}, },
props: { props: {
modelValue: { modelValue: {
@ -43,6 +49,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
local: {
type: Boolean,
default: false,
},
parentPath: { parentPath: {
type: [String, Array], type: [String, Array],
}, },
@ -235,13 +245,14 @@ export default {
case 'admin': case 'admin':
return this.$store.state.adminSettings.config return this.$store.state.adminSettings.config
default: default:
return this.$store.getters.mergedConfig return useMergedConfigStore().mergedConfig
} }
}, },
configSink() { configSink() {
if (this.path == null) { if (this.path == null) {
return (k, v) => this.$emit('update:modelValue', v) return (k, v) => this.$emit('update:modelValue', v)
} }
switch (this.realSource) { switch (this.realSource) {
case 'profile': case 'profile':
return (k, v) => return (k, v) =>
@ -250,15 +261,61 @@ export default {
return (k, v) => return (k, v) =>
this.$store.dispatch('pushAdminSetting', { path: k, value: v }) this.$store.dispatch('pushAdminSetting', { path: k, value: v })
default: default:
if (this.timedApplyMode) { return (readPath, value) => {
return (k, v) => const writePath = `${readPath}`
this.$store.dispatch('setOptionTemporarily', {
name: k, if (!this.timedApplyMode) {
value: v, if (this.local) {
}) useLocalConfigStore().set({
} else { path: writePath,
return (k, v) => value,
this.$store.dispatch('setOption', { name: k, value: v }) })
} else {
useSyncConfigStore().setSimplePrefAndSave({
path: writePath,
value,
})
}
} else {
if (useInterfaceStore().temporaryChangesTimeoutId !== null) {
console.error("Can't track more than one temporary change")
return
}
const oldValue = get(this.configSource, readPath)
if (this.local) {
useLocalConfigStore().setTemporarily({ path: writePath, value })
} else {
useSyncConfigStore().setPreference({ path: writePath, value })
}
const confirm = () => {
if (this.local) {
useLocalConfigStore().set({ path: writePath, value })
} else {
useSyncConfigStore().pushSyncConfig()
}
useInterfaceStore().clearTemporaryChanges()
}
const revert = () => {
if (this.local) {
useLocalConfigStore().unsetTemporarily({
path: writePath,
value,
})
} else {
useSyncConfigStore().setPreference({
path: writePath,
value: oldValue,
})
}
useInterfaceStore().clearTemporaryChanges()
}
useInterfaceStore().setTemporaryChanges({ confirm, revert })
}
} }
} }
}, },
@ -266,13 +323,17 @@ export default {
switch (this.realSource) { switch (this.realSource) {
case 'profile': case 'profile':
return {} return {}
default: default: {
return get(this.$store.getters.defaultConfig, this.path) return get(useMergedConfigStore().mergedConfigDefault, this.path)
}
} }
}, },
isProfileSetting() { isProfileSetting() {
return this.realSource === 'profile' return this.realSource === 'profile'
}, },
isLocalSetting() {
return this.local
},
isChanged() { isChanged() {
if (this.path == null) return false if (this.path == null) return false
switch (this.realSource) { switch (this.realSource) {
@ -318,7 +379,8 @@ export default {
}, },
matchesExpertLevel() { matchesExpertLevel() {
const settingExpertLevel = this.expert || 0 const settingExpertLevel = this.expert || 0
const userToggleExpert = this.$store.state.config.expertLevel || 0 const userToggleExpert =
useMergedConfigStore().mergedConfig.expertLevel || 0
return settingExpertLevel <= userToggleExpert return settingExpertLevel <= userToggleExpert
}, },
@ -344,7 +406,7 @@ export default {
this.draft = cloneDeep(this.state) this.draft = cloneDeep(this.state)
} else { } else {
set( set(
this.$store.getters.mergedConfig, useMergedConfigStore().mergedConfig,
this.path, this.path,
cloneDeep(this.defaultState), cloneDeep(this.defaultState),
) )

View file

@ -1,19 +1,18 @@
import { mapState as mapPiniaState } from 'pinia'
import { mapState } from 'vuex'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const SharedComputedObject = () => ({ const SharedComputedObject = () => ({
user() { ...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
return this.$store.state.users.currentUser ...mapPiniaState(useMergedConfigStore, {
}, expertLevel: (store) => store.mergedConfig.expertLevel,
expertLevel() { }),
return this.$store.getters.mergedConfig.expertLevel > 0 ...mapState({
}, adminConfig: (state) => state.adminSettings.config,
mergedConfig() { adminDraft: (state) => state.adminSettings.draft,
return this.$store.getters.mergedConfig user: (state) => state.users.currentUser,
}, }),
adminConfig() {
return this.$store.state.adminSettings.config
},
adminDraft() {
return this.$store.state.adminSettings.draft
},
}) })
export default SharedComputedObject export default SharedComputedObject

View file

@ -13,7 +13,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}

View file

@ -13,7 +13,7 @@
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"
/> />
<ProfileSettingIndicator :is-profile="isProfileSetting" /> <LocalSettingIndicator :is-local="isLocalSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}

View file

@ -7,6 +7,7 @@
:for="path" :for="path"
class="setting-label size-label" class="setting-label size-label"
> >
<LocalSettingIndicator :is-local="isLocalSetting" />
<ModifiedIndicator <ModifiedIndicator
:changed="isChanged" :changed="isChanged"
:onclick="reset" :onclick="reset"

View file

@ -9,7 +9,16 @@ 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.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import {
LOCAL_ONLY_KEYS,
ROOT_CONFIG,
ROOT_CONFIG_DEFINITIONS,
validateSetting,
} from 'src/modules/default_config_state.js'
import { import {
newExporter, newExporter,
newImporter, newImporter,
@ -134,10 +143,52 @@ const SettingsModal = {
}) })
} }
}, },
onImport(data) { onImport(input) {
if (data) { if (!input) return
this.$store.dispatch('loadSettings', data) const { _pleroma_settings_version, ...data } = input
}
Object.entries(data).forEach(([path, value]) => {
const definition = ROOT_CONFIG_DEFINITIONS[path]
const finalValue = validateSetting({
path,
value,
definition,
throwError: false,
defaultState: ROOT_CONFIG,
})
if (finalValue === undefined) return
if (LOCAL_ONLY_KEYS.has(path)) {
useLocalConfigStore().set({ path, value: finalValue })
} else {
if (path.startsWith('muteFilters')) {
Object.keys(
useMergedConfigStore().mergedConfig.muteFilters,
).forEach((key) => {
useSyncConfigStore().unsetPreference({
path: `simple.${path}.${key}`,
})
})
Object.entries(value).forEach(([key, filter]) => {
useSyncConfigStore().setPreference({
path: `simple.${path}.${key}`,
value: filter,
})
})
} else {
if (finalValue !== undefined) {
useSyncConfigStore().setPreference({
path: `simple.${path}`,
value: finalValue,
})
}
}
}
})
useSyncConfigStore().pushSyncConfig()
}, },
restore() { restore() {
this.dataImporter.importData() this.dataImporter.importData()
@ -149,16 +200,25 @@ const SettingsModal = {
this.dataThemeExporter.exportData() this.dataThemeExporter.exportData()
}, },
generateExport(theme = false) { generateExport(theme = false) {
const { config } = this.$store.state const config = useMergedConfigStore().mergedConfigWithoutDefaults
let sample = config let sample = config
if (!theme) { if (!theme) {
const ignoreList = new Set([ const ignoreList = new Set([
'theme',
'customTheme', 'customTheme',
'customThemeSource', 'customThemeSource',
'colors', 'colors',
'style',
'styleCustomData',
'palette',
'paletteCustomData',
'themeChecksum',
]) ])
sample = Object.fromEntries( sample = Object.fromEntries(
Object.entries(sample).filter(([key]) => !ignoreList.has(key)), Object.entries(sample).filter(
([key, value]) => !ignoreList.has(key) && value !== undefined,
),
) )
} }
const clone = cloneDeep(sample) const clone = cloneDeep(sample)
@ -191,11 +251,11 @@ const SettingsModal = {
}), }),
expertLevel: { expertLevel: {
get() { get() {
return this.$store.state.config.expertLevel > 0 return useMergedConfigStore().mergedConfig.expertLevel > 0
}, },
set(value) { set(value) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'expertLevel', path: 'expertLevel',
value: value ? 1 : 0, value: value ? 1 : 0,
}) })
}, },

View file

@ -73,7 +73,7 @@
} }
.ModifiedIndicator, .ModifiedIndicator,
.ProfileSettingIndicator { .LocalSettingIndicator {
grid-area: indicator; grid-area: indicator;
} }

View file

@ -16,6 +16,7 @@ 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.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -83,7 +84,7 @@ const SettingsModalContent = {
return useInterfaceStore().settingsModalState === 'visible' return useInterfaceStore().settingsModalState === 'visible'
}, },
expertLevel() { expertLevel() {
return this.$store.state.config.expertLevel return useMergedConfigStore().mergedConfig.expertLevel
}, },
}, },
data() { data() {

View file

@ -6,7 +6,6 @@ import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
import IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.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 Preview from './old_theme_tab/theme_preview.vue' import Preview from './old_theme_tab/theme_preview.vue'
@ -77,7 +76,6 @@ const AppearanceTab = {
IntegerSetting, IntegerSetting,
FloatSetting, FloatSetting,
UnitSetting, UnitSetting,
ProfileSettingIndicator,
Preview, Preview,
PaletteEditor, PaletteEditor,
}, },

View file

@ -54,7 +54,7 @@
:key="style.key" :key="style.key"
:data-theme-key="style.key" :data-theme-key="style.key"
class="button-default theme-preview" class="button-default theme-preview"
:class="{ toggled: isThemeActive(style.key), disabled: switchInProgress }" :class="{ toggled: isStyleActive(style.key), disabled: switchInProgress }"
:disabled="switchInProgress" :disabled="switchInProgress"
@click="style.version === 'v2' ? setTheme(style.key) : setStyle(style.key)" @click="style.version === 'v2' ? setTheme(style.key) : setStyle(style.key)"
> >
@ -235,7 +235,7 @@
<li> <li>
<ChoiceSetting <ChoiceSetting
id="underlayOverride" id="underlayOverride"
path="theme3hacks.underlay" path="underlay"
:options="underlayOverrideModes" :options="underlayOverrideModes"
> >
{{ $t('settings.style.themes3.hacks.underlay_overrides') }} {{ $t('settings.style.themes3.hacks.underlay_overrides') }}

View file

@ -12,7 +12,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useSyncConfigStore } from 'src/stores/sync_config.js'
const ClutterTab = { const ClutterTab = {
components: { components: {
@ -33,66 +33,17 @@ const ClutterTab = {
store.instanceIdentity.showInstanceSpecificPanel && store.instanceIdentity.showInstanceSpecificPanel &&
store.instanceIdentity.instanceSpecificPanelContent, store.instanceIdentity.instanceSpecificPanelContent,
}), }),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
muteFilters: (store) => muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters), Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}), }),
onMuteDefaultActionLv1: {
get() {
const value = this.$store.state.config.onMuteDefaultAction
if (value === 'ask' || value === 'forever') {
return value
} else {
return 'temporarily'
}
},
set(value) {
let realValue = value
if (value !== 'ask' && value !== 'forever') {
realValue = '14d'
}
this.$store.dispatch('setOption', {
name: 'onMuteDefaultAction',
value: realValue,
})
},
},
onBlockDefaultActionLv1: {
get() {
const value = this.$store.state.config.onBlockDefaultAction
if (value === 'ask' || value === 'forever') {
return value
} else {
return 'temporarily'
}
},
set(value) {
let realValue = value
if (value !== 'ask' && value !== 'forever') {
realValue = '14d'
}
this.$store.dispatch('setOption', {
name: 'onBlockDefaultAction',
value: realValue,
})
},
},
muteFiltersDraft() {
return Object.entries(this.muteFiltersDraftObject)
},
muteFiltersExpired() {
const now = Date.now()
return Object.entries(this.muteFiltersDraftObject).filter(
([, { expires }]) => expires != null && expires <= now,
)
},
}, },
methods: { methods: {
...mapActions(useServerSideStorageStore, [ ...mapActions(useSyncConfigStore, [
'setPreference', 'setSimplePrefAndSave',
'unsetPreference', 'unsetSimplePrefAndSave',
'pushServerSideStorage', 'pushSyncConfig',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -138,8 +89,8 @@ 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.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -154,20 +105,20 @@ const ClutterTab = {
const newId = uuidv4() const newId = uuidv4()
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
deleteFilter(id) { deleteFilter(id) {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetSimplePrefAndSave({ path: 'muteFilters.' + id, value: null })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
purgeExpiredFilters() { purgeExpiredFilters() {
this.muteFiltersExpired.forEach(([id]) => { this.muteFiltersExpired.forEach(([id]) => {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetSimplePrefAndSave({ path: 'muteFilters.' + id, value: null })
}) })
this.pushServerSideStorage() this.pushSyncConfig()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -189,11 +140,11 @@ const ClutterTab = {
this.muteFiltersDraftDirty[id] = true this.muteFiltersDraftDirty[id] = true
}, },
saveFilter(id) { saveFilter(id) {
this.setPreference({ this.setSimplePrefAndSave({
path: 'simple.muteFilters.' + id, path: 'muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushServerSideStorage() this.pushSyncConfig()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },

View file

@ -19,9 +19,7 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting <BooleanSetting path="hideUserStats">
path="hideUserStats"
>
{{ $t('settings.hide_user_stats') }} {{ $t('settings.hide_user_stats') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
@ -64,12 +62,18 @@
</IntegerSetting> </IntegerSetting>
</li> </li>
<li> <li>
<BooleanSetting path="hideAttachments"> <BooleanSetting
:local="true"
path="hideAttachments"
>
{{ $t('settings.hide_attachments_in_tl') }} {{ $t('settings.hide_attachments_in_tl') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting path="hideAttachmentsInConv"> <BooleanSetting
:local="true"
path="hideAttachmentsInConv"
>
{{ $t('settings.hide_attachments_in_convo') }} {{ $t('settings.hide_attachments_in_convo') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
@ -79,9 +83,7 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
<li v-if="shoutAvailable"> <li v-if="shoutAvailable">
<BooleanSetting <BooleanSetting path="hideShoutbox">
path="hideShoutbox"
>
{{ $t('settings.hide_shoutbox') }} {{ $t('settings.hide_shoutbox') }}
</BooleanSetting> </BooleanSetting>
</li> </li>

View file

@ -8,11 +8,13 @@ import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
import IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.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 { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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'
@ -98,14 +100,13 @@ const ComposingTab = {
FloatSetting, FloatSetting,
UnitSetting, UnitSetting,
InterfaceLanguageSwitcher, InterfaceLanguageSwitcher,
ProfileSettingIndicator,
ScopeSelector, ScopeSelector,
Select, Select,
FontControl, FontControl,
}, },
computed: { computed: {
postFormats() { postFormats() {
return useInstanceStore().postFormats || [] return useInstanceCapabilitiesStore().postFormats
}, },
postContentOptions() { postContentOptions() {
return this.postFormats.map((format) => ({ return this.postFormats.map((format) => ({
@ -116,11 +117,11 @@ const ComposingTab = {
}, },
language: { language: {
get: function () { get: function () {
return this.$store.getters.mergedConfig.interfaceLanguage return useMergedConfigStore().mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'interfaceLanguage', path: 'interfaceLanguage',
value: val, value: val,
}) })
}, },
@ -171,8 +172,8 @@ const ComposingTab = {
}) })
}, },
updateFont(key, value) { updateFont(key, value) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'theme3hacks', path: 'theme3hacks',
value: { value: {
...this.mergedConfig.theme3hacks, ...this.mergedConfig.theme3hacks,
fonts: { fonts: {

View file

@ -8,10 +8,6 @@
class="setting-item " class="setting-item "
for="default-vis" for="default-vis"
> >
<span class="setting-label">
<ProfileSettingIndicator :is-profile="true" />
{{ $t('settings.default_vis') }}
</span>
<ScopeSelector <ScopeSelector
class="scope-selector setting-control" class="scope-selector setting-control"
:show-all="true" :show-all="true"
@ -19,7 +15,6 @@
:initial-scope="$store.state.profileConfig.defaultScope" :initial-scope="$store.state.profileConfig.defaultScope"
:on-scope-change="changeDefaultScope" :on-scope-change="changeDefaultScope"
:unstyled="false" :unstyled="false"
uns
/> />
</label> </label>
</li> </li>
@ -34,6 +29,7 @@
id="postContentType" id="postContentType"
path="postContentType" path="postContentType"
:options="postContentOptions" :options="postContentOptions"
:local="true"
> >
{{ $t('settings.default_post_status_content_type') }} {{ $t('settings.default_post_status_content_type') }}
</ChoiceSetting> </ChoiceSetting>
@ -95,6 +91,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="imageCompression" path="imageCompression"
:local="true"
expert="1" expert="1"
> >
{{ $t('settings.image_compression') }} {{ $t('settings.image_compression') }}
@ -103,6 +100,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="alwaysUseJpeg" path="alwaysUseJpeg"
:local="true"
expert="1" expert="1"
parent-path="imageCompression" parent-path="imageCompression"
> >

View file

@ -28,13 +28,17 @@
<h3>{{ $t('settings.debug') }}</h3> <h3>{{ $t('settings.debug') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<BooleanSetting path="virtualScrolling"> <BooleanSetting
:local="true"
path="virtualScrolling"
>
{{ $t('settings.virtual_scrolling') }} {{ $t('settings.virtual_scrolling') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting <BooleanSetting
path="themeDebug" path="themeDebug"
:local="true"
:expert="1" :expert="1"
> >
{{ $t('settings.theme_debug') }} {{ $t('settings.theme_debug') }}
@ -43,6 +47,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="forceThemeRecompilation" path="forceThemeRecompilation"
:local="true"
:expert="1" :expert="1"
> >
{{ $t('settings.force_theme_recompilation_debug') }} {{ $t('settings.force_theme_recompilation_debug') }}

View file

@ -13,7 +13,8 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { import {
newExporter, newExporter,
@ -36,11 +37,11 @@ const FilteringTab = {
label: this.$t(`user_card.mute_block_${mode}`), label: this.$t(`user_card.mute_block_${mode}`),
})), })),
muteFiltersDraftObject: cloneDeep( muteFiltersDraftObject: cloneDeep(
useServerSideStorageStore().prefsStorage.simple.muteFilters, useSyncConfigStore().prefsStorage.simple.muteFilters,
), ),
muteFiltersDraftDirty: Object.fromEntries( muteFiltersDraftDirty: Object.fromEntries(
Object.entries( Object.entries(
useServerSideStorageStore().prefsStorage.simple.muteFilters, useSyncConfigStore().prefsStorage.simple.muteFilters,
).map(([k]) => [k, false]), ).map(([k]) => [k, false]),
), ),
exportedFilter: null, exportedFilter: null,
@ -92,7 +93,7 @@ const FilteringTab = {
}, },
computed: { computed: {
...SharedComputedObject(), ...SharedComputedObject(),
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
muteFilters: (store) => muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters), Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
@ -100,7 +101,7 @@ const FilteringTab = {
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']), ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
onMuteDefaultActionLv1: { onMuteDefaultActionLv1: {
get() { get() {
const value = this.$store.state.config.onMuteDefaultAction const value = useMergedConfigStore().mergedConfig.onMuteDefaultAction
if (value === 'ask' || value === 'forever') { if (value === 'ask' || value === 'forever') {
return value return value
} else { } else {
@ -112,15 +113,15 @@ const FilteringTab = {
if (value !== 'ask' && value !== 'forever') { if (value !== 'ask' && value !== 'forever') {
realValue = '14d' realValue = '14d'
} }
this.$store.dispatch('setOption', { this.setPreference({
name: 'onMuteDefaultAction', path: 'simple.onMuteDefaultAction',
value: realValue, value: realValue,
}) })
}, },
}, },
onBlockDefaultActionLv1: { onBlockDefaultActionLv1: {
get() { get() {
const value = this.$store.state.config.onBlockDefaultAction const value = useMergedConfigStore().mergedConfig.onBlockDefaultAction
if (value === 'ask' || value === 'forever') { if (value === 'ask' || value === 'forever') {
return value return value
} else { } else {
@ -132,8 +133,8 @@ const FilteringTab = {
if (value !== 'ask' && value !== 'forever') { if (value !== 'ask' && value !== 'forever') {
realValue = '14d' realValue = '14d'
} }
this.$store.dispatch('setOption', { this.setPreference({
name: 'onBlockDefaultAction', path: 'simple.onBlockDefaultAction',
value: realValue, value: realValue,
}) })
}, },
@ -149,10 +150,13 @@ const FilteringTab = {
}, },
}, },
methods: { methods: {
...mapActions(useServerSideStorageStore, [ ...mapActions(useSyncConfigStore, [
'setPreference', 'setPreference',
'setSimplePrefAndSave',
'unsetSimplePrefAndSave',
'unsetPreference', 'unsetPreference',
'pushServerSideStorage', 'unsetPrefAndSave',
'pushSyncConfig',
]), ]),
getDatetimeLocal(timestamp) { getDatetimeLocal(timestamp) {
const date = new Date(timestamp) const date = new Date(timestamp)
@ -198,8 +202,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.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushServerSideStorage()
}, },
exportFilter(id) { exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] } this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
@ -214,20 +217,18 @@ const FilteringTab = {
const newId = uuidv4() const newId = uuidv4()
this.muteFiltersDraftObject[newId] = filter this.muteFiltersDraftObject[newId] = filter
this.setPreference({ path: 'simple.muteFilters.' + newId, value: filter }) this.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushServerSideStorage()
}, },
deleteFilter(id) { deleteFilter(id) {
delete this.muteFiltersDraftObject[id] delete this.muteFiltersDraftObject[id]
this.unsetPreference({ path: 'simple.muteFilters.' + id, value: null }) this.unsetSimplePrefAndSave({ path: 'muteFilters.' + id, value: null })
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.pushServerSideStorage() this.pushSyncConfig()
}, },
updateFilter(id, field, value) { updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] } const filter = { ...this.muteFiltersDraftObject[id] }
@ -249,11 +250,10 @@ const FilteringTab = {
this.muteFiltersDraftDirty[id] = true this.muteFiltersDraftDirty[id] = true
}, },
saveFilter(id) { saveFilter(id) {
this.setPreference({ this.setSimplePrefAndSave({
path: 'simple.muteFilters.' + id, path: 'muteFilters.' + id,
value: this.muteFiltersDraftObject[id], value: this.muteFiltersDraftObject[id],
}) })
this.pushServerSideStorage()
this.muteFiltersDraftDirty[id] = false this.muteFiltersDraftDirty[id] = false
}, },
}, },
@ -262,6 +262,11 @@ const FilteringTab = {
replyVisibility() { replyVisibility() {
this.$store.dispatch('queueFlushAll') this.$store.dispatch('queueFlushAll')
}, },
muteFiltersObject() {
this.muteFiltersDraftObject = cloneDeep(
useMergedConfigStore().mergedConfig.muteFilters,
)
},
}, },
} }

View file

@ -5,12 +5,14 @@ import InterfaceLanguageSwitcher from 'src/components/interface_language_switche
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
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 { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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'
@ -32,16 +34,15 @@ const GeneralTab = {
FloatSetting, FloatSetting,
FontControl, FontControl,
InterfaceLanguageSwitcher, InterfaceLanguageSwitcher,
ProfileSettingIndicator,
}, },
computed: { computed: {
language: { language: {
get: function () { get: function () {
return this.$store.getters.mergedConfig.interfaceLanguage return useMergedConfigStore().mergedConfig.interfaceLanguage
}, },
set: function (val) { set: function (val) {
this.$store.dispatch('setOption', { useSyncConfigStore().setSimplePrefAndSave({
name: 'interfaceLanguage', path: 'interfaceLanguage',
value: val, value: val,
}) })
}, },
@ -64,17 +65,8 @@ const GeneralTab = {
this.$store.commit('setCurrentUser', user) this.$store.commit('setCurrentUser', user)
}) })
}, },
updateFont(key, value) { updateFont(path, value) {
this.$store.dispatch('setOption', { useLocalConfigStore().set({ path, value })
name: 'theme3hacks',
value: {
...this.mergedConfig.theme3hacks,
fonts: {
...this.mergedConfig.theme3hacks.fonts,
[key]: value,
},
},
})
}, },
}, },
} }

View file

@ -9,11 +9,6 @@
class="lang-selector" class="lang-selector"
@update="val => language = val" @update="val => language = val"
/> />
<h4>
{{ $t('settings.email_language') }}
{{ ' ' }}
<ProfileSettingIndicator :is-profile="true" />
</h4>
<interface-language-switcher <interface-language-switcher
v-model="emailLanguage" v-model="emailLanguage"
class="lang-selector" class="lang-selector"
@ -44,6 +39,7 @@
:units="['px', 'rem']" :units="['px', 'rem']"
:reset-default="{ 'px': 14, 'rem': 1 }" :reset-default="{ 'px': 14, 'rem': 1 }"
timed-apply-mode timed-apply-mode
:local="true"
> >
{{ $t('settings.text_size') }} {{ $t('settings.text_size') }}
</UnitSetting> </UnitSetting>
@ -68,27 +64,28 @@
</li> </li>
<li> <li>
<FontControl <FontControl
:model-value="mergedConfig.theme3hacks.fonts.interface" :model-value="mergedConfig.fontInterface"
name="ui" name="ui"
:label="$t('settings.style.fonts.components_inline.interface')" :label="$t('settings.style.fonts.components_inline.interface')"
:fallback="{ family: 'sans-serif' }" :fallback="{ family: 'sans-serif' }"
no-inherit="1" no-inherit="1"
@update:model-value="v => updateFont('interface', v)" @update:model-value="v => updateFont('fontInterface', v)"
/> />
</li> </li>
<li> <li>
<FontControl <FontControl
:model-value="mergedConfig.theme3hacks.fonts.input" :model-value="mergedConfig.fontInput"
name="input" name="input"
:fallback="{ family: 'inherit' }" :fallback="{ family: 'inherit' }"
:label="$t('settings.style.fonts.components_inline.input')" :label="$t('settings.style.fonts.components_inline.input')"
@update:model-value="v => updateFont('input', v)" @update:model-value="v => updateFont('fontInput', v)"
/> />
</li> </li>
<li> <li>
<UnitSetting <UnitSetting
path="emojiSize" path="emojiSize"
:step="0.1" :step="0.1"
:local="true"
:units="['px', 'rem']" :units="['px', 'rem']"
:reset-default="{ 'px': 32, 'rem': 2.2 }" :reset-default="{ 'px': 32, 'rem': 2.2 }"
> >
@ -101,6 +98,7 @@
<FloatSetting <FloatSetting
v-if="user" v-if="user"
path="emojiReactionsScale" path="emojiReactionsScale"
:local="true"
> >
{{ $t('settings.emoji_reactions_scale') }} {{ $t('settings.emoji_reactions_scale') }}
</FloatSetting> </FloatSetting>
@ -128,6 +126,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="useStreamingApi" path="useStreamingApi"
:local="true"
expert="1" expert="1"
> >
{{ $t('settings.useStreamingApi') }} {{ $t('settings.useStreamingApi') }}

View file

@ -2,11 +2,11 @@ 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 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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
const GeneralTab = { const GeneralTab = {
data() { data() {
@ -24,7 +24,6 @@ const GeneralTab = {
BooleanSetting, BooleanSetting,
ChoiceSetting, ChoiceSetting,
UnitSetting, UnitSetting,
ProfileSettingIndicator,
}, },
computed: { computed: {
...mapState(useInstanceCapabilitiesStore, [ ...mapState(useInstanceCapabilitiesStore, [
@ -32,12 +31,12 @@ const GeneralTab = {
'suggestionsEnabled', 'suggestionsEnabled',
]), ]),
columns() { columns() {
const mode = this.$store.getters.mergedConfig.thirdColumnMode const mode = useMergedConfigStore().mergedConfig.thirdColumnMode
const notif = mode === 'none' ? [] : ['notifs'] const notif = mode === 'none' ? [] : ['notifs']
if ( if (
this.$store.getters.mergedConfig.sidebarRight || useMergedConfigStore().mergedConfig.sidebarRight ||
mode === 'postform' mode === 'postform'
) { ) {
return [...notif, 'content', 'sidebar'] return [...notif, 'content', 'sidebar']

View file

@ -40,6 +40,7 @@
<li> <li>
<UnitSetting <UnitSetting
path="themeEditorMinWidth" path="themeEditorMinWidth"
:local="true"
:units="['px', 'rem']" :units="['px', 'rem']"
expert="1" expert="1"
> >
@ -50,6 +51,7 @@
<UnitSetting <UnitSetting
path="navbarSize" path="navbarSize"
:step="0.1" :step="0.1"
:local="true"
:units="['px', 'rem']" :units="['px', 'rem']"
:reset-default="{ 'px': 55, 'rem': 3.5 }" :reset-default="{ 'px': 55, 'rem': 3.5 }"
> >
@ -72,6 +74,7 @@
<li> <li>
<UnitSetting <UnitSetting
path="panelHeaderSize" path="panelHeaderSize"
:local="true"
:step="0.1" :step="0.1"
:units="['px', 'rem']" :units="['px', 'rem']"
:reset-default="{ 'px': 52, 'rem': 3.2 }" :reset-default="{ 'px': 52, 'rem': 3.2 }"
@ -81,12 +84,18 @@
</UnitSetting> </UnitSetting>
</li> </li>
<li> <li>
<BooleanSetting path="sidebarRight"> <BooleanSetting
:local="true"
path="sidebarRight"
>
{{ $t('settings.right_sidebar') }} {{ $t('settings.right_sidebar') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting path="navbarColumnStretch"> <BooleanSetting
:local="true"
path="navbarColumnStretch"
>
{{ $t('settings.navbar_column_stretch') }} {{ $t('settings.navbar_column_stretch') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
@ -106,6 +115,7 @@
<UnitSetting <UnitSetting
v-for="column in columns" v-for="column in columns"
:key="column" :key="column"
:local="true"
:path="column + 'ColumnWidth'" :path="column + 'ColumnWidth'"
:units="horizontalUnits" :units="horizontalUnits"
expert="1" expert="1"

View file

@ -249,6 +249,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="webPushNotifications" path="webPushNotifications"
:local="true"
expert="1" expert="1"
> >
{{ $t('settings.enable_web_push_notifications') }} {{ $t('settings.enable_web_push_notifications') }}
@ -257,6 +258,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
path="webPushAlwaysShowNotifications" path="webPushAlwaysShowNotifications"
:local="true"
:disabled="!mergedConfig.webPushNotifications" :disabled="!mergedConfig.webPushNotifications"
> >
{{ $t('settings.enable_web_push_always_show') }} {{ $t('settings.enable_web_push_always_show') }}
@ -273,6 +275,7 @@
<li> <li>
<BooleanSetting <BooleanSetting
source="profile" source="profile"
:local="true"
path="webPushHideContents" path="webPushHideContents"
expert="1" expert="1"
> >

View file

@ -11,6 +11,7 @@ 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.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { import {
getContrastRatioLayers, getContrastRatioLayers,
@ -81,7 +82,7 @@ export default {
}), }),
availableStyles: [], availableStyles: [],
selected: '', selected: '',
selectedTheme: this.$store.getters.mergedConfig.theme, selectedTheme: useMergedConfigStore().mergedConfig.theme,
themeWarning: undefined, themeWarning: undefined,
tempImportFile: undefined, tempImportFile: undefined,
engineVersion: 0, engineVersion: 0,

View file

@ -2,10 +2,12 @@ import FontControl from 'src/components/font_control/font_control.vue'
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 IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.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'
const GeneralTab = { import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const PostsTab = {
data() { data() {
return { return {
conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({ conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({
@ -60,25 +62,15 @@ const GeneralTab = {
ChoiceSetting, ChoiceSetting,
IntegerSetting, IntegerSetting,
FontControl, FontControl,
ProfileSettingIndicator,
}, },
computed: { computed: {
...SharedComputedObject(), ...SharedComputedObject(),
}, },
methods: { methods: {
updateFont(key, value) { updateFont(path, value) {
this.$store.dispatch('setOption', { useLocalConfigStore().set({ path, value })
name: 'theme3hacks',
value: {
...this.mergedConfig.theme3hacks,
fonts: {
...this.mergedConfig.theme3hacks.fonts,
[key]: value,
},
},
})
}, },
}, },
} }
export default GeneralTab export default PostsTab

View file

@ -56,20 +56,20 @@
</li> </li>
<li> <li>
<FontControl <FontControl
:model-value="mergedConfig.theme3hacks.fonts.post" :model-value="mergedConfig.fontPosts"
name="post" name="post"
:fallback="{ family: 'inherit' }" :fallback="{ family: 'inherit' }"
:label="$t('settings.style.fonts.components.post')" :label="$t('settings.style.fonts.components.post')"
@update:model-value="v => updateFont('post', v)" @update:model-value="v => updateFont('fontPosts', v)"
/> />
</li> </li>
<li> <li>
<FontControl <FontControl
:model-value="mergedConfig.theme3hacks.fonts.monospace" :model-value="mergedConfig.fontMonospace"
name="postCode" name="postCode"
:fallback="{ family: 'monospace' }" :fallback="{ family: 'monospace' }"
:label="$t('settings.style.fonts.components.monospace')" :label="$t('settings.style.fonts.components.monospace')"
@update:model-value="v => updateFont('monospace', v)" @update:model-value="v => updateFont('fontMonospace', v)"
/> />
</li> </li>
<li> <li>
@ -99,6 +99,7 @@
<ChoiceSetting <ChoiceSetting
id="mentionLinkDisplay" id="mentionLinkDisplay"
path="mentionLinkDisplay" path="mentionLinkDisplay"
:local="true"
:options="mentionLinkDisplayOptions" :options="mentionLinkDisplayOptions"
> >
{{ $t('settings.mention_link_display') }} {{ $t('settings.mention_link_display') }}
@ -169,7 +170,10 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
<li> <li>
<BooleanSetting path="hideNsfw"> <BooleanSetting
:local="true"
path="hideNsfw"
>
{{ $t('settings.nsfw_clickthrough') }} {{ $t('settings.nsfw_clickthrough') }}
</BooleanSetting> </BooleanSetting>
<ul class="setting-list suboptions"> <ul class="setting-list suboptions">
@ -177,6 +181,7 @@
<BooleanSetting <BooleanSetting
path="preloadImage" path="preloadImage"
expert="1" expert="1"
:local="true"
parent-path="hideNsfw" parent-path="hideNsfw"
> >
{{ $t('settings.preload_images') }} {{ $t('settings.preload_images') }}
@ -186,6 +191,7 @@
<BooleanSetting <BooleanSetting
path="useOneClickNsfw" path="useOneClickNsfw"
expert="1" expert="1"
:local="true"
parent-path="hideNsfw" parent-path="hideNsfw"
> >
{{ $t('settings.use_one_click_nsfw') }} {{ $t('settings.use_one_click_nsfw') }}

View file

@ -1,7 +1,6 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import UserCard from 'src/components/user_card/user_card.vue' import UserCard from 'src/components/user_card/user_card.vue'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.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 { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -24,7 +23,6 @@ const ProfileTab = {
UserCard, UserCard,
Checkbox, Checkbox,
BooleanSetting, BooleanSetting,
ProfileSettingIndicator,
}, },
computed: { computed: {
user() { user() {

View file

@ -16,7 +16,6 @@
v-model="locked" v-model="locked"
class="setting-label setting-control custom-boolean-setting" class="setting-label setting-control custom-boolean-setting"
> >
<ProfileSettingIndicator :is-profile="true" />
{{ $t('settings.lock_account_description') }} {{ $t('settings.lock_account_description') }}
</Checkbox> </Checkbox>
</div> </div>

View file

@ -10,6 +10,7 @@ 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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useShoutStore } from 'src/stores/shout' import { useShoutStore } from 'src/stores/shout'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -72,7 +73,10 @@ const SideDrawer = {
return useShoutStore().joined return useShoutStore().joined
}, },
unseenNotifications() { unseenNotifications() {
return unseenNotificationsFromStore(this.$store) return unseenNotificationsFromStore(
this.$store,
useMergedConfigStore().mergedConfig.notificationVisibility,
)
}, },
unseenNotificationsCount() { unseenNotificationsCount() {
return this.unseenNotifications.length return this.unseenNotifications.length

View file

@ -23,7 +23,9 @@ import UserPopover from '../user_popover/user_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 { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useServerSideStorageStore } from 'src/stores/serverSideStorage' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.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'
@ -133,25 +135,26 @@ const Status = {
}, },
props: [ props: [
'statusoid', 'statusoid',
'replies',
'expandable', 'expandable',
'inConversation',
'focused', 'focused',
'highlight', 'highlight',
'compact', 'compact',
'replies',
'isPreview', 'isPreview',
'noHeading', 'noHeading',
'inlineExpanded', 'inlineExpanded',
'showPinned', 'showPinned',
'inProfile', 'inProfile',
'profileUserId', 'inConversation',
'inQuote', 'inQuote',
'profileUserId',
'simpleTree', 'simpleTree',
'showOtherRepliesAsButton',
'dive',
'controlledThreadDisplayStatus', 'controlledThreadDisplayStatus',
'controlledToggleThreadDisplay', 'controlledToggleThreadDisplay',
'showOtherRepliesAsButton',
'controlledShowingTall', 'controlledShowingTall',
'controlledToggleShowingTall', 'controlledToggleShowingTall',
'controlledExpandingSubject', 'controlledExpandingSubject',
@ -162,9 +165,8 @@ const Status = {
'controlledToggleReplying', 'controlledToggleReplying',
'controlledMediaPlaying', 'controlledMediaPlaying',
'controlledSetMediaPlaying', 'controlledSetMediaPlaying',
'dive',
], ],
emits: ['interacted'], emits: ['interacted', 'goto', 'toggleExpanded'],
data() { data() {
return { return {
uncontrolledReplying: false, uncontrolledReplying: false,
@ -200,16 +202,14 @@ const Status = {
}, },
repeaterStyle() { repeaterStyle() {
const user = this.statusoid.user const user = this.statusoid.user
const highlight = this.mergedConfig.highlight return highlightStyle(useUserHighlightStore().get(user.screen_name))
return highlightStyle(highlight[user.screen_name])
}, },
userStyle() { userStyle() {
if (this.noHeading) return if (this.noHeading) return
const user = this.retweet const user = this.retweet
? this.statusoid.retweeted_status.user ? this.statusoid.retweeted_status.user
: this.statusoid.user : this.statusoid.user
const highlight = this.mergedConfig.highlight return highlightStyle(useUserHighlightStore().get(user.screen_name))
return highlightStyle(highlight[user.screen_name])
}, },
userProfileLink() { userProfileLink() {
return this.generateUserProfileLink( return this.generateUserProfileLink(
@ -260,9 +260,7 @@ const Status = {
}, },
muteFilterHits() { muteFilterHits() {
return muteFilterHits( return muteFilterHits(
Object.values( Object.values(useSyncConfigStore().prefsStorage.simple.muteFilters),
useServerSideStorageStore().prefsStorage.simple.muteFilters,
),
this.status, this.status,
) )
}, },
@ -481,7 +479,7 @@ const Status = {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
mergedConfig() { mergedConfig() {
return this.$store.getters.mergedConfig return useMergedConfigStore().mergedConfig
}, },
isSuspendable() { isSuspendable() {
return !this.replying && this.mediaPlaying.length === 0 return !this.replying && this.mediaPlaying.length === 0

View file

@ -10,12 +10,13 @@
class="alert error" class="alert error"
> >
{{ error }} {{ error }}
<span <button
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
type="button"
@click="clearError" @click="clearError"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
</span> </button>
</div> </div>
<template v-if="muted && !isPreview"> <template v-if="muted && !isPreview">
<div class="status-container muted"> <div class="status-container muted">

View file

@ -88,7 +88,7 @@
<StatusBookmarkFolderMenu <StatusBookmarkFolderMenu
v-if="button.name === 'bookmark'" v-if="button.name === 'bookmark'"
:status="status" :status="status"
:close="() => { close(); outerClose() }" @close="() => { close(); outerClose?.() }"
/> />
</template> </template>
</Popover> </Popover>

View file

@ -1,6 +1,7 @@
import { useEditStatusStore } from 'src/stores/editStatus.js' import { useEditStatusStore } from 'src/stores/editStatus.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.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'
@ -52,7 +53,7 @@ export const BUTTONS = [
!PRIVATE_SCOPES.has(status.visibility)), !PRIVATE_SCOPES.has(status.visibility)),
toggleable: true, toggleable: true,
confirm: ({ status, getters }) => confirm: ({ status, getters }) =>
!status.repeated && getters.mergedConfig.modalOnRepeat, !status.repeated && useMergedConfigStore().mergedConfig.modalOnRepeat,
confirmStrings: { confirmStrings: {
title: 'status.repeat_confirm_title', title: 'status.repeat_confirm_title',
body: 'status.repeat_confirm', body: 'status.repeat_confirm',
@ -228,7 +229,7 @@ export const BUTTONS = [
currentUser.privileges.includes('messages_delete')) currentUser.privileges.includes('messages_delete'))
) )
}, },
confirm: ({ getters }) => getters.mergedConfig.modalOnDelete, confirm: ({ getters }) => useMergedConfigStore().mergedConfig.modalOnDelete,
confirmStrings: { confirmStrings: {
title: 'status.delete_confirm_title', title: 'status.delete_confirm_title',
body: 'status.delete_confirm', body: 'status.delete_confirm',

View file

@ -5,7 +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 { 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'
@ -36,7 +36,7 @@ const StatusActionButtons = {
ActionButtonContainer, ActionButtonContainer,
}, },
computed: { computed: {
...mapState(useServerSideStorageStore, { ...mapState(useSyncConfigStore, {
pinnedItems: (store) => pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedStatusActions), new Set(store.prefsStorage.collections.pinnedStatusActions),
}), }),
@ -111,18 +111,18 @@ const StatusActionButtons = {
return this.pinnedItems.has(button.name) return this.pinnedItems.has(button.name)
}, },
unpin(button) { unpin(button) {
useServerSideStorageStore().removeCollectionPreference({ useSyncConfigStore().removeCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
pin(button) { pin(button) {
useServerSideStorageStore().addCollectionPreference({ useSyncConfigStore().addCollectionPreference({
path: 'collections.pinnedStatusActions', path: 'collections.pinnedStatusActions',
value: button.name, value: button.name,
}) })
useServerSideStorageStore().pushServerSideStorage() useSyncConfigStore().pushSyncConfig()
}, },
getComponent(button) { getComponent(button) {
if (!this.$store.state.users.currentUser && button.anonLink) { if (!this.$store.state.users.currentUser && button.anonLink) {

View file

@ -1,7 +1,9 @@
import { mapGetters } from 'vuex' import { mapState } from 'pinia'
import RichContent from 'src/components/rich_content/rich_content.jsx' import RichContent from 'src/components/rich_content/rich_content.jsx'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faFile, faFile,
@ -101,14 +103,12 @@ const StatusBody = {
) )
}, },
attachmentTypes() { attachmentTypes() {
return this.status.attachments.map((file) => return this.status.attachments.map((file) => file.type)
file.type,
)
}, },
collapsedStatus() { collapsedStatus() {
return this.status.raw_html.replace(/(\n|<br\s?\/?>)/g, ' ') return this.status.raw_html.replace(/(\n|<br\s?\/?>)/g, ' ')
}, },
...mapGetters(['mergedConfig']), ...mapState(useMergedConfigStore, ['mergedConfig']),
}, },
components: { components: {
RichContent, RichContent,

View file

@ -11,7 +11,8 @@ import { faChevronRight, faFolder } from '@fortawesome/free-solid-svg-icons'
library.add(faChevronRight, faFolder) library.add(faChevronRight, faFolder)
const StatusBookmarkFolderMenu = { const StatusBookmarkFolderMenu = {
props: ['status', 'close'], props: ['status'],
emits: ['success', 'error', 'close'],
data() { data() {
return {} return {}
}, },
@ -33,8 +34,8 @@ const StatusBookmarkFolderMenu = {
this.$store this.$store
.dispatch('bookmark', { id: this.status.id, bookmark_folder_id: value }) .dispatch('bookmark', { id: this.status.id, bookmark_folder_id: value })
.then(() => this.$emit('onSuccess')) .then(() => this.$emit('success'))
.catch((err) => this.$emit('onError', err.error.error)) .catch((err) => this.$emit('error', err.error.error))
}, },
}, },
} }

View file

@ -8,7 +8,7 @@
<button <button
class="main-button" class="main-button"
@click="toggleFolder(folder.id)" @click="toggleFolder(folder.id)"
@click.stop="close" @click.stop="$emit('close')"
> >
<span <span
class="input menu-checkbox -radio" class="input menu-checkbox -radio"

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