@timmo001/groundwork-tokens 0.9.39 → 0.9.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/package.json +2 -1
- package/src/choices.ts +163 -0
- package/src/page.ts +31 -157
package/README.md
CHANGED
|
@@ -55,5 +55,16 @@ import {
|
|
|
55
55
|
} from "@timmo001/groundwork-tokens/desktop-themes";
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
The `choices` export holds the built-in themes as choices, the optional
|
|
59
|
+
themes' documents and `themeBootScript`, with no DOM types, for a server or
|
|
60
|
+
CLI that writes a page. The `page` export re-exports it beside `pageTheme`:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import {
|
|
64
|
+
optionalThemeChoices,
|
|
65
|
+
themeBootScript,
|
|
66
|
+
} from "@timmo001/groundwork-tokens/choices";
|
|
67
|
+
```
|
|
68
|
+
|
|
58
69
|
The themes, their roles and contrast targets are documented at
|
|
59
70
|
[groundwork.timmo.dev/themes](https://groundwork.timmo.dev/themes).
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmo001/groundwork-tokens",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.40",
|
|
4
4
|
"description": "Groundwork's design tokens: the theme schema, the OKLCH solver and every theme as CSS and JSON",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.ts",
|
|
9
9
|
"./runtime": "./src/runtime.ts",
|
|
10
|
+
"./choices": "./src/choices.ts",
|
|
10
11
|
"./page": "./src/page.ts",
|
|
11
12
|
"./webmcp": "./src/webmcp.ts",
|
|
12
13
|
"./omarchy-current": "./src/omarchy-current.ts",
|
package/src/choices.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in themes as choices, the optional themes' documents and the
|
|
3
|
+
* inline script that applies a stored pick before the first paint. It uses
|
|
4
|
+
* no DOM types, so a server or CLI building a page can import it without
|
|
5
|
+
* the DOM lib; `page` re-exports all of it for the browser.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import base from "../themes/base.json" with { type: "json" };
|
|
10
|
+
import bridge from "../themes/bridge.json" with { type: "json" };
|
|
11
|
+
import catppuccinFrappe from "../themes/catppuccin-frappe.json" with { type: "json" };
|
|
12
|
+
import catppuccinLatte from "../themes/catppuccin-latte.json" with { type: "json" };
|
|
13
|
+
import catppuccinMacchiato from "../themes/catppuccin-macchiato.json" with { type: "json" };
|
|
14
|
+
import catppuccinMocha from "../themes/catppuccin-mocha.json" with { type: "json" };
|
|
15
|
+
import githubDimmed from "../themes/github-dimmed.json" with { type: "json" };
|
|
16
|
+
import githubHighContrast from "../themes/github-high-contrast.json" with { type: "json" };
|
|
17
|
+
import github from "../themes/github.json" with { type: "json" };
|
|
18
|
+
import glazing from "../themes/glazing.json" with { type: "json" };
|
|
19
|
+
import slate from "../themes/slate.json" with { type: "json" };
|
|
20
|
+
import snag from "../themes/snag.json" with { type: "json" };
|
|
21
|
+
import survey from "../themes/survey.json" with { type: "json" };
|
|
22
|
+
import tokyoNightDay from "../themes/tokyo-night-day.json" with { type: "json" };
|
|
23
|
+
import tokyoNightMoon from "../themes/tokyo-night-moon.json" with { type: "json" };
|
|
24
|
+
import tokyoNightStorm from "../themes/tokyo-night-storm.json" with { type: "json" };
|
|
25
|
+
import tokyoNight from "../themes/tokyo-night.json" with { type: "json" };
|
|
26
|
+
|
|
27
|
+
/** How light the page is: `auto` follows the system. */
|
|
28
|
+
export type ThemeMode = "auto" | "light" | "dark" | "darker";
|
|
29
|
+
|
|
30
|
+
/** Light or dark: the side of a mode a theme has to cover. Darker is dark. */
|
|
31
|
+
export type ThemeScheme = "light" | "dark";
|
|
32
|
+
|
|
33
|
+
/** The theme id a visitor's own theme is solved under. */
|
|
34
|
+
export const customThemeId = "custom";
|
|
35
|
+
|
|
36
|
+
/** The id of the `<style>` holding a custom theme's CSS. */
|
|
37
|
+
export const customThemeStyleId = "gw-custom-theme";
|
|
38
|
+
|
|
39
|
+
/** The theme id the desktop's Omarchy theme is solved under. */
|
|
40
|
+
export const omarchyThemeId = "omarchy";
|
|
41
|
+
|
|
42
|
+
/** The id of the `<style>` holding the Omarchy theme's CSS. */
|
|
43
|
+
export const omarchyThemeStyleId = "gw-omarchy-theme";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A theme to offer, by id and name. A `Theme` document is one. `mode` marks
|
|
47
|
+
* a theme with only one scheme, such as Catppuccin Latte: it's offered and
|
|
48
|
+
* kept for that scheme alone, beside a pick for the other.
|
|
49
|
+
*/
|
|
50
|
+
export interface ThemeChoice {
|
|
51
|
+
readonly id: string;
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly mode?: ThemeScheme | undefined;
|
|
54
|
+
/** The palette an optional theme comes from, such as `Catppuccin`. */
|
|
55
|
+
readonly family?: string | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Whether `choice` can show in `scheme`. */
|
|
59
|
+
export const themeCovers = (choice: ThemeChoice, scheme: ThemeScheme) =>
|
|
60
|
+
choice.mode === undefined || choice.mode === scheme;
|
|
61
|
+
|
|
62
|
+
/** The core themes by id and name, in the order the docs list them. */
|
|
63
|
+
export const coreThemeChoices: readonly ThemeChoice[] = [
|
|
64
|
+
base,
|
|
65
|
+
glazing,
|
|
66
|
+
survey,
|
|
67
|
+
slate,
|
|
68
|
+
bridge,
|
|
69
|
+
snag,
|
|
70
|
+
].map(({ id, name }) => ({ id, name }));
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The optional themes' documents, by family and then from light to dark.
|
|
74
|
+
* They're bundled with the module, so an app compiled to one binary has them
|
|
75
|
+
* without reading `node_modules`. Decode one with the `MappedTheme` Schema.
|
|
76
|
+
*/
|
|
77
|
+
export const optionalThemeDocuments = [
|
|
78
|
+
catppuccinLatte,
|
|
79
|
+
catppuccinFrappe,
|
|
80
|
+
catppuccinMacchiato,
|
|
81
|
+
catppuccinMocha,
|
|
82
|
+
tokyoNightDay,
|
|
83
|
+
tokyoNight,
|
|
84
|
+
tokyoNightStorm,
|
|
85
|
+
tokyoNightMoon,
|
|
86
|
+
github,
|
|
87
|
+
githubDimmed,
|
|
88
|
+
githubHighContrast,
|
|
89
|
+
] as const;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The optional themes, mapped from other palettes, by family and then from
|
|
93
|
+
* light to dark. One with a single mode is offered for that scheme alone;
|
|
94
|
+
* one with both, such as GitHub's, for either.
|
|
95
|
+
*/
|
|
96
|
+
export const optionalThemeChoices: readonly ThemeChoice[] =
|
|
97
|
+
optionalThemeDocuments.map((theme) => ({
|
|
98
|
+
id: theme.id,
|
|
99
|
+
name: theme.name,
|
|
100
|
+
family: theme.family,
|
|
101
|
+
mode:
|
|
102
|
+
"otherPalette" in theme
|
|
103
|
+
? undefined
|
|
104
|
+
: theme.mode === "light"
|
|
105
|
+
? "light"
|
|
106
|
+
: "dark",
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
/** What the page's pick starts on, and where it's kept. */
|
|
110
|
+
export interface ThemeBootOptions {
|
|
111
|
+
/** The local storage key prefix, such as `my-site:theme`. */
|
|
112
|
+
readonly key: string;
|
|
113
|
+
/** The theme id to start with. */
|
|
114
|
+
readonly defaultTheme: string;
|
|
115
|
+
/** The mode to start with. Defaults to `auto`. */
|
|
116
|
+
readonly defaultMode?: ThemeMode;
|
|
117
|
+
/**
|
|
118
|
+
* Whether the Omarchy theme takes over while the visitor hasn't picked
|
|
119
|
+
* one. With `false` it's only offered, and `defaultTheme` stays in use.
|
|
120
|
+
* Defaults to `true`.
|
|
121
|
+
*/
|
|
122
|
+
readonly followOmarchy?: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** The local storage keys a pick is kept under. */
|
|
126
|
+
export const themeStorageKeys = (key: string) => ({
|
|
127
|
+
mode: `${key}:mode`,
|
|
128
|
+
theme: `${key}:id`,
|
|
129
|
+
dark: `${key}:id-dark`,
|
|
130
|
+
document: `${key}:custom`,
|
|
131
|
+
css: `${key}:custom-css`,
|
|
132
|
+
name: `${key}:custom-name`,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/** The Omarchy theme's cache, kept apart so a reset doesn't drop it. */
|
|
136
|
+
export const omarchyStorageKeys = (key: string) => ({
|
|
137
|
+
css: `${key}:omarchy-css`,
|
|
138
|
+
name: `${key}:omarchy-name`,
|
|
139
|
+
mode: `${key}:omarchy-mode`,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* An inline script that applies the stored mode, theme and any custom or
|
|
144
|
+
* Omarchy theme's cached CSS before the first paint. Takes the same key and
|
|
145
|
+
* defaults as `pageTheme`.
|
|
146
|
+
*/
|
|
147
|
+
export const themeBootScript = (options: ThemeBootOptions) => {
|
|
148
|
+
const config = JSON.stringify({
|
|
149
|
+
keys: themeStorageKeys(options.key),
|
|
150
|
+
omarchy: omarchyStorageKeys(options.key),
|
|
151
|
+
theme: options.defaultTheme,
|
|
152
|
+
mode: options.defaultMode ?? "auto",
|
|
153
|
+
follow: options.followOmarchy !== false,
|
|
154
|
+
custom: customThemeId,
|
|
155
|
+
style: customThemeStyleId,
|
|
156
|
+
omarchyId: omarchyThemeId,
|
|
157
|
+
omarchyStyle: omarchyThemeStyleId,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// With nothing picked, a cached Omarchy theme for the scheme is the
|
|
161
|
+
// default, unless it's only offered
|
|
162
|
+
return `(()=>{const c=${config};let s;try{s=localStorage}catch{}const g=(k)=>{try{return s?.getItem(k)??null}catch{return null}};const r=document.documentElement;const a=(id,css)=>{const e=document.createElement("style");e.id=id;e.textContent=css;document.head.append(e)};const m=g(c.keys.mode)??c.mode;const d=m==="dark"||m==="darker"||(m==="auto"&&matchMedia("(prefers-color-scheme: dark)").matches);const o=g(c.omarchy.css);let t=(d?g(c.keys.dark):null)??g(c.keys.theme)??(c.follow&&o&&g(c.omarchy.mode)===(d?"dark":"light")?c.omarchyId:c.theme);if(t===c.custom){const css=g(c.keys.css);if(css)a(c.style,css);else t=c.theme}else if(t===c.omarchyId){if(o)a(c.omarchyStyle,o);else t=c.theme}r.setAttribute("data-gw-theme",t);if(m==="auto")r.removeAttribute("data-gw-mode");else r.setAttribute("data-gw-mode",m)})();`;
|
|
163
|
+
};
|
package/src/page.ts
CHANGED
|
@@ -9,49 +9,43 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import tokyoNightDay from "../themes/tokyo-night-day.json" with { type: "json" };
|
|
26
|
-
import tokyoNightMoon from "../themes/tokyo-night-moon.json" with { type: "json" };
|
|
27
|
-
import tokyoNightStorm from "../themes/tokyo-night-storm.json" with { type: "json" };
|
|
28
|
-
import tokyoNight from "../themes/tokyo-night.json" with { type: "json" };
|
|
12
|
+
import {
|
|
13
|
+
customThemeId,
|
|
14
|
+
customThemeStyleId,
|
|
15
|
+
omarchyStorageKeys,
|
|
16
|
+
omarchyThemeId,
|
|
17
|
+
omarchyThemeStyleId,
|
|
18
|
+
themeCovers,
|
|
19
|
+
themeStorageKeys,
|
|
20
|
+
type ThemeBootOptions,
|
|
21
|
+
type ThemeChoice,
|
|
22
|
+
type ThemeMode,
|
|
23
|
+
type ThemeScheme,
|
|
24
|
+
} from "./choices.ts";
|
|
29
25
|
import type { OmarchyCurrentTheme } from "./omarchy.ts";
|
|
30
26
|
import type { ThemeStore } from "./runtime.ts";
|
|
31
27
|
import type { Theme } from "./schema.ts";
|
|
32
28
|
// Only for `document.modelContext`'s type; the tools themselves load lazily
|
|
33
29
|
import type {} from "./webmcp.ts";
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
export {
|
|
32
|
+
coreThemeChoices,
|
|
33
|
+
customThemeId,
|
|
34
|
+
customThemeStyleId,
|
|
35
|
+
omarchyThemeId,
|
|
36
|
+
omarchyThemeStyleId,
|
|
37
|
+
optionalThemeChoices,
|
|
38
|
+
optionalThemeDocuments,
|
|
39
|
+
themeBootScript,
|
|
40
|
+
themeCovers,
|
|
41
|
+
type ThemeBootOptions,
|
|
42
|
+
type ThemeChoice,
|
|
43
|
+
type ThemeMode,
|
|
44
|
+
type ThemeScheme,
|
|
45
|
+
} from "./choices.ts";
|
|
49
46
|
|
|
50
47
|
const modes: readonly ThemeMode[] = ["auto", "light", "dark", "darker"];
|
|
51
48
|
|
|
52
|
-
/** Light or dark: the side of a mode a theme has to cover. Darker is dark. */
|
|
53
|
-
export type ThemeScheme = "light" | "dark";
|
|
54
|
-
|
|
55
49
|
export interface PageThemeState {
|
|
56
50
|
readonly mode: ThemeMode;
|
|
57
51
|
/** The scheme in use, with `auto` resolved from the system. */
|
|
@@ -73,73 +67,7 @@ export type ImportResult =
|
|
|
73
67
|
}
|
|
74
68
|
| { readonly ok: false; readonly error: string };
|
|
75
69
|
|
|
76
|
-
|
|
77
|
-
* A theme to offer, by id and name. A `Theme` document is one. `mode` marks
|
|
78
|
-
* a theme with only one scheme, such as Catppuccin Latte: it's offered and
|
|
79
|
-
* kept for that scheme alone, beside a pick for the other.
|
|
80
|
-
*/
|
|
81
|
-
export interface ThemeChoice {
|
|
82
|
-
readonly id: string;
|
|
83
|
-
readonly name: string;
|
|
84
|
-
readonly mode?: ThemeScheme | undefined;
|
|
85
|
-
/** The palette an optional theme comes from, such as `Catppuccin`. */
|
|
86
|
-
readonly family?: string | undefined;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** Whether `choice` can show in `scheme`. */
|
|
90
|
-
export const themeCovers = (choice: ThemeChoice, scheme: ThemeScheme) =>
|
|
91
|
-
choice.mode === undefined || choice.mode === scheme;
|
|
92
|
-
|
|
93
|
-
/** The core themes by id and name, in the order the docs list them. */
|
|
94
|
-
export const coreThemeChoices: readonly ThemeChoice[] = [
|
|
95
|
-
base,
|
|
96
|
-
glazing,
|
|
97
|
-
survey,
|
|
98
|
-
slate,
|
|
99
|
-
bridge,
|
|
100
|
-
snag,
|
|
101
|
-
].map(({ id, name }) => ({ id, name }));
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* The optional themes' documents, by family and then from light to dark.
|
|
105
|
-
* They're bundled with the module, so an app compiled to one binary has them
|
|
106
|
-
* without reading `node_modules`. Decode one with the `MappedTheme` Schema.
|
|
107
|
-
*/
|
|
108
|
-
export const optionalThemeDocuments = [
|
|
109
|
-
catppuccinLatte,
|
|
110
|
-
catppuccinFrappe,
|
|
111
|
-
catppuccinMacchiato,
|
|
112
|
-
catppuccinMocha,
|
|
113
|
-
tokyoNightDay,
|
|
114
|
-
tokyoNight,
|
|
115
|
-
tokyoNightStorm,
|
|
116
|
-
tokyoNightMoon,
|
|
117
|
-
github,
|
|
118
|
-
githubDimmed,
|
|
119
|
-
githubHighContrast,
|
|
120
|
-
] as const;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* The optional themes, mapped from other palettes, by family and then from
|
|
124
|
-
* light to dark. One with a single mode is offered for that scheme alone;
|
|
125
|
-
* one with both, such as GitHub's, for either.
|
|
126
|
-
*/
|
|
127
|
-
export const optionalThemeChoices: readonly ThemeChoice[] =
|
|
128
|
-
optionalThemeDocuments.map((theme) => ({
|
|
129
|
-
id: theme.id,
|
|
130
|
-
name: theme.name,
|
|
131
|
-
family: theme.family,
|
|
132
|
-
mode:
|
|
133
|
-
"otherPalette" in theme
|
|
134
|
-
? undefined
|
|
135
|
-
: theme.mode === "light"
|
|
136
|
-
? "light"
|
|
137
|
-
: "dark",
|
|
138
|
-
}));
|
|
139
|
-
|
|
140
|
-
export interface PageThemeOptions {
|
|
141
|
-
/** The local storage key prefix, such as `my-site:theme`. */
|
|
142
|
-
readonly key: string;
|
|
70
|
+
export interface PageThemeOptions extends ThemeBootOptions {
|
|
143
71
|
/** The built-in themes to offer, their CSS already on the page. */
|
|
144
72
|
readonly themes: readonly ThemeChoice[];
|
|
145
73
|
/**
|
|
@@ -147,16 +75,6 @@ export interface PageThemeOptions {
|
|
|
147
75
|
* register. Defaults to the core themes.
|
|
148
76
|
*/
|
|
149
77
|
readonly documents?: () => Promise<readonly Theme[]>;
|
|
150
|
-
/** The theme id to start with. */
|
|
151
|
-
readonly defaultTheme: string;
|
|
152
|
-
/** The mode to start with. Defaults to `auto`. */
|
|
153
|
-
readonly defaultMode?: ThemeMode;
|
|
154
|
-
/**
|
|
155
|
-
* Whether the Omarchy theme takes over while the visitor hasn't picked
|
|
156
|
-
* one. With `false` it's only offered, and `defaultTheme` stays in use.
|
|
157
|
-
* Defaults to `true`.
|
|
158
|
-
*/
|
|
159
|
-
readonly followOmarchy?: boolean;
|
|
160
78
|
/** The element the attributes go on. Defaults to `<html>`. */
|
|
161
79
|
readonly root?: HTMLElement;
|
|
162
80
|
/**
|
|
@@ -195,22 +113,6 @@ export interface PageTheme {
|
|
|
195
113
|
readonly subscribe: (listener: (state: PageThemeState) => void) => () => void;
|
|
196
114
|
}
|
|
197
115
|
|
|
198
|
-
const keys = (key: string) => ({
|
|
199
|
-
mode: `${key}:mode`,
|
|
200
|
-
theme: `${key}:id`,
|
|
201
|
-
dark: `${key}:id-dark`,
|
|
202
|
-
document: `${key}:custom`,
|
|
203
|
-
css: `${key}:custom-css`,
|
|
204
|
-
name: `${key}:custom-name`,
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
/** The Omarchy theme's cache, kept apart so a reset doesn't drop it. */
|
|
208
|
-
const omarchyKeys = (key: string) => ({
|
|
209
|
-
css: `${key}:omarchy-css`,
|
|
210
|
-
name: `${key}:omarchy-name`,
|
|
211
|
-
mode: `${key}:omarchy-mode`,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
116
|
const read = (key: string) => {
|
|
215
117
|
try {
|
|
216
118
|
return localStorage.getItem(key);
|
|
@@ -228,34 +130,6 @@ const write = (key: string, value: string | null) => {
|
|
|
228
130
|
}
|
|
229
131
|
};
|
|
230
132
|
|
|
231
|
-
/**
|
|
232
|
-
* An inline script that applies the stored mode, theme and any custom or
|
|
233
|
-
* Omarchy theme's cached CSS before the first paint. Takes the same key and
|
|
234
|
-
* defaults as `pageTheme`.
|
|
235
|
-
*/
|
|
236
|
-
export const themeBootScript = (
|
|
237
|
-
options: Pick<
|
|
238
|
-
PageThemeOptions,
|
|
239
|
-
"key" | "defaultTheme" | "defaultMode" | "followOmarchy"
|
|
240
|
-
>,
|
|
241
|
-
) => {
|
|
242
|
-
const config = JSON.stringify({
|
|
243
|
-
keys: keys(options.key),
|
|
244
|
-
omarchy: omarchyKeys(options.key),
|
|
245
|
-
theme: options.defaultTheme,
|
|
246
|
-
mode: options.defaultMode ?? "auto",
|
|
247
|
-
follow: options.followOmarchy !== false,
|
|
248
|
-
custom: customThemeId,
|
|
249
|
-
style: customThemeStyleId,
|
|
250
|
-
omarchyId: omarchyThemeId,
|
|
251
|
-
omarchyStyle: omarchyThemeStyleId,
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// With nothing picked, a cached Omarchy theme for the scheme is the
|
|
255
|
-
// default, unless it's only offered
|
|
256
|
-
return `(()=>{const c=${config};let s;try{s=localStorage}catch{}const g=(k)=>{try{return s?.getItem(k)??null}catch{return null}};const r=document.documentElement;const a=(id,css)=>{const e=document.createElement("style");e.id=id;e.textContent=css;document.head.append(e)};const m=g(c.keys.mode)??c.mode;const d=m==="dark"||m==="darker"||(m==="auto"&&matchMedia("(prefers-color-scheme: dark)").matches);const o=g(c.omarchy.css);let t=(d?g(c.keys.dark):null)??g(c.keys.theme)??(c.follow&&o&&g(c.omarchy.mode)===(d?"dark":"light")?c.omarchyId:c.theme);if(t===c.custom){const css=g(c.keys.css);if(css)a(c.style,css);else t=c.theme}else if(t===c.omarchyId){if(o)a(c.omarchyStyle,o);else t=c.theme}r.setAttribute("data-gw-theme",t);if(m==="auto")r.removeAttribute("data-gw-mode");else r.setAttribute("data-gw-mode",m)})();`;
|
|
257
|
-
};
|
|
258
|
-
|
|
259
133
|
/** Reads a theme from JSON text or an Omarchy `colors.toml`. */
|
|
260
134
|
const readTheme = async (text: string) => {
|
|
261
135
|
const { Result } = await import("effect");
|
|
@@ -274,8 +148,8 @@ const readTheme = async (text: string) => {
|
|
|
274
148
|
* and registers the WebMCP theme tools where the browser offers them.
|
|
275
149
|
*/
|
|
276
150
|
export const pageTheme = (options: PageThemeOptions): PageTheme => {
|
|
277
|
-
const stored =
|
|
278
|
-
const storedOmarchy =
|
|
151
|
+
const stored = themeStorageKeys(options.key);
|
|
152
|
+
const storedOmarchy = omarchyStorageKeys(options.key);
|
|
279
153
|
const root = options.root ?? document.documentElement;
|
|
280
154
|
const defaultMode = options.defaultMode ?? "auto";
|
|
281
155
|
const listeners = new Set<(state: PageThemeState) => void>();
|