@svadmin/core 0.9.0 → 0.10.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/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/theme.svelte.ts +229 -11
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -37,8 +37,8 @@ export { audit, setAuditHandler, setAuditLogProvider, getAuditLogProvider } from
|
|
|
37
37
|
export type { AuditLogProvider } from './audit';
|
|
38
38
|
export { setChatProvider, getChatProvider, setChatContext, getChatContext } from './chatProvider.svelte';
|
|
39
39
|
export type { ChatProvider, ChatMessage, ChatContext, ChatAction } from './chatProvider.svelte';
|
|
40
|
-
export { getTheme, setTheme, toggleTheme, getResolvedTheme, getColorTheme, setColorTheme, colorThemes, configureTheme, getThemeConfig, clearCssOverrides } from './theme.svelte';
|
|
41
|
-
export type { ThemeMode, ColorTheme, ThemeStrategy, ThemeConfig } from './theme.svelte';
|
|
40
|
+
export { getTheme, setTheme, toggleTheme, getResolvedTheme, getColorTheme, setColorTheme, colorThemes, configureTheme, getThemeConfig, clearCssOverrides, builtinPresets, registerColorPreset, getColorPresets } from './theme.svelte';
|
|
41
|
+
export type { ThemeMode, ColorTheme, ThemeStrategy, ThemeConfig, ColorPreset } from './theme.svelte';
|
|
42
42
|
export { setUnsavedChanges, getUnsavedChanges, initUnsavedChangesNotifier } from './unsaved-changes.svelte';
|
|
43
43
|
export { setAdminOptions, getAdminOptions, getTextTransformers } from './options';
|
|
44
44
|
export type { AdminOptions, TextTransformers, OvertimeConfig } from './options';
|
package/src/theme.svelte.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Supports two class strategies:
|
|
4
4
|
// - 'standard' (default): adds 'dark' class for dark mode (light-first)
|
|
5
|
-
// - 'dark-first': adds 'light' class for light mode (dark-first
|
|
5
|
+
// - 'dark-first': adds 'light' class for light mode (dark-first)
|
|
6
6
|
|
|
7
7
|
export type ThemeMode = 'light' | 'dark' | 'system';
|
|
8
8
|
export type ColorTheme = 'blue' | 'green' | 'rose' | 'orange' | 'violet' | 'zinc';
|
|
@@ -10,6 +10,220 @@ export type ColorTheme = 'blue' | 'green' | 'rose' | 'orange' | 'violet' | 'zinc
|
|
|
10
10
|
/** Controls how the theme class is applied to <html> */
|
|
11
11
|
export type ThemeStrategy = 'standard' | 'dark-first';
|
|
12
12
|
|
|
13
|
+
// ── Color Preset System ──────────────────────────────────
|
|
14
|
+
|
|
15
|
+
/** A color preset defines CSS variable overrides for light and dark modes. */
|
|
16
|
+
export interface ColorPreset {
|
|
17
|
+
/** Unique name (e.g. 'indigo', 'blue') */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Display label (e.g. 'Indigo', 'Blue') */
|
|
20
|
+
label: string;
|
|
21
|
+
/** Preview swatch color (hex) for UI pickers */
|
|
22
|
+
color: string;
|
|
23
|
+
/** CSS variable overrides for light mode */
|
|
24
|
+
light: Record<string, string>;
|
|
25
|
+
/** CSS variable overrides for dark mode */
|
|
26
|
+
dark: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Built-in color presets — consumers can extend via registerColorPreset(). */
|
|
30
|
+
export const builtinPresets: Record<string, ColorPreset> = {
|
|
31
|
+
neutral: {
|
|
32
|
+
name: 'neutral',
|
|
33
|
+
label: 'Neutral',
|
|
34
|
+
color: '#71717a',
|
|
35
|
+
light: {
|
|
36
|
+
'--primary': 'oklch(0.205 0.006 286)',
|
|
37
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
38
|
+
'--ring': 'oklch(0.205 0.006 286)',
|
|
39
|
+
'--sidebar-primary': 'oklch(0.205 0.006 286)',
|
|
40
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
41
|
+
'--sidebar-ring': 'oklch(0.205 0.006 286)',
|
|
42
|
+
'--chart-1': 'oklch(0.488 0.243 264.376)',
|
|
43
|
+
},
|
|
44
|
+
dark: {
|
|
45
|
+
'--primary': 'oklch(0.922 0.004 286)',
|
|
46
|
+
'--primary-foreground': 'oklch(0.205 0.006 286)',
|
|
47
|
+
'--ring': 'oklch(0.556 0.004 286)',
|
|
48
|
+
'--sidebar-primary': 'oklch(0.922 0.004 286)',
|
|
49
|
+
'--sidebar-primary-foreground': 'oklch(0.205 0.006 286)',
|
|
50
|
+
'--sidebar-ring': 'oklch(0.556 0.004 286)',
|
|
51
|
+
'--chart-1': 'oklch(0.585 0.233 264)',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
indigo: {
|
|
55
|
+
name: 'indigo',
|
|
56
|
+
label: 'Indigo',
|
|
57
|
+
color: '#4f46e5',
|
|
58
|
+
light: {
|
|
59
|
+
'--primary': 'oklch(0.488 0.243 264.376)',
|
|
60
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
61
|
+
'--ring': 'oklch(0.488 0.243 264.376)',
|
|
62
|
+
'--sidebar-primary': 'oklch(0.488 0.243 264.376)',
|
|
63
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
64
|
+
'--sidebar-ring': 'oklch(0.488 0.243 264.376)',
|
|
65
|
+
'--chart-1': 'oklch(0.488 0.243 264.376)',
|
|
66
|
+
},
|
|
67
|
+
dark: {
|
|
68
|
+
'--primary': 'oklch(0.585 0.233 264)',
|
|
69
|
+
'--primary-foreground': 'oklch(0.15 0.04 265)',
|
|
70
|
+
'--ring': 'oklch(0.55 0.18 264)',
|
|
71
|
+
'--sidebar-primary': 'oklch(0.585 0.233 264)',
|
|
72
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
73
|
+
'--sidebar-ring': 'oklch(0.55 0.18 264)',
|
|
74
|
+
'--chart-1': 'oklch(0.585 0.233 264)',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
blue: {
|
|
78
|
+
name: 'blue',
|
|
79
|
+
label: 'Blue',
|
|
80
|
+
color: '#3b82f6',
|
|
81
|
+
light: {
|
|
82
|
+
'--primary': 'oklch(0.546 0.245 262.881)',
|
|
83
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
84
|
+
'--ring': 'oklch(0.546 0.245 262.881)',
|
|
85
|
+
'--sidebar-primary': 'oklch(0.546 0.245 262.881)',
|
|
86
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
87
|
+
'--sidebar-ring': 'oklch(0.546 0.245 262.881)',
|
|
88
|
+
'--chart-1': 'oklch(0.546 0.245 262.881)',
|
|
89
|
+
},
|
|
90
|
+
dark: {
|
|
91
|
+
'--primary': 'oklch(0.623 0.214 259.815)',
|
|
92
|
+
'--primary-foreground': 'oklch(0.15 0.04 265)',
|
|
93
|
+
'--ring': 'oklch(0.546 0.245 262.881)',
|
|
94
|
+
'--sidebar-primary': 'oklch(0.623 0.214 259.815)',
|
|
95
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
96
|
+
'--sidebar-ring': 'oklch(0.546 0.245 262.881)',
|
|
97
|
+
'--chart-1': 'oklch(0.623 0.214 259.815)',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
green: {
|
|
101
|
+
name: 'green',
|
|
102
|
+
label: 'Green',
|
|
103
|
+
color: '#22c55e',
|
|
104
|
+
light: {
|
|
105
|
+
'--primary': 'oklch(0.527 0.185 150.069)',
|
|
106
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
107
|
+
'--ring': 'oklch(0.527 0.185 150.069)',
|
|
108
|
+
'--sidebar-primary': 'oklch(0.527 0.185 150.069)',
|
|
109
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
110
|
+
'--sidebar-ring': 'oklch(0.527 0.185 150.069)',
|
|
111
|
+
'--chart-1': 'oklch(0.527 0.185 150.069)',
|
|
112
|
+
},
|
|
113
|
+
dark: {
|
|
114
|
+
'--primary': 'oklch(0.627 0.194 149.214)',
|
|
115
|
+
'--primary-foreground': 'oklch(0.15 0.05 150)',
|
|
116
|
+
'--ring': 'oklch(0.527 0.185 150.069)',
|
|
117
|
+
'--sidebar-primary': 'oklch(0.627 0.194 149.214)',
|
|
118
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
119
|
+
'--sidebar-ring': 'oklch(0.527 0.185 150.069)',
|
|
120
|
+
'--chart-1': 'oklch(0.627 0.194 149.214)',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
rose: {
|
|
124
|
+
name: 'rose',
|
|
125
|
+
label: 'Rose',
|
|
126
|
+
color: '#f43f5e',
|
|
127
|
+
light: {
|
|
128
|
+
'--primary': 'oklch(0.577 0.245 27.325)',
|
|
129
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
130
|
+
'--ring': 'oklch(0.577 0.245 27.325)',
|
|
131
|
+
'--sidebar-primary': 'oklch(0.577 0.245 27.325)',
|
|
132
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
133
|
+
'--sidebar-ring': 'oklch(0.577 0.245 27.325)',
|
|
134
|
+
'--chart-1': 'oklch(0.577 0.245 27.325)',
|
|
135
|
+
},
|
|
136
|
+
dark: {
|
|
137
|
+
'--primary': 'oklch(0.577 0.245 27.325)',
|
|
138
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
139
|
+
'--ring': 'oklch(0.577 0.245 27.325)',
|
|
140
|
+
'--sidebar-primary': 'oklch(0.577 0.245 27.325)',
|
|
141
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
142
|
+
'--sidebar-ring': 'oklch(0.577 0.245 27.325)',
|
|
143
|
+
'--chart-1': 'oklch(0.577 0.245 27.325)',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
orange: {
|
|
147
|
+
name: 'orange',
|
|
148
|
+
label: 'Orange',
|
|
149
|
+
color: '#f97316',
|
|
150
|
+
light: {
|
|
151
|
+
'--primary': 'oklch(0.646 0.222 41.116)',
|
|
152
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
153
|
+
'--ring': 'oklch(0.646 0.222 41.116)',
|
|
154
|
+
'--sidebar-primary': 'oklch(0.646 0.222 41.116)',
|
|
155
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
156
|
+
'--sidebar-ring': 'oklch(0.646 0.222 41.116)',
|
|
157
|
+
'--chart-1': 'oklch(0.646 0.222 41.116)',
|
|
158
|
+
},
|
|
159
|
+
dark: {
|
|
160
|
+
'--primary': 'oklch(0.646 0.222 41.116)',
|
|
161
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
162
|
+
'--ring': 'oklch(0.646 0.222 41.116)',
|
|
163
|
+
'--sidebar-primary': 'oklch(0.646 0.222 41.116)',
|
|
164
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
165
|
+
'--sidebar-ring': 'oklch(0.646 0.222 41.116)',
|
|
166
|
+
'--chart-1': 'oklch(0.646 0.222 41.116)',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
violet: {
|
|
170
|
+
name: 'violet',
|
|
171
|
+
label: 'Violet',
|
|
172
|
+
color: '#8b5cf6',
|
|
173
|
+
light: {
|
|
174
|
+
'--primary': 'oklch(0.541 0.281 293.009)',
|
|
175
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
176
|
+
'--ring': 'oklch(0.541 0.281 293.009)',
|
|
177
|
+
'--sidebar-primary': 'oklch(0.541 0.281 293.009)',
|
|
178
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
179
|
+
'--sidebar-ring': 'oklch(0.541 0.281 293.009)',
|
|
180
|
+
'--chart-1': 'oklch(0.541 0.281 293.009)',
|
|
181
|
+
},
|
|
182
|
+
dark: {
|
|
183
|
+
'--primary': 'oklch(0.541 0.281 293.009)',
|
|
184
|
+
'--primary-foreground': 'oklch(0.985 0 0)',
|
|
185
|
+
'--ring': 'oklch(0.541 0.281 293.009)',
|
|
186
|
+
'--sidebar-primary': 'oklch(0.541 0.281 293.009)',
|
|
187
|
+
'--sidebar-primary-foreground': 'oklch(0.985 0 0)',
|
|
188
|
+
'--sidebar-ring': 'oklch(0.541 0.281 293.009)',
|
|
189
|
+
'--chart-1': 'oklch(0.541 0.281 293.009)',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/** Register a custom color preset. Overwrites any built-in preset with the same name. */
|
|
195
|
+
export function registerColorPreset(preset: ColorPreset): void {
|
|
196
|
+
builtinPresets[preset.name] = preset;
|
|
197
|
+
// Update colorThemes display list
|
|
198
|
+
const idx = colorThemes.findIndex(ct => ct.id === preset.name);
|
|
199
|
+
const entry = { id: preset.name as ColorTheme, label: preset.label, color: preset.color };
|
|
200
|
+
if (idx >= 0) colorThemes[idx] = entry;
|
|
201
|
+
else colorThemes.push(entry);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Resolve a preset by name or return the preset object directly. */
|
|
205
|
+
function resolvePreset(preset: ColorPreset | string): ColorPreset | undefined {
|
|
206
|
+
if (typeof preset === 'string') return builtinPresets[preset];
|
|
207
|
+
return preset;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Apply a color preset's CSS variables based on current resolved theme. */
|
|
211
|
+
function applyColorPreset(preset: ColorPreset): void {
|
|
212
|
+
if (typeof document === 'undefined') return;
|
|
213
|
+
const resolved = mode === 'system' ? getSystemPreference() : mode;
|
|
214
|
+
const vars = resolved === 'dark' ? preset.dark : preset.light;
|
|
215
|
+
const root = document.documentElement;
|
|
216
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
217
|
+
const cssVar = key.startsWith('--') ? key : `--${key}`;
|
|
218
|
+
root.style.setProperty(cssVar, value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Get all available color presets (built-in + registered). */
|
|
223
|
+
export function getColorPresets(): ColorPreset[] {
|
|
224
|
+
return Object.values(builtinPresets);
|
|
225
|
+
}
|
|
226
|
+
|
|
13
227
|
export interface ThemeConfig {
|
|
14
228
|
/** Class strategy: 'standard' toggles '.dark', 'dark-first' toggles '.light' */
|
|
15
229
|
strategy?: ThemeStrategy;
|
|
@@ -17,6 +231,8 @@ export interface ThemeConfig {
|
|
|
17
231
|
cssOverrides?: Record<string, string>;
|
|
18
232
|
/** Whether to disable the built-in color-scheme attribute */
|
|
19
233
|
disableColorScheme?: boolean;
|
|
234
|
+
/** Built-in color preset name (e.g. 'indigo', 'blue') or a custom ColorPreset object */
|
|
235
|
+
colorPreset?: ColorPreset | string;
|
|
20
236
|
}
|
|
21
237
|
|
|
22
238
|
const STORAGE_KEY = 'svadmin-theme';
|
|
@@ -33,7 +249,12 @@ export function configureTheme(config: ThemeConfig): void {
|
|
|
33
249
|
themeConfig = { ...config };
|
|
34
250
|
// Re-apply the current theme with new strategy
|
|
35
251
|
applyTheme(mode);
|
|
36
|
-
// Apply
|
|
252
|
+
// Apply color preset first (lower priority)
|
|
253
|
+
if (config.colorPreset) {
|
|
254
|
+
const preset = resolvePreset(config.colorPreset);
|
|
255
|
+
if (preset) applyColorPreset(preset);
|
|
256
|
+
}
|
|
257
|
+
// Then apply manual CSS overrides (higher priority)
|
|
37
258
|
if (config.cssOverrides) {
|
|
38
259
|
applyCssOverrides(config.cssOverrides);
|
|
39
260
|
}
|
|
@@ -70,15 +291,12 @@ export function clearCssOverrides(keys?: string[]): void {
|
|
|
70
291
|
}
|
|
71
292
|
}
|
|
72
293
|
|
|
73
|
-
// ── Color themes (display metadata)
|
|
74
|
-
export const colorThemes: { id: ColorTheme; label: string; color: string }[] =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
{ id: 'violet', label: 'Violet', color: '#8b5cf6' },
|
|
80
|
-
{ id: 'zinc', label: 'Zinc', color: '#71717a' },
|
|
81
|
-
];
|
|
294
|
+
// ── Color themes (display metadata, derived from presets) ──
|
|
295
|
+
export const colorThemes: { id: ColorTheme | string; label: string; color: string }[] = Object.values(builtinPresets).map(p => ({
|
|
296
|
+
id: p.name as ColorTheme,
|
|
297
|
+
label: p.label,
|
|
298
|
+
color: p.color,
|
|
299
|
+
}));
|
|
82
300
|
|
|
83
301
|
// ── Dark/Light mode ──────────────────────────────────────
|
|
84
302
|
|