From 97e328c7e5b42a4cd8435f8cf78aa55be211070a Mon Sep 17 00:00:00 2001 From: daniaGit123 Date: Sun, 30 Aug 2026 19:35:11 +0300 Subject: [PATCH 1/2] P1A --- .devcontainer/devcontainer.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f7e0298e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,5 @@ +{ + "name": "Project 1A", + "image": "node:24-slim", + "workspaces": ["packages/*"] +} \ No newline at end of file From 1428d2d32e5301f3d47a9e5179236895a5f45cc3 Mon Sep 17 00:00:00 2001 From: daniaGit123 Date: Thu, 3 Sep 2026 18:20:08 +0300 Subject: [PATCH 2/2] Refactor onStorage to reduce complexity by extracting helper function --- packages/ui/src/theme/context.tsx | 759 +++++++++++++++--------------- 1 file changed, 386 insertions(+), 373 deletions(-) diff --git a/packages/ui/src/theme/context.tsx b/packages/ui/src/theme/context.tsx index f225ee33..5bf54980 100644 --- a/packages/ui/src/theme/context.tsx +++ b/packages/ui/src/theme/context.tsx @@ -1,373 +1,386 @@ -// @refresh reload - -import { createEffect, onMount } from "solid-js" -import { createStore } from "solid-js/store" -import { makeEventListener } from "@solid-primitives/event-listener" -import { createSimpleContext } from "../context/helper" -import oc2ThemeJson from "./themes/oc-2.json" -import { resolveThemeVariant, themeToCss } from "./resolve" -import { resolveThemeVariantV2, themeV2ToCss } from "./v2/resolve" -import type { DesktopTheme } from "./types" - -export type ColorScheme = "light" | "dark" | "system" - -const STORAGE_KEYS = { - THEME_ID: "opencode-theme-id", - COLOR_SCHEME: "opencode-color-scheme", - THEME_CSS_LIGHT: "opencode-theme-css-light", - THEME_CSS_DARK: "opencode-theme-css-dark", -} as const - -const THEME_STYLE_ID = "oc-theme" -let files: Record Promise<{ default: DesktopTheme }>> | undefined -let ids: string[] | undefined -let known: Set | undefined - -function getFiles() { - if (files) return files - files = import.meta.glob<{ default: DesktopTheme }>("./themes/*.json") - return files -} - -function themeIDs() { - if (ids) return ids - ids = Object.keys(getFiles()) - .map((path) => path.slice("./themes/".length, -".json".length)) - .sort() - return ids -} - -function knownThemes() { - if (known) return known - known = new Set(themeIDs()) - return known -} - -const names: Record = { - "oc-2": "OC-2", - amoled: "AMOLED", - aura: "Aura", - ayu: "Ayu", - carbonfox: "Carbonfox", - catppuccin: "Catppuccin", - "catppuccin-frappe": "Catppuccin Frappe", - "catppuccin-macchiato": "Catppuccin Macchiato", - cobalt2: "Cobalt2", - cursor: "Cursor", - dracula: "Dracula", - everforest: "Everforest", - flexoki: "Flexoki", - github: "GitHub", - gruvbox: "Gruvbox", - kanagawa: "Kanagawa", - "lucent-orng": "Lucent Orng", - material: "Material", - matrix: "Matrix", - mercury: "Mercury", - monokai: "Monokai", - nightowl: "Night Owl", - nord: "Nord", - "one-dark": "One Dark", - onedarkpro: "One Dark Pro", - opencode: "OpenCode", - orng: "Orng", - "osaka-jade": "Osaka Jade", - palenight: "Palenight", - rosepine: "Rose Pine", - shadesofpurple: "Shades of Purple", - solarized: "Solarized", - synthwave84: "Synthwave '84", - tokyonight: "Tokyonight", - vercel: "Vercel", - vesper: "Vesper", - zenburn: "Zenburn", -} -const oc2Theme = oc2ThemeJson as DesktopTheme - -function normalize(id: string | null | undefined) { - return id === "oc-1" ? "oc-2" : id -} - -function read(key: string) { - if (typeof localStorage !== "object") return null - try { - return localStorage.getItem(key) - } catch { - return null - } -} - -function write(key: string, value: string) { - if (typeof localStorage !== "object") return - try { - localStorage.setItem(key, value) - } catch {} -} - -function drop(key: string) { - if (typeof localStorage !== "object") return - try { - localStorage.removeItem(key) - } catch {} -} - -function clear() { - drop(STORAGE_KEYS.THEME_CSS_LIGHT) - drop(STORAGE_KEYS.THEME_CSS_DARK) -} - -function ensureThemeStyleElement(): HTMLStyleElement { - const existing = document.getElementById(THEME_STYLE_ID) as HTMLStyleElement | null - if (existing) return existing - const element = document.createElement("style") - element.id = THEME_STYLE_ID - document.head.appendChild(element) - return element -} - -function getSystemMode(): "light" | "dark" { - if (typeof window !== "object") return "light" - return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" -} - -function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "dark") { - const isDark = mode === "dark" - const variant = isDark ? theme.dark : theme.light - const tokens = resolveThemeVariant(variant, isDark) - const css = themeToCss(tokens) - const v2 = themeV2ToCss(resolveThemeVariantV2(variant, isDark)) - - if (themeId !== "oc-2") { - write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, `${css}\n ${v2}`) - } - - const fullCss = `:root { - color-scheme: ${mode}; - --text-mix-blend-mode: ${isDark ? "plus-lighter" : "multiply"}; - ${css} - ${v2} -}` - - document.getElementById("oc-theme-preload")?.remove() - ensureThemeStyleElement().textContent = fullCss - document.documentElement.dataset.theme = themeId - document.documentElement.dataset.colorScheme = mode - document.documentElement.style.backgroundColor = isDark ? "#080808" : "#fafafa" - - // Update theme-color meta tag to match light/dark mode - const meta = document.querySelector('meta[name="theme-color"]') - if (meta) meta.setAttribute("content", isDark ? "#080808" : "#fafafa") -} - -function cacheThemeVariants(theme: DesktopTheme, themeId: string) { - if (themeId === "oc-2") return - for (const mode of ["light", "dark"] as const) { - const isDark = mode === "dark" - const variant = isDark ? theme.dark : theme.light - const tokens = resolveThemeVariant(variant, isDark) - const css = themeToCss(tokens) - const v2 = themeV2ToCss(resolveThemeVariantV2(variant, isDark)) - write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, `${css}\n ${v2}`) - } -} - -export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ - name: "Theme", - init: (props: { - defaultTheme?: string - onThemeApplied?: (theme: DesktopTheme, mode: "light" | "dark", scheme: ColorScheme) => void - }) => { - const themeId = normalize(read(STORAGE_KEYS.THEME_ID) ?? props.defaultTheme) ?? "oc-2" - const colorScheme = (read(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null) ?? "system" - const mode = colorScheme === "system" ? getSystemMode() : colorScheme - const [store, setStore] = createStore({ - themes: { - "oc-2": oc2Theme, - } as Record, - themeId, - colorScheme, - mode, - previewThemeId: null as string | null, - previewScheme: null as ColorScheme | null, - }) - - const loads = new Map>() - - const load = (id: string) => { - const next = normalize(id) - if (!next) return Promise.resolve(undefined) - const hit = store.themes[next] - if (hit) return Promise.resolve(hit) - const pending = loads.get(next) - if (pending) return pending - const file = getFiles()[`./themes/${next}.json`] - if (!file) return Promise.resolve(undefined) - const task = file() - .then((mod) => { - const theme = mod.default - setStore("themes", next, theme) - return theme - }) - .finally(() => { - loads.delete(next) - }) - loads.set(next, task) - return task - } - - const applyTheme = (theme: DesktopTheme, themeId: string, mode: "light" | "dark", scheme: ColorScheme) => { - applyThemeCss(theme, themeId, mode) - props.onThemeApplied?.(theme, mode, scheme) - } - - const ids = () => { - const extra = Object.keys(store.themes) - .filter((id) => !knownThemes().has(id)) - .sort() - const all = themeIDs() - if (extra.length === 0) return all - return [...all, ...extra] - } - - const loadThemes = () => Promise.all(themeIDs().map(load)).then(() => store.themes) - - const onStorage = (e: StorageEvent) => { - if (e.key === STORAGE_KEYS.THEME_ID && e.newValue) { - const next = normalize(e.newValue) - if (!next) return - if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) return - setStore("themeId", next) - if (next === "oc-2") { - clear() - return - } - void load(next).then((theme) => { - if (!theme || store.themeId !== next) return - cacheThemeVariants(theme, next) - }) - } - if (e.key === STORAGE_KEYS.COLOR_SCHEME && e.newValue) { - setStore("colorScheme", e.newValue as ColorScheme) - setStore("mode", e.newValue === "system" ? getSystemMode() : (e.newValue as "light" | "dark")) - } - } - - onMount(() => { - makeEventListener(window, "storage", onStorage) - - const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") - const onMedia = () => { - if (store.colorScheme !== "system") return - setStore("mode", getSystemMode()) - } - makeEventListener(mediaQuery, "change", onMedia) - - const rawTheme = read(STORAGE_KEYS.THEME_ID) - const savedTheme = normalize(rawTheme ?? props.defaultTheme) ?? "oc-2" - const savedScheme = (read(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null) ?? "system" - if (rawTheme && rawTheme !== savedTheme) { - write(STORAGE_KEYS.THEME_ID, savedTheme) - clear() - } - if (savedTheme !== store.themeId) setStore("themeId", savedTheme) - if (savedScheme !== store.colorScheme) setStore("colorScheme", savedScheme) - setStore("mode", savedScheme === "system" ? getSystemMode() : savedScheme) - void load(savedTheme).then((theme) => { - if (!theme || store.themeId !== savedTheme) return - cacheThemeVariants(theme, savedTheme) - }) - }) - - createEffect(() => { - const theme = store.themes[store.themeId] - if (!theme) return - applyTheme(theme, store.themeId, store.mode, store.colorScheme) - }) - - const setTheme = (id: string) => { - const next = normalize(id) - if (!next) { - console.warn(`Theme "${id}" not found`) - return - } - if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) { - console.warn(`Theme "${id}" not found`) - return - } - setStore("themeId", next) - if (next === "oc-2") { - write(STORAGE_KEYS.THEME_ID, next) - clear() - return - } - void load(next).then((theme) => { - if (!theme || store.themeId !== next) return - cacheThemeVariants(theme, next) - write(STORAGE_KEYS.THEME_ID, next) - }) - } - - const setColorScheme = (scheme: ColorScheme) => { - setStore("colorScheme", scheme) - write(STORAGE_KEYS.COLOR_SCHEME, scheme) - setStore("mode", scheme === "system" ? getSystemMode() : scheme) - } - - return { - themeId: () => store.themeId, - colorScheme: () => store.colorScheme, - mode: () => store.mode, - ids, - name: (id: string) => store.themes[id]?.name ?? names[id] ?? id, - loadThemes, - themes: () => store.themes, - setTheme, - setColorScheme, - registerTheme: (theme: DesktopTheme) => setStore("themes", theme.id, theme), - previewTheme: (id: string) => { - const next = normalize(id) - if (!next) return - if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) return - setStore("previewThemeId", next) - void load(next).then((theme) => { - if (!theme || store.previewThemeId !== next) return - const mode = store.previewScheme - ? store.previewScheme === "system" - ? getSystemMode() - : store.previewScheme - : store.mode - applyTheme(theme, next, mode, store.previewScheme ?? store.colorScheme) - }) - }, - previewColorScheme: (scheme: ColorScheme) => { - setStore("previewScheme", scheme) - const mode = scheme === "system" ? getSystemMode() : scheme - const id = store.previewThemeId ?? store.themeId - void load(id).then((theme) => { - if (!theme) return - if ((store.previewThemeId ?? store.themeId) !== id) return - if (store.previewScheme !== scheme) return - applyTheme(theme, id, mode, scheme) - }) - }, - commitPreview: () => { - if (store.previewThemeId) { - setTheme(store.previewThemeId) - } - if (store.previewScheme) { - setColorScheme(store.previewScheme) - } - setStore("previewThemeId", null) - setStore("previewScheme", null) - }, - cancelPreview: () => { - setStore("previewThemeId", null) - setStore("previewScheme", null) - void load(store.themeId).then((theme) => { - if (!theme) return - applyTheme(theme, store.themeId, store.mode, store.colorScheme) - }) - }, - } - }, -}) +// @refresh reload + +import { createEffect, onMount } from "solid-js" +import { createStore } from "solid-js/store" +import { makeEventListener } from "@solid-primitives/event-listener" +import { createSimpleContext } from "../context/helper" +import oc2ThemeJson from "./themes/oc-2.json" +import { resolveThemeVariant, themeToCss } from "./resolve" +import { resolveThemeVariantV2, themeV2ToCss } from "./v2/resolve" +import type { DesktopTheme } from "./types" + +export type ColorScheme = "light" | "dark" | "system" + +const STORAGE_KEYS = { + THEME_ID: "opencode-theme-id", + COLOR_SCHEME: "opencode-color-scheme", + THEME_CSS_LIGHT: "opencode-theme-css-light", + THEME_CSS_DARK: "opencode-theme-css-dark", +} as const + +const THEME_STYLE_ID = "oc-theme" +let files: Record Promise<{ default: DesktopTheme }>> | undefined +let ids: string[] | undefined +let known: Set | undefined + +function getFiles() { + if (files) return files + files = import.meta.glob<{ default: DesktopTheme }>("./themes/*.json") + return files +} + +function themeIDs() { + if (ids) return ids + ids = Object.keys(getFiles()) + .map((path) => path.slice("./themes/".length, -".json".length)) + .sort() + return ids +} + +function knownThemes() { + if (known) return known + known = new Set(themeIDs()) + return known +} + +const names: Record = { + "oc-2": "OC-2", + amoled: "AMOLED", + aura: "Aura", + ayu: "Ayu", + carbonfox: "Carbonfox", + catppuccin: "Catppuccin", + "catppuccin-frappe": "Catppuccin Frappe", + "catppuccin-macchiato": "Catppuccin Macchiato", + cobalt2: "Cobalt2", + cursor: "Cursor", + dracula: "Dracula", + everforest: "Everforest", + flexoki: "Flexoki", + github: "GitHub", + gruvbox: "Gruvbox", + kanagawa: "Kanagawa", + "lucent-orng": "Lucent Orng", + material: "Material", + matrix: "Matrix", + mercury: "Mercury", + monokai: "Monokai", + nightowl: "Night Owl", + nord: "Nord", + "one-dark": "One Dark", + onedarkpro: "One Dark Pro", + opencode: "OpenCode", + orng: "Orng", + "osaka-jade": "Osaka Jade", + palenight: "Palenight", + rosepine: "Rose Pine", + shadesofpurple: "Shades of Purple", + solarized: "Solarized", + synthwave84: "Synthwave '84", + tokyonight: "Tokyonight", + vercel: "Vercel", + vesper: "Vesper", + zenburn: "Zenburn", +} +const oc2Theme = oc2ThemeJson as DesktopTheme + +function normalize(id: string | null | undefined) { + return id === "oc-1" ? "oc-2" : id +} + +function read(key: string) { + if (typeof localStorage !== "object") return null + try { + return localStorage.getItem(key) + } catch { + return null + } +} + +function write(key: string, value: string) { + if (typeof localStorage !== "object") return + try { + localStorage.setItem(key, value) + } catch {} +} + +function drop(key: string) { + if (typeof localStorage !== "object") return + try { + localStorage.removeItem(key) + } catch {} +} + +function clear() { + drop(STORAGE_KEYS.THEME_CSS_LIGHT) + drop(STORAGE_KEYS.THEME_CSS_DARK) +} + +function ensureThemeStyleElement(): HTMLStyleElement { + const existing = document.getElementById(THEME_STYLE_ID) as HTMLStyleElement | null + if (existing) return existing + const element = document.createElement("style") + element.id = THEME_STYLE_ID + document.head.appendChild(element) + return element +} + +function getSystemMode(): "light" | "dark" { + if (typeof window !== "object") return "light" + return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" +} + +function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "dark") { + const isDark = mode === "dark" + const variant = isDark ? theme.dark : theme.light + const tokens = resolveThemeVariant(variant, isDark) + const css = themeToCss(tokens) + const v2 = themeV2ToCss(resolveThemeVariantV2(variant, isDark)) + + if (themeId !== "oc-2") { + write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, `${css}\n ${v2}`) + } + + const fullCss = `:root { + color-scheme: ${mode}; + --text-mix-blend-mode: ${isDark ? "plus-lighter" : "multiply"}; + ${css} + ${v2} +}` + + document.getElementById("oc-theme-preload")?.remove() + ensureThemeStyleElement().textContent = fullCss + document.documentElement.dataset.theme = themeId + document.documentElement.dataset.colorScheme = mode + document.documentElement.style.backgroundColor = isDark ? "#080808" : "#fafafa" + + // Update theme-color meta tag to match light/dark mode + const meta = document.querySelector('meta[name="theme-color"]') + if (meta) meta.setAttribute("content", isDark ? "#080808" : "#fafafa") +} + +function cacheThemeVariants(theme: DesktopTheme, themeId: string) { + if (themeId === "oc-2") return + for (const mode of ["light", "dark"] as const) { + const isDark = mode === "dark" + const variant = isDark ? theme.dark : theme.light + const tokens = resolveThemeVariant(variant, isDark) + const css = themeToCss(tokens) + const v2 = themeV2ToCss(resolveThemeVariantV2(variant, isDark)) + write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, `${css}\n ${v2}`) + } +} + +export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ + name: "Theme", + init: (props: { + defaultTheme?: string + onThemeApplied?: (theme: DesktopTheme, mode: "light" | "dark", scheme: ColorScheme) => void + }) => { + const themeId = normalize(read(STORAGE_KEYS.THEME_ID) ?? props.defaultTheme) ?? "oc-2" + const colorScheme = (read(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null) ?? "system" + const mode = colorScheme === "system" ? getSystemMode() : colorScheme + const [store, setStore] = createStore({ + themes: { + "oc-2": oc2Theme, + } as Record, + themeId, + colorScheme, + mode, + previewThemeId: null as string | null, + previewScheme: null as ColorScheme | null, + }) + + const loads = new Map>() + + const load = (id: string) => { + const next = normalize(id) + if (!next) return Promise.resolve(undefined) + const hit = store.themes[next] + if (hit) return Promise.resolve(hit) + const pending = loads.get(next) + if (pending) return pending + const file = getFiles()[`./themes/${next}.json`] + if (!file) return Promise.resolve(undefined) + const task = file() + .then((mod) => { + const theme = mod.default + setStore("themes", next, theme) + return theme + }) + .finally(() => { + loads.delete(next) + }) + loads.set(next, task) + return task + } + + const applyTheme = (theme: DesktopTheme, themeId: string, mode: "light" | "dark", scheme: ColorScheme) => { + applyThemeCss(theme, themeId, mode) + props.onThemeApplied?.(theme, mode, scheme) + } + + const ids = () => { + const extra = Object.keys(store.themes) + .filter((id) => !knownThemes().has(id)) + .sort() + const all = themeIDs() + if (extra.length === 0) return all + return [...all, ...extra] + } + + const loadThemes = () => Promise.all(themeIDs().map(load)).then(() => store.themes) + + const handleThemeChange = (newValue: string) => { + const next = normalize(newValue); + if (!next) return; + + if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) return; + + setStore("themeId", next); + + if (next === "oc-2") { + clear(); + return; + } + + void load(next).then((theme) => { + if (!theme || store.themeId !== next) return; + cacheThemeVariants(theme, next); + }); + }; + + const onStorage = (e: StorageEvent) => { + if (e.key === STORAGE_KEYS.THEME_ID && e.newValue) { + handleThemeChange(e.newValue); + } + + if (e.key === STORAGE_KEYS.COLOR_SCHEME && e.newValue) { + setStore("colorScheme", e.newValue as ColorScheme); + setStore( + "mode", + e.newValue === "system" ? getSystemMode() : (e.newValue as "light" | "dark") + ); + } + }; + + + onMount(() => { + makeEventListener(window, "storage", onStorage) + + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") + const onMedia = () => { + if (store.colorScheme !== "system") return + setStore("mode", getSystemMode()) + } + makeEventListener(mediaQuery, "change", onMedia) + + const rawTheme = read(STORAGE_KEYS.THEME_ID) + const savedTheme = normalize(rawTheme ?? props.defaultTheme) ?? "oc-2" + const savedScheme = (read(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null) ?? "system" + if (rawTheme && rawTheme !== savedTheme) { + write(STORAGE_KEYS.THEME_ID, savedTheme) + clear() + } + if (savedTheme !== store.themeId) setStore("themeId", savedTheme) + if (savedScheme !== store.colorScheme) setStore("colorScheme", savedScheme) + setStore("mode", savedScheme === "system" ? getSystemMode() : savedScheme) + void load(savedTheme).then((theme) => { + if (!theme || store.themeId !== savedTheme) return + cacheThemeVariants(theme, savedTheme) + }) + }) + + createEffect(() => { + const theme = store.themes[store.themeId] + if (!theme) return + applyTheme(theme, store.themeId, store.mode, store.colorScheme) + }) + + const setTheme = (id: string) => { + const next = normalize(id) + if (!next) { + console.warn(`Theme "${id}" not found`) + return + } + if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) { + console.warn(`Theme "${id}" not found`) + return + } + setStore("themeId", next) + if (next === "oc-2") { + write(STORAGE_KEYS.THEME_ID, next) + clear() + return + } + void load(next).then((theme) => { + if (!theme || store.themeId !== next) return + cacheThemeVariants(theme, next) + write(STORAGE_KEYS.THEME_ID, next) + }) + } + + const setColorScheme = (scheme: ColorScheme) => { + setStore("colorScheme", scheme) + write(STORAGE_KEYS.COLOR_SCHEME, scheme) + setStore("mode", scheme === "system" ? getSystemMode() : scheme) + } + + return { + themeId: () => store.themeId, + colorScheme: () => store.colorScheme, + mode: () => store.mode, + ids, + name: (id: string) => store.themes[id]?.name ?? names[id] ?? id, + loadThemes, + themes: () => store.themes, + setTheme, + setColorScheme, + registerTheme: (theme: DesktopTheme) => setStore("themes", theme.id, theme), + previewTheme: (id: string) => { + const next = normalize(id) + if (!next) return + if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) return + setStore("previewThemeId", next) + void load(next).then((theme) => { + if (!theme || store.previewThemeId !== next) return + const mode = store.previewScheme + ? store.previewScheme === "system" + ? getSystemMode() + : store.previewScheme + : store.mode + applyTheme(theme, next, mode, store.previewScheme ?? store.colorScheme) + }) + }, + previewColorScheme: (scheme: ColorScheme) => { + setStore("previewScheme", scheme) + const mode = scheme === "system" ? getSystemMode() : scheme + const id = store.previewThemeId ?? store.themeId + void load(id).then((theme) => { + if (!theme) return + if ((store.previewThemeId ?? store.themeId) !== id) return + if (store.previewScheme !== scheme) return + applyTheme(theme, id, mode, scheme) + }) + }, + commitPreview: () => { + if (store.previewThemeId) { + setTheme(store.previewThemeId) + } + if (store.previewScheme) { + setColorScheme(store.previewScheme) + } + setStore("previewThemeId", null) + setStore("previewScheme", null) + }, + cancelPreview: () => { + setStore("previewThemeId", null) + setStore("previewScheme", null) + void load(store.themeId).then((theme) => { + if (!theme) return + applyTheme(theme, store.themeId, store.mode, store.colorScheme) + }) + }, + } + }, +})