diff --git a/src/SEQTA.ts b/src/SEQTA.ts index 6bb36d76..c74107ad 100644 --- a/src/SEQTA.ts +++ b/src/SEQTA.ts @@ -38,6 +38,7 @@ import documentLoadCSS from '@/css/documentload.scss?inline' import renderSvelte from '@/svelte-interface/main' import Settings from '@/svelte-interface/pages/settings.svelte' import { settingsPopup } from './svelte-interface/hooks/SettingsPopup' +import { OpenThemeCreator } from './seqta/ui/ThemeCreator' let SettingsClicked = false export let MenuOptionsOpen = false @@ -461,6 +462,8 @@ export async function finishLoad() { console.error("Error during loading cleanup:", err); } + OpenThemeCreator() + if (settingsState.justupdated && !document.getElementById('whatsnewbk')) { OpenWhatsNewPopup(); } diff --git a/src/seqta/ui/ThemeCreator.ts b/src/seqta/ui/ThemeCreator.ts index 2dee76e3..498aa380 100644 --- a/src/seqta/ui/ThemeCreator.ts +++ b/src/seqta/ui/ThemeCreator.ts @@ -1,6 +1,7 @@ import renderSvelte from "@/svelte-interface/main" import themeCreator from "@/svelte-interface/pages/themeCreator.svelte" import { unmount } from "svelte" +import { ClearThemePreview } from "./themes/UpdateThemePreview" let themeCreatorSvelteApp: any = null @@ -30,7 +31,11 @@ export function OpenThemeCreator(themeID: string = "") { const closeButton = document.createElement("button") closeButton.classList.add("themeCloseButton") closeButton.textContent = "×" - closeButton.addEventListener("click", CloseThemeCreator) + closeButton.addEventListener("click", () => { + CloseThemeCreator() + ClearThemePreview() + }) + document.body.appendChild(closeButton) const resizeBar = document.createElement("div") diff --git a/src/seqta/ui/themes/Themes.ts b/src/seqta/ui/themes/Themes.ts index 1462ebef..cd309d2b 100644 --- a/src/seqta/ui/themes/Themes.ts +++ b/src/seqta/ui/themes/Themes.ts @@ -1,17 +1,5 @@ -import { base64toblobURL } from '@/seqta/utils/imageConversions'; - export const imageData: Record = {}; -export const UpdateImageData = (image: { id: string; base64: string }) => { - const { id, base64 } = image; - - if (imageData[id]) { - imageData[id].url = base64toblobURL(base64); - const { variableName } = imageData[id]; - document.documentElement.style.setProperty('--' + variableName, `url(${imageData[id].url})`); - } -}; - export function applyCustomCSS(customCSS: string) { let styleElement = document.getElementById('custom-theme'); if (!styleElement) { diff --git a/src/seqta/ui/themes/UpdateThemePreview.ts b/src/seqta/ui/themes/UpdateThemePreview.ts index 08f1e23c..288ded87 100644 --- a/src/seqta/ui/themes/UpdateThemePreview.ts +++ b/src/seqta/ui/themes/UpdateThemePreview.ts @@ -1,65 +1,75 @@ -import type { CustomThemeBase64 } from '@/types/CustomThemes'; -import { applyCustomCSS, imageData, removeImageFromDocument, UpdateImageData } from './Themes'; +import type { LoadedCustomTheme } from '@/types/CustomThemes'; +import { applyCustomCSS, removeImageFromDocument } from './Themes'; import { settingsState } from '@/seqta/utils/listeners/SettingsState'; +let previousImageVariableNames: string[] = []; +let originalColor: string | null = null; +let originalTheme: boolean | null = null; -export const UpdateThemePreview = async (updatedTheme: CustomThemeBase64 /* Omit & { CustomImages: Omit[] } */) => { - const { CustomCSS, CustomImages, defaultColour } = updatedTheme; +export const UpdateThemePreview = async (updatedTheme: LoadedCustomTheme) => { + const { CustomCSS, CustomImages, defaultColour, forceDark } = updatedTheme; - if (updatedTheme.forceDark != undefined) { - if (updatedTheme.forceDark) { - settingsState.DarkMode = true; - } else { - settingsState.DarkMode = false; + // Update dark mode setting + if (forceDark !== undefined) { + // Store the original theme if it hasn't been stored yet + if (originalTheme === null) { + originalTheme = settingsState.DarkMode; } + settingsState.DarkMode = forceDark; } - // Update image data - const currentImageIds = Object.keys(imageData); - const updatedImageIds = CustomImages.map((image) => image.id); + // Get the new image variable names + const newImageVariableNames = CustomImages.map(image => image.variableName); - // Remove unused images from imageData and document - currentImageIds.forEach((imageId) => { - if (!updatedImageIds.includes(imageId)) { - const { variableName } = imageData[imageId]; + // Remove images that are no longer present + previousImageVariableNames.forEach(variableName => { + if (!newImageVariableNames.includes(variableName)) { removeImageFromDocument(variableName); - delete imageData[imageId]; } }); - // Update or add new images to imageData - CustomImages.forEach((image) => { - const existingImage = imageData[image.id]; - - if (existingImage && existingImage.variableName !== image.variableName) { - // Remove the previous variableName from the document - removeImageFromDocument(existingImage.variableName); - - // Update the variableName in imageData - imageData[image.id].variableName = image.variableName; - - // Update the variableName in the document - document.documentElement.style.setProperty('--' + image.variableName, `url(${existingImage.url})`); - } - - if (image.url) { - UpdateImageData({ - id: image.id, - base64: image.url - }); - } - - imageData[image.id] = { - url: imageData[image.id]?.url || '', - variableName: image.variableName, - }; + // Update or add new images + CustomImages.forEach((image: any) => { + document.documentElement.style.setProperty(`--${image.variableName}`, `url(${image.url})`); }); + // Update the previousImageVariableNames for the next run + previousImageVariableNames = newImageVariableNames; + // Apply custom CSS applyCustomCSS(CustomCSS); // Apply default color - if (defaultColour !== '') { - settingsState.selectedColor = defaultColour + if (defaultColour) { + // Store the original color if it hasn't been stored yet + if (originalColor === null) { + originalColor = settingsState.selectedColor; + } + settingsState.selectedColor = defaultColour; } }; + +export const ClearThemePreview = () => { + previousImageVariableNames.forEach(variableName => { + removeImageFromDocument(variableName); + }); + + previousImageVariableNames = []; + + let styleElement = document.getElementById('custom-theme'); + if (styleElement) { + styleElement.remove(); + } + + // Reset the color to the original value + if (originalColor !== null) { + settingsState.selectedColor = originalColor; + originalColor = null; + } + + // Reset the theme (dark/light mode) to the original value + if (originalTheme !== null) { + settingsState.DarkMode = originalTheme; + originalTheme = null; + } +} \ No newline at end of file diff --git a/src/seqta/ui/themes/saveTheme.ts b/src/seqta/ui/themes/saveTheme.ts index c1a272ae..febe17f8 100644 --- a/src/seqta/ui/themes/saveTheme.ts +++ b/src/seqta/ui/themes/saveTheme.ts @@ -1,27 +1,18 @@ import localforage from 'localforage'; -import type { CustomTheme, CustomThemeBase64 } from '@/types/CustomThemes'; +import type { LoadedCustomTheme } from '@/types/CustomThemes'; import { disableTheme } from './disableTheme'; -export const saveTheme = async (theme: CustomThemeBase64) => { +export const saveTheme = async (theme: LoadedCustomTheme) => { try { - const updatedTheme: CustomTheme = { - ...theme, - coverImage: theme.coverImage ? await fetch(theme.coverImage).then((res) => res.blob()) : null, - CustomImages: await Promise.all( - theme.CustomImages.map(async (image) => ({ - id: image.id, - blob: await fetch(image.url).then((res) => res.blob()), - variableName: image.variableName, - })) - ), - }; - disableTheme(); - console.debug('Theme to save:', updatedTheme); + console.debug('Theme to save:', theme); - await localforage.setItem(updatedTheme.id, updatedTheme); + /* remove blob urls from theme */ + const updatedTheme = { ...theme, CustomImages: theme.CustomImages.map((image) => ({ ...image, blob: null })) } + + await localforage.setItem(theme.id, updatedTheme); await localforage.getItem('customThemes').then((themes: unknown) => { const themeList = themes as string[] | null; if (themeList) { diff --git a/src/svelte-interface/pages/themeCreator.svelte b/src/svelte-interface/pages/themeCreator.svelte index c3b99b03..d288a4ca 100644 --- a/src/svelte-interface/pages/themeCreator.svelte +++ b/src/svelte-interface/pages/themeCreator.svelte @@ -22,6 +22,9 @@ handleImageVariableChange, handleCoverImageUpload } from '../utils/themeImageHandlers'; + import { ClearThemePreview, UpdateThemePreview } from '@/seqta/ui/themes/UpdateThemePreview' + import { saveTheme } from '@/seqta/ui/themes/saveTheme' + import { CloseThemeCreator } from '@/seqta/ui/ThemeCreator' const { themeID } = $props<{ themeID: string }>() let theme = $state({ @@ -83,8 +86,16 @@ theme = await handleCoverImageUpload(event, theme); } + function submitTheme() { + console.log('saving theme', theme) + + ClearThemePreview(); + saveTheme(theme); + CloseThemeCreator(); + } + $effect(() => { - + UpdateThemePreview(theme); }); type SettingType = 'switch' | 'button' | 'slider' | 'colourPicker' | 'select' | 'codeEditor' | 'imageUpload' | 'conditional' | 'lightDarkToggle'; @@ -314,9 +325,7 @@ {/each} diff --git a/src/types/CustomThemes.ts b/src/types/CustomThemes.ts index 78c2ec6b..79990f56 100644 --- a/src/types/CustomThemes.ts +++ b/src/types/CustomThemes.ts @@ -16,12 +16,12 @@ export type CustomTheme = { } export type LoadedCustomTheme = CustomTheme & { - CustomImages: Array<{ + CustomImages: { id: string; blob: Blob; variableName: string; url: string | null; - }>; + }[]; coverImageUrl?: string; }; @@ -35,17 +35,6 @@ export type CustomImage = { variableName: string; } -export type CustomImageBase64 = { - id: string; - url: string; - variableName: string; -} - -export type CustomThemeBase64 = Omit & { - CustomImages: CustomImageBase64[]; - coverImage: string | null; -} - export type ThemeList = { themes: CustomTheme[]; selectedTheme: string;