@nastechai/agent 0.16.0 → 0.17.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/eslint.config.js +23 -0
- package/index.html +24 -0
- package/package.json +54 -26
- package/package.json.bak +89 -0
- package/package.json.pub +88 -0
- package/src/App.tsx +1173 -0
- package/src/components/AuthWidget.tsx +150 -0
- package/src/components/AutoField.tsx +206 -0
- package/src/components/Backdrop.tsx +93 -0
- package/src/components/ChatSidebar.tsx +394 -0
- package/src/components/DeleteConfirmDialog.tsx +40 -0
- package/src/components/LanguageSwitcher.tsx +186 -0
- package/src/components/Markdown.tsx +383 -0
- package/src/components/ModelInfoCard.tsx +112 -0
- package/src/components/ModelPickerDialog.tsx +470 -0
- package/src/components/OAuthLoginModal.tsx +374 -0
- package/src/components/OAuthProvidersCard.tsx +287 -0
- package/src/components/PlatformsCard.tsx +97 -0
- package/src/components/ScheduleBuilder.tsx +273 -0
- package/src/components/SidebarFooter.tsx +42 -0
- package/src/components/SidebarStatusStrip.tsx +72 -0
- package/src/components/SlashPopover.tsx +171 -0
- package/src/components/ThemeSwitcher.tsx +243 -0
- package/src/components/ToolCall.tsx +228 -0
- package/src/components/ToolsetConfigDrawer.tsx +448 -0
- package/src/contexts/PageHeaderProvider.tsx +139 -0
- package/src/contexts/SystemActions.tsx +120 -0
- package/src/contexts/page-header-context.ts +12 -0
- package/src/contexts/system-actions-context.ts +18 -0
- package/src/contexts/usePageHeader.ts +10 -0
- package/src/contexts/useSystemActions.ts +15 -0
- package/src/hooks/useModalBehavior.ts +44 -0
- package/src/hooks/useSidebarStatus.ts +27 -0
- package/src/i18n/af.ts +702 -0
- package/src/i18n/context.tsx +123 -0
- package/src/i18n/de.ts +701 -0
- package/src/i18n/en.ts +708 -0
- package/src/i18n/es.ts +701 -0
- package/src/i18n/fr.ts +701 -0
- package/src/i18n/ga.ts +702 -0
- package/src/i18n/hu.ts +702 -0
- package/src/i18n/index.ts +2 -0
- package/src/i18n/it.ts +701 -0
- package/src/i18n/ja.ts +702 -0
- package/src/i18n/ko.ts +702 -0
- package/src/i18n/pt.ts +702 -0
- package/src/i18n/ru.ts +702 -0
- package/src/i18n/tr.ts +702 -0
- package/src/i18n/types.ts +710 -0
- package/src/i18n/uk.ts +702 -0
- package/src/i18n/zh-hant.ts +702 -0
- package/src/i18n/zh.ts +698 -0
- package/src/index.css +274 -0
- package/src/lib/api.ts +1585 -0
- package/src/lib/dashboard-flags.ts +15 -0
- package/src/lib/format.ts +9 -0
- package/src/lib/fuzzy.ts +192 -0
- package/src/lib/gatewayClient.ts +253 -0
- package/src/lib/nested.ts +23 -0
- package/src/lib/resolve-page-title.ts +41 -0
- package/src/lib/schedule.ts +382 -0
- package/src/lib/slashExec.ts +163 -0
- package/src/lib/utils.ts +35 -0
- package/src/main.tsx +25 -0
- package/src/pages/AnalyticsPage.tsx +601 -0
- package/src/pages/ChannelsPage.tsx +772 -0
- package/src/pages/ChatPage.tsx +889 -0
- package/src/pages/ConfigPage.tsx +660 -0
- package/src/pages/CronPage.tsx +524 -0
- package/src/pages/DocsPage.tsx +69 -0
- package/src/pages/EnvPage.tsx +918 -0
- package/src/pages/LogsPage.tsx +246 -0
- package/src/pages/McpPage.tsx +757 -0
- package/src/pages/ModelsPage.tsx +994 -0
- package/src/pages/PairingPage.tsx +276 -0
- package/src/pages/PluginsPage.tsx +580 -0
- package/src/pages/ProfilesPage.tsx +559 -0
- package/src/pages/SessionsPage.tsx +936 -0
- package/src/pages/SkillsPage.tsx +557 -0
- package/src/pages/SystemPage.tsx +1259 -0
- package/src/pages/WebhooksPage.tsx +483 -0
- package/src/plugins/PluginPage.tsx +64 -0
- package/src/plugins/index.ts +6 -0
- package/src/plugins/registry.ts +151 -0
- package/src/plugins/sdk.d.ts +160 -0
- package/src/plugins/slots.ts +199 -0
- package/src/plugins/types.ts +37 -0
- package/src/plugins/usePlugins.ts +133 -0
- package/src/themes/context.tsx +443 -0
- package/src/themes/fonts.ts +160 -0
- package/src/themes/index.ts +3 -0
- package/src/themes/presets.ts +477 -0
- package/src/themes/types.ts +187 -0
- package/tsconfig.app.json +34 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +26 -0
- package/vite.config.ts +124 -0
- package/vite.config.ts.timestamp-1780999102396-af6b77b30ebd8.mjs +105 -0
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import type { DashboardTheme, ThemeTypography, ThemeLayout } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Built-in dashboard themes.
|
|
5
|
+
*
|
|
6
|
+
* Each theme defines its own palette, typography, and layout so switching
|
|
7
|
+
* themes produces visible changes beyond just color — fonts, density, and
|
|
8
|
+
* corner-radius all shift to match the theme's personality.
|
|
9
|
+
*
|
|
10
|
+
* Theme names must stay in sync with the backend's
|
|
11
|
+
* `_BUILTIN_DASHBOARD_THEMES` list in `nastech_cli/web_server.py`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Shared typography / layout presets
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/** Default system stack — neutral, safe fallback for every platform. */
|
|
19
|
+
const SYSTEM_SANS =
|
|
20
|
+
'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
21
|
+
const SYSTEM_MONO =
|
|
22
|
+
'ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace';
|
|
23
|
+
|
|
24
|
+
const DEFAULT_TYPOGRAPHY: ThemeTypography = {
|
|
25
|
+
fontSans: SYSTEM_SANS,
|
|
26
|
+
fontMono: SYSTEM_MONO,
|
|
27
|
+
baseSize: "15px",
|
|
28
|
+
lineHeight: "1.55",
|
|
29
|
+
letterSpacing: "0",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const DEFAULT_LAYOUT: ThemeLayout = {
|
|
33
|
+
radius: "0.5rem",
|
|
34
|
+
density: "comfortable",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Rounded layout — softer, more playful corners everywhere. */
|
|
38
|
+
export const ROUNDED_LAYOUT: ThemeLayout = {
|
|
39
|
+
radius: "1.25rem",
|
|
40
|
+
density: "comfortable",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Themes
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
export const defaultTheme: DashboardTheme = {
|
|
48
|
+
name: "default",
|
|
49
|
+
label: "NasTech Teal",
|
|
50
|
+
description: "Classic dark teal — the canonical NasTech look",
|
|
51
|
+
palette: {
|
|
52
|
+
background: { hex: "#041c1c", alpha: 1 },
|
|
53
|
+
midground: { hex: "#ffe6cb", alpha: 1 },
|
|
54
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
55
|
+
warmGlow: "rgba(255, 189, 56, 0.35)",
|
|
56
|
+
noiseOpacity: 1,
|
|
57
|
+
},
|
|
58
|
+
typography: DEFAULT_TYPOGRAPHY,
|
|
59
|
+
layout: DEFAULT_LAYOUT,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const midnightTheme: DashboardTheme = {
|
|
63
|
+
name: "midnight",
|
|
64
|
+
label: "Midnight",
|
|
65
|
+
description: "Deep blue-violet with cool accents",
|
|
66
|
+
palette: {
|
|
67
|
+
background: { hex: "#0a0a1f", alpha: 1 },
|
|
68
|
+
midground: { hex: "#d4c8ff", alpha: 1 },
|
|
69
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
70
|
+
warmGlow: "rgba(167, 139, 250, 0.32)",
|
|
71
|
+
noiseOpacity: 0.8,
|
|
72
|
+
},
|
|
73
|
+
typography: {
|
|
74
|
+
...DEFAULT_TYPOGRAPHY,
|
|
75
|
+
fontSans: `"Inter", ${SYSTEM_SANS}`,
|
|
76
|
+
fontMono: `"JetBrains Mono", ${SYSTEM_MONO}`,
|
|
77
|
+
fontUrl:
|
|
78
|
+
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap",
|
|
79
|
+
letterSpacing: "-0.005em",
|
|
80
|
+
},
|
|
81
|
+
layout: {
|
|
82
|
+
...DEFAULT_LAYOUT,
|
|
83
|
+
radius: "0.75rem",
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const emberTheme: DashboardTheme = {
|
|
88
|
+
name: "ember",
|
|
89
|
+
label: "Ember",
|
|
90
|
+
description: "Warm crimson and bronze — forge vibes",
|
|
91
|
+
palette: {
|
|
92
|
+
background: { hex: "#1a0a06", alpha: 1 },
|
|
93
|
+
midground: { hex: "#ffd8b0", alpha: 1 },
|
|
94
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
95
|
+
warmGlow: "rgba(249, 115, 22, 0.38)",
|
|
96
|
+
noiseOpacity: 1,
|
|
97
|
+
},
|
|
98
|
+
typography: {
|
|
99
|
+
...DEFAULT_TYPOGRAPHY,
|
|
100
|
+
fontSans: `"Spectral", Georgia, "Times New Roman", serif`,
|
|
101
|
+
fontMono: `"IBM Plex Mono", ${SYSTEM_MONO}`,
|
|
102
|
+
fontUrl:
|
|
103
|
+
"https://fonts.googleapis.com/css2?family=Spectral:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;700&display=swap",
|
|
104
|
+
},
|
|
105
|
+
layout: {
|
|
106
|
+
...DEFAULT_LAYOUT,
|
|
107
|
+
radius: "0.25rem",
|
|
108
|
+
},
|
|
109
|
+
colorOverrides: {
|
|
110
|
+
destructive: "#c92d0f",
|
|
111
|
+
warning: "#f97316",
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const monoTheme: DashboardTheme = {
|
|
116
|
+
name: "mono",
|
|
117
|
+
label: "Mono",
|
|
118
|
+
description: "Clean grayscale — minimal and focused",
|
|
119
|
+
palette: {
|
|
120
|
+
background: { hex: "#0e0e0e", alpha: 1 },
|
|
121
|
+
midground: { hex: "#eaeaea", alpha: 1 },
|
|
122
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
123
|
+
warmGlow: "rgba(255, 255, 255, 0.1)",
|
|
124
|
+
noiseOpacity: 0.6,
|
|
125
|
+
},
|
|
126
|
+
typography: {
|
|
127
|
+
...DEFAULT_TYPOGRAPHY,
|
|
128
|
+
fontSans: `"IBM Plex Sans", ${SYSTEM_SANS}`,
|
|
129
|
+
fontMono: `"IBM Plex Mono", ${SYSTEM_MONO}`,
|
|
130
|
+
fontUrl:
|
|
131
|
+
"https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap",
|
|
132
|
+
},
|
|
133
|
+
layout: {
|
|
134
|
+
...DEFAULT_LAYOUT,
|
|
135
|
+
radius: "0",
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const cyberpunkTheme: DashboardTheme = {
|
|
140
|
+
name: "cyberpunk",
|
|
141
|
+
label: "Cyberpunk",
|
|
142
|
+
description: "Neon green on black — matrix terminal",
|
|
143
|
+
palette: {
|
|
144
|
+
background: { hex: "#040608", alpha: 1 },
|
|
145
|
+
midground: { hex: "#9bffcf", alpha: 1 },
|
|
146
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
147
|
+
warmGlow: "rgba(0, 255, 136, 0.22)",
|
|
148
|
+
noiseOpacity: 1.2,
|
|
149
|
+
},
|
|
150
|
+
typography: {
|
|
151
|
+
...DEFAULT_TYPOGRAPHY,
|
|
152
|
+
fontSans: `"Share Tech Mono", "JetBrains Mono", ${SYSTEM_MONO}`,
|
|
153
|
+
fontMono: `"Share Tech Mono", "JetBrains Mono", ${SYSTEM_MONO}`,
|
|
154
|
+
fontUrl:
|
|
155
|
+
"https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=JetBrains+Mono:wght@400;700&display=swap",
|
|
156
|
+
},
|
|
157
|
+
layout: {
|
|
158
|
+
...DEFAULT_LAYOUT,
|
|
159
|
+
radius: "0",
|
|
160
|
+
},
|
|
161
|
+
colorOverrides: {
|
|
162
|
+
success: "#00ff88",
|
|
163
|
+
warning: "#ffd700",
|
|
164
|
+
destructive: "#ff0055",
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const roseTheme: DashboardTheme = {
|
|
169
|
+
name: "rose",
|
|
170
|
+
label: "Rosé",
|
|
171
|
+
description: "Soft pink and warm ivory — easy on the eyes",
|
|
172
|
+
palette: {
|
|
173
|
+
background: { hex: "#1a0f15", alpha: 1 },
|
|
174
|
+
midground: { hex: "#ffd4e1", alpha: 1 },
|
|
175
|
+
foreground: { hex: "#ffffff", alpha: 0 },
|
|
176
|
+
warmGlow: "rgba(249, 168, 212, 0.3)",
|
|
177
|
+
noiseOpacity: 0.9,
|
|
178
|
+
},
|
|
179
|
+
typography: {
|
|
180
|
+
...DEFAULT_TYPOGRAPHY,
|
|
181
|
+
fontSans: `"Fraunces", Georgia, serif`,
|
|
182
|
+
fontMono: `"DM Mono", ${SYSTEM_MONO}`,
|
|
183
|
+
fontUrl:
|
|
184
|
+
"https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=DM+Mono:wght@400;500&display=swap",
|
|
185
|
+
},
|
|
186
|
+
layout: {
|
|
187
|
+
...DEFAULT_LAYOUT,
|
|
188
|
+
radius: "1rem",
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* AMOLED Black — pure #000000 background for OLED screens.
|
|
194
|
+
* Full iOS-style glassmorphism: every surface is frosted glass with
|
|
195
|
+
* backdrop-filter blur, semi-transparent backgrounds, cyan glow accents,
|
|
196
|
+
* pill-shaped nav items, and thin cyan scrollbars.
|
|
197
|
+
*/
|
|
198
|
+
export const amoledTheme: DashboardTheme = {
|
|
199
|
+
name: "amoled",
|
|
200
|
+
label: "AMOLED Black",
|
|
201
|
+
description: "Pure black OLED glass — iOS frosted panels, cyan accents, zero grain",
|
|
202
|
+
palette: {
|
|
203
|
+
background: { hex: "#000000", alpha: 1 },
|
|
204
|
+
midground: { hex: "#00e5ff", alpha: 1 },
|
|
205
|
+
foreground: { hex: "#ffffff", alpha: 0.04 },
|
|
206
|
+
warmGlow: "rgba(0, 229, 255, 0.14)",
|
|
207
|
+
noiseOpacity: 0,
|
|
208
|
+
},
|
|
209
|
+
typography: {
|
|
210
|
+
...DEFAULT_TYPOGRAPHY,
|
|
211
|
+
fontSans: `"Inter", ${SYSTEM_SANS}`,
|
|
212
|
+
fontMono: `"JetBrains Mono", ${SYSTEM_MONO}`,
|
|
213
|
+
fontUrl:
|
|
214
|
+
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap",
|
|
215
|
+
letterSpacing: "-0.01em",
|
|
216
|
+
},
|
|
217
|
+
layout: {
|
|
218
|
+
radius: "1.25rem",
|
|
219
|
+
density: "comfortable",
|
|
220
|
+
},
|
|
221
|
+
componentStyles: {
|
|
222
|
+
sidebar: {
|
|
223
|
+
background: "rgba(0, 0, 0, 0.72)",
|
|
224
|
+
},
|
|
225
|
+
header: {
|
|
226
|
+
background: "rgba(0, 0, 0, 0.80)",
|
|
227
|
+
},
|
|
228
|
+
card: {
|
|
229
|
+
background: "rgba(6, 6, 6, 0.70)",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
colorOverrides: {
|
|
233
|
+
primary: "#00e5ff",
|
|
234
|
+
primaryForeground: "#000000",
|
|
235
|
+
accent: "#00e5ff",
|
|
236
|
+
accentForeground: "#000000",
|
|
237
|
+
border: "rgba(0, 229, 255, 0.08)",
|
|
238
|
+
input: "rgba(255, 255, 255, 0.05)",
|
|
239
|
+
muted: "rgba(0, 0, 0, 0.50)",
|
|
240
|
+
mutedForeground: "#6b7280",
|
|
241
|
+
card: "rgba(6, 6, 6, 0.70)",
|
|
242
|
+
popover: "rgba(4, 4, 4, 0.88)",
|
|
243
|
+
success: "#00ff88",
|
|
244
|
+
warning: "#ffcc00",
|
|
245
|
+
destructive: "#ff3b5c",
|
|
246
|
+
ring: "#00e5ff",
|
|
247
|
+
},
|
|
248
|
+
customCSS: `
|
|
249
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
250
|
+
iOS-AMOLED Glass — frosted glass on every surface
|
|
251
|
+
═══════════════════════════════════════════════════════════════════ */
|
|
252
|
+
|
|
253
|
+
/* ── Sidebar: deep frosted glass panel ─────────────────────────────── */
|
|
254
|
+
#app-sidebar {
|
|
255
|
+
backdrop-filter: blur(32px) saturate(200%) brightness(0.88) !important;
|
|
256
|
+
-webkit-backdrop-filter: blur(32px) saturate(200%) brightness(0.88) !important;
|
|
257
|
+
border-right: 1px solid rgba(0, 229, 255, 0.07) !important;
|
|
258
|
+
box-shadow: 4px 0 48px rgba(0,0,0,0.65), inset -1px 0 0 rgba(0,229,255,0.04) !important;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* ── Mobile top bar: glass bar ──────────────────────────────────────── */
|
|
262
|
+
header {
|
|
263
|
+
backdrop-filter: blur(24px) saturate(180%) !important;
|
|
264
|
+
-webkit-backdrop-filter: blur(24px) saturate(180%) !important;
|
|
265
|
+
border-bottom: 1px solid rgba(0, 229, 255, 0.07) !important;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* ── Sidebar nav items: iOS pill shape ──────────────────────────────── */
|
|
269
|
+
#app-sidebar nav a,
|
|
270
|
+
#app-sidebar nav li > button:not([size="icon"]) {
|
|
271
|
+
border-radius: 0.875rem !important;
|
|
272
|
+
margin: 1px 8px !important;
|
|
273
|
+
padding-left: 12px !important;
|
|
274
|
+
padding-right: 12px !important;
|
|
275
|
+
transition: background 150ms ease, box-shadow 150ms ease !important;
|
|
276
|
+
}
|
|
277
|
+
#app-sidebar nav a[aria-current="page"] {
|
|
278
|
+
background: rgba(0, 229, 255, 0.10) !important;
|
|
279
|
+
box-shadow: inset 0 0 0 1px rgba(0, 229, 255, 0.22), 0 0 16px rgba(0,229,255,0.05) !important;
|
|
280
|
+
}
|
|
281
|
+
#app-sidebar nav a:not([aria-current="page"]):hover {
|
|
282
|
+
background: rgba(255, 255, 255, 0.04) !important;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* ── Modals / dialogs / popovers: deepest glass ─────────────────────── */
|
|
286
|
+
[role="dialog"],
|
|
287
|
+
[data-radix-popper-content-wrapper] > *,
|
|
288
|
+
[data-state][data-side] {
|
|
289
|
+
backdrop-filter: blur(40px) saturate(200%) !important;
|
|
290
|
+
-webkit-backdrop-filter: blur(40px) saturate(200%) !important;
|
|
291
|
+
background: rgba(4, 4, 4, 0.88) !important;
|
|
292
|
+
border: 1px solid rgba(0, 229, 255, 0.09) !important;
|
|
293
|
+
border-radius: var(--theme-radius) !important;
|
|
294
|
+
box-shadow: 0 32px 80px rgba(0,0,0,0.88), 0 0 0 1px rgba(255,255,255,0.025) !important;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* ── Inputs: glass with cyan focus glow ─────────────────────────────── */
|
|
298
|
+
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
|
|
299
|
+
textarea,
|
|
300
|
+
select {
|
|
301
|
+
background: rgba(255, 255, 255, 0.04) !important;
|
|
302
|
+
border-color: rgba(0, 229, 255, 0.14) !important;
|
|
303
|
+
border-radius: var(--theme-radius) !important;
|
|
304
|
+
transition: border-color 120ms ease, box-shadow 120ms ease, background 120ms ease !important;
|
|
305
|
+
}
|
|
306
|
+
input:not([type="checkbox"]):not([type="radio"]):focus-visible,
|
|
307
|
+
textarea:focus-visible,
|
|
308
|
+
select:focus {
|
|
309
|
+
border-color: rgba(0, 229, 255, 0.55) !important;
|
|
310
|
+
box-shadow: 0 0 0 3px rgba(0, 229, 255, 0.10), 0 0 20px rgba(0,229,255,0.06) !important;
|
|
311
|
+
outline: none !important;
|
|
312
|
+
background: rgba(0, 229, 255, 0.03) !important;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* ── Search inputs: full pill ────────────────────────────────────────── */
|
|
316
|
+
input[type="search"],
|
|
317
|
+
input[placeholder*="Search"],
|
|
318
|
+
input[placeholder*="search"],
|
|
319
|
+
input[placeholder*="Filter"],
|
|
320
|
+
input[placeholder*="filter"] {
|
|
321
|
+
border-radius: 9999px !important;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* ── Buttons: rounded everywhere ─────────────────────────────────────── */
|
|
325
|
+
button:not([role="switch"]):not([class*="rounded-full"]),
|
|
326
|
+
[role="button"]:not([role="switch"]) {
|
|
327
|
+
border-radius: calc(var(--theme-radius) * 0.75) !important;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ── Cards: subtle glass depth ───────────────────────────────────────── */
|
|
331
|
+
.card,
|
|
332
|
+
[class*="rounded-lg"],
|
|
333
|
+
[class*="rounded-xl"],
|
|
334
|
+
[class*="rounded-2xl"] {
|
|
335
|
+
backdrop-filter: blur(8px) !important;
|
|
336
|
+
-webkit-backdrop-filter: blur(8px) !important;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* ── Thin cyan scrollbars ─────────────────────────────────────────────── */
|
|
340
|
+
* {
|
|
341
|
+
scrollbar-width: thin;
|
|
342
|
+
scrollbar-color: rgba(0, 229, 255, 0.16) transparent;
|
|
343
|
+
}
|
|
344
|
+
::-webkit-scrollbar { width: 3px; height: 3px; }
|
|
345
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
346
|
+
::-webkit-scrollbar-thumb {
|
|
347
|
+
background: rgba(0, 229, 255, 0.16);
|
|
348
|
+
border-radius: 99px;
|
|
349
|
+
}
|
|
350
|
+
::-webkit-scrollbar-thumb:hover { background: rgba(0, 229, 255, 0.35); }
|
|
351
|
+
|
|
352
|
+
/* ── Text selection: cyan highlight ──────────────────────────────────── */
|
|
353
|
+
::selection {
|
|
354
|
+
background: rgba(0, 229, 255, 0.22);
|
|
355
|
+
color: #ffffff;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* ── Kill grain completely ───────────────────────────────────────────── */
|
|
359
|
+
.grain::after { display: none !important; }
|
|
360
|
+
`,
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Cloud — maximum rounding, soft lavender-white palette.
|
|
365
|
+
* The "bubbly" feel: every element has pill-shaped corners.
|
|
366
|
+
*/
|
|
367
|
+
export const cloudTheme: DashboardTheme = {
|
|
368
|
+
name: "cloud",
|
|
369
|
+
label: "Cloud",
|
|
370
|
+
description: "Soft, rounded, airy — lavender haze with pillowy corners",
|
|
371
|
+
palette: {
|
|
372
|
+
background: { hex: "#0f0d1a", alpha: 1 },
|
|
373
|
+
midground: { hex: "#e8e0ff", alpha: 1 },
|
|
374
|
+
foreground: { hex: "#ffffff", alpha: 0.02 },
|
|
375
|
+
warmGlow: "rgba(180, 160, 255, 0.28)",
|
|
376
|
+
noiseOpacity: 0.5,
|
|
377
|
+
},
|
|
378
|
+
typography: {
|
|
379
|
+
...DEFAULT_TYPOGRAPHY,
|
|
380
|
+
fontSans: `"Nunito", "Outfit", ${SYSTEM_SANS}`,
|
|
381
|
+
fontMono: `"Fira Code", ${SYSTEM_MONO}`,
|
|
382
|
+
fontUrl:
|
|
383
|
+
"https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800&family=Fira+Code:wght@400;500&display=swap",
|
|
384
|
+
lineHeight: "1.65",
|
|
385
|
+
letterSpacing: "0.01em",
|
|
386
|
+
},
|
|
387
|
+
layout: {
|
|
388
|
+
radius: "1.5rem",
|
|
389
|
+
density: "spacious",
|
|
390
|
+
},
|
|
391
|
+
colorOverrides: {
|
|
392
|
+
primary: "#a78bfa",
|
|
393
|
+
primaryForeground: "#0f0d1a",
|
|
394
|
+
accent: "#c4b5fd",
|
|
395
|
+
accentForeground: "#0f0d1a",
|
|
396
|
+
border: "#2a2040",
|
|
397
|
+
card: "#16112a",
|
|
398
|
+
success: "#86efac",
|
|
399
|
+
warning: "#fde68a",
|
|
400
|
+
destructive: "#f87171",
|
|
401
|
+
ring: "#a78bfa",
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Nord — the classic Arctic color palette. Rounded, calm, professional.
|
|
407
|
+
*/
|
|
408
|
+
export const nordTheme: DashboardTheme = {
|
|
409
|
+
name: "nord",
|
|
410
|
+
label: "Nord",
|
|
411
|
+
description: "Arctic blue — calm, clean, Scandinavian minimalism",
|
|
412
|
+
palette: {
|
|
413
|
+
background: { hex: "#2e3440", alpha: 1 },
|
|
414
|
+
midground: { hex: "#d8dee9", alpha: 1 },
|
|
415
|
+
foreground: { hex: "#eceff4", alpha: 0.03 },
|
|
416
|
+
warmGlow: "rgba(136, 192, 208, 0.2)",
|
|
417
|
+
noiseOpacity: 0.4,
|
|
418
|
+
},
|
|
419
|
+
typography: {
|
|
420
|
+
...DEFAULT_TYPOGRAPHY,
|
|
421
|
+
fontSans: `"Inter", ${SYSTEM_SANS}`,
|
|
422
|
+
fontMono: `"JetBrains Mono", ${SYSTEM_MONO}`,
|
|
423
|
+
fontUrl:
|
|
424
|
+
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap",
|
|
425
|
+
letterSpacing: "-0.005em",
|
|
426
|
+
},
|
|
427
|
+
layout: {
|
|
428
|
+
radius: "0.75rem",
|
|
429
|
+
density: "comfortable",
|
|
430
|
+
},
|
|
431
|
+
colorOverrides: {
|
|
432
|
+
primary: "#88c0d0",
|
|
433
|
+
primaryForeground: "#2e3440",
|
|
434
|
+
accent: "#81a1c1",
|
|
435
|
+
accentForeground: "#eceff4",
|
|
436
|
+
border: "#3b4252",
|
|
437
|
+
card: "#3b4252",
|
|
438
|
+
success: "#a3be8c",
|
|
439
|
+
warning: "#ebcb8b",
|
|
440
|
+
destructive: "#bf616a",
|
|
441
|
+
ring: "#88c0d0",
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Same look as ``defaultTheme`` but with a larger root font size, looser
|
|
447
|
+
* line-height, and ``spacious`` density so every rem-based size in the
|
|
448
|
+
* dashboard scales up. For users who find the default 15px UI too dense.
|
|
449
|
+
*/
|
|
450
|
+
export const defaultLargeTheme: DashboardTheme = {
|
|
451
|
+
name: "default-large",
|
|
452
|
+
label: "NasTech Teal (Large)",
|
|
453
|
+
description: "NasTech Teal with bigger fonts and roomier spacing",
|
|
454
|
+
palette: defaultTheme.palette,
|
|
455
|
+
typography: {
|
|
456
|
+
...DEFAULT_TYPOGRAPHY,
|
|
457
|
+
baseSize: "18px",
|
|
458
|
+
lineHeight: "1.65",
|
|
459
|
+
},
|
|
460
|
+
layout: {
|
|
461
|
+
...DEFAULT_LAYOUT,
|
|
462
|
+
density: "spacious",
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
export const BUILTIN_THEMES: Record<string, DashboardTheme> = {
|
|
467
|
+
default: defaultTheme,
|
|
468
|
+
"default-large": defaultLargeTheme,
|
|
469
|
+
midnight: midnightTheme,
|
|
470
|
+
ember: emberTheme,
|
|
471
|
+
mono: monoTheme,
|
|
472
|
+
cyberpunk: cyberpunkTheme,
|
|
473
|
+
rose: roseTheme,
|
|
474
|
+
amoled: amoledTheme,
|
|
475
|
+
cloud: cloudTheme,
|
|
476
|
+
nord: nordTheme,
|
|
477
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard theme model.
|
|
3
|
+
*
|
|
4
|
+
* Themes customise three orthogonal layers:
|
|
5
|
+
*
|
|
6
|
+
* 1. `palette` — the 3-layer color triplet (background/midground/
|
|
7
|
+
* foreground) + warm-glow + noise opacity. The
|
|
8
|
+
* design-system cascade in `src/index.css` derives
|
|
9
|
+
* every shadcn-compat token (card, muted, border,
|
|
10
|
+
* primary, etc.) from this triplet via `color-mix()`.
|
|
11
|
+
* 2. `typography` — font families, base font size, line height,
|
|
12
|
+
* letter spacing. An optional `fontUrl` is injected
|
|
13
|
+
* as `<link rel="stylesheet">` so self-hosted and
|
|
14
|
+
* Google/Bunny/etc-hosted fonts both work.
|
|
15
|
+
* 3. `layout` — corner radius and density (spacing multiplier).
|
|
16
|
+
*
|
|
17
|
+
* Plus an optional `colorOverrides` escape hatch for themes that want to
|
|
18
|
+
* pin specific shadcn tokens to exact values (e.g. a pastel theme that
|
|
19
|
+
* needs a softer `destructive` red than the derived default).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** A color layer: hex base + alpha (0–1). */
|
|
23
|
+
export interface ThemeLayer {
|
|
24
|
+
alpha: number;
|
|
25
|
+
hex: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ThemePalette {
|
|
29
|
+
/** Deepest canvas color (typically near-black). */
|
|
30
|
+
background: ThemeLayer;
|
|
31
|
+
/** Primary text + accent. Most UI chrome reads this. */
|
|
32
|
+
midground: ThemeLayer;
|
|
33
|
+
/** Top-layer highlight. In LENS_0 this is white @ alpha 0 — invisible by
|
|
34
|
+
* default but still drives `--color-ring`-style accents. */
|
|
35
|
+
foreground: ThemeLayer;
|
|
36
|
+
/** Warm vignette color for <Backdrop />, as an rgba() string. */
|
|
37
|
+
warmGlow: string;
|
|
38
|
+
/** Scalar multiplier (0–1.2) on the noise overlay. Lower for softer themes
|
|
39
|
+
* like Mono and Rosé, higher for grittier themes like Cyberpunk. */
|
|
40
|
+
noiseOpacity: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ThemeTypography {
|
|
44
|
+
/** CSS font-family stack for sans-serif body copy. */
|
|
45
|
+
fontSans: string;
|
|
46
|
+
/** CSS font-family stack for monospace / code blocks. */
|
|
47
|
+
fontMono: string;
|
|
48
|
+
/** Optional display/heading font stack. Falls back to `fontSans`. */
|
|
49
|
+
fontDisplay?: string;
|
|
50
|
+
/** Optional external stylesheet URL (e.g. Google Fonts, Bunny Fonts,
|
|
51
|
+
* self-hosted .woff2 @font-face sheet). Injected as a <link> in <head>
|
|
52
|
+
* on theme switch. Same URL is never injected twice. */
|
|
53
|
+
fontUrl?: string;
|
|
54
|
+
/** Root font size (controls rem scale). Example: `"14px"`, `"16px"`. */
|
|
55
|
+
baseSize: string;
|
|
56
|
+
/** Default line-height. Example: `"1.5"`, `"1.65"`. */
|
|
57
|
+
lineHeight: string;
|
|
58
|
+
/** Default letter-spacing. Example: `"0"`, `"0.01em"`, `"-0.01em"`. */
|
|
59
|
+
letterSpacing: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type ThemeDensity = "compact" | "comfortable" | "spacious";
|
|
63
|
+
|
|
64
|
+
export interface ThemeLayout {
|
|
65
|
+
/** Corner-radius token. Example: `"0"`, `"0.25rem"`, `"0.5rem"`,
|
|
66
|
+
* `"1rem"`. Maps to `--radius` and cascades into every component. */
|
|
67
|
+
radius: string;
|
|
68
|
+
/** Spacing multiplier. `compact` = 0.85, `comfortable` = 1.0 (default),
|
|
69
|
+
* `spacious` = 1.2. Applied via the `--spacing-mul` CSS var. */
|
|
70
|
+
density: ThemeDensity;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Overall layout variant the shell renders. `standard` = default single-
|
|
74
|
+
* column page layout. `cockpit` = reserves a left sidebar rail for a
|
|
75
|
+
* plugin slot (intended for HUD-style themes with persistent status panels).
|
|
76
|
+
* `tiled` = relaxes the main content max-width so pages can use the full
|
|
77
|
+
* viewport width. Themes set this; plugins react via CSS vars /
|
|
78
|
+
* `[data-layout-variant="..."]` selectors. */
|
|
79
|
+
export type ThemeLayoutVariant = "standard" | "cockpit" | "tiled";
|
|
80
|
+
|
|
81
|
+
/** Named hero/background assets a theme can populate. Each value is
|
|
82
|
+
* emitted as a CSS var (`--theme-asset-<name>`). The default shell
|
|
83
|
+
* consumes `bg` in `<Backdrop />` when present; other slots are
|
|
84
|
+
* plugin-facing — a cockpit sidebar plugin reads `--theme-asset-hero`
|
|
85
|
+
* to render its hero render without coupling to the theme name. */
|
|
86
|
+
export interface ThemeAssets {
|
|
87
|
+
/** Full-viewport background image URL, injected under the noise layer. */
|
|
88
|
+
bg?: string;
|
|
89
|
+
/** Hero render (Gundam, mascot, wallpaper) — for plugin sidebars/overlays. */
|
|
90
|
+
hero?: string;
|
|
91
|
+
/** Logo mark — header slot consumers use this. */
|
|
92
|
+
logo?: string;
|
|
93
|
+
/** Faction/brand crest — header-left decoration. */
|
|
94
|
+
crest?: string;
|
|
95
|
+
/** Secondary sidebar illustration. */
|
|
96
|
+
sidebar?: string;
|
|
97
|
+
/** Alternate header artwork. */
|
|
98
|
+
header?: string;
|
|
99
|
+
/** User-defined named assets. Keyed by [a-zA-Z0-9_-] only.
|
|
100
|
+
* Emitted as `--theme-asset-custom-<key>`. */
|
|
101
|
+
custom?: Record<string, string>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Component-style override buckets. Each bucket's entries become CSS
|
|
105
|
+
* vars (`--component-<bucket>-<kebab-property>`) that shell components
|
|
106
|
+
* (Card, Backdrop, App header/footer, etc.) read. Values are plain CSS
|
|
107
|
+
* strings — we don't parse them, so themes can use `clip-path`,
|
|
108
|
+
* `border-image`, `background`, `box-shadow`, and anything else CSS
|
|
109
|
+
* accepts. */
|
|
110
|
+
export interface ThemeComponentStyles {
|
|
111
|
+
card?: Record<string, string>;
|
|
112
|
+
header?: Record<string, string>;
|
|
113
|
+
footer?: Record<string, string>;
|
|
114
|
+
sidebar?: Record<string, string>;
|
|
115
|
+
tab?: Record<string, string>;
|
|
116
|
+
progress?: Record<string, string>;
|
|
117
|
+
badge?: Record<string, string>;
|
|
118
|
+
backdrop?: Record<string, string>;
|
|
119
|
+
page?: Record<string, string>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Optional hex overrides keyed by shadcn-compat token name (without the
|
|
123
|
+
* `--color-` prefix). Any key set here wins over the DS cascade. */
|
|
124
|
+
export interface ThemeColorOverrides {
|
|
125
|
+
card?: string;
|
|
126
|
+
cardForeground?: string;
|
|
127
|
+
popover?: string;
|
|
128
|
+
popoverForeground?: string;
|
|
129
|
+
primary?: string;
|
|
130
|
+
primaryForeground?: string;
|
|
131
|
+
secondary?: string;
|
|
132
|
+
secondaryForeground?: string;
|
|
133
|
+
muted?: string;
|
|
134
|
+
mutedForeground?: string;
|
|
135
|
+
accent?: string;
|
|
136
|
+
accentForeground?: string;
|
|
137
|
+
destructive?: string;
|
|
138
|
+
destructiveForeground?: string;
|
|
139
|
+
success?: string;
|
|
140
|
+
warning?: string;
|
|
141
|
+
border?: string;
|
|
142
|
+
input?: string;
|
|
143
|
+
ring?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface DashboardTheme {
|
|
147
|
+
description: string;
|
|
148
|
+
label: string;
|
|
149
|
+
name: string;
|
|
150
|
+
palette: ThemePalette;
|
|
151
|
+
typography: ThemeTypography;
|
|
152
|
+
layout: ThemeLayout;
|
|
153
|
+
/** Overall shell layout. Defaults to `"standard"` when absent. */
|
|
154
|
+
layoutVariant?: ThemeLayoutVariant;
|
|
155
|
+
/** Named + custom asset URLs exposed as CSS vars on theme apply. */
|
|
156
|
+
assets?: ThemeAssets;
|
|
157
|
+
/** Raw CSS injected as a scoped `<style>` tag on theme apply, cleaned up
|
|
158
|
+
* on theme switch. Intended for selector-level chrome that's too
|
|
159
|
+
* expressive for componentStyles alone (e.g. `::before` pseudo-elements,
|
|
160
|
+
* complex animations, media queries). */
|
|
161
|
+
customCSS?: string;
|
|
162
|
+
/** Per-component CSS-var overrides. See `ThemeComponentStyles`. */
|
|
163
|
+
componentStyles?: ThemeComponentStyles;
|
|
164
|
+
colorOverrides?: ThemeColorOverrides;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Wire response shape for `GET /api/dashboard/themes`.
|
|
169
|
+
*
|
|
170
|
+
* The `themes` list is intentionally partial — built-in themes are fully
|
|
171
|
+
* defined in `presets.ts`; user themes carry their full definition so the
|
|
172
|
+
* client can apply them without a second round-trip.
|
|
173
|
+
*/
|
|
174
|
+
export interface ThemeListEntry {
|
|
175
|
+
description: string;
|
|
176
|
+
label: string;
|
|
177
|
+
name: string;
|
|
178
|
+
/** Full theme definition. Present for user-defined themes loaded from
|
|
179
|
+
* `~/.nastech/dashboard-themes/*.yaml`; undefined for built-ins (the
|
|
180
|
+
* client already has those in `BUILTIN_THEMES`). */
|
|
181
|
+
definition?: DashboardTheme;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ThemeListResponse {
|
|
185
|
+
active: string;
|
|
186
|
+
themes: ThemeListEntry[];
|
|
187
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"types": ["vite/client"],
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
|
|
11
|
+
/* Bundler mode */
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"moduleDetection": "force",
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
|
|
19
|
+
/* Path aliases */
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
/* Linting */
|
|
26
|
+
"strict": true,
|
|
27
|
+
"noUnusedLocals": true,
|
|
28
|
+
"noUnusedParameters": true,
|
|
29
|
+
"erasableSyntaxOnly": true,
|
|
30
|
+
"noFallthroughCasesInSwitch": true,
|
|
31
|
+
"noUncheckedSideEffectImports": true
|
|
32
|
+
},
|
|
33
|
+
"include": ["src"]
|
|
34
|
+
}
|