mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
fix(themes): theme wallpapers dont apply on firefox
This commit is contained in:
@@ -17,6 +17,12 @@ import {
|
||||
clearCustomThemeAdaptiveCssVariables,
|
||||
setCustomThemeAdaptiveCssVariables,
|
||||
} from "@/seqta/ui/colors/customThemeAdaptiveBindings";
|
||||
import {
|
||||
clearThemeInPage,
|
||||
syncThemeToPage,
|
||||
type ThemePageSyncInput,
|
||||
} from "@/seqta/utils/patchThemeImagesPageContext";
|
||||
import { verboseDebug, verboseInfo } from "@/utils/verboseLog";
|
||||
import {
|
||||
clearThemeRuntime,
|
||||
injectThemeDom,
|
||||
@@ -56,18 +62,15 @@ export type InstallThemeMeta = {
|
||||
export class ThemeManager {
|
||||
private static instance: ThemeManager;
|
||||
private currentTheme: CustomTheme | null = null;
|
||||
private styleElement: HTMLStyleElement | null = null;
|
||||
private previewStyleElement: HTMLStyleElement | null = null;
|
||||
private previousImageVariableNames: string[] = [];
|
||||
private lastSyncedImageKey: string | null = null;
|
||||
private originalPreviewColor: string | null = null;
|
||||
private originalPreviewTheme: boolean | null = null;
|
||||
private imageUrlCache: Map<string, string> = new Map();
|
||||
private lastTransitionPoint: { x: number; y: number } = { x: 0, y: 0 };
|
||||
private storeUpdateCheckRunning = false;
|
||||
private headObserver: MutationObserver | null = null;
|
||||
|
||||
private constructor() {
|
||||
console.debug("[ThemeManager] Initializing...");
|
||||
verboseDebug("[ThemeManager] Initializing...");
|
||||
}
|
||||
|
||||
public static getInstance(): ThemeManager {
|
||||
@@ -88,7 +91,7 @@ export class ThemeManager {
|
||||
* Get a theme by ID from storage
|
||||
*/
|
||||
public async getTheme(themeId: string): Promise<CustomTheme | null> {
|
||||
console.debug("[ThemeManager] Getting theme:", themeId);
|
||||
verboseDebug("[ThemeManager] Getting theme:", themeId);
|
||||
try {
|
||||
const theme = (await localforage.getItem(themeId)) as CustomTheme;
|
||||
return theme;
|
||||
@@ -164,17 +167,17 @@ export class ThemeManager {
|
||||
* Disable the current theme without deleting it
|
||||
*/
|
||||
public async disableTheme(): Promise<void> {
|
||||
console.debug("[ThemeManager] Disabling current theme");
|
||||
verboseDebug("[ThemeManager] Disabling current theme");
|
||||
try {
|
||||
if (!this.currentTheme) {
|
||||
console.debug("[ThemeManager] No theme to disable");
|
||||
verboseDebug("[ThemeManager] No theme to disable");
|
||||
return;
|
||||
}
|
||||
|
||||
await this.removeTheme(this.currentTheme);
|
||||
this.currentTheme = null;
|
||||
settingsState.selectedTheme = "";
|
||||
console.debug("[ThemeManager] Theme disabled successfully");
|
||||
verboseDebug("[ThemeManager] Theme disabled successfully");
|
||||
} catch (error) {
|
||||
console.error("[ThemeManager] Error disabling theme:", error);
|
||||
}
|
||||
@@ -211,7 +214,7 @@ export class ThemeManager {
|
||||
* Initialize the theme system and restore previous state
|
||||
*/
|
||||
public async initialize(): Promise<void> {
|
||||
console.debug("[ThemeManager] Starting initialization");
|
||||
verboseDebug("[ThemeManager] Starting initialization");
|
||||
try {
|
||||
const neumorphicThemeId = "9a9786d1-b5fc-4a91-8c7a-f8bf7f7679ad";
|
||||
const migrationCSS = "#title {\nbackground: transparent !important;\n}";
|
||||
@@ -224,7 +227,7 @@ export class ThemeManager {
|
||||
|
||||
const themeCreatorOpen = localStorage.getItem("themeCreatorOpen");
|
||||
if (themeCreatorOpen === "true") {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Theme creator was open, clearing preview state",
|
||||
);
|
||||
this.clearPreview();
|
||||
@@ -232,7 +235,7 @@ export class ThemeManager {
|
||||
}
|
||||
|
||||
if (settingsState.selectedTheme) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Found selected theme, restoring:",
|
||||
settingsState.selectedTheme,
|
||||
);
|
||||
@@ -249,7 +252,7 @@ export class ThemeManager {
|
||||
* Clean up theme system resources
|
||||
*/
|
||||
public async cleanup(): Promise<void> {
|
||||
console.debug("[ThemeManager] Cleaning up resources");
|
||||
verboseDebug("[ThemeManager] Cleaning up resources");
|
||||
try {
|
||||
if (this.currentTheme) {
|
||||
await this.removeTheme(this.currentTheme, false);
|
||||
@@ -263,7 +266,7 @@ export class ThemeManager {
|
||||
* Set and apply a theme by ID
|
||||
*/
|
||||
public async setTheme(themeId: string, applyViewTransition: boolean = true): Promise<void> {
|
||||
console.debug("[ThemeManager] Setting theme:", themeId);
|
||||
verboseDebug("[ThemeManager] Setting theme:", themeId);
|
||||
try {
|
||||
const theme = (await localforage.getItem(themeId)) as CustomTheme;
|
||||
if (!theme) {
|
||||
@@ -273,7 +276,7 @@ export class ThemeManager {
|
||||
|
||||
// Store original settings before applying new theme
|
||||
if (!settingsState.selectedTheme) {
|
||||
console.debug("[ThemeManager] Storing original settings");
|
||||
verboseDebug("[ThemeManager] Storing original settings");
|
||||
settingsState.originalSelectedColor = settingsState.selectedColor;
|
||||
|
||||
if (shouldForceThemeAppearance(theme)) {
|
||||
@@ -286,7 +289,7 @@ export class ThemeManager {
|
||||
await this.applyViewTransition(async () => {
|
||||
// Remove current theme if exists
|
||||
if (this.currentTheme) {
|
||||
console.debug("[ThemeManager] Removing current theme");
|
||||
verboseDebug("[ThemeManager] Removing current theme");
|
||||
await this.removeThemeWithoutTransition(this.currentTheme);
|
||||
}
|
||||
|
||||
@@ -298,7 +301,7 @@ export class ThemeManager {
|
||||
} else {
|
||||
// Remove current theme if exists
|
||||
if (this.currentTheme) {
|
||||
console.debug("[ThemeManager] Removing current theme");
|
||||
verboseDebug("[ThemeManager] Removing current theme");
|
||||
await this.removeThemeWithoutTransition(this.currentTheme);
|
||||
}
|
||||
|
||||
@@ -317,7 +320,7 @@ export class ThemeManager {
|
||||
* Apply theme components (CSS, images, settings)
|
||||
*/
|
||||
private async applyTheme(theme: CustomTheme): Promise<void> {
|
||||
console.debug("[ThemeManager] Applying theme:", theme.name);
|
||||
verboseDebug("[ThemeManager] Applying theme:", theme.name);
|
||||
try {
|
||||
// Run the theme script BEFORE injecting CustomCSS so any state the
|
||||
// script publishes (e.g. `data-city-state` and `--city-sky-color` for
|
||||
@@ -326,40 +329,34 @@ export class ThemeManager {
|
||||
// its previous state before snapping to the right colour.
|
||||
runThemeScript(theme.themeScript);
|
||||
|
||||
// Apply custom CSS
|
||||
if (theme.CustomCSS) {
|
||||
console.debug("[ThemeManager] Applying custom CSS");
|
||||
this.applyCustomCSS(theme.CustomCSS);
|
||||
}
|
||||
|
||||
// Apply custom images
|
||||
if (theme.CustomImages) {
|
||||
console.debug("[ThemeManager] Applying custom images");
|
||||
theme.CustomImages.forEach((image) => {
|
||||
const imageUrl = URL.createObjectURL(image.blob);
|
||||
document.documentElement.style.setProperty(
|
||||
"--" + image.variableName,
|
||||
`url(${imageUrl})`,
|
||||
);
|
||||
});
|
||||
// Custom CSS + images must be applied in page context (Firefox).
|
||||
verboseDebug("[ThemeManager] Applying theme styles in page context");
|
||||
await syncThemeToPage({
|
||||
customCss: theme.CustomCSS || "",
|
||||
images: theme.CustomImages ?? [],
|
||||
});
|
||||
if (theme.CustomImages?.length) {
|
||||
this.lastSyncedImageKey = this.imageSyncKey(theme.CustomImages);
|
||||
} else {
|
||||
this.lastSyncedImageKey = null;
|
||||
}
|
||||
|
||||
// Apply theme settings
|
||||
if (shouldForceThemeAppearance(theme)) {
|
||||
const dark = getForcedDarkMode(theme);
|
||||
console.debug("[ThemeManager] Setting dark mode:", dark);
|
||||
verboseDebug("[ThemeManager] Setting dark mode:", dark);
|
||||
settingsState.DarkMode = dark;
|
||||
}
|
||||
|
||||
// Use the stored selected color if available, otherwise use the default
|
||||
if (theme.selectedColor) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Restoring saved color:",
|
||||
theme.selectedColor,
|
||||
);
|
||||
settingsState.selectedColor = theme.selectedColor;
|
||||
} else if (theme.defaultColour) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Using default color:",
|
||||
theme.defaultColour,
|
||||
);
|
||||
@@ -381,7 +378,7 @@ export class ThemeManager {
|
||||
theme: CustomTheme,
|
||||
clearSelectedTheme: boolean = true,
|
||||
): Promise<void> {
|
||||
console.debug("[ThemeManager] Removing theme with transition:", theme.name);
|
||||
verboseDebug("[ThemeManager] Removing theme with transition:", theme.name);
|
||||
try {
|
||||
await this.applyViewTransition(async () => {
|
||||
await this.removeThemeWithoutTransition(theme, clearSelectedTheme);
|
||||
@@ -398,37 +395,13 @@ export class ThemeManager {
|
||||
theme: CustomTheme,
|
||||
clearSelectedTheme: boolean = true,
|
||||
): Promise<void> {
|
||||
console.debug("[ThemeManager] Removing theme:", theme.name);
|
||||
verboseDebug("[ThemeManager] Removing theme:", theme.name);
|
||||
try {
|
||||
clearThemeRuntime();
|
||||
|
||||
// Disconnect the head observer BEFORE removing the style element,
|
||||
// otherwise the removal fires the observer and it would no-op only
|
||||
// because the style is already gone — wasted work, but harmless.
|
||||
this.disconnectStyleObserver();
|
||||
|
||||
// Remove custom CSS
|
||||
if (this.styleElement) {
|
||||
console.debug("[ThemeManager] Removing custom CSS");
|
||||
this.styleElement.remove();
|
||||
this.styleElement = null;
|
||||
}
|
||||
|
||||
// Remove custom images
|
||||
if (theme.CustomImages) {
|
||||
console.debug("[ThemeManager] Removing custom images");
|
||||
theme.CustomImages.forEach((image) => {
|
||||
const value = document.documentElement.style.getPropertyValue(
|
||||
"--" + image.variableName,
|
||||
);
|
||||
if (value) {
|
||||
URL.revokeObjectURL(value.slice(4, -1)); // Remove url() wrapper
|
||||
}
|
||||
document.documentElement.style.removeProperty(
|
||||
"--" + image.variableName,
|
||||
);
|
||||
});
|
||||
}
|
||||
verboseDebug("[ThemeManager] Removing theme page styles");
|
||||
clearThemeInPage();
|
||||
this.lastSyncedImageKey = null;
|
||||
|
||||
if (this.currentTheme) {
|
||||
// Store the current color with the theme before removing it
|
||||
@@ -449,7 +422,7 @@ export class ThemeManager {
|
||||
|
||||
// Restore original settings
|
||||
if (settingsState.originalSelectedColor) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Restoring original color:",
|
||||
settingsState.originalSelectedColor,
|
||||
);
|
||||
@@ -457,7 +430,7 @@ export class ThemeManager {
|
||||
}
|
||||
|
||||
if (settingsState.originalDarkMode !== undefined) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Restoring original dark mode:",
|
||||
settingsState.originalDarkMode,
|
||||
);
|
||||
@@ -476,58 +449,21 @@ export class ThemeManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply custom CSS to the document. The `<style>` element is always
|
||||
* re-appended to the end of `<head>` so it wins specificity ties
|
||||
* against any styles SEQTA's late-loading injected.scss adds in dev
|
||||
* mode (where `import("@/css/injected.scss")` is fire-and-forget and
|
||||
* can resolve after the theme has already been applied). The head
|
||||
* observer below keeps us at the end if anything else gets appended
|
||||
* later (Vite HMR, another script-injected stylesheet, etc.).
|
||||
* Stable key so preview updates can skip re-encoding image blobs when only CSS changed.
|
||||
*/
|
||||
private applyCustomCSS(css: string): void {
|
||||
console.debug("[ThemeManager] Applying custom CSS");
|
||||
try {
|
||||
if (!this.styleElement) {
|
||||
this.styleElement = document.createElement("style");
|
||||
this.styleElement.id = "custom-theme";
|
||||
}
|
||||
this.styleElement.textContent = css;
|
||||
document.head.appendChild(this.styleElement);
|
||||
this.ensureStyleStaysLast();
|
||||
} catch (error) {
|
||||
console.error("[ThemeManager] Error applying custom CSS:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch `<head>` for any child-list changes and re-append the theme
|
||||
* style element if anything has been added after it. Idempotent: the
|
||||
* observer's own re-append fires the callback again, but the early
|
||||
* `lastElementChild === style` check short-circuits the second pass.
|
||||
*/
|
||||
private ensureStyleStaysLast(): void {
|
||||
if (this.headObserver) return;
|
||||
this.headObserver = new MutationObserver(() => {
|
||||
const style = this.styleElement;
|
||||
if (!style || !document.head.contains(style)) return;
|
||||
if (document.head.lastElementChild === style) return;
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
this.headObserver.observe(document.head, { childList: true });
|
||||
}
|
||||
|
||||
private disconnectStyleObserver(): void {
|
||||
if (this.headObserver) {
|
||||
this.headObserver.disconnect();
|
||||
this.headObserver = null;
|
||||
}
|
||||
private imageSyncKey(
|
||||
images: Array<{ id: string; variableName: string; blob: Blob }>,
|
||||
): string {
|
||||
return images
|
||||
.map((image) => `${image.id}:${image.variableName}:${image.blob.size}`)
|
||||
.join("|");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of available themes
|
||||
*/
|
||||
public async getAvailableThemes(): Promise<CustomTheme[]> {
|
||||
console.debug("[ThemeManager] Getting available themes");
|
||||
verboseDebug("[ThemeManager] Getting available themes");
|
||||
try {
|
||||
const themeIds = (await localforage.getItem("customThemes")) as
|
||||
| string[]
|
||||
@@ -553,7 +489,7 @@ export class ThemeManager {
|
||||
* Save or update a theme
|
||||
*/
|
||||
public async saveTheme(theme: LoadedCustomTheme): Promise<void> {
|
||||
console.debug("[ThemeManager] Saving theme:", theme.name);
|
||||
verboseDebug("[ThemeManager] Saving theme:", theme.name);
|
||||
try {
|
||||
const existing = (await localforage.getItem(theme.id)) as CustomTheme | null;
|
||||
let toSave = theme;
|
||||
@@ -583,7 +519,7 @@ export class ThemeManager {
|
||||
* Delete a theme
|
||||
*/
|
||||
public async deleteTheme(themeId: string): Promise<void> {
|
||||
console.debug("[ThemeManager] Deleting theme:", themeId);
|
||||
verboseDebug("[ThemeManager] Deleting theme:", themeId);
|
||||
try {
|
||||
const theme = (await localforage.getItem(themeId)) as CustomTheme;
|
||||
if (theme) {
|
||||
@@ -653,7 +589,7 @@ export class ThemeManager {
|
||||
theme_json_url?: string;
|
||||
updated_at?: number;
|
||||
}): Promise<void> {
|
||||
console.debug("[ThemeManager] Downloading theme:", themeContent.name);
|
||||
verboseDebug("[ThemeManager] Downloading theme:", themeContent.name);
|
||||
if (!themeContent.id) {
|
||||
throw new Error("Missing theme id");
|
||||
}
|
||||
@@ -689,7 +625,7 @@ export class ThemeManager {
|
||||
themeData: ThemeContent,
|
||||
meta?: InstallThemeMeta,
|
||||
): Promise<void> {
|
||||
console.debug("[ThemeManager] Installing theme:", themeData.name);
|
||||
verboseDebug("[ThemeManager] Installing theme:", themeData.name);
|
||||
try {
|
||||
// Validate required fields
|
||||
if (!themeData.id || !themeData.name) {
|
||||
@@ -860,7 +796,7 @@ export class ThemeManager {
|
||||
name: theme.name,
|
||||
updated_at: serverUpdated,
|
||||
});
|
||||
console.log(
|
||||
verboseInfo(
|
||||
"[ThemeManager] Theme auto-updated from store:",
|
||||
theme.name,
|
||||
);
|
||||
@@ -893,7 +829,7 @@ export class ThemeManager {
|
||||
* Share a theme by exporting it
|
||||
*/
|
||||
public async shareTheme(themeId: string): Promise<void> {
|
||||
console.debug("[ThemeManager] Sharing theme:", themeId);
|
||||
verboseDebug("[ThemeManager] Sharing theme:", themeId);
|
||||
try {
|
||||
const theme = (await localforage.getItem(themeId)) as LoadedCustomTheme;
|
||||
if (!theme) {
|
||||
@@ -947,7 +883,7 @@ export class ThemeManager {
|
||||
* Preview a theme without applying it
|
||||
*/
|
||||
public async previewTheme(theme: LoadedCustomTheme): Promise<void> {
|
||||
console.debug("[ThemeManager] Previewing theme:", theme.name);
|
||||
verboseDebug("[ThemeManager] Previewing theme:", theme.name);
|
||||
try {
|
||||
const { CustomCSS, CustomImages, defaultColour } = theme;
|
||||
|
||||
@@ -965,35 +901,16 @@ export class ThemeManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply custom CSS
|
||||
if (CustomCSS) {
|
||||
this.applyPreviewCSS(CustomCSS);
|
||||
}
|
||||
|
||||
// Apply custom images
|
||||
const newImageVariableNames = CustomImages.map(
|
||||
// Apply custom CSS + images in page context (preview stylesheet)
|
||||
await syncThemeToPage({
|
||||
previewCss: CustomCSS,
|
||||
images: CustomImages,
|
||||
});
|
||||
this.lastSyncedImageKey = this.imageSyncKey(CustomImages);
|
||||
this.previousImageVariableNames = CustomImages.map(
|
||||
(image) => image.variableName,
|
||||
);
|
||||
|
||||
// Remove old preview images
|
||||
this.previousImageVariableNames.forEach((variableName) => {
|
||||
if (!newImageVariableNames.includes(variableName)) {
|
||||
this.removeImageFromDocument(variableName);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply new images
|
||||
CustomImages.forEach((image) => {
|
||||
const imageUrl = URL.createObjectURL(image.blob);
|
||||
document.documentElement.style.setProperty(
|
||||
`--${image.variableName}`,
|
||||
`url(${imageUrl})`,
|
||||
);
|
||||
});
|
||||
|
||||
// Update previousImageVariableNames
|
||||
this.previousImageVariableNames = newImageVariableNames;
|
||||
|
||||
// Apply theme settings
|
||||
if (shouldForceThemeAppearance(theme)) {
|
||||
settingsState.DarkMode = getForcedDarkMode(theme);
|
||||
@@ -1014,7 +931,7 @@ export class ThemeManager {
|
||||
* Update the preview of a theme in real-time (for theme creator)
|
||||
*/
|
||||
public async updatePreview(theme: Partial<LoadedCustomTheme>): Promise<void> {
|
||||
console.debug("[ThemeManager] Updating theme preview");
|
||||
verboseDebug("[ThemeManager] Updating theme preview");
|
||||
try {
|
||||
// Only store original settings if this is a new theme (not editing)
|
||||
// We can tell it's a new theme if it has no webURL (which is set when a theme is saved/loaded)
|
||||
@@ -1027,49 +944,28 @@ export class ThemeManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply CSS if changed
|
||||
const newImageVariableNames =
|
||||
theme.CustomImages?.map((image) => image.variableName) ?? [];
|
||||
|
||||
const syncInput: ThemePageSyncInput = {};
|
||||
|
||||
if (theme.CustomCSS !== undefined) {
|
||||
this.applyPreviewCSS(theme.CustomCSS);
|
||||
syncInput.previewCss = theme.CustomCSS;
|
||||
}
|
||||
|
||||
// Handle images if present
|
||||
if (theme.CustomImages) {
|
||||
const newImageVariableNames = theme.CustomImages.map(
|
||||
(image) => image.variableName,
|
||||
);
|
||||
|
||||
// Remove old preview images that are no longer present
|
||||
this.previousImageVariableNames.forEach((variableName) => {
|
||||
if (!newImageVariableNames.includes(variableName)) {
|
||||
this.removeImageFromDocument(variableName);
|
||||
// Clean up cached URL
|
||||
this.imageUrlCache.delete(variableName);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply or update images
|
||||
theme.CustomImages.forEach((image) => {
|
||||
const existingUrl = this.imageUrlCache.get(image.variableName);
|
||||
if (!existingUrl) {
|
||||
// Only create new URL if one doesn't exist
|
||||
const imageUrl = URL.createObjectURL(image.blob);
|
||||
this.imageUrlCache.set(image.variableName, imageUrl);
|
||||
document.documentElement.style.setProperty(
|
||||
`--${image.variableName}`,
|
||||
`url(${imageUrl})`,
|
||||
);
|
||||
} else {
|
||||
// Reuse existing URL
|
||||
document.documentElement.style.setProperty(
|
||||
`--${image.variableName}`,
|
||||
`url(${existingUrl})`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const imageKey = this.imageSyncKey(theme.CustomImages);
|
||||
if (imageKey !== this.lastSyncedImageKey) {
|
||||
syncInput.images = theme.CustomImages;
|
||||
this.lastSyncedImageKey = imageKey;
|
||||
}
|
||||
this.previousImageVariableNames = newImageVariableNames;
|
||||
}
|
||||
|
||||
if (Object.keys(syncInput).length > 0) {
|
||||
await syncThemeToPage(syncInput);
|
||||
}
|
||||
|
||||
// Always apply dark mode setting when theme forces appearance
|
||||
if (shouldForceThemeAppearance(theme as CustomTheme)) {
|
||||
settingsState.DarkMode = getForcedDarkMode(theme as CustomTheme);
|
||||
@@ -1102,23 +998,12 @@ export class ThemeManager {
|
||||
* Clear theme preview
|
||||
*/
|
||||
public clearPreview(): void {
|
||||
console.debug("[ThemeManager] Clearing theme preview");
|
||||
verboseDebug("[ThemeManager] Clearing theme preview");
|
||||
try {
|
||||
// Remove preview images and revoke URLs
|
||||
this.previousImageVariableNames.forEach((variableName) => {
|
||||
this.removeImageFromDocument(variableName);
|
||||
});
|
||||
// Clear all cached URLs
|
||||
this.imageUrlCache.forEach((url) => URL.revokeObjectURL(url));
|
||||
this.imageUrlCache.clear();
|
||||
void syncThemeToPage({ clearPreview: true, images: [] });
|
||||
this.lastSyncedImageKey = null;
|
||||
this.previousImageVariableNames = [];
|
||||
|
||||
// Remove preview CSS
|
||||
if (this.previewStyleElement) {
|
||||
this.previewStyleElement.remove();
|
||||
this.previewStyleElement = null;
|
||||
}
|
||||
|
||||
clearCustomThemeAdaptiveCssVariables();
|
||||
|
||||
// Restore original settings
|
||||
@@ -1128,22 +1013,22 @@ export class ThemeManager {
|
||||
settingsState.selectedColor = storedColor;
|
||||
localStorage.removeItem("originalPreviewColor");
|
||||
} else if (this.originalPreviewColor !== null) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Restoring color from memory:",
|
||||
this.originalPreviewColor,
|
||||
);
|
||||
settingsState.selectedColor = this.originalPreviewColor;
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Color after restore:",
|
||||
settingsState.selectedColor,
|
||||
);
|
||||
} else {
|
||||
console.debug("[ThemeManager] No color to restore found");
|
||||
verboseDebug("[ThemeManager] No color to restore found");
|
||||
}
|
||||
this.originalPreviewColor = null;
|
||||
|
||||
if (this.originalPreviewTheme !== null) {
|
||||
console.debug(
|
||||
verboseDebug(
|
||||
"[ThemeManager] Restoring dark mode:",
|
||||
this.originalPreviewTheme,
|
||||
);
|
||||
@@ -1218,36 +1103,4 @@ export class ThemeManager {
|
||||
console.error("[ThemeManager] Error saving theme file:", err);
|
||||
}
|
||||
}
|
||||
|
||||
private removeImageFromDocument(variableName: string): void {
|
||||
try {
|
||||
const value = document.documentElement.style.getPropertyValue(
|
||||
"--" + variableName,
|
||||
);
|
||||
if (value) {
|
||||
const url = this.imageUrlCache.get(variableName);
|
||||
if (url) {
|
||||
URL.revokeObjectURL(url);
|
||||
this.imageUrlCache.delete(variableName);
|
||||
}
|
||||
}
|
||||
document.documentElement.style.removeProperty("--" + variableName);
|
||||
} catch (err) {
|
||||
console.error("[ThemeManager] Error removing image from document:", err);
|
||||
}
|
||||
}
|
||||
|
||||
private applyPreviewCSS(css: string): void {
|
||||
console.debug("[ThemeManager] Applying preview CSS");
|
||||
try {
|
||||
if (!this.previewStyleElement) {
|
||||
this.previewStyleElement = document.createElement("style");
|
||||
this.previewStyleElement.id = "custom-theme-preview";
|
||||
document.head.appendChild(this.previewStyleElement);
|
||||
}
|
||||
this.previewStyleElement.textContent = css;
|
||||
} catch (error) {
|
||||
console.error("[ThemeManager] Error applying preview CSS:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user