@adea-ai/ui 0.22.1 → 0.23.0
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 +6 -3
- package/dist/components/account-drawer.d.ts +3 -3
- package/dist/components/account-drawer.js +119 -19
- package/dist/components/on-screen-controls.d.ts +2 -1
- package/dist/components/on-screen-controls.js +158 -46
- package/dist/components/scene-settings.d.ts +3 -3
- package/dist/components/scene-settings.js +247 -28
- package/dist/components/theme-provider.d.ts +27 -5
- package/dist/components/theme-provider.js +96 -7
- package/dist/components/theme-toggle.d.ts +4 -4
- package/dist/components/theme-toggle.js +62 -18
- package/dist/components/ui/badge.d.ts +4 -3
- package/dist/components/ui/badge.js +31 -30
- package/dist/components/ui/button.d.ts +4 -3
- package/dist/components/ui/button.js +49 -32
- package/dist/components/ui/card.d.ts +3 -3
- package/dist/components/ui/card.js +25 -6
- package/dist/components/ui/dialog.d.ts +13 -13
- package/dist/components/ui/dialog.js +94 -26
- package/dist/components/ui/drawer.d.ts +23 -15
- package/dist/components/ui/drawer.js +109 -64
- package/dist/components/ui/dropdown-menu.d.ts +28 -22
- package/dist/components/ui/dropdown-menu.js +165 -36
- package/dist/components/ui/empty.d.ts +7 -6
- package/dist/components/ui/empty.js +78 -26
- package/dist/components/ui/field.d.ts +15 -14
- package/dist/components/ui/field.js +177 -55
- package/dist/components/ui/input.d.ts +2 -2
- package/dist/components/ui/input.js +20 -5
- package/dist/components/ui/label.d.ts +2 -2
- package/dist/components/ui/label.js +15 -5
- package/dist/components/ui/radio-group.d.ts +4 -4
- package/dist/components/ui/radio-group.js +36 -9
- package/dist/components/ui/separator.d.ts +6 -2
- package/dist/components/ui/separator.js +18 -6
- package/dist/components/ui/skeleton.d.ts +2 -1
- package/dist/components/ui/skeleton.js +15 -4
- package/dist/components/ui/spinner.d.ts +4 -3
- package/dist/components/ui/spinner.js +15 -5
- package/dist/components/ui/switch.d.ts +6 -3
- package/dist/components/ui/switch.js +57 -6
- package/dist/components/ui/tabs.d.ts +6 -5
- package/dist/components/ui/tabs.js +52 -24
- package/dist/components/ui/toggle-group.d.ts +10 -8
- package/dist/components/ui/toggle-group.js +91 -20
- package/dist/components/ui/toggle.d.ts +4 -2
- package/dist/components/ui/toggle.js +38 -23
- package/dist/components/ui/tooltip.d.ts +13 -6
- package/dist/components/ui/tooltip.js +51 -14
- package/dist/components/version-dialog.d.ts +2 -2
- package/dist/components/version-dialog.js +322 -129
- package/dist/components/workspace-brand.d.ts +1 -1
- package/dist/components/workspace-brand.js +12 -3
- package/dist/components/workspace-logo.d.ts +2 -2
- package/dist/components/workspace-logo.js +15 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -19
- package/dist/lib/utils.js +7 -4
- package/dist/lib/version-notes.js +14 -29
- package/package.json +18 -16
- package/src/components/account-drawer.tsx +48 -67
- package/src/components/on-screen-controls.tsx +55 -62
- package/src/components/scene-settings.tsx +97 -100
- package/src/components/theme-provider.tsx +122 -22
- package/src/components/theme-toggle.tsx +29 -54
- package/src/components/ui/badge.tsx +14 -23
- package/src/components/ui/button.tsx +9 -11
- package/src/components/ui/card.tsx +9 -6
- package/src/components/ui/dialog.tsx +58 -55
- package/src/components/ui/drawer.tsx +84 -125
- package/src/components/ui/dropdown-menu.tsx +130 -153
- package/src/components/ui/empty.tsx +29 -26
- package/src/components/ui/field.tsx +83 -87
- package/src/components/ui/input.tsx +8 -8
- package/src/components/ui/label.tsx +6 -7
- package/src/components/ui/radio-group.tsx +22 -19
- package/src/components/ui/separator.tsx +16 -9
- package/src/components/ui/skeleton.tsx +6 -3
- package/src/components/ui/spinner.tsx +9 -5
- package/src/components/ui/switch.tsx +47 -20
- package/src/components/ui/tabs.tsx +31 -30
- package/src/components/ui/toggle-group.tsx +65 -54
- package/src/components/ui/toggle.tsx +9 -12
- package/src/components/ui/tooltip.tsx +41 -36
- package/src/components/version-dialog.tsx +144 -144
- package/src/components/workspace-brand.tsx +5 -5
- package/src/components/workspace-logo.tsx +9 -8
- package/src/index.tsx +7 -1
- package/src/styles/base.css +637 -0
- package/src/styles/globals.css +1 -1
- package/tsconfig.json +2 -1
- package/components.json +0 -19
|
@@ -1,34 +1,253 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { Button } from "./ui/button.js";
|
|
2
|
+
import { AccountDrawer } from "./account-drawer.js";
|
|
3
|
+
import { Portal, createComponent, insert, template } from "solid-js/web";
|
|
4
|
+
import { Box, Camera, Focus, Grid3X3, UserRoundPen } from "lucide-solid";
|
|
5
|
+
import { Show, createEffect, createSignal } from "solid-js";
|
|
6
|
+
//#region src/components/scene-settings.tsx
|
|
7
|
+
var _tmpl$ = /*#__PURE__*/ template(`<div class=workspace-camera-control role=group aria-label="Camera view">`);
|
|
8
|
+
var _tmpl$2 = /*#__PURE__*/ template(`<span class=workspace-character-designer-label>Character`);
|
|
9
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<span class=workspace-room-designer-label>Room designer`);
|
|
10
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<span class=workspace-scene-editor-label>Scene editor`);
|
|
11
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<div class="fixed right-4 top-16 z-40">`);
|
|
8
12
|
function usePortalTarget(targetId) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
const [target, setTarget] = createSignal(null);
|
|
14
|
+
createEffect(() => {
|
|
15
|
+
const id = targetId();
|
|
16
|
+
setTarget(id ? document.getElementById(id) : null);
|
|
17
|
+
});
|
|
18
|
+
return target;
|
|
14
19
|
}
|
|
15
20
|
function renderInTarget(content, target) {
|
|
16
|
-
|
|
21
|
+
return target ? createComponent(Portal, {
|
|
22
|
+
mount: target,
|
|
23
|
+
children: content
|
|
24
|
+
}) : content;
|
|
17
25
|
}
|
|
18
26
|
/** Compact scene controls shared by the HQ shell and other scene hosts. */
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
function SceneSettings(props) {
|
|
28
|
+
const cameraTarget = usePortalTarget(() => props.cameraTargetId);
|
|
29
|
+
const characterDesignerTarget = usePortalTarget(() => props.characterDesignerTargetId);
|
|
30
|
+
const roomDesignerTarget = usePortalTarget(() => props.roomDesignerTargetId);
|
|
31
|
+
const sceneEditorTarget = usePortalTarget(() => props.sceneEditorTargetId);
|
|
32
|
+
const cameraControl = (() => {
|
|
33
|
+
var _el$ = _tmpl$();
|
|
34
|
+
insert(_el$, createComponent(Button, {
|
|
35
|
+
type: "button",
|
|
36
|
+
size: "sm",
|
|
37
|
+
get variant() {
|
|
38
|
+
return props.cameraViewMode === "perspective" ? "default" : "outline";
|
|
39
|
+
},
|
|
40
|
+
"class": "workspace-camera-button",
|
|
41
|
+
"aria-label": "Perspective camera",
|
|
42
|
+
title: "Perspective camera",
|
|
43
|
+
get ["aria-pressed"]() {
|
|
44
|
+
return props.cameraViewMode === "perspective";
|
|
45
|
+
},
|
|
46
|
+
onClick: () => props.onCameraViewModeChange("perspective"),
|
|
47
|
+
get children() {
|
|
48
|
+
return [createComponent(Camera, { "aria-hidden": "true" }), "Perspective"];
|
|
49
|
+
}
|
|
50
|
+
}), null);
|
|
51
|
+
insert(_el$, createComponent(Button, {
|
|
52
|
+
type: "button",
|
|
53
|
+
size: "sm",
|
|
54
|
+
get variant() {
|
|
55
|
+
return props.cameraViewMode === "orthographic" ? "default" : "outline";
|
|
56
|
+
},
|
|
57
|
+
"class": "workspace-camera-button",
|
|
58
|
+
"aria-label": "Top-down camera",
|
|
59
|
+
title: "Top-down camera",
|
|
60
|
+
get ["aria-pressed"]() {
|
|
61
|
+
return props.cameraViewMode === "orthographic";
|
|
62
|
+
},
|
|
63
|
+
onClick: () => props.onCameraViewModeChange("orthographic"),
|
|
64
|
+
get children() {
|
|
65
|
+
return [createComponent(Focus, { "aria-hidden": "true" }), "Top-down"];
|
|
66
|
+
}
|
|
67
|
+
}), null);
|
|
68
|
+
return _el$;
|
|
69
|
+
})();
|
|
70
|
+
const characterDesignerControl = createComponent(Button, {
|
|
71
|
+
type: "button",
|
|
72
|
+
get variant() {
|
|
73
|
+
return props.characterDesignerEnabled ? "default" : "outline";
|
|
74
|
+
},
|
|
75
|
+
size: "sm",
|
|
76
|
+
"aria-haspopup": "dialog",
|
|
77
|
+
get ["aria-label"]() {
|
|
78
|
+
return props.characterDesignerEnabled ? "Close character designer" : "Open character designer";
|
|
79
|
+
},
|
|
80
|
+
get title() {
|
|
81
|
+
return props.characterDesignerEnabled ? "Close character designer" : "Open character designer";
|
|
82
|
+
},
|
|
83
|
+
get ["aria-pressed"]() {
|
|
84
|
+
return props.characterDesignerEnabled;
|
|
85
|
+
},
|
|
86
|
+
onClick: () => props.onCharacterDesignerChange?.(!props.characterDesignerEnabled),
|
|
87
|
+
get children() {
|
|
88
|
+
return [createComponent(UserRoundPen, {
|
|
89
|
+
"class": "size-4",
|
|
90
|
+
"aria-hidden": "true"
|
|
91
|
+
}), _tmpl$2()];
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const roomDesignerControl = createComponent(Button, {
|
|
95
|
+
type: "button",
|
|
96
|
+
variant: "outline",
|
|
97
|
+
size: "sm",
|
|
98
|
+
"aria-haspopup": "dialog",
|
|
99
|
+
"aria-label": "Open room designer",
|
|
100
|
+
title: "Open room designer",
|
|
101
|
+
onClick: () => props.onOpenRoomDesigner?.(),
|
|
102
|
+
get children() {
|
|
103
|
+
return [createComponent(Grid3X3, {
|
|
104
|
+
"class": "size-4",
|
|
105
|
+
"aria-hidden": "true"
|
|
106
|
+
}), _tmpl$3()];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const sceneEditorControl = createComponent(Button, {
|
|
110
|
+
type: "button",
|
|
111
|
+
get variant() {
|
|
112
|
+
return props.sceneEditorEnabled ? "default" : "outline";
|
|
113
|
+
},
|
|
114
|
+
size: "sm",
|
|
115
|
+
"aria-haspopup": "dialog",
|
|
116
|
+
get ["aria-label"]() {
|
|
117
|
+
return props.sceneEditorEnabled ? "Close scene editor" : "Open scene editor";
|
|
118
|
+
},
|
|
119
|
+
get title() {
|
|
120
|
+
return props.sceneEditorEnabled ? "Close scene editor" : "Open scene editor";
|
|
121
|
+
},
|
|
122
|
+
get ["aria-pressed"]() {
|
|
123
|
+
return props.sceneEditorEnabled;
|
|
124
|
+
},
|
|
125
|
+
onClick: () => props.onSceneEditorChange?.(!props.sceneEditorEnabled),
|
|
126
|
+
get children() {
|
|
127
|
+
return [createComponent(Box, {
|
|
128
|
+
"class": "size-4",
|
|
129
|
+
"aria-hidden": "true"
|
|
130
|
+
}), _tmpl$4()];
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const showCharacterDesignerControl = () => props.characterDesignerEnabled != null && !props.characterDesignerEnabled && Boolean(props.onCharacterDesignerChange);
|
|
134
|
+
const showRoomDesignerControl = () => Boolean(props.onOpenRoomDesigner) && props.cameraViewMode === "orthographic";
|
|
135
|
+
const showSceneEditorControl = () => props.sceneEditorEnabled != null && !props.sceneEditorEnabled && Boolean(props.onSceneEditorChange) && props.cameraViewMode === "perspective";
|
|
136
|
+
return [
|
|
137
|
+
createComponent(Show, {
|
|
138
|
+
get when() {
|
|
139
|
+
return props.showAccountDrawer ?? true;
|
|
140
|
+
},
|
|
141
|
+
get children() {
|
|
142
|
+
return createComponent(AccountDrawer, {
|
|
143
|
+
get accountLabel() {
|
|
144
|
+
return props.accountLabel;
|
|
145
|
+
},
|
|
146
|
+
get authenticated() {
|
|
147
|
+
return props.accountAuthenticated;
|
|
148
|
+
},
|
|
149
|
+
get busy() {
|
|
150
|
+
return props.accountBusy;
|
|
151
|
+
},
|
|
152
|
+
get musicControl() {
|
|
153
|
+
return props.accountMusicControl;
|
|
154
|
+
},
|
|
155
|
+
get triggerTargetId() {
|
|
156
|
+
return props.accountTargetId;
|
|
157
|
+
},
|
|
158
|
+
get onSignIn() {
|
|
159
|
+
return props.onAccountSignIn;
|
|
160
|
+
},
|
|
161
|
+
get onSignOut() {
|
|
162
|
+
return props.onAccountSignOut;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}),
|
|
167
|
+
createComponent(Show, {
|
|
168
|
+
get when() {
|
|
169
|
+
return props.allowCameraViewModeChange ?? true;
|
|
170
|
+
},
|
|
171
|
+
get children() {
|
|
172
|
+
return renderInTarget(cameraControl, cameraTarget());
|
|
173
|
+
}
|
|
174
|
+
}),
|
|
175
|
+
createComponent(Show, {
|
|
176
|
+
get when() {
|
|
177
|
+
return showCharacterDesignerControl();
|
|
178
|
+
},
|
|
179
|
+
get children() {
|
|
180
|
+
return createComponent(Show, {
|
|
181
|
+
get when() {
|
|
182
|
+
return characterDesignerTarget();
|
|
183
|
+
},
|
|
184
|
+
get fallback() {
|
|
185
|
+
return (() => {
|
|
186
|
+
var _el$5 = _tmpl$5();
|
|
187
|
+
insert(_el$5, characterDesignerControl);
|
|
188
|
+
return _el$5;
|
|
189
|
+
})();
|
|
190
|
+
},
|
|
191
|
+
children: (target) => createComponent(Portal, {
|
|
192
|
+
get mount() {
|
|
193
|
+
return target();
|
|
194
|
+
},
|
|
195
|
+
children: characterDesignerControl
|
|
196
|
+
})
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}),
|
|
200
|
+
createComponent(Show, {
|
|
201
|
+
get when() {
|
|
202
|
+
return showRoomDesignerControl();
|
|
203
|
+
},
|
|
204
|
+
get children() {
|
|
205
|
+
return createComponent(Show, {
|
|
206
|
+
get when() {
|
|
207
|
+
return roomDesignerTarget();
|
|
208
|
+
},
|
|
209
|
+
get fallback() {
|
|
210
|
+
return (() => {
|
|
211
|
+
var _el$6 = _tmpl$5();
|
|
212
|
+
insert(_el$6, roomDesignerControl);
|
|
213
|
+
return _el$6;
|
|
214
|
+
})();
|
|
215
|
+
},
|
|
216
|
+
children: (target) => createComponent(Portal, {
|
|
217
|
+
get mount() {
|
|
218
|
+
return target();
|
|
219
|
+
},
|
|
220
|
+
children: roomDesignerControl
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}),
|
|
225
|
+
createComponent(Show, {
|
|
226
|
+
get when() {
|
|
227
|
+
return showSceneEditorControl();
|
|
228
|
+
},
|
|
229
|
+
get children() {
|
|
230
|
+
return createComponent(Show, {
|
|
231
|
+
get when() {
|
|
232
|
+
return sceneEditorTarget();
|
|
233
|
+
},
|
|
234
|
+
get fallback() {
|
|
235
|
+
return (() => {
|
|
236
|
+
var _el$7 = _tmpl$5();
|
|
237
|
+
insert(_el$7, sceneEditorControl);
|
|
238
|
+
return _el$7;
|
|
239
|
+
})();
|
|
240
|
+
},
|
|
241
|
+
children: (target) => createComponent(Portal, {
|
|
242
|
+
get mount() {
|
|
243
|
+
return target();
|
|
244
|
+
},
|
|
245
|
+
children: sceneEditorControl
|
|
246
|
+
})
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
];
|
|
34
251
|
}
|
|
252
|
+
//#endregion
|
|
253
|
+
export { SceneSettings };
|
|
@@ -1,5 +1,27 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { type Accessor, type JSX, type ParentProps } from 'solid-js';
|
|
2
|
+
export type Theme = 'light' | 'dark' | 'system';
|
|
3
|
+
export type ResolvedTheme = 'light' | 'dark';
|
|
4
|
+
type ThemeContextValue = {
|
|
5
|
+
theme: Accessor<Theme>;
|
|
6
|
+
resolvedTheme: Accessor<ResolvedTheme>;
|
|
7
|
+
setTheme: (theme: Theme) => void;
|
|
8
|
+
};
|
|
9
|
+
type ThemeProviderProps = ParentProps<{
|
|
10
|
+
defaultTheme?: Theme;
|
|
11
|
+
disableTransitionOnChange?: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* The shared Solid theme provider. It owns the same contract the previous
|
|
15
|
+
* provider exposed to the token layer: a `dark` class on the document element
|
|
16
|
+
* plus a `color-scheme` style, persisted in `localStorage` and defaulting to
|
|
17
|
+
* the system preference.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ThemeProvider(props: ThemeProviderProps): JSX.Element;
|
|
20
|
+
export declare function useTheme(): ThemeContextValue;
|
|
21
|
+
/**
|
|
22
|
+
* Pre-paint theme restore for server-rendered documents. Rendered in the
|
|
23
|
+
* document head, it applies the stored or system theme before first paint so
|
|
24
|
+
* hydration never shows the wrong palette.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ThemeScript(): JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -1,8 +1,97 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { createComponent, template } from "solid-js/web";
|
|
2
|
+
import { createContext, createEffect, createSignal, onCleanup, useContext } from "solid-js";
|
|
3
|
+
//#region src/components/theme-provider.tsx
|
|
4
|
+
var _tmpl$ = /*#__PURE__*/ template(`<script>`);
|
|
5
|
+
var STORAGE_KEY = "theme";
|
|
6
|
+
var DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
7
|
+
var ThemeContext = createContext();
|
|
8
|
+
function readStoredTheme() {
|
|
9
|
+
if (typeof window === "undefined") return "system";
|
|
10
|
+
try {
|
|
11
|
+
const stored = window.localStorage.getItem(STORAGE_KEY);
|
|
12
|
+
return stored === "light" || stored === "dark" || stored === "system" ? stored : "system";
|
|
13
|
+
} catch {
|
|
14
|
+
return "system";
|
|
15
|
+
}
|
|
8
16
|
}
|
|
17
|
+
function systemPrefersDark() {
|
|
18
|
+
return typeof window !== "undefined" && window.matchMedia(DARK_QUERY).matches;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Applies the resolved theme to the document and suppresses transitions for the
|
|
22
|
+
* frame that carries the change, so a theme switch cannot animate page-wide.
|
|
23
|
+
*/
|
|
24
|
+
function applyTheme(theme, disableTransitionOnChange) {
|
|
25
|
+
if (typeof document === "undefined") return;
|
|
26
|
+
const root = document.documentElement;
|
|
27
|
+
let restoreTransitions;
|
|
28
|
+
if (disableTransitionOnChange) {
|
|
29
|
+
const style = document.createElement("style");
|
|
30
|
+
style.appendChild(document.createTextNode("*{transition:none !important}"));
|
|
31
|
+
document.head.appendChild(style);
|
|
32
|
+
style.offsetHeight;
|
|
33
|
+
restoreTransitions = () => style.remove();
|
|
34
|
+
}
|
|
35
|
+
root.classList.toggle("dark", theme === "dark");
|
|
36
|
+
root.style.colorScheme = theme;
|
|
37
|
+
if (restoreTransitions) requestAnimationFrame(() => requestAnimationFrame(() => restoreTransitions?.()));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The shared Solid theme provider. It owns the same contract the previous
|
|
41
|
+
* provider exposed to the token layer: a `dark` class on the document element
|
|
42
|
+
* plus a `color-scheme` style, persisted in `localStorage` and defaulting to
|
|
43
|
+
* the system preference.
|
|
44
|
+
*/
|
|
45
|
+
function ThemeProvider(props) {
|
|
46
|
+
const [theme, setThemeSignal] = createSignal(props.defaultTheme ?? readStoredTheme());
|
|
47
|
+
const [prefersDark, setPrefersDark] = createSignal(systemPrefersDark());
|
|
48
|
+
const resolvedTheme = () => {
|
|
49
|
+
const current = theme();
|
|
50
|
+
if (current === "system") return prefersDark() ? "dark" : "light";
|
|
51
|
+
return current;
|
|
52
|
+
};
|
|
53
|
+
if (typeof window !== "undefined") {
|
|
54
|
+
const media = window.matchMedia(DARK_QUERY);
|
|
55
|
+
const onChange = (event) => setPrefersDark(event.matches);
|
|
56
|
+
media.addEventListener("change", onChange);
|
|
57
|
+
onCleanup(() => media.removeEventListener("change", onChange));
|
|
58
|
+
}
|
|
59
|
+
createEffect(() => {
|
|
60
|
+
applyTheme(resolvedTheme(), props.disableTransitionOnChange ?? true);
|
|
61
|
+
});
|
|
62
|
+
const setTheme = (next) => {
|
|
63
|
+
setThemeSignal(next);
|
|
64
|
+
try {
|
|
65
|
+
window.localStorage.setItem(STORAGE_KEY, next);
|
|
66
|
+
} catch {}
|
|
67
|
+
};
|
|
68
|
+
return createComponent(ThemeContext.Provider, {
|
|
69
|
+
value: {
|
|
70
|
+
theme,
|
|
71
|
+
resolvedTheme,
|
|
72
|
+
setTheme
|
|
73
|
+
},
|
|
74
|
+
get children() {
|
|
75
|
+
return props.children;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function useTheme() {
|
|
80
|
+
const context = useContext(ThemeContext);
|
|
81
|
+
if (!context) throw new Error("useTheme must be used within a ThemeProvider.");
|
|
82
|
+
return context;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Pre-paint theme restore for server-rendered documents. Rendered in the
|
|
86
|
+
* document head, it applies the stored or system theme before first paint so
|
|
87
|
+
* hydration never shows the wrong palette.
|
|
88
|
+
*/
|
|
89
|
+
function ThemeScript() {
|
|
90
|
+
return (() => {
|
|
91
|
+
var _el$ = _tmpl$();
|
|
92
|
+
_el$.innerHTML = "(function(){try{var t=localStorage.getItem('theme')||'system';var d=t==='dark'||(t==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);var r=document.documentElement;r.classList.toggle('dark',d);r.style.colorScheme=d?'dark':'light'}catch(e){}})();";
|
|
93
|
+
return _el$;
|
|
94
|
+
})();
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { ThemeProvider, ThemeScript, useTheme };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Compact sun/moon theme selector. Wired to the
|
|
2
|
+
* Compact sun/moon theme selector. Wired to the shared theme provider so the
|
|
3
3
|
* choice persists across the app (localStorage) and applies to every scene.
|
|
4
4
|
*/
|
|
5
|
-
export declare function ThemeToggle(
|
|
6
|
-
|
|
7
|
-
}): import("
|
|
5
|
+
export declare function ThemeToggle(props: {
|
|
6
|
+
class?: string;
|
|
7
|
+
}): import("solid-js").JSX.Element;
|
|
@@ -1,20 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Button } from "./ui/button.js";
|
|
3
|
+
import { useTheme } from "./theme-provider.js";
|
|
4
|
+
import { className, createComponent, effect, insert, template } from "solid-js/web";
|
|
5
|
+
import { Monitor, Moon, Sun } from "lucide-solid";
|
|
6
|
+
import { For } from "solid-js";
|
|
7
|
+
//#region src/components/theme-toggle.tsx
|
|
8
|
+
var _tmpl$ = /*#__PURE__*/ template(`<div role=radiogroup aria-label=Theme>`);
|
|
9
|
+
var THEMES = [
|
|
10
|
+
{
|
|
11
|
+
value: "system",
|
|
12
|
+
label: "System theme",
|
|
13
|
+
icon: Monitor
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
value: "light",
|
|
17
|
+
label: "Light theme",
|
|
18
|
+
icon: Sun
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: "dark",
|
|
22
|
+
label: "Dark theme",
|
|
23
|
+
icon: Moon
|
|
24
|
+
}
|
|
25
|
+
];
|
|
8
26
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
* Compact sun/moon theme selector. Wired to the shared theme provider so the
|
|
28
|
+
* choice persists across the app (localStorage) and applies to every scene.
|
|
29
|
+
*/
|
|
30
|
+
function ThemeToggle(props) {
|
|
31
|
+
const { theme, setTheme } = useTheme();
|
|
32
|
+
return (() => {
|
|
33
|
+
var _el$ = _tmpl$();
|
|
34
|
+
insert(_el$, createComponent(For, {
|
|
35
|
+
each: THEMES,
|
|
36
|
+
children: (option) => createComponent(Button, {
|
|
37
|
+
type: "button",
|
|
38
|
+
role: "radio",
|
|
39
|
+
get ["aria-checked"]() {
|
|
40
|
+
return theme() === option.value;
|
|
41
|
+
},
|
|
42
|
+
get ["aria-label"]() {
|
|
43
|
+
return option.label;
|
|
44
|
+
},
|
|
45
|
+
get variant() {
|
|
46
|
+
return theme() === option.value ? "default" : "ghost";
|
|
47
|
+
},
|
|
48
|
+
size: "icon-sm",
|
|
49
|
+
onClick: () => setTheme(option.value),
|
|
50
|
+
"class": "rounded-full",
|
|
51
|
+
get children() {
|
|
52
|
+
return createComponent(option.icon, {
|
|
53
|
+
"class": "size-4",
|
|
54
|
+
"aria-hidden": "true"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}));
|
|
59
|
+
effect(() => className(_el$, cn("inline-flex items-center gap-2 rounded-full border border-input bg-background p-2", props.class)));
|
|
60
|
+
return _el$;
|
|
61
|
+
})();
|
|
20
62
|
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { ThemeToggle };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useRender } from '@base-ui/react/use-render';
|
|
2
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { type ComponentProps } from 'solid-js';
|
|
3
3
|
declare const badgeVariants: (props?: ({
|
|
4
4
|
variant?: "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
type BadgeProps = ComponentProps<'span'> & VariantProps<typeof badgeVariants>;
|
|
7
|
+
declare function Badge(props: BadgeProps): import("solid-js").JSX.Element;
|
|
8
|
+
export { Badge, badgeVariants, type BadgeProps };
|
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
variant: 'default',
|
|
18
|
-
},
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { mergeProps, spread, template } from "solid-js/web";
|
|
3
|
+
import { splitProps } from "solid-js";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
//#region src/components/ui/badge.tsx
|
|
6
|
+
var _tmpl$ = /*#__PURE__*/ template(`<span data-slot=badge>`);
|
|
7
|
+
var badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
|
|
8
|
+
variants: { variant: {
|
|
9
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
10
|
+
secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
|
11
|
+
destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
|
|
12
|
+
outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
|
|
13
|
+
ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
|
|
14
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
15
|
+
} },
|
|
16
|
+
defaultVariants: { variant: "default" }
|
|
19
17
|
});
|
|
20
|
-
function Badge(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
function Badge(props) {
|
|
19
|
+
const [local, rest] = splitProps(props, ["class", "variant"]);
|
|
20
|
+
return (() => {
|
|
21
|
+
var _el$ = _tmpl$();
|
|
22
|
+
spread(_el$, mergeProps({
|
|
23
|
+
get ["data-variant"]() {
|
|
24
|
+
return local.variant ?? "default";
|
|
25
|
+
},
|
|
26
|
+
get ["class"]() {
|
|
27
|
+
return cn(badgeVariants({ variant: local.variant }), local.class);
|
|
28
|
+
}
|
|
29
|
+
}, rest), false, false);
|
|
30
|
+
return _el$;
|
|
31
|
+
})();
|
|
32
32
|
}
|
|
33
|
+
//#endregion
|
|
33
34
|
export { Badge, badgeVariants };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Button as ButtonPrimitive } from '@base-ui/react/button';
|
|
2
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { type ComponentProps } from 'solid-js';
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
4
|
variant?: "default" | "outline" | "secondary" | "ghost" | "destructive" | "success" | "link" | null | undefined;
|
|
5
5
|
size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
|
|
8
|
+
declare function Button(props: ButtonProps): import("solid-js").JSX.Element;
|
|
9
|
+
export { Button, buttonVariants, type ButtonProps };
|