theme/style/palette seem to be working

This commit is contained in:
Henry Jameson 2026-01-23 14:11:48 +02:00
commit 1f57fab6ae
10 changed files with 122 additions and 63 deletions

View file

@ -25,6 +25,7 @@ import { useInterfaceStore } from 'src/stores/interface.js'
import { useShoutStore } from 'src/stores/shout.js' import { useShoutStore } from 'src/stores/shout.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { applyStyleConfig } from 'src/services/style_setter/style_setter.js'
import { getOrCreateServiceWorker } from 'src/services/sw/sw' import { getOrCreateServiceWorker } from 'src/services/sw/sw'
import { import {
windowHeight, windowHeight,
@ -76,7 +77,9 @@ export default {
}, },
created() { created() {
document.getElementById('modal').classList = ['-' + this.layoutType] document.getElementById('modal').classList = ['-' + this.layoutType]
useI18nStore().setLanguage() useI18nStore().setLanguage()
applyStyleConfig(useSyncConfigStore().mergedConfig)
// Create bound handlers // Create bound handlers
this.updateScrollState = throttle(this.scrollHandler, 200) this.updateScrollState = throttle(this.scrollHandler, 200)

View file

@ -18,7 +18,7 @@ config.autoAddCss = false
import App from '../App.vue' import App from '../App.vue'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import FaviconService from '../services/favicon_service/favicon_service.js' import FaviconService from '../services/favicon_service/favicon_service.js'
import { applyConfig } from '../services/style_setter/style_setter.js' import { applyStyleConfig } from '../services/style_setter/style_setter.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js' import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
import { import {
windowHeight, windowHeight,
@ -26,12 +26,13 @@ import {
} from '../services/window_utils/window_utils' } from '../services/window_utils/window_utils'
import routes from './routes' import routes from './routes'
import { useAnnouncementsStore } from 'src/stores/announcements' import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useAuthFlowStore } from 'src/stores/auth_flow' import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { useI18nStore } from 'src/stores/i18n' import { useI18nStore } from 'src/stores/i18n.js'
import { useInstanceStore } from 'src/stores/instance' import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth' import { useOAuthStore } from 'src/stores/oauth.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import VBodyScrollLock from 'src/directives/body_scroll_lock' import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { import {
@ -164,7 +165,6 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
} else { } else {
config = { ...staticConfig, ...apiConfig } config = { ...staticConfig, ...apiConfig }
} }
console.trace(config)
const copyInstanceIdentityOption = (path) => { const copyInstanceIdentityOption = (path) => {
if (get(config, path) !== undefined) { if (get(config, path) !== undefined) {
@ -567,7 +567,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
return Promise.reject(e) return Promise.reject(e)
} }
applyConfig(store.state.config, i18n.global) applyStyleConfig(useSyncConfigStore().mergedConfig)
// 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

@ -281,7 +281,7 @@ const AppearanceTab = {
}, },
instanceWallpaperUsed() { instanceWallpaperUsed() {
return ( return (
useInstanceStore().background && this.instanceWallpaper &&
!this.$store.state.users.currentUser.background_image !this.$store.state.users.currentUser.background_image
) )
}, },
@ -312,9 +312,9 @@ const AppearanceTab = {
}, },
onImport(parsed, filename) { onImport(parsed, filename) {
if (filename.endsWith('.json')) { if (filename.endsWith('.json')) {
useInterfaceStore().setThemeCustom(parsed.source || parsed.theme) this.setThemeCustom(parsed.source || parsed.theme)
} else if (filename.endsWith('.iss')) { } else if (filename.endsWith('.iss')) {
useInterfaceStore().setStyleCustom(parsed) this.setStyleCustom(parsed)
} }
}, },
onImportFailure(result) { onImportFailure(result) {
@ -336,25 +336,42 @@ const AppearanceTab = {
} }
}, },
isThemeActive(key) { isThemeActive(key) {
return key === (this.mergedConfig.theme || useInstanceStore().theme) return (
key ===
(useSyncConfigStore().mergedConfig.theme)
)
}, },
isStyleActive(key) { isStyleActive(key) {
return key === (this.mergedConfig.style || useInstanceStore().style) return (
key ===
(useSyncConfigStore().mergedConfig.style)
)
}, },
isPaletteActive(key) { isPaletteActive(key) {
return key === (this.mergedConfig.palette || useInstanceStore().palette) return (
key ===
(useSyncConfigStore().mergedConfig.palette ||
useInstanceStore().palette)
)
}, },
...mapActions(useInterfaceStore, ['setStyle', 'setTheme']), ...mapActions(useInterfaceStore, [
setPalette(name, data) { 'setStyle',
useInterfaceStore().setPalette(name) 'setStyleCustom',
'setPalette',
'setPaletteCustom',
'setTheme',
'setThemeCustom',
]),
setLocalPalette(name, data) {
this.setPalette(name)
this.userPalette = data this.userPalette = data
}, },
setPaletteCustom(data) { setLocalPaletteCustom(data) {
useInterfaceStore().setPaletteCustom(data) this.setPaletteCustom(data)
this.userPalette = data this.userPalette = data
}, },
resetTheming() { resetTheming() {
useInterfaceStore().setStyle('stock') this.setStyle('stock')
}, },
previewTheme(key, version, input) { previewTheme(key, version, input) {
let theme3 let theme3

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)"
> >
@ -90,7 +90,7 @@
class="btn button-default palette-entry" class="btn button-default palette-entry"
:class="{ toggled: isPaletteActive(p.key), disabled: switchInProgress }" :class="{ toggled: isPaletteActive(p.key), disabled: switchInProgress }"
:disabled="switchInProgress" :disabled="switchInProgress"
@click="() => setPalette(p.key, p)" @click="() => setLocalPalette(p.key, p)"
> >
<div class="palette-label"> <div class="palette-label">
<label> <label>
@ -113,7 +113,7 @@
class="btn button-default palette-entry" class="btn button-default palette-entry"
:class="{ toggled: isPaletteActive(p.key), disabled: switchInProgress }" :class="{ toggled: isPaletteActive(p.key), disabled: switchInProgress }"
:disabled="switchInProgress" :disabled="switchInProgress"
@click="() => setPalette(p.key, p)" @click="() => setLocalPalette(p.key, p)"
> >
<div class="palette-label"> <div class="palette-label">
<label> <label>
@ -143,7 +143,7 @@
:compact="true" :compact="true"
:apply="true" :apply="true"
:disabled="switchInProgress" :disabled="switchInProgress"
@apply-palette="data => setPaletteCustom(data)" @apply-palette="data => setLocalPaletteCustom(data)"
/> />
</template> </template>
<template v-else-if="customThemeVersion === 'v2'"> <template v-else-if="customThemeVersion === 'v2'">

29
src/lib/style.js Normal file
View file

@ -0,0 +1,29 @@
import { applyStyleConfig } from 'src/services/style_setter/style_setter.js'
const APPEARANCE_SETTINGS_KEYS = new Set(
[
'sidebarColumnWidth',
'contentColumnWidth',
'notifsColumnWidth',
'themeEditorMinWidth',
'textSize',
'navbarSize',
'panelHeaderSize',
'forcedRoundness',
'emojiSize',
'emojiReactionsScale',
].map((x) => 'simple.' + x),
)
export const piniaStylePlugin = ({ store, options }) => {
if (store.$id === 'sync_config') {
store.$onAction(({ name, args }) => {
if (name === 'setPreference') {
const { path, value } = args[0]
if (APPEARANCE_SETTINGS_KEYS.has(path)) {
applyStyleConfig(store.mergedConfig)
}
}
})
}
}

View file

@ -27,6 +27,7 @@ import {
import vuexModules from './modules/index.js' import vuexModules from './modules/index.js'
import { piniaLanguagePlugin } from 'src/lib/language.js' import { piniaLanguagePlugin } from 'src/lib/language.js'
import { piniaStylePlugin } from 'src/lib/style.js'
const currentLocale = (window.navigator.language || 'en').split('-')[0] const currentLocale = (window.navigator.language || 'en').split('-')[0]
@ -75,6 +76,7 @@ const persistedStateOptions = {
const pinia = createPinia() const pinia = createPinia()
pinia.use(piniaPersistPlugin()) pinia.use(piniaPersistPlugin())
pinia.use(piniaLanguagePlugin) pinia.use(piniaLanguagePlugin)
pinia.use(piniaStylePlugin)
pinia.use(piniaPushNotificationsPlugin) pinia.use(piniaPushNotificationsPlugin)
try { try {

View file

@ -1,27 +1,15 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { set } from 'lodash' import { set } from 'lodash'
import messages from '../i18n/messages'
import localeService from '../services/locale/locale.service.js'
import { applyConfig } from '../services/style_setter/style_setter.js'
import { defaultState, instanceDefaultConfig } from './default_config_state.js' import { defaultState, instanceDefaultConfig } from './default_config_state.js'
import { useI18nStore } from 'src/stores/i18n.js' import { useI18nStore } from 'src/stores/i18n.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import messages from 'src/i18n/messages'
import localeService from 'src/services/locale/locale.service.js'
const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage' const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage'
const APPEARANCE_SETTINGS_KEYS = new Set([
'sidebarColumnWidth',
'contentColumnWidth',
'notifsColumnWidth',
'themeEditorMinWidth',
'textSize',
'navbarSize',
'panelHeaderSize',
'forcedRoundness',
'emojiSize',
'emojiReactionsScale',
])
/* TODO this is a bit messy. /* TODO this is a bit messy.
* We need to declare settings with their types and also deal with * We need to declare settings with their types and also deal with
@ -46,7 +34,6 @@ const config = {
mutations: { mutations: {
setOptionTemporarily(state, { name, value }) { setOptionTemporarily(state, { name, value }) {
set(state, name, value) set(state, name, value)
applyConfig(state)
}, },
setOption(state, { name, value }) { setOption(state, { name, value }) {
set(state, name, value) set(state, name, value)
@ -95,9 +82,6 @@ const config = {
} }
} else { } else {
commit('setOption', { name, value }) commit('setOption', { name, value })
if (APPEARANCE_SETTINGS_KEYS.has(name)) {
applyConfig(state)
}
if (name.startsWith('theme3hacks')) { if (name.startsWith('theme3hacks')) {
dispatch('applyTheme', { recompile: true }) dispatch('applyTheme', { recompile: true })
} }

View file

@ -255,7 +255,7 @@ const extractStyleConfig = ({
const defaultStyleConfig = extractStyleConfig(defaultState) const defaultStyleConfig = extractStyleConfig(defaultState)
export const applyConfig = (input) => { export const applyStyleConfig = (input) => {
const config = extractStyleConfig(input) const config = extractStyleConfig(input)
if (config === defaultStyleConfig) { if (config === defaultStyleConfig) {

View file

@ -209,7 +209,6 @@ export const useEmojiStore = defineStore('emoji', {
) )
} }
console.log('EMOJI', useInstanceStore().server)
const emoji = Object.entries(values) const emoji = Object.entries(values)
.map(([key, value]) => { .map(([key, value]) => {
const imageUrl = value.image_url const imageUrl = value.image_url

View file

@ -243,7 +243,8 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
useSyncConfigStore().setPreference({ path: 'palette', value }) useSyncConfigStore().setPreference({ path: 'simple.palette', value })
useSyncConfigStore().pushSyncConfig()
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -251,7 +252,11 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
useSyncConfigStore().setPreference({ path: 'paletteCustomData', value }) useSyncConfigStore().setPreference({
path: 'simple.paletteCustomData',
value,
})
useSyncConfigStore().pushSyncConfig()
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -277,7 +282,8 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV2() this.resetThemeV2()
this.resetThemeV3Palette() this.resetThemeV3Palette()
useSyncConfigStore().setPreference({ path: 'style', value }) useSyncConfigStore().setPreference({ path: 'simple.style', value })
useSyncConfigStore().pushSyncConfig()
this.useStylePalette = true this.useStylePalette = true
this.applyTheme({ recompile: true }).then(() => { this.applyTheme({ recompile: true }).then(() => {
@ -289,7 +295,11 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV2() this.resetThemeV2()
this.resetThemeV3Palette() this.resetThemeV3Palette()
useSyncConfigStore().setPreference({ path: 'styleCustomData', value }) useSyncConfigStore().setPreference({
path: 'simple.styleCustomData',
value,
})
useSyncConfigStore().pushSyncConfig()
this.useStylePalette = true this.useStylePalette = true
this.applyTheme({ recompile: true }).then(() => { this.applyTheme({ recompile: true }).then(() => {
@ -315,7 +325,8 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
useSyncConfigStore().setPreference({ name: 'theme', value }) useSyncConfigStore().setPreference({ path: 'simple.theme', value })
useSyncConfigStore().pushSyncConfig()
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
@ -324,32 +335,45 @@ export const useInterfaceStore = defineStore('interface', {
this.resetThemeV3Palette() this.resetThemeV3Palette()
this.resetThemeV2() this.resetThemeV2()
useSyncConfigStore().setPreference({ path: 'customTheme', value }) useSyncConfigStore().setPreference({ path: 'simple.customTheme', value })
useSyncConfigStore().setPreference({ path: 'customThemeSource', value }) useSyncConfigStore().setPreference({
path: 'simple.customThemeSource',
value,
})
useSyncConfigStore().pushSyncConfig()
this.applyTheme({ recompile: true }) this.applyTheme({ recompile: true })
}, },
resetThemeV3() { resetThemeV3() {
useSyncConfigStore().setPreference({ path: 'style', value: null }) useSyncConfigStore().setPreference({ path: 'simple.style', value: null })
useSyncConfigStore().setPreference({ useSyncConfigStore().setPreference({
path: 'styleCustomData', path: 'simple.styleCustomData',
value: null, value: null,
}) })
useSyncConfigStore().pushSyncConfig()
}, },
resetThemeV3Palette() { resetThemeV3Palette() {
useSyncConfigStore().setPreference({ path: 'palette', value: null })
useSyncConfigStore().setPreference({ useSyncConfigStore().setPreference({
name: 'paletteCustomData', path: 'simple.palette',
value: null, value: null,
}) })
useSyncConfigStore().setPreference({
path: 'simple.paletteCustomData',
value: null,
})
useSyncConfigStore().pushSyncConfig()
}, },
resetThemeV2() { resetThemeV2() {
useSyncConfigStore().setPreference({ path: 'theme', value: null }) useSyncConfigStore().setPreference({ path: 'simple.theme', value: null })
useSyncConfigStore().setPreference({ path: 'customTheme', value: null })
useSyncConfigStore().setPreference({ useSyncConfigStore().setPreference({
path: 'customThemeSource', path: 'simple.customTheme',
value: null, value: null,
}) })
useSyncConfigStore().setPreference({
path: 'simple.customThemeSource',
value: null,
})
useSyncConfigStore().pushSyncConfig()
}, },
async getThemeData() { async getThemeData() {
const getData = async (resource, index, customData, name) => { const getData = async (resource, index, customData, name) => {
@ -406,13 +430,13 @@ export const useInterfaceStore = defineStore('interface', {
styleCustomData: userStyleCustomData, styleCustomData: userStyleCustomData,
palette: userPaletteName, palette: userPaletteName,
paletteCustomData: userPaletteCustomData, paletteCustomData: userPaletteCustomData,
} = window.vuex.state.config } = useSyncConfigStore().mergedConfig
let { let {
theme: userThemeV2Name, theme: userThemeV2Name,
customTheme: userThemeV2Snapshot, customTheme: userThemeV2Snapshot,
customThemeSource: userThemeV2Source, customThemeSource: userThemeV2Source,
} = window.vuex.state.config } = useSyncConfigStore().mergedConfig
let majorVersionUsed let majorVersionUsed
@ -516,9 +540,10 @@ export const useInterfaceStore = defineStore('interface', {
if (this.useStylePalette) { if (this.useStylePalette) {
useSyncConfigStore().setPreference({ useSyncConfigStore().setPreference({
path: 'palette', path: 'path.palette',
value: firstStylePaletteName, value: firstStylePaletteName,
}) })
useSyncConfigStore().pushSyncConfig()
} }
this.paletteNameUsed = palette.nameUsed this.paletteNameUsed = palette.nameUsed