From ac1ee702aec2cc98fc13afb66e723703b3463e69 Mon Sep 17 00:00:00 2001 From: StroepWafel Date: Mon, 6 Apr 2026 14:24:08 +0930 Subject: [PATCH] quick fix to forced mode as well --- src/interface/pages/themeCreator.svelte | 31 ++++++++++++++--- src/plugins/built-in/themes/theme-manager.ts | 35 ++++++++++++++------ src/types/CustomThemes.ts | 20 +++++++++++ 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/interface/pages/themeCreator.svelte b/src/interface/pages/themeCreator.svelte index a51b7e58..d8da6b95 100644 --- a/src/interface/pages/themeCreator.svelte +++ b/src/interface/pages/themeCreator.svelte @@ -4,7 +4,10 @@ import { slide } from 'svelte/transition'; import { fade } from 'svelte/transition'; - import { type LoadedCustomTheme } from '@/types/CustomThemes' + import { + type LoadedCustomTheme, + shouldForceThemeAppearance, + } from '@/types/CustomThemes' import { settingsState } from '@/seqta/utils/listeners/SettingsState' @@ -40,6 +43,7 @@ coverImage: null, isEditable: true, hideThemeName: false, + forceTheme: undefined, forceDark: undefined, adaptiveCssVariables: [], }) @@ -84,6 +88,9 @@ theme = { ...loadedTheme, adaptiveCssVariables: loadedTheme.adaptiveCssVariables ?? [], + forceTheme: + loadedTheme.forceTheme ?? + (loadedTheme.forceDark !== undefined ? true : undefined), } themeLoaded = true } else { @@ -119,6 +126,13 @@ })) themeClone.coverImage = theme.coverImage + if (shouldForceThemeAppearance(themeClone)) { + themeClone.forceTheme = true; + } else { + themeClone.forceTheme = false; + themeClone.forceDark = undefined; + } + themeManager.clearPreview(); await themeManager.saveTheme(themeClone); await themeManager.setTheme(themeClone.id); @@ -357,21 +371,28 @@ title: 'Force Theme', description: 'Force users to use either dark or light mode', props: { - state: theme.forceDark !== undefined, - onChange: (value: boolean) => theme = { ...theme, forceDark: value ? false : undefined } + state: shouldForceThemeAppearance(theme), + onChange: (value: boolean) => { + if (value) { + theme = { ...theme, forceTheme: true, forceDark: false }; + } else { + theme = { ...theme, forceTheme: false, forceDark: undefined }; + } + } } }, { type: 'conditional', props: { - condition: theme.forceDark !== undefined, + condition: shouldForceThemeAppearance(theme), children: { type: 'lightDarkToggle', title: 'Mode', description: 'Choose whether to force light or dark mode', props: { state: theme.forceDark === true, - onChange: (value: boolean) => theme = { ...theme, forceDark: value } + onChange: (value: boolean) => + (theme = { ...theme, forceDark: value, forceTheme: true }) } } } diff --git a/src/plugins/built-in/themes/theme-manager.ts b/src/plugins/built-in/themes/theme-manager.ts index cd499c3a..64ac26c8 100644 --- a/src/plugins/built-in/themes/theme-manager.ts +++ b/src/plugins/built-in/themes/theme-manager.ts @@ -1,6 +1,11 @@ import localforage from "localforage"; import browser from "webextension-polyfill"; -import type { CustomTheme, LoadedCustomTheme } from "@/types/CustomThemes"; +import { + type CustomTheme, + type LoadedCustomTheme, + getForcedDarkMode, + shouldForceThemeAppearance, +} from "@/types/CustomThemes"; import { settingsState } from "@/seqta/utils/listeners/SettingsState"; import debounce from "@/seqta/utils/debounce"; import { updateAllColors } from "@/seqta/ui/colors/Manager"; @@ -19,6 +24,7 @@ type ThemeContent = { CustomCSS?: string; hideThemeName?: boolean; forceDark?: boolean; + forceTheme?: boolean; adaptiveCssVariables?: string[]; images: { id: string; variableName: string; data: string }[]; // data: base64 }; @@ -215,7 +221,7 @@ export class ThemeManager { console.debug("[ThemeManager] Storing original settings"); settingsState.originalSelectedColor = settingsState.selectedColor; - if (theme.forceDark) { + if (shouldForceThemeAppearance(theme)) { settingsState.originalDarkMode = settingsState.DarkMode; } } @@ -277,9 +283,10 @@ export class ThemeManager { } // Apply theme settings - if (theme.forceDark !== undefined) { - console.debug("[ThemeManager] Setting dark mode:", theme.forceDark); - settingsState.DarkMode = theme.forceDark; + if (shouldForceThemeAppearance(theme)) { + const dark = getForcedDarkMode(theme); + console.debug("[ThemeManager] Setting dark mode:", dark); + settingsState.DarkMode = dark; } // Use the stored selected color if available, otherwise use the default @@ -595,6 +602,12 @@ export class ThemeManager { isEditable: false, hideThemeName: themeData.hideThemeName ?? false, forceDark: themeData.forceDark, + forceTheme: + themeData.forceTheme !== undefined + ? themeData.forceTheme + : themeData.forceDark !== undefined + ? true + : undefined, adaptiveCssVariables: themeData.adaptiveCssVariables, }; @@ -662,7 +675,7 @@ export class ThemeManager { public async previewTheme(theme: LoadedCustomTheme): Promise { console.debug("[ThemeManager] Previewing theme:", theme.name); try { - const { CustomCSS, CustomImages, defaultColour, forceDark } = theme; + const { CustomCSS, CustomImages, defaultColour } = theme; // Store original settings only if this is a new theme if (!theme.webURL) { @@ -708,8 +721,8 @@ export class ThemeManager { this.previousImageVariableNames = newImageVariableNames; // Apply theme settings - if (forceDark !== undefined) { - settingsState.DarkMode = forceDark; + if (shouldForceThemeAppearance(theme)) { + settingsState.DarkMode = getForcedDarkMode(theme); } if (defaultColour) { @@ -783,9 +796,9 @@ export class ThemeManager { this.previousImageVariableNames = newImageVariableNames; } - // Always apply dark mode setting - if (theme.forceDark !== undefined) { - settingsState.DarkMode = theme.forceDark; + // Always apply dark mode setting when theme forces appearance + if (shouldForceThemeAppearance(theme as CustomTheme)) { + settingsState.DarkMode = getForcedDarkMode(theme as CustomTheme); } // Only apply color if this is a new theme diff --git a/src/types/CustomThemes.ts b/src/types/CustomThemes.ts index 92498428..6ff7def4 100644 --- a/src/types/CustomThemes.ts +++ b/src/types/CustomThemes.ts @@ -12,6 +12,11 @@ export type CustomTheme = { hideThemeName: boolean; webURL?: string; selectedColor?: string; + /** + * When true, the theme forces light/dark via `forceDark` (`false` = light, `true` = dark). + * When false/omitted, use legacy rule: `forceDark !== undefined` still means "force" for old JSON. + */ + forceTheme?: boolean; forceDark?: boolean; /** CSS custom property names (e.g. `--my-accent`) that receive the same value as `--better-main` when adaptive colours apply. */ adaptiveCssVariables?: string[]; @@ -39,3 +44,18 @@ export type ThemeList = { themes: CustomTheme[]; selectedTheme: string; }; + +/** Whether the theme forces appearance (light vs dark). */ +export function shouldForceThemeAppearance(theme: { + forceTheme?: boolean; + forceDark?: boolean; +}): boolean { + if (theme.forceTheme === true) return true; + if (theme.forceTheme === false) return false; + return theme.forceDark !== undefined; +} + +/** Resolved forced dark mode when forcing is active. */ +export function getForcedDarkMode(theme: { forceDark?: boolean }): boolean { + return theme.forceDark === true; +}