@fayz-ai/ui 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/README.md +2 -2
- package/dist/analytics/AnalyticsCard.d.ts +10 -0
- package/dist/analytics/AnalyticsCard.d.ts.map +1 -0
- package/dist/analytics/AnalyticsControls.d.ts +18 -0
- package/dist/analytics/AnalyticsControls.d.ts.map +1 -0
- package/dist/analytics/AnalyticsGrid.d.ts +16 -0
- package/dist/analytics/AnalyticsGrid.d.ts.map +1 -0
- package/dist/analytics/context.d.ts +58 -0
- package/dist/analytics/context.d.ts.map +1 -0
- package/dist/analytics/derive.d.ts +81 -0
- package/dist/analytics/derive.d.ts.map +1 -0
- package/dist/analytics/index.d.ts +13 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/range.d.ts +22 -0
- package/dist/analytics/range.d.ts.map +1 -0
- package/dist/{chunk-PVIB724L.js → chunk-22EVFMS3.js} +5 -3
- package/dist/chunk-22EVFMS3.js.map +1 -0
- package/dist/{chunk-G6OKZ7WL.js → chunk-6V5MGYXH.js} +13 -9
- package/dist/chunk-6V5MGYXH.js.map +1 -0
- package/dist/{chunk-KV3MHB6N.js → chunk-H63TOSQ7.js} +196 -53
- package/dist/chunk-H63TOSQ7.js.map +1 -0
- package/dist/{chunk-OUPJDGKE.js → chunk-I6CPKAOD.js} +134 -37
- package/dist/chunk-I6CPKAOD.js.map +1 -0
- package/dist/{chunk-YRVE4FOD.js → chunk-OKZ6WQB3.js} +3 -3
- package/dist/chunk-OKZ6WQB3.js.map +1 -0
- package/dist/{chunk-S5KNM4D2.js → chunk-SEIY2F5F.js} +235 -107
- package/dist/chunk-SEIY2F5F.js.map +1 -0
- package/dist/{chunk-75EFDLST.js → chunk-VAKWUUVC.js} +157 -6
- package/dist/chunk-VAKWUUVC.js.map +1 -0
- package/dist/dashboard/OnboardingWidget.d.ts +2 -14
- package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
- package/dist/dashboard/SidebarOnboarding.d.ts +28 -0
- package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -0
- package/dist/dashboard/index.d.ts +2 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +4 -4
- package/dist/dashboard/types.d.ts +18 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/dashboard/useOnboardingProgress.d.ts +28 -0
- package/dist/dashboard/useOnboardingProgress.d.ts.map +1 -0
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +960 -14
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +14 -1
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +11 -2
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/Sidebar.d.ts +8 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/index.js +4 -4
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/preset.d.ts +3 -0
- package/dist/preset.d.ts.map +1 -0
- package/dist/primitives/data-table.d.ts +19 -4
- package/dist/primitives/data-table.d.ts.map +1 -1
- package/dist/primitives/date-picker.d.ts +4 -2
- package/dist/primitives/date-picker.d.ts.map +1 -1
- package/dist/primitives/filter-chip.d.ts +26 -0
- package/dist/primitives/filter-chip.d.ts.map +1 -0
- package/dist/primitives/header-tabs.d.ts +32 -0
- package/dist/primitives/header-tabs.d.ts.map +1 -0
- package/dist/primitives/hint.d.ts +25 -0
- package/dist/primitives/hint.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +7 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +4 -4
- package/dist/primitives/list-view.d.ts +14 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/page-header.d.ts +23 -0
- package/dist/primitives/page-header.d.ts.map +1 -0
- package/dist/primitives/stat-tiles.d.ts +30 -0
- package/dist/primitives/stat-tiles.d.ts.map +1 -0
- package/dist/primitives/switch.d.ts +11 -0
- package/dist/primitives/switch.d.ts.map +1 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +69 -0
- package/dist/stores/page-header.store.d.ts.map +1 -0
- package/package.json +4 -13
- package/dist/chunk-75EFDLST.js.map +0 -1
- package/dist/chunk-G6OKZ7WL.js.map +0 -1
- package/dist/chunk-KV3MHB6N.js.map +0 -1
- package/dist/chunk-OUPJDGKE.js.map +0 -1
- package/dist/chunk-PVIB724L.js.map +0 -1
- package/dist/chunk-S5KNM4D2.js.map +0 -1
- package/dist/chunk-YRVE4FOD.js.map +0 -1
- package/dist/utils/cn.d.ts.map +0 -1
- package/src/dashboard/ChartWidget.tsx +0 -50
- package/src/dashboard/ChartWidgetInner.tsx +0 -83
- package/src/dashboard/DashboardCanvas.tsx +0 -210
- package/src/dashboard/DashboardCustomizeMenu.tsx +0 -53
- package/src/dashboard/DashboardGrid.tsx +0 -35
- package/src/dashboard/DashboardRange.tsx +0 -62
- package/src/dashboard/GoldCard.tsx +0 -38
- package/src/dashboard/KpiCard.tsx +0 -238
- package/src/dashboard/OnboardingWidget.tsx +0 -140
- package/src/dashboard/TableWidget.tsx +0 -51
- package/src/dashboard/define.ts +0 -53
- package/src/dashboard/icon.ts +0 -13
- package/src/dashboard/index.ts +0 -38
- package/src/dashboard/layout.ts +0 -50
- package/src/dashboard/preferences.ts +0 -71
- package/src/dashboard/types.ts +0 -41
- package/src/icons.ts +0 -66
- package/src/index.ts +0 -238
- package/src/layout/AppShell.tsx +0 -987
- package/src/layout/ContentSplit.tsx +0 -153
- package/src/layout/ModulePage.tsx +0 -466
- package/src/layout/PageTransition.tsx +0 -57
- package/src/layout/SaveBar.tsx +0 -247
- package/src/layout/Sidebar.tsx +0 -535
- package/src/layout/Topbar.tsx +0 -462
- package/src/layout/index.ts +0 -39
- package/src/layout/useCrossModuleBack.ts +0 -30
- package/src/primitives/Avatar.tsx +0 -48
- package/src/primitives/SearchCombobox.tsx +0 -216
- package/src/primitives/badge.tsx +0 -68
- package/src/primitives/breadcrumb.tsx +0 -43
- package/src/primitives/button.tsx +0 -60
- package/src/primitives/card.tsx +0 -79
- package/src/primitives/checkbox.tsx +0 -53
- package/src/primitives/confirm-dialog.tsx +0 -125
- package/src/primitives/currency-input.tsx +0 -121
- package/src/primitives/data-table.tsx +0 -160
- package/src/primitives/date-picker.tsx +0 -225
- package/src/primitives/dropdown.tsx +0 -196
- package/src/primitives/index.ts +0 -87
- package/src/primitives/input.tsx +0 -50
- package/src/primitives/list-view.tsx +0 -252
- package/src/primitives/markdown-editor.tsx +0 -75
- package/src/primitives/markdown.tsx +0 -169
- package/src/primitives/modal.tsx +0 -156
- package/src/primitives/phone-link.tsx +0 -138
- package/src/primitives/popover.tsx +0 -30
- package/src/primitives/search-select.tsx +0 -314
- package/src/primitives/segmented-control.tsx +0 -66
- package/src/primitives/select.tsx +0 -157
- package/src/primitives/separator.tsx +0 -29
- package/src/primitives/sheet.tsx +0 -181
- package/src/primitives/skeleton.tsx +0 -46
- package/src/primitives/tabs.tsx +0 -53
- package/src/primitives/time-picker.tsx +0 -148
- package/src/primitives/toast.tsx +0 -46
- package/src/primitives/tooltip.tsx +0 -28
- package/src/stores/index.ts +0 -10
- package/src/stores/layout.store.ts +0 -31
- package/src/stores/theme.store.ts +0 -457
- package/src/styles.css +0 -461
- package/src/tailwind.ts +0 -43
- package/src/theme/index.ts +0 -94
- package/src/theme/preset.ts +0 -209
- package/src/theme/presets.ts +0 -106
- package/src/utils/cn.ts +0 -6
- /package/dist/{utils → lib}/cn.d.ts +0 -0
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
import { create, type StoreApi, type UseBoundStore } from 'zustand'
|
|
2
|
-
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
// Theme token types
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
export interface SemanticColors {
|
|
8
|
-
primary: string
|
|
9
|
-
primaryForeground: string
|
|
10
|
-
secondary: string
|
|
11
|
-
secondaryForeground: string
|
|
12
|
-
accent: string
|
|
13
|
-
accentForeground: string
|
|
14
|
-
background: string
|
|
15
|
-
foreground: string
|
|
16
|
-
card: string
|
|
17
|
-
cardForeground: string
|
|
18
|
-
muted: string
|
|
19
|
-
mutedForeground: string
|
|
20
|
-
border: string
|
|
21
|
-
input: string
|
|
22
|
-
ring: string
|
|
23
|
-
popover: string
|
|
24
|
-
popoverForeground: string
|
|
25
|
-
destructive: string
|
|
26
|
-
destructiveForeground: string
|
|
27
|
-
success: string
|
|
28
|
-
successForeground: string
|
|
29
|
-
warning: string
|
|
30
|
-
warningForeground: string
|
|
31
|
-
// Layout surface colors
|
|
32
|
-
sidebar: string
|
|
33
|
-
sidebarForeground: string
|
|
34
|
-
sidebarBorder: string
|
|
35
|
-
sidebarAccent: string
|
|
36
|
-
sidebarAccentForeground: string
|
|
37
|
-
sidebarMuted: string
|
|
38
|
-
content: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface UIPerceptionTokens {
|
|
42
|
-
buttonRadius: string
|
|
43
|
-
cardRadius: string
|
|
44
|
-
inputRadius: string
|
|
45
|
-
modalRadius: string
|
|
46
|
-
fontFamily: string
|
|
47
|
-
fontFamilyMono: string
|
|
48
|
-
shadowSm: string
|
|
49
|
-
shadowMd: string
|
|
50
|
-
shadowLg: string
|
|
51
|
-
shadowButton?: string
|
|
52
|
-
shadowButtonPrimary?: string
|
|
53
|
-
shadowButtonInset?: string
|
|
54
|
-
surfaceBackdropFilter?: string
|
|
55
|
-
modalBackground?: string
|
|
56
|
-
modalBorder?: string
|
|
57
|
-
modalOverlayBackground?: string
|
|
58
|
-
modalOverlayBackdropFilter?: string
|
|
59
|
-
modalShadow?: string
|
|
60
|
-
glassEdgeGradient?: string
|
|
61
|
-
glassPrimaryEdgeGradient?: string
|
|
62
|
-
glassInnerHighlight?: string
|
|
63
|
-
fieldBackground?: string
|
|
64
|
-
fieldBorder?: string
|
|
65
|
-
fieldShadow?: string
|
|
66
|
-
buttonBackground?: string
|
|
67
|
-
buttonBackgroundHover?: string
|
|
68
|
-
buttonBorder?: string
|
|
69
|
-
buttonPrimaryBackground?: string
|
|
70
|
-
buttonPrimaryBackgroundHover?: string
|
|
71
|
-
buttonPrimaryBorder?: string
|
|
72
|
-
buttonBackdropFilter?: string
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface ThemeTokens {
|
|
76
|
-
name: string
|
|
77
|
-
colors: SemanticColors
|
|
78
|
-
perception: UIPerceptionTokens
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface CreateThemeOptions {
|
|
82
|
-
name?: string
|
|
83
|
-
colors?: Partial<SemanticColors>
|
|
84
|
-
/** Dark mode color overrides — applied instead of `colors` when in dark mode */
|
|
85
|
-
darkColors?: Partial<SemanticColors>
|
|
86
|
-
perception?: Partial<UIPerceptionTokens>
|
|
87
|
-
/** Shorthand: single HSL value that auto-derives primary, ring, and accent */
|
|
88
|
-
brand?: string
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
// Built-in themes
|
|
93
|
-
// ---------------------------------------------------------------------------
|
|
94
|
-
|
|
95
|
-
export const lightTheme: ThemeTokens = {
|
|
96
|
-
name: 'light',
|
|
97
|
-
colors: {
|
|
98
|
-
primary: '0 0% 18.8%',
|
|
99
|
-
primaryForeground: '0 0% 100%',
|
|
100
|
-
secondary: '0 0% 96.9%',
|
|
101
|
-
secondaryForeground: '0 0% 18.8%',
|
|
102
|
-
accent: '0 0% 94.5%',
|
|
103
|
-
accentForeground: '0 0% 18.8%',
|
|
104
|
-
background: '0 0% 94.5%',
|
|
105
|
-
foreground: '0 0% 18.8%',
|
|
106
|
-
card: '0 0% 100%',
|
|
107
|
-
cardForeground: '0 0% 18.8%',
|
|
108
|
-
muted: '0 0% 96.9%',
|
|
109
|
-
mutedForeground: '0 0% 38%',
|
|
110
|
-
border: '0 0% 89%',
|
|
111
|
-
input: '0 0% 54.1%',
|
|
112
|
-
ring: '214 100% 41.4%',
|
|
113
|
-
popover: '0 0% 100%',
|
|
114
|
-
popoverForeground: '0 0% 18.8%',
|
|
115
|
-
destructive: '354 92% 41%',
|
|
116
|
-
destructiveForeground: '0 0% 100%',
|
|
117
|
-
success: '167 95% 25.1%',
|
|
118
|
-
successForeground: '0 0% 100%',
|
|
119
|
-
warning: '43 100% 50%',
|
|
120
|
-
warningForeground: '0 0% 18.8%',
|
|
121
|
-
sidebar: '0 0% 92.2%',
|
|
122
|
-
sidebarForeground: '0 0% 18.8%',
|
|
123
|
-
sidebarBorder: '0 0% 86.3%',
|
|
124
|
-
sidebarAccent: '0 0% 100%',
|
|
125
|
-
sidebarAccentForeground: '0 0% 18.8%',
|
|
126
|
-
sidebarMuted: '0 0% 38%',
|
|
127
|
-
content: '0 0% 94.5%',
|
|
128
|
-
},
|
|
129
|
-
perception: {
|
|
130
|
-
buttonRadius: '0.5rem',
|
|
131
|
-
cardRadius: '0.5rem',
|
|
132
|
-
inputRadius: '0.5rem',
|
|
133
|
-
modalRadius: '1rem',
|
|
134
|
-
fontFamily: 'Inter, ui-sans-serif, system-ui, -apple-system, sans-serif',
|
|
135
|
-
fontFamilyMono: 'JetBrains Mono, ui-monospace, SFMono-Regular, monospace',
|
|
136
|
-
shadowSm: '0 1px 0 rgba(0, 0, 0, 0.05), 0 1px 3px 0 rgba(26, 26, 26, 0.06), 0 1px 2px -1px rgba(26, 26, 26, 0.06)',
|
|
137
|
-
shadowMd: '0 1px 1px -1px rgba(26, 26, 26, 0.07), 0 4px 8px -2px rgba(26, 26, 26, 0.10)',
|
|
138
|
-
shadowLg: '0 4px 12px -2px rgba(26, 26, 26, 0.15), 0 1px 3px rgba(26, 26, 26, 0.08)',
|
|
139
|
-
shadowButton:
|
|
140
|
-
'inset 0 -1px 0 rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.50), 0 1px 0 rgba(0,0,0,0.05)',
|
|
141
|
-
shadowButtonPrimary:
|
|
142
|
-
'inset 0 -1px 0 rgba(0,0,0,0.20), inset 0 1px 0 rgba(255,255,255,0.20), 0 1px 1.5px rgba(0,0,0,0.20)',
|
|
143
|
-
shadowButtonInset:
|
|
144
|
-
'inset 0 2px 1px -1px rgba(0,0,0,0.20), inset 0 0 0 1px rgba(0,0,0,0.05)',
|
|
145
|
-
surfaceBackdropFilter: 'none',
|
|
146
|
-
buttonBackground: 'hsl(var(--card))',
|
|
147
|
-
buttonBackgroundHover: 'hsl(var(--muted))',
|
|
148
|
-
buttonBorder: 'hsl(var(--border))',
|
|
149
|
-
buttonPrimaryBackground: 'hsl(var(--primary))',
|
|
150
|
-
buttonPrimaryBackgroundHover: 'hsl(var(--primary) / 0.9)',
|
|
151
|
-
buttonPrimaryBorder: 'hsl(var(--primary))',
|
|
152
|
-
buttonBackdropFilter: 'none',
|
|
153
|
-
},
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export const darkTheme: ThemeTokens = {
|
|
157
|
-
name: 'dark',
|
|
158
|
-
colors: {
|
|
159
|
-
primary: '0 0% 100%',
|
|
160
|
-
primaryForeground: '0 0% 10.2%',
|
|
161
|
-
secondary: '0 0% 18.8%',
|
|
162
|
-
secondaryForeground: '0 0% 89%',
|
|
163
|
-
accent: '0 0% 22.7%',
|
|
164
|
-
accentForeground: '0 0% 100%',
|
|
165
|
-
background: '0 0% 10.2%',
|
|
166
|
-
foreground: '0 0% 89%',
|
|
167
|
-
card: '0 0% 14.9%',
|
|
168
|
-
cardForeground: '0 0% 89%',
|
|
169
|
-
muted: '0 0% 18.8%',
|
|
170
|
-
mutedForeground: '0 0% 64.7%',
|
|
171
|
-
border: '0 0% 22.7%',
|
|
172
|
-
input: '0 0% 32.2%',
|
|
173
|
-
ring: '217 100% 68.4%',
|
|
174
|
-
popover: '0 0% 18.8%',
|
|
175
|
-
popoverForeground: '0 0% 89%',
|
|
176
|
-
destructive: '7 100% 44.9%',
|
|
177
|
-
destructiveForeground: '0 0% 100%',
|
|
178
|
-
success: '156 71% 42.5%',
|
|
179
|
-
successForeground: '0 0% 0%',
|
|
180
|
-
warning: '41 100% 65.1%',
|
|
181
|
-
warningForeground: '0 0% 10.2%',
|
|
182
|
-
sidebar: '0 0% 10.2%',
|
|
183
|
-
sidebarForeground: '0 0% 89%',
|
|
184
|
-
sidebarBorder: '0 0% 16.5%',
|
|
185
|
-
sidebarAccent: '0 0% 18.8%',
|
|
186
|
-
sidebarAccentForeground: '0 0% 100%',
|
|
187
|
-
sidebarMuted: '0 0% 64.7%',
|
|
188
|
-
content: '0 0% 10.2%',
|
|
189
|
-
},
|
|
190
|
-
perception: {
|
|
191
|
-
buttonRadius: '0.5rem',
|
|
192
|
-
cardRadius: '0.5rem',
|
|
193
|
-
inputRadius: '0.5rem',
|
|
194
|
-
modalRadius: '1rem',
|
|
195
|
-
fontFamily: 'Inter, ui-sans-serif, system-ui, -apple-system, sans-serif',
|
|
196
|
-
fontFamilyMono: 'JetBrains Mono, ui-monospace, SFMono-Regular, monospace',
|
|
197
|
-
shadowSm: '0 1px 0 rgba(0, 0, 0, 0.4), 0 1px 3px 0 rgba(0, 0, 0, 0.35), 0 1px 2px -1px rgba(0, 0, 0, 0.35)',
|
|
198
|
-
shadowMd: '0 1px 1px -1px rgba(0, 0, 0, 0.5), 0 4px 8px -2px rgba(0, 0, 0, 0.6)',
|
|
199
|
-
shadowLg: '0 4px 12px -2px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.4)',
|
|
200
|
-
shadowButton:
|
|
201
|
-
'inset 0 -1px 0 rgba(0,0,0,0.40), inset 0 1px 0 rgba(255,255,255,0.08), 0 1px 0 rgba(0,0,0,0.30)',
|
|
202
|
-
shadowButtonPrimary:
|
|
203
|
-
'inset 0 -1px 0 rgba(0,0,0,0.20), inset 0 1px 0 rgba(255,255,255,0.40), 0 1px 1.5px rgba(0,0,0,0.40)',
|
|
204
|
-
shadowButtonInset:
|
|
205
|
-
'inset 0 2px 1px -1px rgba(0,0,0,0.50), inset 0 0 0 1px rgba(0,0,0,0.20)',
|
|
206
|
-
surfaceBackdropFilter: 'none',
|
|
207
|
-
buttonBackground: 'hsl(var(--card))',
|
|
208
|
-
buttonBackgroundHover: 'hsl(var(--muted))',
|
|
209
|
-
buttonBorder: 'hsl(var(--border))',
|
|
210
|
-
buttonPrimaryBackground: 'hsl(var(--primary))',
|
|
211
|
-
buttonPrimaryBackgroundHover: 'hsl(var(--primary) / 0.9)',
|
|
212
|
-
buttonPrimaryBorder: 'hsl(var(--primary))',
|
|
213
|
-
buttonBackdropFilter: 'none',
|
|
214
|
-
},
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// ---------------------------------------------------------------------------
|
|
218
|
-
// CSS variable maps
|
|
219
|
-
// ---------------------------------------------------------------------------
|
|
220
|
-
|
|
221
|
-
const colorVarMap: Record<string, string> = {
|
|
222
|
-
primary: '--primary',
|
|
223
|
-
primaryForeground: '--primary-foreground',
|
|
224
|
-
secondary: '--secondary',
|
|
225
|
-
secondaryForeground: '--secondary-foreground',
|
|
226
|
-
accent: '--accent',
|
|
227
|
-
accentForeground: '--accent-foreground',
|
|
228
|
-
background: '--background',
|
|
229
|
-
foreground: '--foreground',
|
|
230
|
-
card: '--card',
|
|
231
|
-
cardForeground: '--card-foreground',
|
|
232
|
-
muted: '--muted',
|
|
233
|
-
mutedForeground: '--muted-foreground',
|
|
234
|
-
border: '--border',
|
|
235
|
-
input: '--input',
|
|
236
|
-
ring: '--ring',
|
|
237
|
-
popover: '--popover',
|
|
238
|
-
popoverForeground: '--popover-foreground',
|
|
239
|
-
destructive: '--destructive',
|
|
240
|
-
destructiveForeground: '--destructive-foreground',
|
|
241
|
-
success: '--success',
|
|
242
|
-
successForeground: '--success-foreground',
|
|
243
|
-
warning: '--warning',
|
|
244
|
-
warningForeground: '--warning-foreground',
|
|
245
|
-
sidebar: '--sidebar',
|
|
246
|
-
sidebarForeground: '--sidebar-foreground',
|
|
247
|
-
sidebarBorder: '--sidebar-border',
|
|
248
|
-
sidebarAccent: '--sidebar-accent',
|
|
249
|
-
sidebarAccentForeground: '--sidebar-accent-foreground',
|
|
250
|
-
sidebarMuted: '--sidebar-muted',
|
|
251
|
-
content: '--content',
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const perceptionVarMap: Record<string, string> = {
|
|
255
|
-
buttonRadius: '--button-radius',
|
|
256
|
-
cardRadius: '--card-radius',
|
|
257
|
-
inputRadius: '--input-radius',
|
|
258
|
-
modalRadius: '--modal-radius',
|
|
259
|
-
fontFamily: '--font-family',
|
|
260
|
-
fontFamilyMono: '--font-family-mono',
|
|
261
|
-
shadowSm: '--shadow-sm',
|
|
262
|
-
shadowMd: '--shadow-md',
|
|
263
|
-
shadowLg: '--shadow-lg',
|
|
264
|
-
shadowButton: '--shadow-button',
|
|
265
|
-
shadowButtonPrimary: '--shadow-button-primary',
|
|
266
|
-
shadowButtonInset: '--shadow-button-inset',
|
|
267
|
-
surfaceBackdropFilter: '--surface-backdrop-filter',
|
|
268
|
-
modalBackground: '--modal-bg',
|
|
269
|
-
modalBorder: '--modal-border',
|
|
270
|
-
modalOverlayBackground: '--modal-overlay-bg',
|
|
271
|
-
modalOverlayBackdropFilter: '--modal-overlay-backdrop-filter',
|
|
272
|
-
modalShadow: '--modal-shadow',
|
|
273
|
-
glassEdgeGradient: '--glass-edge-gradient',
|
|
274
|
-
glassPrimaryEdgeGradient: '--glass-primary-edge-gradient',
|
|
275
|
-
glassInnerHighlight: '--glass-inner-highlight',
|
|
276
|
-
fieldBackground: '--field-bg',
|
|
277
|
-
fieldBorder: '--field-border',
|
|
278
|
-
fieldShadow: '--field-shadow',
|
|
279
|
-
buttonBackground: '--button-bg',
|
|
280
|
-
buttonBackgroundHover: '--button-hover-bg',
|
|
281
|
-
buttonBorder: '--button-border',
|
|
282
|
-
buttonPrimaryBackground: '--button-primary-bg',
|
|
283
|
-
buttonPrimaryBackgroundHover: '--button-primary-hover-bg',
|
|
284
|
-
buttonPrimaryBorder: '--button-primary-border',
|
|
285
|
-
buttonBackdropFilter: '--button-backdrop-filter',
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function applyTheme(theme: ThemeTokens, element?: HTMLElement): void {
|
|
289
|
-
const target = element ?? document.documentElement
|
|
290
|
-
|
|
291
|
-
for (const [key, cssVar] of Object.entries(colorVarMap)) {
|
|
292
|
-
const value = theme.colors[key as keyof typeof theme.colors]
|
|
293
|
-
if (value) {
|
|
294
|
-
target.style.setProperty(cssVar, value)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
for (const [key, cssVar] of Object.entries(perceptionVarMap)) {
|
|
299
|
-
const value = theme.perception[key as keyof typeof theme.perception]
|
|
300
|
-
if (value) {
|
|
301
|
-
target.style.setProperty(cssVar, value)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// ---------------------------------------------------------------------------
|
|
307
|
-
// Store
|
|
308
|
-
// ---------------------------------------------------------------------------
|
|
309
|
-
|
|
310
|
-
type ThemeMode = 'light' | 'dark' | 'system'
|
|
311
|
-
|
|
312
|
-
const STORAGE_KEY = 'fayz-ui:theme-mode'
|
|
313
|
-
|
|
314
|
-
interface ThemeState {
|
|
315
|
-
mode: ThemeMode
|
|
316
|
-
resolvedMode: 'light' | 'dark'
|
|
317
|
-
/** Only the user's partial overrides — NOT a full theme */
|
|
318
|
-
overrides: CreateThemeOptions | null
|
|
319
|
-
setMode: (mode: ThemeMode) => void
|
|
320
|
-
setOverrides: (overrides: CreateThemeOptions | null) => void
|
|
321
|
-
initialize: () => void
|
|
322
|
-
// Keep old API name working
|
|
323
|
-
setCustomTheme: (theme: ThemeTokens | null) => void
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function getSystemPreference(): 'light' | 'dark' {
|
|
327
|
-
if (typeof window === 'undefined') return 'light'
|
|
328
|
-
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function getSavedMode(): ThemeMode {
|
|
332
|
-
if (typeof window === 'undefined') return 'light'
|
|
333
|
-
const saved = localStorage.getItem(STORAGE_KEY)
|
|
334
|
-
if (saved === 'light' || saved === 'dark' || saved === 'system') return saved
|
|
335
|
-
return 'light'
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function resolveMode(mode: ThemeMode): 'light' | 'dark' {
|
|
339
|
-
return mode === 'system' ? getSystemPreference() : mode
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/** Merge base theme (light or dark) with user's partial overrides */
|
|
343
|
-
function buildTheme(base: ThemeTokens, overrides: CreateThemeOptions | null): ThemeTokens {
|
|
344
|
-
if (!overrides) return base
|
|
345
|
-
|
|
346
|
-
const isDark = base.name === 'dark'
|
|
347
|
-
const colors = { ...base.colors }
|
|
348
|
-
|
|
349
|
-
// Brand shorthand: derive primary, ring, accent from single HSL
|
|
350
|
-
if (overrides.brand) {
|
|
351
|
-
colors.primary = overrides.brand
|
|
352
|
-
colors.primaryForeground = '0 0% 100%'
|
|
353
|
-
colors.ring = overrides.brand
|
|
354
|
-
const parts = overrides.brand.split(' ')
|
|
355
|
-
if (parts.length >= 3) {
|
|
356
|
-
const hue = (parseFloat(parts[0]) - 50 + 360) % 360
|
|
357
|
-
colors.accent = `${hue} ${parts[1]} ${parts[2]}`
|
|
358
|
-
colors.accentForeground = '0 0% 100%'
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Apply explicit color overrides.
|
|
363
|
-
const colorOverrides = isDark && overrides.darkColors
|
|
364
|
-
? overrides.darkColors
|
|
365
|
-
: overrides.colors
|
|
366
|
-
|
|
367
|
-
if (colorOverrides) {
|
|
368
|
-
for (const [key, value] of Object.entries(colorOverrides)) {
|
|
369
|
-
if (value !== undefined) {
|
|
370
|
-
(colors as any)[key] = value
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return {
|
|
376
|
-
name: overrides.name ?? base.name,
|
|
377
|
-
colors,
|
|
378
|
-
perception: {
|
|
379
|
-
...base.perception,
|
|
380
|
-
...(overrides.perception ?? {}),
|
|
381
|
-
},
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const STORE_KEY = '__fayz_ui_theme_store__'
|
|
386
|
-
|
|
387
|
-
function createThemeStore(): UseBoundStore<StoreApi<ThemeState>> {
|
|
388
|
-
// Window-level singleton to survive linked-package dual-module loading
|
|
389
|
-
if (typeof window !== 'undefined' && (window as any)[STORE_KEY]) {
|
|
390
|
-
return (window as any)[STORE_KEY]
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const store = create<ThemeState>((set, get) => ({
|
|
394
|
-
mode: getSavedMode(),
|
|
395
|
-
resolvedMode: 'light',
|
|
396
|
-
overrides: null,
|
|
397
|
-
|
|
398
|
-
setMode: (mode) => {
|
|
399
|
-
const resolved = resolveMode(mode)
|
|
400
|
-
set({ mode, resolvedMode: resolved })
|
|
401
|
-
|
|
402
|
-
if (typeof window !== 'undefined') {
|
|
403
|
-
localStorage.setItem(STORAGE_KEY, mode)
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const { overrides } = get()
|
|
407
|
-
const baseTheme = resolved === 'dark' ? darkTheme : lightTheme
|
|
408
|
-
const theme = buildTheme(baseTheme, overrides)
|
|
409
|
-
|
|
410
|
-
if (typeof document !== 'undefined') {
|
|
411
|
-
document.documentElement.classList.add('theme-transitioning')
|
|
412
|
-
applyTheme(theme)
|
|
413
|
-
document.documentElement.classList.toggle('dark', resolved === 'dark')
|
|
414
|
-
setTimeout(() => {
|
|
415
|
-
document.documentElement.classList.remove('theme-transitioning')
|
|
416
|
-
}, 450)
|
|
417
|
-
} else {
|
|
418
|
-
applyTheme(theme)
|
|
419
|
-
}
|
|
420
|
-
},
|
|
421
|
-
|
|
422
|
-
setOverrides: (overrides) => {
|
|
423
|
-
set({ overrides })
|
|
424
|
-
const { resolvedMode } = get()
|
|
425
|
-
const baseTheme = resolvedMode === 'dark' ? darkTheme : lightTheme
|
|
426
|
-
const theme = buildTheme(baseTheme, overrides)
|
|
427
|
-
applyTheme(theme)
|
|
428
|
-
},
|
|
429
|
-
|
|
430
|
-
// Legacy compat
|
|
431
|
-
setCustomTheme: (_theme) => {
|
|
432
|
-
// Ignore — callers should use setOverrides now
|
|
433
|
-
},
|
|
434
|
-
|
|
435
|
-
initialize: () => {
|
|
436
|
-
const { mode, setMode } = get()
|
|
437
|
-
setMode(mode)
|
|
438
|
-
|
|
439
|
-
if (typeof window !== 'undefined') {
|
|
440
|
-
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
441
|
-
const current = get()
|
|
442
|
-
if (current.mode === 'system') {
|
|
443
|
-
current.setMode('system')
|
|
444
|
-
}
|
|
445
|
-
})
|
|
446
|
-
}
|
|
447
|
-
},
|
|
448
|
-
}))
|
|
449
|
-
|
|
450
|
-
if (typeof window !== 'undefined') {
|
|
451
|
-
(window as any)[STORE_KEY] = store
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return store
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export const useThemeStore = createThemeStore()
|