diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js
index 8a121befc..e1a28a8f1 100644
--- a/src/components/emoji_reactions/emoji_reactions.js
+++ b/src/components/emoji_reactions/emoji_reactions.js
@@ -2,6 +2,8 @@ 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'
@@ -42,7 +44,7 @@ const EmojiReactions = {
return !!this.$store.state.users.currentUser
},
remoteInteractionLink() {
- return this.$store.getters.remoteInteractionLink({
+ return useInstanceStore().getRemoteInteractionLink({
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 b0eac97c0..d94191c9d 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -48,9 +48,6 @@ const GeneralTab = {
},
...SharedComputedObject(),
...mapState(useInstanceCapabilitiesStore, ['blockExpiration']),
- ...mapState(useSyncConfigStore, {
- theme3hacks: (store) => store.mergedConfig.theme3hacks,
- }),
},
methods: {
updateProfile() {
@@ -67,17 +64,8 @@ const GeneralTab = {
this.$store.commit('setCurrentUser', user)
})
},
- updateFont(key, value) {
- useLocalConfigStore().set({
- path: 'theme3hacks',
- value: {
- ...this.mergedConfig.theme3hacks,
- fonts: {
- ...this.mergedConfig.theme3hacks.fonts,
- [key]: value,
- },
- },
- })
+ updateFont(path, value) {
+ useLocalConfigStore().set({ path, value })
},
},
}
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index a3cb5be07..19800e0dd 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -64,21 +64,21 @@
updateFont('interface', v)"
+ @update:model-value="v => updateFont('fontInterface', v)"
/>
updateFont('input', v)"
+ @update:model-value="v => updateFont('fontInput', v)"
/>
diff --git a/src/components/settings_modal/tabs/posts_tab.js b/src/components/settings_modal/tabs/posts_tab.js
index 467c2a4da..ab00e52e7 100644
--- a/src/components/settings_modal/tabs/posts_tab.js
+++ b/src/components/settings_modal/tabs/posts_tab.js
@@ -4,9 +4,10 @@ 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 GeneralTab = {
+const PostsTab = {
data() {
return {
conversationDisplayOptions: ['tree', 'linear'].map((mode) => ({
@@ -66,19 +67,10 @@ const GeneralTab = {
...SharedComputedObject(),
},
methods: {
- updateFont(key, value) {
- useSyncConfigStore().setSimplePrefAndSave({
- path: 'theme3hacks',
- value: {
- ...this.mergedConfig.theme3hacks,
- fonts: {
- ...this.mergedConfig.theme3hacks.fonts,
- [key]: value,
- },
- },
- })
+ updateFont(path, value) {
+ useLocalConfigStore().set({ path, value })
},
},
}
-export default GeneralTab
+export default PostsTab
diff --git a/src/components/settings_modal/tabs/posts_tab.vue b/src/components/settings_modal/tabs/posts_tab.vue
index 444f96392..1e684246d 100644
--- a/src/components/settings_modal/tabs/posts_tab.vue
+++ b/src/components/settings_modal/tabs/posts_tab.vue
@@ -56,22 +56,20 @@
updateFont('post', v)"
+ @update:model-value="v => updateFont('fontPosts', v)"
/>
updateFont('monospace', v)"
+ @update:model-value="v => updateFont('fontMonospace', v)"
/>
diff --git a/src/lib/style.js b/src/lib/style.js
index 50120b37b..343d24aea 100644
--- a/src/lib/style.js
+++ b/src/lib/style.js
@@ -1,3 +1,4 @@
+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'
@@ -23,6 +24,15 @@ 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),
@@ -36,6 +46,9 @@ 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 7823777a9..8634752bd 100644
--- a/src/modules/default_config_state.js
+++ b/src/modules/default_config_state.js
@@ -181,6 +181,13 @@ 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))
@@ -212,16 +219,4 @@ 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 dc15e1c24..935239d16 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 defaultConfigSync = {
+export const oldDefaultConfigSync = {
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 e741877a6..d9e42ea76 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -702,13 +702,15 @@ 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 5840d6b34..32a8226b4 100644
--- a/src/stores/interface.js
+++ b/src/stores/interface.js
@@ -598,8 +598,9 @@ export const useInterfaceStore = defineStore('interface', {
this.themeApplied = true
},
async applyTheme({ recompile = false } = {}) {
- const { forceThemeRecompilation, themeDebug, theme3hacks } =
- useSyncConfigStore().mergedConfig
+ const { mergedConfig } = useSyncConfigStore()
+ const { forceThemeRecompilation, themeDebug } = mergedConfig
+
this.themeChangeInProgress = true
// If we're not forced to recompile try using
// cache (tryLoadCache return true if load successful)
@@ -646,68 +647,41 @@ export const useInterfaceStore = defineStore('interface', {
convertTheme2To3(normalizeThemeData(this.themeDataUsed))
const hacks = []
- 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
- }
+ 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}"`,
+ },
+ })
}
})
+ 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,
@@ -724,6 +698,7 @@ 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 73ea1d7d4..096d0b3f1 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] = blankState[k]
+ this.prefsStorage[k] = undefined
+ this.tempStorage[k] = undefined
})
},
},
diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js
index e9a4a278e..ba4031e9a 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 { defaultConfigSync } from 'src/modules/old_default_config_state.js'
+import { oldDefaultConfigSync } 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(defaultConfigSync).forEach(([key, value]) => {
+ Object.entries(oldDefaultConfigSync).forEach(([key, value]) => {
const oldValue = vuexState.config[key]
const defaultValue = value
@@ -638,7 +638,30 @@ export const useSyncConfigStore = defineStore('sync_config', {
if (present && !migrated && different) {
console.debug(`Migrating config ${key}: ${oldValue}`)
- this.setPreference({ path: `simple.${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 })
+ }
migratedEntries.add(key)
needUpload = true
}
@@ -705,8 +728,7 @@ 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: {