|
@@ -1,7 +1,7 @@
|
|
|
import { createEffect, onCleanup, onMount } from "solid-js"
|
|
import { createEffect, onCleanup, onMount } from "solid-js"
|
|
|
import { createStore } from "solid-js/store"
|
|
import { createStore } from "solid-js/store"
|
|
|
import { createSimpleContext } from "../context/helper"
|
|
import { createSimpleContext } from "../context/helper"
|
|
|
-import { DEFAULT_THEMES } from "./default-themes"
|
|
|
|
|
|
|
+import oc2ThemeJson from "./themes/oc-2.json"
|
|
|
import { resolveThemeVariant, themeToCss } from "./resolve"
|
|
import { resolveThemeVariant, themeToCss } from "./resolve"
|
|
|
import type { DesktopTheme } from "./types"
|
|
import type { DesktopTheme } from "./types"
|
|
|
|
|
|
|
@@ -15,14 +15,101 @@ const STORAGE_KEYS = {
|
|
|
} as const
|
|
} as const
|
|
|
|
|
|
|
|
const THEME_STYLE_ID = "oc-theme"
|
|
const THEME_STYLE_ID = "oc-theme"
|
|
|
|
|
+let files: Record<string, () => Promise<{ default: DesktopTheme }>> | undefined
|
|
|
|
|
+let ids: string[] | undefined
|
|
|
|
|
+let known: Set<string> | 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<string, string> = {
|
|
|
|
|
+ "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) {
|
|
function normalize(id: string | null | undefined) {
|
|
|
return id === "oc-1" ? "oc-2" : id
|
|
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() {
|
|
function clear() {
|
|
|
- localStorage.removeItem(STORAGE_KEYS.THEME_CSS_LIGHT)
|
|
|
|
|
- localStorage.removeItem(STORAGE_KEYS.THEME_CSS_DARK)
|
|
|
|
|
|
|
+ drop(STORAGE_KEYS.THEME_CSS_LIGHT)
|
|
|
|
|
+ drop(STORAGE_KEYS.THEME_CSS_DARK)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function ensureThemeStyleElement(): HTMLStyleElement {
|
|
function ensureThemeStyleElement(): HTMLStyleElement {
|
|
@@ -35,6 +122,7 @@ function ensureThemeStyleElement(): HTMLStyleElement {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function getSystemMode(): "light" | "dark" {
|
|
function getSystemMode(): "light" | "dark" {
|
|
|
|
|
+ if (typeof window !== "object") return "light"
|
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -45,9 +133,7 @@ function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "da
|
|
|
const css = themeToCss(tokens)
|
|
const css = themeToCss(tokens)
|
|
|
|
|
|
|
|
if (themeId !== "oc-2") {
|
|
if (themeId !== "oc-2") {
|
|
|
- try {
|
|
|
|
|
- localStorage.setItem(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, css)
|
|
|
|
|
- } catch {}
|
|
|
|
|
|
|
+ write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, css)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const fullCss = `:root {
|
|
const fullCss = `:root {
|
|
@@ -69,74 +155,122 @@ function cacheThemeVariants(theme: DesktopTheme, themeId: string) {
|
|
|
const variant = isDark ? theme.dark : theme.light
|
|
const variant = isDark ? theme.dark : theme.light
|
|
|
const tokens = resolveThemeVariant(variant, isDark)
|
|
const tokens = resolveThemeVariant(variant, isDark)
|
|
|
const css = themeToCss(tokens)
|
|
const css = themeToCss(tokens)
|
|
|
- try {
|
|
|
|
|
- localStorage.setItem(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, css)
|
|
|
|
|
- } catch {}
|
|
|
|
|
|
|
+ write(isDark ? STORAGE_KEYS.THEME_CSS_DARK : STORAGE_KEYS.THEME_CSS_LIGHT, css)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
|
name: "Theme",
|
|
name: "Theme",
|
|
|
init: (props: { defaultTheme?: string; onThemeApplied?: (theme: DesktopTheme, mode: "light" | "dark") => void }) => {
|
|
init: (props: { defaultTheme?: string; onThemeApplied?: (theme: DesktopTheme, mode: "light" | "dark") => 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({
|
|
const [store, setStore] = createStore({
|
|
|
- themes: DEFAULT_THEMES as Record<string, DesktopTheme>,
|
|
|
|
|
- themeId: normalize(props.defaultTheme) ?? "oc-2",
|
|
|
|
|
- colorScheme: "system" as ColorScheme,
|
|
|
|
|
- mode: getSystemMode(),
|
|
|
|
|
|
|
+ themes: {
|
|
|
|
|
+ "oc-2": oc2Theme,
|
|
|
|
|
+ } as Record<string, DesktopTheme>,
|
|
|
|
|
+ themeId,
|
|
|
|
|
+ colorScheme,
|
|
|
|
|
+ mode,
|
|
|
previewThemeId: null as string | null,
|
|
previewThemeId: null as string | null,
|
|
|
previewScheme: null as ColorScheme | null,
|
|
previewScheme: null as ColorScheme | null,
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- window.addEventListener("storage", (e) => {
|
|
|
|
|
- if (e.key === STORAGE_KEYS.THEME_ID && e.newValue) setStore("themeId", e.newValue)
|
|
|
|
|
|
|
+ const loads = new Map<string, Promise<DesktopTheme | undefined>>()
|
|
|
|
|
+
|
|
|
|
|
+ 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") => {
|
|
|
|
|
+ applyThemeCss(theme, themeId, mode)
|
|
|
|
|
+ props.onThemeApplied?.(theme, mode)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ 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) {
|
|
if (e.key === STORAGE_KEYS.COLOR_SCHEME && e.newValue) {
|
|
|
setStore("colorScheme", e.newValue as ColorScheme)
|
|
setStore("colorScheme", e.newValue as ColorScheme)
|
|
|
- setStore("mode", e.newValue === "system" ? getSystemMode() : (e.newValue as any))
|
|
|
|
|
|
|
+ setStore("mode", e.newValue === "system" ? getSystemMode() : (e.newValue as "light" | "dark"))
|
|
|
}
|
|
}
|
|
|
- })
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (typeof window === "object") {
|
|
|
|
|
+ window.addEventListener("storage", onStorage)
|
|
|
|
|
+ onCleanup(() => window.removeEventListener("storage", onStorage))
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
onMount(() => {
|
|
onMount(() => {
|
|
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
|
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
|
|
|
- const handler = () => {
|
|
|
|
|
- if (store.colorScheme === "system") {
|
|
|
|
|
- setStore("mode", getSystemMode())
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- mediaQuery.addEventListener("change", handler)
|
|
|
|
|
- onCleanup(() => mediaQuery.removeEventListener("change", handler))
|
|
|
|
|
-
|
|
|
|
|
- const savedTheme = localStorage.getItem(STORAGE_KEYS.THEME_ID)
|
|
|
|
|
- const themeId = normalize(savedTheme)
|
|
|
|
|
- const savedScheme = localStorage.getItem(STORAGE_KEYS.COLOR_SCHEME) as ColorScheme | null
|
|
|
|
|
- if (themeId && store.themes[themeId]) {
|
|
|
|
|
- setStore("themeId", themeId)
|
|
|
|
|
|
|
+ const onMedia = () => {
|
|
|
|
|
+ if (store.colorScheme !== "system") return
|
|
|
|
|
+ setStore("mode", getSystemMode())
|
|
|
}
|
|
}
|
|
|
- if (savedTheme && themeId && savedTheme !== themeId) {
|
|
|
|
|
- localStorage.setItem(STORAGE_KEYS.THEME_ID, themeId)
|
|
|
|
|
|
|
+ mediaQuery.addEventListener("change", onMedia)
|
|
|
|
|
+ onCleanup(() => mediaQuery.removeEventListener("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()
|
|
clear()
|
|
|
}
|
|
}
|
|
|
- if (savedScheme) {
|
|
|
|
|
- setStore("colorScheme", savedScheme)
|
|
|
|
|
- if (savedScheme !== "system") {
|
|
|
|
|
- setStore("mode", savedScheme)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- const currentTheme = store.themes[store.themeId]
|
|
|
|
|
- if (currentTheme) {
|
|
|
|
|
- cacheThemeVariants(currentTheme, store.themeId)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ 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)
|
|
|
|
|
+ })
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- const applyTheme = (theme: DesktopTheme, themeId: string, mode: "light" | "dark") => {
|
|
|
|
|
- applyThemeCss(theme, themeId, mode)
|
|
|
|
|
- props.onThemeApplied?.(theme, mode)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
createEffect(() => {
|
|
createEffect(() => {
|
|
|
const theme = store.themes[store.themeId]
|
|
const theme = store.themes[store.themeId]
|
|
|
- if (theme) {
|
|
|
|
|
- applyTheme(theme, store.themeId, store.mode)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!theme) return
|
|
|
|
|
+ applyTheme(theme, store.themeId, store.mode)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const setTheme = (id: string) => {
|
|
const setTheme = (id: string) => {
|
|
@@ -145,23 +279,26 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
|
console.warn(`Theme "${id}" not found`)
|
|
console.warn(`Theme "${id}" not found`)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- const theme = store.themes[next]
|
|
|
|
|
- if (!theme) {
|
|
|
|
|
|
|
+ if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) {
|
|
|
console.warn(`Theme "${id}" not found`)
|
|
console.warn(`Theme "${id}" not found`)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
setStore("themeId", next)
|
|
setStore("themeId", next)
|
|
|
- localStorage.setItem(STORAGE_KEYS.THEME_ID, next)
|
|
|
|
|
if (next === "oc-2") {
|
|
if (next === "oc-2") {
|
|
|
|
|
+ write(STORAGE_KEYS.THEME_ID, next)
|
|
|
clear()
|
|
clear()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- cacheThemeVariants(theme, next)
|
|
|
|
|
|
|
+ void load(next).then((theme) => {
|
|
|
|
|
+ if (!theme || store.themeId !== next) return
|
|
|
|
|
+ cacheThemeVariants(theme, next)
|
|
|
|
|
+ write(STORAGE_KEYS.THEME_ID, next)
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const setColorScheme = (scheme: ColorScheme) => {
|
|
const setColorScheme = (scheme: ColorScheme) => {
|
|
|
setStore("colorScheme", scheme)
|
|
setStore("colorScheme", scheme)
|
|
|
- localStorage.setItem(STORAGE_KEYS.COLOR_SCHEME, scheme)
|
|
|
|
|
|
|
+ write(STORAGE_KEYS.COLOR_SCHEME, scheme)
|
|
|
setStore("mode", scheme === "system" ? getSystemMode() : scheme)
|
|
setStore("mode", scheme === "system" ? getSystemMode() : scheme)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -169,6 +306,9 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
|
themeId: () => store.themeId,
|
|
themeId: () => store.themeId,
|
|
|
colorScheme: () => store.colorScheme,
|
|
colorScheme: () => store.colorScheme,
|
|
|
mode: () => store.mode,
|
|
mode: () => store.mode,
|
|
|
|
|
+ ids,
|
|
|
|
|
+ name: (id: string) => store.themes[id]?.name ?? names[id] ?? id,
|
|
|
|
|
+ loadThemes,
|
|
|
themes: () => store.themes,
|
|
themes: () => store.themes,
|
|
|
setTheme,
|
|
setTheme,
|
|
|
setColorScheme,
|
|
setColorScheme,
|
|
@@ -176,24 +316,28 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
|
previewTheme: (id: string) => {
|
|
previewTheme: (id: string) => {
|
|
|
const next = normalize(id)
|
|
const next = normalize(id)
|
|
|
if (!next) return
|
|
if (!next) return
|
|
|
- const theme = store.themes[next]
|
|
|
|
|
- if (!theme) return
|
|
|
|
|
|
|
+ if (next !== "oc-2" && !knownThemes().has(next) && !store.themes[next]) return
|
|
|
setStore("previewThemeId", next)
|
|
setStore("previewThemeId", next)
|
|
|
- const previewMode = store.previewScheme
|
|
|
|
|
- ? store.previewScheme === "system"
|
|
|
|
|
- ? getSystemMode()
|
|
|
|
|
- : store.previewScheme
|
|
|
|
|
- : store.mode
|
|
|
|
|
- applyTheme(theme, next, previewMode)
|
|
|
|
|
|
|
+ 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)
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
previewColorScheme: (scheme: ColorScheme) => {
|
|
previewColorScheme: (scheme: ColorScheme) => {
|
|
|
setStore("previewScheme", scheme)
|
|
setStore("previewScheme", scheme)
|
|
|
- const previewMode = scheme === "system" ? getSystemMode() : scheme
|
|
|
|
|
|
|
+ const mode = scheme === "system" ? getSystemMode() : scheme
|
|
|
const id = store.previewThemeId ?? store.themeId
|
|
const id = store.previewThemeId ?? store.themeId
|
|
|
- const theme = store.themes[id]
|
|
|
|
|
- if (theme) {
|
|
|
|
|
- applyTheme(theme, id, previewMode)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ void load(id).then((theme) => {
|
|
|
|
|
+ if (!theme) return
|
|
|
|
|
+ if ((store.previewThemeId ?? store.themeId) !== id) return
|
|
|
|
|
+ if (store.previewScheme !== scheme) return
|
|
|
|
|
+ applyTheme(theme, id, mode)
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
commitPreview: () => {
|
|
commitPreview: () => {
|
|
|
if (store.previewThemeId) {
|
|
if (store.previewThemeId) {
|
|
@@ -208,10 +352,10 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
|
|
cancelPreview: () => {
|
|
cancelPreview: () => {
|
|
|
setStore("previewThemeId", null)
|
|
setStore("previewThemeId", null)
|
|
|
setStore("previewScheme", null)
|
|
setStore("previewScheme", null)
|
|
|
- const theme = store.themes[store.themeId]
|
|
|
|
|
- if (theme) {
|
|
|
|
|
|
|
+ void load(store.themeId).then((theme) => {
|
|
|
|
|
+ if (!theme) return
|
|
|
applyTheme(theme, store.themeId, store.mode)
|
|
applyTheme(theme, store.themeId, store.mode)
|
|
|
- }
|
|
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|