diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js
index e1a28a8f1..8a121befc 100644
--- a/src/components/emoji_reactions/emoji_reactions.js
+++ b/src/components/emoji_reactions/emoji_reactions.js
@@ -2,8 +2,6 @@ import StillImage from 'src/components/still-image/still-image.vue'
import UserAvatar from '../user_avatar/user_avatar.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 { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
@@ -44,7 +42,7 @@ const EmojiReactions = {
return !!this.$store.state.users.currentUser
},
remoteInteractionLink() {
- return useInstanceStore().getRemoteInteractionLink({
+ return this.$store.getters.remoteInteractionLink({
statusId: this.status.id,
})
},
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index d94191c9d..b0eac97c0 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -48,6 +48,9 @@ const GeneralTab = {
},
...SharedComputedObject(),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
+ ...mapState(useSyncConfigStore, {
+ theme3hacks: (store) => store.mergedConfig.theme3hacks,
+ }),
},
methods: {
updateProfile() {
@@ -64,8 +67,17 @@ const GeneralTab = {
this.$store.commit('setCurrentUser', user)
})
},
- updateFont(path, value) {
- useLocalConfigStore().set({ path, value })
+ updateFont(key, value) {
+ useLocalConfigStore().set({
+ path: 'theme3hacks',
+ value: {
+ ...this.mergedConfig.theme3hacks,
+ fonts: {
+ ...this.mergedConfig.theme3hacks.fonts,
+ [key]: value,
+ },
+ },
+ })
},
},
}
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 19800e0dd..a3cb5be07 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -64,21 +64,21 @@
updateFont('fontInterface', v)"
+ @update:model-value="v => updateFont('interface', v)"
/>
updateFont('fontInput', v)"
+ @update:model-value="v => updateFont('input', v)"
/>
diff --git a/src/components/settings_modal/tabs/posts_tab.js b/src/components/settings_modal/tabs/posts_tab.js
index ab00e52e7..467c2a4da 100644
--- a/src/components/settings_modal/tabs/posts_tab.js
+++ b/src/components/settings_modal/tabs/posts_tab.js
@@ -4,10 +4,9 @@ import ChoiceSetting from '../helpers/choice_setting.vue'
import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
-import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
-const PostsTab = {
+const GeneralTab = {
data() {
return {
conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({
@@ -67,10 +66,19 @@ const PostsTab = {
...SharedComputedObject(),
},
methods: {
- updateFont(path, value) {
- useLocalConfigStore().set({ path, value })
+ updateFont(key, value) {
+ useSyncConfigStore().setSimplePrefAndSave({
+ path: 'theme3hacks',
+ value: {
+ ...this.mergedConfig.theme3hacks,
+ fonts: {
+ ...this.mergedConfig.theme3hacks.fonts,
+ [key]: value,
+ },
+ },
+ })
},
},
}
-export default PostsTab
+export default GeneralTab
diff --git a/src/components/settings_modal/tabs/posts_tab.vue b/src/components/settings_modal/tabs/posts_tab.vue
index 1e684246d..444f96392 100644
--- a/src/components/settings_modal/tabs/posts_tab.vue
+++ b/src/components/settings_modal/tabs/posts_tab.vue
@@ -56,20 +56,22 @@
updateFont('fontPosts', v)"
+ @update:model-value="v => updateFont('post', v)"
/>
updateFont('fontMonospace', v)"
+ @update:model-value="v => updateFont('monospace', v)"
/>
diff --git a/src/lib/style.js b/src/lib/style.js
index 343d24aea..50120b37b 100644
--- a/src/lib/style.js
+++ b/src/lib/style.js
@@ -1,4 +1,3 @@
-import { useInterfaceStore } from 'src/stores/interface.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { applyStyleConfig } from 'src/services/style_setter/style_setter.js'
@@ -24,15 +23,6 @@ const APPEARANCE_SETTINGS_KEYS = [
'emojiSize',
'emojiReactionsScale',
]
-
-const HACKS_KEYS = new Set([
- 'fontInterface',
- 'fontPosts',
- 'fontInput',
- 'fontMonospace',
- 'underlay',
-])
-
const MIXED_KEYS = new Set([
...APPEARANCE_SETTINGS_KEYS,
...APPEARANCE_SETTINGS_KEYS.map((x) => 'simple.' + x),
@@ -46,9 +36,6 @@ export const piniaStylePlugin = ({ store, options }) => {
if (MIXED_KEYS.has(path)) {
after(() => applyStyleConfig(useSyncConfigStore().mergedConfig))
}
- if (HACKS_KEYS.has(path)) {
- after(() => useInterfaceStore().applyTheme({ recompile: true }))
- }
}
})
}
diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js
index 8634752bd..7823777a9 100644
--- a/src/modules/default_config_state.js
+++ b/src/modules/default_config_state.js
@@ -181,13 +181,6 @@ export const defaultConfigLocal = {
alwaysUseJpeg: false,
imageCompression: true,
useStreamingApi: false,
- underlay: 'none',
- fontInterface: undefined,
- fontInput: undefined,
- fontPosts: undefined,
- fontMonospace: undefined,
- themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
- forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
}
export const LOCAL_ONLY_KEYS = new Set(Object.keys(defaultConfigLocal))
@@ -219,4 +212,16 @@ export const defaultState = {
styleCustomData: null,
palette: null,
paletteCustomData: null,
+ themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
+ forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
+ theme3hacks: {
+ // Hacks, user overrides that are independent of theme used
+ underlay: 'none',
+ fonts: {
+ interface: undefined,
+ input: undefined,
+ post: undefined,
+ monospace: undefined,
+ },
+ },
}
diff --git a/src/modules/old_default_config_state.js b/src/modules/old_default_config_state.js
index 935239d16..dc15e1c24 100644
--- a/src/modules/old_default_config_state.js
+++ b/src/modules/old_default_config_state.js
@@ -2,7 +2,7 @@
// used to migrate from old config.
// commented entries are unsynced stuff
-export const oldDefaultConfigSync = {
+export const defaultConfigSync = {
expertLevel: 0, // used to track which settings to show and hide
hideISP: false,
hideInstanceWallpaper: false,
diff --git a/src/modules/users.js b/src/modules/users.js
index d9e42ea76..e741877a6 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -702,15 +702,13 @@ const users = {
user.domainMutes = []
commit('setCurrentUser', user)
- useSyncConfigStore()
- .initSyncConfig(user)
- .then(() => {
- useInterfaceStore()
- .applyTheme()
- .catch((e) => {
- console.error('Error setting theme', e)
- })
- })
+ useSyncConfigStore().initSyncConfig(user).then(() => {
+ useInterfaceStore()
+ .applyTheme()
+ .catch((e) => {
+ console.error('Error setting theme', e)
+ })
+ })
useUserHighlightStore().initUserHighlight(user)
commit('addNewUsers', [user])
diff --git a/src/stores/interface.js b/src/stores/interface.js
index 32a8226b4..5840d6b34 100644
--- a/src/stores/interface.js
+++ b/src/stores/interface.js
@@ -598,9 +598,8 @@ export const useInterfaceStore = defineStore('interface', {
this.themeApplied = true
},
async applyTheme({ recompile = false } = {}) {
- const { mergedConfig } = useSyncConfigStore()
- const { forceThemeRecompilation, themeDebug } = mergedConfig
-
+ const { forceThemeRecompilation, themeDebug, theme3hacks } =
+ useSyncConfigStore().mergedConfig
this.themeChangeInProgress = true
// If we're not forced to recompile try using
// cache (tryLoadCache return true if load successful)
@@ -647,41 +646,68 @@ export const useInterfaceStore = defineStore('interface', {
convertTheme2To3(normalizeThemeData(this.themeDataUsed))
const hacks = []
- const fontMap = {
- Interface: 'Root',
- Input: 'Input',
- Posts: 'Post',
- Monospace: 'Root',
- }
-
- Object.entries(fontMap).forEach(([font, component]) => {
- const family = mergedConfig[`font${font}`]?.family
- const variable = font === 'Monospace' ? '--monoFont' : '--font'
- if (family) {
- hacks.push({
- component,
- directives: {
- [variable]: `generic | "${family}"`,
- },
- })
+ Object.entries(theme3hacks).forEach(([key, value]) => {
+ switch (key) {
+ case 'fonts': {
+ Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => {
+ if (!font?.family) return
+ switch (fontKey) {
+ case 'interface':
+ hacks.push({
+ component: 'Root',
+ directives: {
+ '--font': 'generic | ' + font.family,
+ },
+ })
+ break
+ case 'input':
+ hacks.push({
+ component: 'Input',
+ directives: {
+ '--font': 'generic | ' + font.family,
+ },
+ })
+ break
+ case 'post':
+ hacks.push({
+ component: 'RichContent',
+ directives: {
+ '--font': 'generic | ' + font.family,
+ },
+ })
+ break
+ case 'monospace':
+ hacks.push({
+ component: 'Root',
+ directives: {
+ '--monoFont': 'generic | ' + font.family,
+ },
+ })
+ break
+ }
+ })
+ break
+ }
+ case 'underlay': {
+ if (value !== 'none') {
+ const newRule = {
+ component: 'Underlay',
+ directives: {},
+ }
+ if (value === 'opaque') {
+ newRule.directives.opacity = 1
+ newRule.directives.background = '--wallpaper'
+ }
+ if (value === 'transparent') {
+ newRule.directives.opacity = 0
+ }
+ hacks.push(newRule)
+ }
+ break
+ }
}
})
- if (mergedConfig.underlay !== 'none') {
- const newRule = {
- component: 'Underlay',
- directives: {},
- }
- if (mergedConfig.underlay === 'opaque') {
- newRule.directives.opacity = 1
- newRule.directives.background = '--wallpaper'
- }
- if (mergedConfig.underlay === 'transparent') {
- newRule.directives.opacity = 0
- }
- hacks.push(newRule)
- }
-
const rulesetArray = [
theme2ruleset,
this.styleDataUsed,
@@ -698,7 +724,6 @@ export const useInterfaceStore = defineStore('interface', {
themeDebug,
)
} catch (e) {
- console.error(e)
window.splashError(e)
}
},
diff --git a/src/stores/local_config.js b/src/stores/local_config.js
index 096d0b3f1..73ea1d7d4 100644
--- a/src/stores/local_config.js
+++ b/src/stores/local_config.js
@@ -33,9 +33,9 @@ export const useLocalConfigStore = defineStore('local_config', {
set(this.prefsStorage, path, undefined)
},
clearLocalConfig() {
+ const blankState = { ...cloneDeep(defaultState) }
Object.keys(this).forEach((k) => {
- this.prefsStorage[k] = undefined
- this.tempStorage[k] = undefined
+ this.prefsStorage[k] = blankState[k]
})
},
},
diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js
index ba4031e9a..e9a4a278e 100644
--- a/src/stores/sync_config.js
+++ b/src/stores/sync_config.js
@@ -28,7 +28,7 @@ import {
instanceDefaultConfig,
LOCAL_ONLY_KEYS,
} from 'src/modules/default_config_state.js'
-import { oldDefaultConfigSync } from 'src/modules/old_default_config_state.js'
+import { defaultConfigSync } from 'src/modules/old_default_config_state.js'
export const VERSION = 2
export const NEW_USER_DATE = new Date('2026-03-16') // date of writing this, basically
@@ -628,7 +628,7 @@ export const useSyncConfigStore = defineStore('sync_config', {
const migratedEntries = new Set(vuexState.config._syncMigration ?? [])
console.debug(`Already migrated Values: ${[...migratedEntries].join()}`)
- Object.entries(oldDefaultConfigSync).forEach(([key, value]) => {
+ Object.entries(defaultConfigSync).forEach(([key, value]) => {
const oldValue = vuexState.config[key]
const defaultValue = value
@@ -638,30 +638,7 @@ export const useSyncConfigStore = defineStore('sync_config', {
if (present && !migrated && different) {
console.debug(`Migrating config ${key}: ${oldValue}`)
- if (key === 'theme3hacks') {
- useLocalConfigStore().set({
- path: 'fontInterface',
- value: oldValue.fonts.interface,
- })
- useLocalConfigStore().set({
- path: 'fontInput',
- value: oldValue.fonts.input,
- })
- useLocalConfigStore().set({
- path: 'fontPost',
- value: oldValue.fonts.post,
- })
- useLocalConfigStore().set({
- path: 'fontMonospace',
- value: oldValue.fonts.monospace,
- })
- useLocalConfigStore().set({
- path: 'underlay',
- value: oldValue.underlay,
- })
- } else {
- this.setPreference({ path: `simple.${key}`, value: oldValue })
- }
+ this.setPreference({ path: `simple.${key}`, oldValue })
migratedEntries.add(key)
needUpload = true
}
@@ -728,7 +705,8 @@ export const useSyncConfigStore = defineStore('sync_config', {
if (!needPush) return
this.updateCache({ username: window.vuex.state.users.currentUser.fqn })
const params = { pleroma_settings_store: { 'pleroma-fe': this.cache } }
- window.vuex.state.api.backendInteractor.updateProfileJSON({ params })
+ window.vuex.state.api.backendInteractor
+ .updateProfileJSON({ params })
},
},
getters: {