quick fix to forced mode as well

This commit is contained in:
2026-04-06 14:24:08 +09:30
parent e657152e3f
commit ac1ee702ae
3 changed files with 70 additions and 16 deletions
+26 -5
View File
@@ -4,7 +4,10 @@
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
import { fade } 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' import { settingsState } from '@/seqta/utils/listeners/SettingsState'
@@ -40,6 +43,7 @@
coverImage: null, coverImage: null,
isEditable: true, isEditable: true,
hideThemeName: false, hideThemeName: false,
forceTheme: undefined,
forceDark: undefined, forceDark: undefined,
adaptiveCssVariables: [], adaptiveCssVariables: [],
}) })
@@ -84,6 +88,9 @@
theme = { theme = {
...loadedTheme, ...loadedTheme,
adaptiveCssVariables: loadedTheme.adaptiveCssVariables ?? [], adaptiveCssVariables: loadedTheme.adaptiveCssVariables ?? [],
forceTheme:
loadedTheme.forceTheme ??
(loadedTheme.forceDark !== undefined ? true : undefined),
} }
themeLoaded = true themeLoaded = true
} else { } else {
@@ -119,6 +126,13 @@
})) }))
themeClone.coverImage = theme.coverImage themeClone.coverImage = theme.coverImage
if (shouldForceThemeAppearance(themeClone)) {
themeClone.forceTheme = true;
} else {
themeClone.forceTheme = false;
themeClone.forceDark = undefined;
}
themeManager.clearPreview(); themeManager.clearPreview();
await themeManager.saveTheme(themeClone); await themeManager.saveTheme(themeClone);
await themeManager.setTheme(themeClone.id); await themeManager.setTheme(themeClone.id);
@@ -357,21 +371,28 @@
title: 'Force Theme', title: 'Force Theme',
description: 'Force users to use either dark or light mode', description: 'Force users to use either dark or light mode',
props: { props: {
state: theme.forceDark !== undefined, state: shouldForceThemeAppearance(theme),
onChange: (value: boolean) => theme = { ...theme, forceDark: value ? false : undefined } onChange: (value: boolean) => {
if (value) {
theme = { ...theme, forceTheme: true, forceDark: false };
} else {
theme = { ...theme, forceTheme: false, forceDark: undefined };
}
}
} }
}, },
{ {
type: 'conditional', type: 'conditional',
props: { props: {
condition: theme.forceDark !== undefined, condition: shouldForceThemeAppearance(theme),
children: { children: {
type: 'lightDarkToggle', type: 'lightDarkToggle',
title: 'Mode', title: 'Mode',
description: 'Choose whether to force light or dark mode', description: 'Choose whether to force light or dark mode',
props: { props: {
state: theme.forceDark === true, state: theme.forceDark === true,
onChange: (value: boolean) => theme = { ...theme, forceDark: value } onChange: (value: boolean) =>
(theme = { ...theme, forceDark: value, forceTheme: true })
} }
} }
} }
+24 -11
View File
@@ -1,6 +1,11 @@
import localforage from "localforage"; import localforage from "localforage";
import browser from "webextension-polyfill"; 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 { settingsState } from "@/seqta/utils/listeners/SettingsState";
import debounce from "@/seqta/utils/debounce"; import debounce from "@/seqta/utils/debounce";
import { updateAllColors } from "@/seqta/ui/colors/Manager"; import { updateAllColors } from "@/seqta/ui/colors/Manager";
@@ -19,6 +24,7 @@ type ThemeContent = {
CustomCSS?: string; CustomCSS?: string;
hideThemeName?: boolean; hideThemeName?: boolean;
forceDark?: boolean; forceDark?: boolean;
forceTheme?: boolean;
adaptiveCssVariables?: string[]; adaptiveCssVariables?: string[];
images: { id: string; variableName: string; data: string }[]; // data: base64 images: { id: string; variableName: string; data: string }[]; // data: base64
}; };
@@ -215,7 +221,7 @@ export class ThemeManager {
console.debug("[ThemeManager] Storing original settings"); console.debug("[ThemeManager] Storing original settings");
settingsState.originalSelectedColor = settingsState.selectedColor; settingsState.originalSelectedColor = settingsState.selectedColor;
if (theme.forceDark) { if (shouldForceThemeAppearance(theme)) {
settingsState.originalDarkMode = settingsState.DarkMode; settingsState.originalDarkMode = settingsState.DarkMode;
} }
} }
@@ -277,9 +283,10 @@ export class ThemeManager {
} }
// Apply theme settings // Apply theme settings
if (theme.forceDark !== undefined) { if (shouldForceThemeAppearance(theme)) {
console.debug("[ThemeManager] Setting dark mode:", theme.forceDark); const dark = getForcedDarkMode(theme);
settingsState.DarkMode = theme.forceDark; console.debug("[ThemeManager] Setting dark mode:", dark);
settingsState.DarkMode = dark;
} }
// Use the stored selected color if available, otherwise use the default // Use the stored selected color if available, otherwise use the default
@@ -595,6 +602,12 @@ export class ThemeManager {
isEditable: false, isEditable: false,
hideThemeName: themeData.hideThemeName ?? false, hideThemeName: themeData.hideThemeName ?? false,
forceDark: themeData.forceDark, forceDark: themeData.forceDark,
forceTheme:
themeData.forceTheme !== undefined
? themeData.forceTheme
: themeData.forceDark !== undefined
? true
: undefined,
adaptiveCssVariables: themeData.adaptiveCssVariables, adaptiveCssVariables: themeData.adaptiveCssVariables,
}; };
@@ -662,7 +675,7 @@ export class ThemeManager {
public async previewTheme(theme: LoadedCustomTheme): Promise<void> { public async previewTheme(theme: LoadedCustomTheme): Promise<void> {
console.debug("[ThemeManager] Previewing theme:", theme.name); console.debug("[ThemeManager] Previewing theme:", theme.name);
try { try {
const { CustomCSS, CustomImages, defaultColour, forceDark } = theme; const { CustomCSS, CustomImages, defaultColour } = theme;
// Store original settings only if this is a new theme // Store original settings only if this is a new theme
if (!theme.webURL) { if (!theme.webURL) {
@@ -708,8 +721,8 @@ export class ThemeManager {
this.previousImageVariableNames = newImageVariableNames; this.previousImageVariableNames = newImageVariableNames;
// Apply theme settings // Apply theme settings
if (forceDark !== undefined) { if (shouldForceThemeAppearance(theme)) {
settingsState.DarkMode = forceDark; settingsState.DarkMode = getForcedDarkMode(theme);
} }
if (defaultColour) { if (defaultColour) {
@@ -783,9 +796,9 @@ export class ThemeManager {
this.previousImageVariableNames = newImageVariableNames; this.previousImageVariableNames = newImageVariableNames;
} }
// Always apply dark mode setting // Always apply dark mode setting when theme forces appearance
if (theme.forceDark !== undefined) { if (shouldForceThemeAppearance(theme as CustomTheme)) {
settingsState.DarkMode = theme.forceDark; settingsState.DarkMode = getForcedDarkMode(theme as CustomTheme);
} }
// Only apply color if this is a new theme // Only apply color if this is a new theme
+20
View File
@@ -12,6 +12,11 @@ export type CustomTheme = {
hideThemeName: boolean; hideThemeName: boolean;
webURL?: string; webURL?: string;
selectedColor?: 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; forceDark?: boolean;
/** CSS custom property names (e.g. `--my-accent`) that receive the same value as `--better-main` when adaptive colours apply. */ /** CSS custom property names (e.g. `--my-accent`) that receive the same value as `--better-main` when adaptive colours apply. */
adaptiveCssVariables?: string[]; adaptiveCssVariables?: string[];
@@ -39,3 +44,18 @@ export type ThemeList = {
themes: CustomTheme[]; themes: CustomTheme[];
selectedTheme: string; 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;
}