sonance-brand-mcp 1.3.1 → 1.3.3
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/dist/assets/api/sonance-analyze/route.ts +1116 -0
- package/dist/assets/api/sonance-assets/route.ts +113 -0
- package/dist/assets/api/sonance-components/route.ts +41 -0
- package/dist/assets/api/sonance-inject-id/route.ts +363 -0
- package/dist/assets/api/sonance-save-logo/route.ts +426 -0
- package/dist/assets/api/sonance-theme/route.ts +106 -0
- package/dist/assets/brand-system.ts +1265 -0
- package/dist/assets/components/accordion.stories.tsx +26 -26
- package/dist/assets/components/accordion.tsx +3 -3
- package/dist/assets/components/alert-dialog.stories.tsx +7 -7
- package/dist/assets/components/alert-dialog.tsx +2 -1
- package/dist/assets/components/alert.stories.tsx +3 -3
- package/dist/assets/components/alert.tsx +4 -3
- package/dist/assets/components/aspect-ratio.stories.tsx +4 -1
- package/dist/assets/components/autocomplete.stories.tsx +9 -9
- package/dist/assets/components/autocomplete.tsx +3 -3
- package/dist/assets/components/avatar.stories.tsx +5 -5
- package/dist/assets/components/avatar.tsx +4 -4
- package/dist/assets/components/badge.stories.tsx +10 -10
- package/dist/assets/components/badge.tsx +3 -3
- package/dist/assets/components/breadcrumbs.stories.tsx +7 -7
- package/dist/assets/components/breadcrumbs.tsx +13 -8
- package/dist/assets/components/button.stories.tsx +74 -74
- package/dist/assets/components/button.tsx +2 -0
- package/dist/assets/components/calendar.stories.tsx +11 -11
- package/dist/assets/components/calendar.tsx +4 -4
- package/dist/assets/components/card.stories.tsx +22 -22
- package/dist/assets/components/card.tsx +7 -3
- package/dist/assets/components/carousel.stories.tsx +6 -6
- package/dist/assets/components/carousel.tsx +10 -8
- package/dist/assets/components/chart.tsx +5 -5
- package/dist/assets/components/checkbox-group.stories.tsx +6 -6
- package/dist/assets/components/checkbox-group.tsx +3 -3
- package/dist/assets/components/checkbox.stories.tsx +23 -20
- package/dist/assets/components/checkbox.tsx +13 -16
- package/dist/assets/components/code.stories.tsx +24 -24
- package/dist/assets/components/code.tsx +7 -14
- package/dist/assets/components/collapsible.stories.tsx +3 -3
- package/dist/assets/components/command.stories.tsx +14 -14
- package/dist/assets/components/command.tsx +4 -3
- package/dist/assets/components/context-menu.stories.tsx +1 -1
- package/dist/assets/components/context-menu.tsx +3 -7
- package/dist/assets/components/date-input.stories.tsx +9 -9
- package/dist/assets/components/date-input.tsx +2 -2
- package/dist/assets/components/date-picker.stories.tsx +9 -9
- package/dist/assets/components/date-picker.tsx +3 -3
- package/dist/assets/components/date-range-picker.stories.tsx +12 -12
- package/dist/assets/components/date-range-picker.tsx +3 -3
- package/dist/assets/components/dialog.stories.tsx +40 -40
- package/dist/assets/components/dialog.tsx +8 -12
- package/dist/assets/components/divider.stories.tsx +30 -30
- package/dist/assets/components/divider.tsx +4 -8
- package/dist/assets/components/drawer.stories.tsx +32 -31
- package/dist/assets/components/drawer.tsx +7 -6
- package/dist/assets/components/dropdown-menu.tsx +3 -7
- package/dist/assets/components/dropdown.stories.tsx +12 -12
- package/dist/assets/components/dropdown.tsx +5 -5
- package/dist/assets/components/form.stories.tsx +30 -29
- package/dist/assets/components/form.tsx +5 -5
- package/dist/assets/components/hover-card.stories.tsx +12 -10
- package/dist/assets/components/hover-card.tsx +1 -1
- package/dist/assets/components/image.stories.tsx +48 -25
- package/dist/assets/components/image.tsx +8 -5
- package/dist/assets/components/input-otp.stories.tsx +15 -15
- package/dist/assets/components/input-otp.tsx +5 -5
- package/dist/assets/components/input.stories.tsx +30 -25
- package/dist/assets/components/input.tsx +7 -4
- package/dist/assets/components/kbd.stories.tsx +34 -34
- package/dist/assets/components/kbd.tsx +5 -5
- package/dist/assets/components/link.stories.tsx +36 -36
- package/dist/assets/components/link.tsx +4 -0
- package/dist/assets/components/listbox.stories.tsx +5 -5
- package/dist/assets/components/listbox.tsx +4 -4
- package/dist/assets/components/menubar.tsx +3 -7
- package/dist/assets/components/navbar.stories.tsx +24 -24
- package/dist/assets/components/navbar.tsx +8 -14
- package/dist/assets/components/navigation-menu.stories.tsx +11 -9
- package/dist/assets/components/navigation-menu.tsx +1 -1
- package/dist/assets/components/number-input.stories.tsx +11 -11
- package/dist/assets/components/number-input.tsx +3 -3
- package/dist/assets/components/pagination.stories.tsx +13 -13
- package/dist/assets/components/pagination.tsx +6 -6
- package/dist/assets/components/popover.stories.tsx +35 -35
- package/dist/assets/components/popover.tsx +98 -15
- package/dist/assets/components/progress.stories.tsx +5 -5
- package/dist/assets/components/progress.tsx +5 -5
- package/dist/assets/components/radio-group.stories.tsx +7 -7
- package/dist/assets/components/radio-group.tsx +3 -3
- package/dist/assets/components/range-calendar.stories.tsx +18 -18
- package/dist/assets/components/range-calendar.tsx +3 -3
- package/dist/assets/components/resizable.stories.tsx +23 -23
- package/dist/assets/components/resizable.tsx +1 -1
- package/dist/assets/components/scroll-area.stories.tsx +15 -15
- package/dist/assets/components/scroll-area.tsx +1 -1
- package/dist/assets/components/scroll-shadow.stories.tsx +17 -17
- package/dist/assets/components/scroll-shadow.tsx +2 -2
- package/dist/assets/components/select.stories.tsx +20 -19
- package/dist/assets/components/select.tsx +10 -6
- package/dist/assets/components/separator.tsx +1 -1
- package/dist/assets/components/sheet.tsx +3 -7
- package/dist/assets/components/sidebar.stories.tsx +30 -30
- package/dist/assets/components/sidebar.tsx +24 -27
- package/dist/assets/components/skeleton.stories.tsx +3 -3
- package/dist/assets/components/skeleton.tsx +2 -2
- package/dist/assets/components/slider.stories.tsx +6 -6
- package/dist/assets/components/slider.tsx +3 -3
- package/dist/assets/components/spacer.stories.tsx +11 -11
- package/dist/assets/components/spacer.tsx +2 -2
- package/dist/assets/components/spinner.stories.tsx +8 -8
- package/dist/assets/components/spinner.tsx +5 -5
- package/dist/assets/components/switch.stories.tsx +24 -20
- package/dist/assets/components/switch.tsx +14 -6
- package/dist/assets/components/table.stories.tsx +7 -7
- package/dist/assets/components/table.tsx +8 -8
- package/dist/assets/components/tabs.stories.tsx +37 -37
- package/dist/assets/components/tabs.tsx +3 -3
- package/dist/assets/components/textarea.stories.tsx +13 -12
- package/dist/assets/components/textarea.tsx +3 -3
- package/dist/assets/components/theme-toggle.stories.tsx +31 -30
- package/dist/assets/components/theme-toggle.tsx +2 -2
- package/dist/assets/components/time-input.stories.tsx +16 -16
- package/dist/assets/components/time-input.tsx +2 -2
- package/dist/assets/components/toast.stories.tsx +8 -5
- package/dist/assets/components/toast.tsx +6 -6
- package/dist/assets/components/toggle-group.tsx +1 -1
- package/dist/assets/components/toggle.tsx +1 -1
- package/dist/assets/components/tooltip.stories.tsx +49 -27
- package/dist/assets/components/tooltip.tsx +1 -1
- package/dist/assets/components/user.stories.tsx +23 -23
- package/dist/assets/components/user.tsx +7 -4
- package/dist/assets/dev-tools/SonanceDevTools.tsx +4201 -0
- package/dist/assets/dev-tools/index.ts +10 -0
- package/dist/assets/globals.css +9 -0
- package/dist/assets/styles/brand-overrides.css +37 -0
- package/dist/index.js +1882 -7
- package/package.json +1 -1
|
@@ -0,0 +1,1265 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// SONANCE BRAND SYSTEM
|
|
3
|
+
// Core theme configuration and utilities for the Sonance brand family
|
|
4
|
+
// ============================================
|
|
5
|
+
|
|
6
|
+
// ---- Types ----
|
|
7
|
+
|
|
8
|
+
export interface ThemeConfig {
|
|
9
|
+
// Colors
|
|
10
|
+
baseColor: string;
|
|
11
|
+
accentColor: string;
|
|
12
|
+
|
|
13
|
+
// Radius
|
|
14
|
+
radius: 'none' | 'sm' | 'md' | 'lg';
|
|
15
|
+
|
|
16
|
+
// Typography
|
|
17
|
+
headingWeight: 400 | 500 | 600 | 700;
|
|
18
|
+
bodyWeight: 300 | 400 | 500;
|
|
19
|
+
typographyScale: 'compact' | 'default' | 'large';
|
|
20
|
+
|
|
21
|
+
// Spacing
|
|
22
|
+
spacing: 'compact' | 'default' | 'relaxed';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type BrandId = 'sonance' | 'iport' | 'blaze';
|
|
26
|
+
|
|
27
|
+
export interface BrandPreset {
|
|
28
|
+
id: BrandId;
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
config: ThemeConfig;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BrandLogos {
|
|
35
|
+
light: string; // Logo for light mode (dark logo on light bg)
|
|
36
|
+
dark: string; // Logo for dark mode (light logo on dark bg)
|
|
37
|
+
alt: string; // Alt text
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ColorPreset {
|
|
41
|
+
name: string;
|
|
42
|
+
value: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ComponentSnippet {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
category: string;
|
|
49
|
+
description: string;
|
|
50
|
+
code: string;
|
|
51
|
+
/** The component file name (without extension) in src/components/ui */
|
|
52
|
+
fileName?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ---- Default Configuration ----
|
|
56
|
+
|
|
57
|
+
export const defaultThemeConfig: ThemeConfig = {
|
|
58
|
+
baseColor: '#333F48', // Sonance Charcoal
|
|
59
|
+
accentColor: '#00A3E1', // Sonance Blue
|
|
60
|
+
radius: 'sm',
|
|
61
|
+
headingWeight: 600,
|
|
62
|
+
bodyWeight: 400,
|
|
63
|
+
typographyScale: 'default',
|
|
64
|
+
spacing: 'default',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// ---- Brand Presets ----
|
|
68
|
+
|
|
69
|
+
export const brandPresets: BrandPreset[] = [
|
|
70
|
+
{
|
|
71
|
+
id: 'sonance',
|
|
72
|
+
name: 'Sonance',
|
|
73
|
+
description: 'Clean, premium audio brand',
|
|
74
|
+
config: {
|
|
75
|
+
baseColor: '#333F48', // Sonance Charcoal
|
|
76
|
+
accentColor: '#00A3E1', // Sonance Blue
|
|
77
|
+
radius: 'sm',
|
|
78
|
+
headingWeight: 600,
|
|
79
|
+
bodyWeight: 400,
|
|
80
|
+
typographyScale: 'default',
|
|
81
|
+
spacing: 'default',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'iport',
|
|
86
|
+
name: 'IPORT',
|
|
87
|
+
description: 'Bold, modern tech brand',
|
|
88
|
+
config: {
|
|
89
|
+
baseColor: '#FC4C02', // IPORT Orange
|
|
90
|
+
accentColor: '#0F161D', // IPORT Dark
|
|
91
|
+
radius: 'sm',
|
|
92
|
+
headingWeight: 700,
|
|
93
|
+
bodyWeight: 400,
|
|
94
|
+
typographyScale: 'default',
|
|
95
|
+
spacing: 'default',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'blaze',
|
|
100
|
+
name: 'Blaze Audio',
|
|
101
|
+
description: 'Professional audio solutions',
|
|
102
|
+
config: {
|
|
103
|
+
baseColor: '#00A3E1', // Blaze Blue
|
|
104
|
+
accentColor: '#28282B', // Blaze Dark Gray
|
|
105
|
+
radius: 'sm',
|
|
106
|
+
headingWeight: 600,
|
|
107
|
+
bodyWeight: 400,
|
|
108
|
+
typographyScale: 'default',
|
|
109
|
+
spacing: 'compact',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
// ---- Brand Logo Assets ----
|
|
115
|
+
|
|
116
|
+
export const brandLogos: Record<BrandId, BrandLogos> = {
|
|
117
|
+
sonance: {
|
|
118
|
+
light: '/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Dark.png',
|
|
119
|
+
dark: '/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Light.png',
|
|
120
|
+
alt: 'Sonance',
|
|
121
|
+
},
|
|
122
|
+
iport: {
|
|
123
|
+
light: '/logos/iport/IPORT_Sonance_LockUp_2C_Dark_RGB.png',
|
|
124
|
+
dark: '/logos/iport/IPORT_Sonance_LockUp_2C_Light_RGB.png',
|
|
125
|
+
alt: 'IPORT',
|
|
126
|
+
},
|
|
127
|
+
blaze: {
|
|
128
|
+
light: '/logos/blaze/BlazeBySonance_Logo_Lockup_3C_Dark_RGB_05162025.png',
|
|
129
|
+
dark: '/logos/blaze/BlazeBySonance_Logo_Lockup_2C_Light_RGB_05162025.png',
|
|
130
|
+
alt: 'Blaze Audio',
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Logo dimension overrides
|
|
135
|
+
export const logoSizes: Record<string, { width?: number; height?: number; scale?: number }> = {
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// ---- Color Presets ----
|
|
153
|
+
|
|
154
|
+
export const colorPresets: ColorPreset[] = [
|
|
155
|
+
{ name: 'Sonance Charcoal', value: '#333F48' },
|
|
156
|
+
{ name: 'Sonance Blue', value: '#00A3E1' },
|
|
157
|
+
{ name: 'IPORT Dark', value: '#0F161D' },
|
|
158
|
+
{ name: 'IPORT Orange', value: '#FC4C02' },
|
|
159
|
+
{ name: 'Blaze Dark', value: '#28282B' },
|
|
160
|
+
{ name: 'Blaze Red', value: '#C02B0A' },
|
|
161
|
+
{ name: 'Foundation Green', value: '#00B2A9' },
|
|
162
|
+
{ name: 'Slate', value: '#64748b' },
|
|
163
|
+
{ name: 'Zinc', value: '#71717a' },
|
|
164
|
+
{ name: 'Stone', value: '#78716c' },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// ---- Scale Values ----
|
|
168
|
+
|
|
169
|
+
export const radiusValues: Record<ThemeConfig['radius'], string> = {
|
|
170
|
+
none: '0px',
|
|
171
|
+
sm: '2px',
|
|
172
|
+
md: '4px',
|
|
173
|
+
lg: '8px',
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const typographyScales: Record<ThemeConfig['typographyScale'], number> = {
|
|
177
|
+
compact: 0.9,
|
|
178
|
+
default: 1,
|
|
179
|
+
large: 1.1,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export const spacingScales: Record<ThemeConfig['spacing'], number> = {
|
|
183
|
+
compact: 0.875,
|
|
184
|
+
default: 1,
|
|
185
|
+
relaxed: 1.125,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// ---- Color Utilities ----
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Darken a hex color by a percentage
|
|
192
|
+
*/
|
|
193
|
+
export function darken(hex: string, percent: number): string {
|
|
194
|
+
const num = parseInt(hex.replace('#', ''), 16);
|
|
195
|
+
const amt = Math.round(2.55 * percent);
|
|
196
|
+
const R = Math.max(0, (num >> 16) - amt);
|
|
197
|
+
const G = Math.max(0, ((num >> 8) & 0x00ff) - amt);
|
|
198
|
+
const B = Math.max(0, (num & 0x0000ff) - amt);
|
|
199
|
+
return `#${(0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1)}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Lighten a hex color by a percentage
|
|
204
|
+
*/
|
|
205
|
+
export function lighten(hex: string, percent: number): string {
|
|
206
|
+
const num = parseInt(hex.replace('#', ''), 16);
|
|
207
|
+
const amt = Math.round(2.55 * percent);
|
|
208
|
+
const R = Math.min(255, (num >> 16) + amt);
|
|
209
|
+
const G = Math.min(255, ((num >> 8) & 0x00ff) + amt);
|
|
210
|
+
const B = Math.min(255, (num & 0x0000ff) + amt);
|
|
211
|
+
return `#${(0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1)}`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Check if a color is light (for contrast calculations)
|
|
216
|
+
*/
|
|
217
|
+
export function isLightColor(hex: string): boolean {
|
|
218
|
+
const c = hex.replace('#', '');
|
|
219
|
+
const r = parseInt(c.substring(0, 2), 16);
|
|
220
|
+
const g = parseInt(c.substring(2, 4), 16);
|
|
221
|
+
const b = parseInt(c.substring(4, 6), 16);
|
|
222
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
223
|
+
return luminance > 0.5;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ---- CSS Generation ----
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Generate CSS variables object from theme config
|
|
230
|
+
*/
|
|
231
|
+
export function generateThemeVariables(config: ThemeConfig): Record<string, string> {
|
|
232
|
+
const radiusValue = radiusValues[config.radius];
|
|
233
|
+
const typographyScale = typographyScales[config.typographyScale];
|
|
234
|
+
const spacingScale = spacingScales[config.spacing];
|
|
235
|
+
const foregroundColor = isLightColor(config.baseColor) ? '#000000' : '#FFFFFF';
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
// Primary colors
|
|
239
|
+
'--primary': config.baseColor,
|
|
240
|
+
'--primary-hover': darken(config.baseColor, 8),
|
|
241
|
+
'--primary-active': darken(config.baseColor, 15),
|
|
242
|
+
'--primary-foreground': foregroundColor,
|
|
243
|
+
'--color-primary': config.baseColor,
|
|
244
|
+
'--color-primary-hover': darken(config.baseColor, 8),
|
|
245
|
+
'--color-primary-foreground': foregroundColor,
|
|
246
|
+
|
|
247
|
+
// Theme-specific variables
|
|
248
|
+
'--theme-primary': config.baseColor,
|
|
249
|
+
'--theme-primary-hover': darken(config.baseColor, 8),
|
|
250
|
+
'--theme-primary-active': darken(config.baseColor, 15),
|
|
251
|
+
'--theme-primary-foreground': foregroundColor,
|
|
252
|
+
|
|
253
|
+
'--theme-accent': config.accentColor,
|
|
254
|
+
'--theme-accent-hover': darken(config.accentColor, 8),
|
|
255
|
+
|
|
256
|
+
// Radius
|
|
257
|
+
'--theme-radius': radiusValue,
|
|
258
|
+
'--radius-sm': radiusValue,
|
|
259
|
+
|
|
260
|
+
// Typography
|
|
261
|
+
'--theme-heading-weight': String(config.headingWeight),
|
|
262
|
+
'--theme-body-weight': String(config.bodyWeight),
|
|
263
|
+
'--theme-text-xs': `${0.75 * typographyScale}rem`,
|
|
264
|
+
'--theme-text-sm': `${0.875 * typographyScale}rem`,
|
|
265
|
+
'--theme-text-base': `${1 * typographyScale}rem`,
|
|
266
|
+
'--theme-text-lg': `${1.125 * typographyScale}rem`,
|
|
267
|
+
|
|
268
|
+
// Spacing
|
|
269
|
+
'--theme-space-1': `${0.25 * spacingScale}rem`,
|
|
270
|
+
'--theme-space-2': `${0.5 * spacingScale}rem`,
|
|
271
|
+
'--theme-space-3': `${0.75 * spacingScale}rem`,
|
|
272
|
+
'--theme-space-4': `${1 * spacingScale}rem`,
|
|
273
|
+
'--theme-space-6': `${1.5 * spacingScale}rem`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Generate CSS variables string from theme config (for export)
|
|
279
|
+
*/
|
|
280
|
+
export function generateThemeCSS(config: ThemeConfig): string {
|
|
281
|
+
const variables = generateThemeVariables(config);
|
|
282
|
+
return Object.entries(variables)
|
|
283
|
+
.map(([key, value]) => ` ${key}: ${value};`)
|
|
284
|
+
.join('\n');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Apply theme configuration to the document root
|
|
289
|
+
*/
|
|
290
|
+
export function applyThemeToDOM(config: ThemeConfig): void {
|
|
291
|
+
if (typeof document === 'undefined') return;
|
|
292
|
+
|
|
293
|
+
const variables = generateThemeVariables(config);
|
|
294
|
+
const root = document.documentElement;
|
|
295
|
+
|
|
296
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
297
|
+
root.style.setProperty(key, value);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Reset theme to default by removing inline styles
|
|
303
|
+
*/
|
|
304
|
+
export function resetThemeFromDOM(): void {
|
|
305
|
+
if (typeof document === 'undefined') return;
|
|
306
|
+
|
|
307
|
+
const variables = generateThemeVariables(defaultThemeConfig);
|
|
308
|
+
const root = document.documentElement;
|
|
309
|
+
|
|
310
|
+
Object.keys(variables).forEach((key) => {
|
|
311
|
+
root.style.removeProperty(key);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ---- Random Theme Generation ----
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Generate a random theme configuration
|
|
319
|
+
*/
|
|
320
|
+
export function generateRandomTheme(): ThemeConfig {
|
|
321
|
+
const randomColor = colorPresets[Math.floor(Math.random() * colorPresets.length)];
|
|
322
|
+
const accentColors = colorPresets.filter(c => c.value !== randomColor.value);
|
|
323
|
+
const randomAccent = accentColors[Math.floor(Math.random() * accentColors.length)];
|
|
324
|
+
|
|
325
|
+
const radiusOptions: ThemeConfig['radius'][] = ['none', 'sm', 'md', 'lg'];
|
|
326
|
+
const headingWeights: ThemeConfig['headingWeight'][] = [400, 500, 600, 700];
|
|
327
|
+
const bodyWeights: ThemeConfig['bodyWeight'][] = [300, 400, 500];
|
|
328
|
+
const typographyScaleOptions: ThemeConfig['typographyScale'][] = ['compact', 'default', 'large'];
|
|
329
|
+
const spacingOptions: ThemeConfig['spacing'][] = ['compact', 'default', 'relaxed'];
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
baseColor: randomColor.value,
|
|
333
|
+
accentColor: randomAccent.value,
|
|
334
|
+
radius: radiusOptions[Math.floor(Math.random() * radiusOptions.length)],
|
|
335
|
+
headingWeight: headingWeights[Math.floor(Math.random() * headingWeights.length)],
|
|
336
|
+
bodyWeight: bodyWeights[Math.floor(Math.random() * bodyWeights.length)],
|
|
337
|
+
typographyScale: typographyScaleOptions[Math.floor(Math.random() * typographyScaleOptions.length)],
|
|
338
|
+
spacing: spacingOptions[Math.floor(Math.random() * spacingOptions.length)],
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ---- Component Snippets ----
|
|
343
|
+
|
|
344
|
+
export const componentSnippets: ComponentSnippet[] = [
|
|
345
|
+
// ============================================
|
|
346
|
+
// BUTTONS
|
|
347
|
+
// ============================================
|
|
348
|
+
{
|
|
349
|
+
id: 'button-primary',
|
|
350
|
+
name: 'Primary Button',
|
|
351
|
+
category: 'Buttons',
|
|
352
|
+
description: 'Standard primary action button',
|
|
353
|
+
fileName: 'button',
|
|
354
|
+
code: `<button data-sonance-name="button-primary" className="bg-primary text-primary-foreground px-6 py-3 text-sm font-medium uppercase tracking-wide rounded-sm hover:opacity-90 transition-opacity">
|
|
355
|
+
Button Text
|
|
356
|
+
</button>`,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
id: 'button-secondary',
|
|
360
|
+
name: 'Secondary Button',
|
|
361
|
+
category: 'Buttons',
|
|
362
|
+
description: 'Secondary/outline button style',
|
|
363
|
+
fileName: 'button',
|
|
364
|
+
code: `<button data-sonance-name="button-secondary" className="border border-border bg-transparent text-foreground px-6 py-3 text-sm font-medium uppercase tracking-wide rounded-sm hover:bg-secondary-hover transition-colors">
|
|
365
|
+
Button Text
|
|
366
|
+
</button>`,
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
id: 'button-ghost',
|
|
370
|
+
name: 'Ghost Button',
|
|
371
|
+
category: 'Buttons',
|
|
372
|
+
description: 'Minimal ghost/text button',
|
|
373
|
+
fileName: 'button',
|
|
374
|
+
code: `<button data-sonance-name="button-ghost" className="text-foreground px-4 py-2 text-sm font-medium hover:bg-background-secondary rounded-sm transition-colors">
|
|
375
|
+
Ghost
|
|
376
|
+
</button>`,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: 'button-destructive',
|
|
380
|
+
name: 'Destructive Button',
|
|
381
|
+
category: 'Buttons',
|
|
382
|
+
description: 'Danger/delete action button',
|
|
383
|
+
fileName: 'button',
|
|
384
|
+
code: `<button data-sonance-name="button-destructive" className="bg-destructive text-destructive-foreground px-6 py-3 text-sm font-medium uppercase tracking-wide rounded-sm hover:opacity-90 transition-opacity">
|
|
385
|
+
Delete
|
|
386
|
+
</button>`,
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
// ============================================
|
|
390
|
+
// FORMS
|
|
391
|
+
// ============================================
|
|
392
|
+
{
|
|
393
|
+
id: 'input',
|
|
394
|
+
name: 'Input Field',
|
|
395
|
+
category: 'Forms',
|
|
396
|
+
description: 'Standard text input with label',
|
|
397
|
+
fileName: 'input',
|
|
398
|
+
code: `<div data-sonance-name="input" className="space-y-2">
|
|
399
|
+
<label className="text-sm font-medium text-foreground">Label</label>
|
|
400
|
+
<input
|
|
401
|
+
type="text"
|
|
402
|
+
placeholder="Placeholder text"
|
|
403
|
+
className="w-full px-4 py-2 border border-input-border rounded-sm bg-input text-foreground placeholder:text-input-placeholder focus:outline-none focus:ring-1 focus:ring-input-focus"
|
|
404
|
+
/>
|
|
405
|
+
</div>`,
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
id: 'textarea',
|
|
409
|
+
name: 'Textarea',
|
|
410
|
+
category: 'Forms',
|
|
411
|
+
description: 'Multi-line text input',
|
|
412
|
+
fileName: 'textarea',
|
|
413
|
+
code: `<div data-sonance-name="textarea" className="space-y-2">
|
|
414
|
+
<label className="text-sm font-medium text-foreground">Message</label>
|
|
415
|
+
<textarea
|
|
416
|
+
placeholder="Enter your message..."
|
|
417
|
+
rows={4}
|
|
418
|
+
className="w-full px-4 py-2 border border-input-border rounded-sm bg-input text-foreground placeholder:text-input-placeholder focus:outline-none focus:ring-1 focus:ring-input-focus resize-none"
|
|
419
|
+
/>
|
|
420
|
+
</div>`,
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
id: 'checkbox',
|
|
424
|
+
name: 'Checkbox',
|
|
425
|
+
category: 'Forms',
|
|
426
|
+
description: 'Checkbox with label',
|
|
427
|
+
fileName: 'checkbox',
|
|
428
|
+
code: `<label data-sonance-name="checkbox" className="flex items-center gap-3 cursor-pointer">
|
|
429
|
+
<input
|
|
430
|
+
type="checkbox"
|
|
431
|
+
className="h-4 w-4 rounded border-border text-primary focus:ring-primary"
|
|
432
|
+
/>
|
|
433
|
+
<span className="text-sm text-foreground">Accept terms and conditions</span>
|
|
434
|
+
</label>`,
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
id: 'radio-group',
|
|
438
|
+
name: 'Radio Group',
|
|
439
|
+
category: 'Forms',
|
|
440
|
+
description: 'Radio button group',
|
|
441
|
+
fileName: 'radio-group',
|
|
442
|
+
code: `<div data-sonance-name="radio-group" className="space-y-3">
|
|
443
|
+
<label className="flex items-center gap-3 cursor-pointer">
|
|
444
|
+
<input type="radio" name="option" className="h-4 w-4 border-border text-primary focus:ring-primary" />
|
|
445
|
+
<span className="text-sm text-foreground">Option One</span>
|
|
446
|
+
</label>
|
|
447
|
+
<label className="flex items-center gap-3 cursor-pointer">
|
|
448
|
+
<input type="radio" name="option" className="h-4 w-4 border-border text-primary focus:ring-primary" />
|
|
449
|
+
<span className="text-sm text-foreground">Option Two</span>
|
|
450
|
+
</label>
|
|
451
|
+
</div>`,
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
id: 'select',
|
|
455
|
+
name: 'Select',
|
|
456
|
+
category: 'Forms',
|
|
457
|
+
description: 'Dropdown select input',
|
|
458
|
+
fileName: 'select',
|
|
459
|
+
code: `<div data-sonance-name="select" className="space-y-2">
|
|
460
|
+
<label className="text-sm font-medium text-foreground">Choose option</label>
|
|
461
|
+
<select className="w-full px-4 py-2 border border-input-border rounded-sm bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-input-focus">
|
|
462
|
+
<option>Select an option</option>
|
|
463
|
+
<option>Option 1</option>
|
|
464
|
+
<option>Option 2</option>
|
|
465
|
+
</select>
|
|
466
|
+
</div>`,
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: 'switch',
|
|
470
|
+
name: 'Switch',
|
|
471
|
+
category: 'Forms',
|
|
472
|
+
description: 'Toggle switch control',
|
|
473
|
+
fileName: 'switch',
|
|
474
|
+
code: `<label data-sonance-name="switch" className="flex items-center gap-3 cursor-pointer">
|
|
475
|
+
<button
|
|
476
|
+
role="switch"
|
|
477
|
+
aria-checked="true"
|
|
478
|
+
className="relative h-6 w-11 rounded-full bg-primary transition-colors"
|
|
479
|
+
>
|
|
480
|
+
<span className="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition-transform translate-x-5" />
|
|
481
|
+
</button>
|
|
482
|
+
<span className="text-sm text-foreground">Enable notifications</span>
|
|
483
|
+
</label>`,
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
id: 'slider',
|
|
487
|
+
name: 'Slider',
|
|
488
|
+
category: 'Forms',
|
|
489
|
+
description: 'Range slider input',
|
|
490
|
+
fileName: 'slider',
|
|
491
|
+
code: `<div data-sonance-name="slider" className="space-y-2">
|
|
492
|
+
<label className="text-sm font-medium text-foreground">Volume</label>
|
|
493
|
+
<input
|
|
494
|
+
type="range"
|
|
495
|
+
min="0"
|
|
496
|
+
max="100"
|
|
497
|
+
defaultValue="50"
|
|
498
|
+
className="w-full h-2 rounded-full bg-background-secondary accent-primary"
|
|
499
|
+
/>
|
|
500
|
+
</div>`,
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
id: 'calendar',
|
|
504
|
+
name: 'Calendar',
|
|
505
|
+
category: 'Forms',
|
|
506
|
+
description: 'Date selection calendar',
|
|
507
|
+
fileName: 'calendar',
|
|
508
|
+
code: `<div data-sonance-name="calendar" className="p-3 border border-border rounded-sm inline-block bg-card">
|
|
509
|
+
<div className="flex justify-between items-center mb-4">
|
|
510
|
+
<button className="p-1 hover:bg-background-secondary rounded-sm">←</button>
|
|
511
|
+
<span className="text-sm font-medium">January 2024</span>
|
|
512
|
+
<button className="p-1 hover:bg-background-secondary rounded-sm">→</button>
|
|
513
|
+
</div>
|
|
514
|
+
<div className="grid grid-cols-7 gap-1 text-center text-xs mb-2">
|
|
515
|
+
<div className="text-foreground-muted">Su</div>
|
|
516
|
+
<div className="text-foreground-muted">Mo</div>
|
|
517
|
+
<div className="text-foreground-muted">Tu</div>
|
|
518
|
+
<div className="text-foreground-muted">We</div>
|
|
519
|
+
<div className="text-foreground-muted">Th</div>
|
|
520
|
+
<div className="text-foreground-muted">Fr</div>
|
|
521
|
+
<div className="text-foreground-muted">Sa</div>
|
|
522
|
+
</div>
|
|
523
|
+
<div className="grid grid-cols-7 gap-1 text-center text-sm">
|
|
524
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary text-foreground-muted">29</button>
|
|
525
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary text-foreground-muted">30</button>
|
|
526
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary text-foreground-muted">31</button>
|
|
527
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary">1</button>
|
|
528
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary">2</button>
|
|
529
|
+
<button className="p-2 rounded-sm bg-primary text-primary-foreground">3</button>
|
|
530
|
+
<button className="p-2 rounded-sm hover:bg-background-secondary">4</button>
|
|
531
|
+
</div>
|
|
532
|
+
</div>`,
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
id: 'date-picker',
|
|
536
|
+
name: 'Date Picker',
|
|
537
|
+
category: 'Forms',
|
|
538
|
+
description: 'Input with calendar popover',
|
|
539
|
+
fileName: 'date-picker',
|
|
540
|
+
code: `<div data-sonance-name="date-picker" className="relative inline-block">
|
|
541
|
+
<button className="w-[240px] flex items-center justify-between px-3 py-2 text-sm border border-input-border rounded-sm bg-input text-foreground hover:bg-background-secondary">
|
|
542
|
+
<span>Pick a date</span>
|
|
543
|
+
<span className="opacity-50">📅</span>
|
|
544
|
+
</button>
|
|
545
|
+
</div>`,
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
id: 'input-otp',
|
|
549
|
+
name: 'Input OTP',
|
|
550
|
+
category: 'Forms',
|
|
551
|
+
description: 'One-time password input',
|
|
552
|
+
fileName: 'input-otp',
|
|
553
|
+
code: `<div data-sonance-name="input-otp" className="flex gap-2">
|
|
554
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
555
|
+
<div key={i} className="relative w-10 h-12">
|
|
556
|
+
<input
|
|
557
|
+
type="text"
|
|
558
|
+
className="w-full h-full text-center border border-input-border rounded-sm bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-input-focus"
|
|
559
|
+
maxLength={1}
|
|
560
|
+
/>
|
|
561
|
+
</div>
|
|
562
|
+
))}
|
|
563
|
+
</div>`,
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
id: 'number-input',
|
|
567
|
+
name: 'Number Input',
|
|
568
|
+
category: 'Forms',
|
|
569
|
+
description: 'Numeric input with controls',
|
|
570
|
+
fileName: 'number-input',
|
|
571
|
+
code: `<div data-sonance-name="number-input" className="flex items-center border border-input-border rounded-sm w-32">
|
|
572
|
+
<button className="px-3 py-2 text-foreground hover:bg-background-secondary border-r border-input-border">-</button>
|
|
573
|
+
<input
|
|
574
|
+
type="number"
|
|
575
|
+
className="w-full text-center bg-input text-foreground focus:outline-none py-2"
|
|
576
|
+
defaultValue="1"
|
|
577
|
+
/>
|
|
578
|
+
<button className="px-3 py-2 text-foreground hover:bg-background-secondary border-l border-input-border">+</button>
|
|
579
|
+
</div>`,
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
id: 'toggle',
|
|
583
|
+
name: 'Toggle',
|
|
584
|
+
category: 'Forms',
|
|
585
|
+
description: 'Toggle button state',
|
|
586
|
+
fileName: 'toggle',
|
|
587
|
+
code: `<button data-sonance-name="toggle" className="p-2 rounded-sm hover:bg-background-secondary data-[state=on]:bg-background-secondary data-[state=on]:text-foreground">
|
|
588
|
+
<span className="sr-only">Toggle bold</span>
|
|
589
|
+
<span className="font-bold">B</span>
|
|
590
|
+
</button>`,
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
id: 'toggle-group',
|
|
594
|
+
name: 'Toggle Group',
|
|
595
|
+
category: 'Forms',
|
|
596
|
+
description: 'Group of toggle buttons',
|
|
597
|
+
fileName: 'toggle-group',
|
|
598
|
+
code: `<div data-sonance-name="toggle-group" className="inline-flex rounded-sm border border-border p-1 gap-1">
|
|
599
|
+
<button className="px-3 py-1.5 text-xs font-medium rounded-sm hover:bg-background-secondary">Left</button>
|
|
600
|
+
<button className="px-3 py-1.5 text-xs font-medium rounded-sm bg-background-secondary text-foreground shadow-sm">Center</button>
|
|
601
|
+
<button className="px-3 py-1.5 text-xs font-medium rounded-sm hover:bg-background-secondary">Right</button>
|
|
602
|
+
</div>`,
|
|
603
|
+
},
|
|
604
|
+
|
|
605
|
+
// ============================================
|
|
606
|
+
// LAYOUT
|
|
607
|
+
// ============================================
|
|
608
|
+
{
|
|
609
|
+
id: 'card',
|
|
610
|
+
name: 'Card',
|
|
611
|
+
category: 'Layout',
|
|
612
|
+
description: 'Basic content card container',
|
|
613
|
+
fileName: 'card',
|
|
614
|
+
code: `<div data-sonance-name="card" className="bg-card border border-card-border rounded-sm p-6">
|
|
615
|
+
<h3 className="text-lg font-medium text-foreground">Card Title</h3>
|
|
616
|
+
<p className="text-foreground-secondary mt-2">Card content goes here.</p>
|
|
617
|
+
</div>`,
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
id: 'accordion',
|
|
621
|
+
name: 'Accordion',
|
|
622
|
+
category: 'Layout',
|
|
623
|
+
description: 'Expandable content section',
|
|
624
|
+
fileName: 'accordion',
|
|
625
|
+
code: `<div data-sonance-name="accordion" className="border border-border rounded-sm divide-y divide-border">
|
|
626
|
+
<details className="group">
|
|
627
|
+
<summary className="flex items-center justify-between px-4 py-3 cursor-pointer text-foreground font-medium">
|
|
628
|
+
Section Title
|
|
629
|
+
<span className="transition-transform group-open:rotate-180">▼</span>
|
|
630
|
+
</summary>
|
|
631
|
+
<div className="px-4 py-3 text-foreground-secondary text-sm">
|
|
632
|
+
Accordion content goes here.
|
|
633
|
+
</div>
|
|
634
|
+
</details>
|
|
635
|
+
</div>`,
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
id: 'tabs',
|
|
639
|
+
name: 'Tabs',
|
|
640
|
+
category: 'Layout',
|
|
641
|
+
description: 'Tab navigation component',
|
|
642
|
+
fileName: 'tabs',
|
|
643
|
+
code: `<div data-sonance-name="tabs" className="border-b border-border">
|
|
644
|
+
<nav className="flex gap-4">
|
|
645
|
+
<button className="px-4 py-2 text-sm font-medium border-b-2 border-primary text-primary">
|
|
646
|
+
Tab 1
|
|
647
|
+
</button>
|
|
648
|
+
<button className="px-4 py-2 text-sm font-medium text-foreground-muted hover:text-foreground">
|
|
649
|
+
Tab 2
|
|
650
|
+
</button>
|
|
651
|
+
<button className="px-4 py-2 text-sm font-medium text-foreground-muted hover:text-foreground">
|
|
652
|
+
Tab 3
|
|
653
|
+
</button>
|
|
654
|
+
</nav>
|
|
655
|
+
</div>`,
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
id: 'separator',
|
|
659
|
+
name: 'Separator',
|
|
660
|
+
category: 'Layout',
|
|
661
|
+
description: 'Horizontal divider line',
|
|
662
|
+
fileName: 'separator',
|
|
663
|
+
code: `<div data-sonance-name="separator" className="h-px bg-border my-4" />`,
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
id: 'aspect-ratio',
|
|
667
|
+
name: 'Aspect Ratio',
|
|
668
|
+
category: 'Layout',
|
|
669
|
+
description: 'Fixed aspect ratio container',
|
|
670
|
+
fileName: 'aspect-ratio',
|
|
671
|
+
code: `<div data-sonance-name="aspect-ratio" className="relative aspect-video bg-background-secondary rounded-sm overflow-hidden">
|
|
672
|
+
<img src="/placeholder.jpg" alt="Media" className="object-cover w-full h-full" />
|
|
673
|
+
</div>`,
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
id: 'scroll-area',
|
|
677
|
+
name: 'Scroll Area',
|
|
678
|
+
category: 'Layout',
|
|
679
|
+
description: 'Custom scrollable area',
|
|
680
|
+
fileName: 'scroll-area',
|
|
681
|
+
code: `<div data-sonance-name="scroll-area" className="h-[200px] w-[350px] rounded-md border border-border p-4 overflow-y-auto">
|
|
682
|
+
<h4 className="mb-4 text-sm font-medium leading-none">Tags</h4>
|
|
683
|
+
{Array.from({ length: 50 }).map((_, i) => (
|
|
684
|
+
<div key={i} className="text-sm border-b border-border py-2 last:border-0">
|
|
685
|
+
Tag {i + 1}
|
|
686
|
+
</div>
|
|
687
|
+
))}
|
|
688
|
+
</div>`,
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
id: 'resizable',
|
|
692
|
+
name: 'Resizable',
|
|
693
|
+
category: 'Layout',
|
|
694
|
+
description: 'Resizable panel group',
|
|
695
|
+
fileName: 'resizable',
|
|
696
|
+
code: `<div data-sonance-name="resizable" className="flex h-[200px] w-full max-w-md items-center justify-center rounded-md border border-border">
|
|
697
|
+
<div className="w-[50%] p-6">
|
|
698
|
+
<span className="font-semibold">One</span>
|
|
699
|
+
</div>
|
|
700
|
+
<div className="w-px h-full bg-border cursor-col-resize flex items-center justify-center">
|
|
701
|
+
<div className="h-4 w-1 bg-foreground-muted rounded-full" />
|
|
702
|
+
</div>
|
|
703
|
+
<div className="w-[50%] p-6">
|
|
704
|
+
<span className="font-semibold">Two</span>
|
|
705
|
+
</div>
|
|
706
|
+
</div>`,
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
id: 'collapsible',
|
|
710
|
+
name: 'Collapsible',
|
|
711
|
+
category: 'Layout',
|
|
712
|
+
description: 'Interactive component which expands/collapses a panel',
|
|
713
|
+
fileName: 'collapsible',
|
|
714
|
+
code: `<div data-sonance-name="collapsible" className="w-[350px] space-y-2">
|
|
715
|
+
<div className="flex items-center justify-between space-x-4 px-4">
|
|
716
|
+
<h4 className="text-sm font-semibold">@peduarte starred 3 repositories</h4>
|
|
717
|
+
<button className="p-2 hover:bg-background-secondary rounded-sm">▼</button>
|
|
718
|
+
</div>
|
|
719
|
+
<div className="rounded-md border border-border px-4 py-3 font-mono text-sm">
|
|
720
|
+
@radix-ui/primitives
|
|
721
|
+
</div>
|
|
722
|
+
<div className="rounded-md border border-border px-4 py-3 font-mono text-sm">
|
|
723
|
+
@radix-ui/colors
|
|
724
|
+
</div>
|
|
725
|
+
</div>`,
|
|
726
|
+
},
|
|
727
|
+
|
|
728
|
+
// ============================================
|
|
729
|
+
// OVERLAYS
|
|
730
|
+
// ============================================
|
|
731
|
+
{
|
|
732
|
+
id: 'popover',
|
|
733
|
+
name: 'Popover',
|
|
734
|
+
category: 'Overlays',
|
|
735
|
+
description: 'Floating content panel',
|
|
736
|
+
fileName: 'popover',
|
|
737
|
+
code: `<div data-sonance-name="popover" className="relative inline-block">
|
|
738
|
+
<button className="text-sm font-medium text-foreground border-b border-dashed border-border">Open Popover</button>
|
|
739
|
+
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-2 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none z-50">
|
|
740
|
+
<div className="space-y-2">
|
|
741
|
+
<h4 className="font-medium leading-none">Dimensions</h4>
|
|
742
|
+
<p className="text-sm text-foreground-muted">Set the dimensions for the layer.</p>
|
|
743
|
+
</div>
|
|
744
|
+
</div>
|
|
745
|
+
</div>`,
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
id: 'hover-card',
|
|
749
|
+
name: 'Hover Card',
|
|
750
|
+
category: 'Overlays',
|
|
751
|
+
description: 'Preview card on hover',
|
|
752
|
+
fileName: 'hover-card',
|
|
753
|
+
code: `<div data-sonance-name="hover-card" className="relative inline-block group">
|
|
754
|
+
<button className="text-sm font-medium underline decoration-dotted">@nextjs</button>
|
|
755
|
+
<div className="absolute top-full left-0 mt-2 w-80 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md opacity-0 group-hover:opacity-100 transition-opacity z-50">
|
|
756
|
+
<div className="flex justify-between space-x-4">
|
|
757
|
+
<div className="space-y-1">
|
|
758
|
+
<h4 className="text-sm font-semibold">@nextjs</h4>
|
|
759
|
+
<p className="text-sm">The React Framework – created and maintained by @vercel.</p>
|
|
760
|
+
<div className="flex items-center pt-2">
|
|
761
|
+
<span className="text-xs text-foreground-muted">Joined December 2021</span>
|
|
762
|
+
</div>
|
|
763
|
+
</div>
|
|
764
|
+
</div>
|
|
765
|
+
</div>
|
|
766
|
+
</div>`,
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
id: 'context-menu',
|
|
770
|
+
name: 'Context Menu',
|
|
771
|
+
category: 'Overlays',
|
|
772
|
+
description: 'Right-click menu',
|
|
773
|
+
fileName: 'context-menu',
|
|
774
|
+
code: `<div data-sonance-name="context-menu" className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-border text-sm">
|
|
775
|
+
Right click here
|
|
776
|
+
|
|
777
|
+
{/* Hidden menu structure */}
|
|
778
|
+
<div className="hidden absolute w-64 rounded-md border border-border bg-popover p-1 shadow-md">
|
|
779
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground">
|
|
780
|
+
Back
|
|
781
|
+
<span className="ml-auto text-xs tracking-widest text-foreground-muted">⌘[</span>
|
|
782
|
+
</div>
|
|
783
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground">
|
|
784
|
+
Forward
|
|
785
|
+
<span className="ml-auto text-xs tracking-widest text-foreground-muted">⌘]</span>
|
|
786
|
+
</div>
|
|
787
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground">
|
|
788
|
+
Reload
|
|
789
|
+
<span className="ml-auto text-xs tracking-widest text-foreground-muted">⌘R</span>
|
|
790
|
+
</div>
|
|
791
|
+
</div>
|
|
792
|
+
</div>`,
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
id: 'alert-dialog',
|
|
796
|
+
name: 'Alert Dialog',
|
|
797
|
+
category: 'Overlays',
|
|
798
|
+
description: 'Modal that interrupts user',
|
|
799
|
+
fileName: 'alert-dialog',
|
|
800
|
+
code: `<div data-sonance-name="alert-dialog" className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm flex items-center justify-center">
|
|
801
|
+
<div className="fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg">
|
|
802
|
+
<div className="flex flex-col space-y-2 text-center sm:text-left">
|
|
803
|
+
<h2 className="text-lg font-semibold text-foreground">Are you absolutely sure?</h2>
|
|
804
|
+
<p className="text-sm text-foreground-muted">
|
|
805
|
+
This action cannot be undone. This will permanently delete your account and remove your data from our servers.
|
|
806
|
+
</p>
|
|
807
|
+
</div>
|
|
808
|
+
<div className="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
|
809
|
+
<button className="px-4 py-2 border border-border rounded-sm hover:bg-accent">Cancel</button>
|
|
810
|
+
<button className="px-4 py-2 bg-destructive text-destructive-foreground hover:bg-destructive/90 rounded-sm">Continue</button>
|
|
811
|
+
</div>
|
|
812
|
+
</div>
|
|
813
|
+
</div>`,
|
|
814
|
+
},
|
|
815
|
+
|
|
816
|
+
// ============================================
|
|
817
|
+
// NAVIGATION
|
|
818
|
+
// ============================================
|
|
819
|
+
{
|
|
820
|
+
id: 'breadcrumb',
|
|
821
|
+
name: 'Breadcrumb',
|
|
822
|
+
category: 'Navigation',
|
|
823
|
+
description: 'Navigation breadcrumb trail',
|
|
824
|
+
fileName: 'breadcrumbs',
|
|
825
|
+
code: `<nav data-sonance-name="breadcrumb" className="flex items-center gap-2 text-sm">
|
|
826
|
+
<a href="#" className="text-foreground-muted hover:text-foreground">Home</a>
|
|
827
|
+
<span className="text-foreground-muted">/</span>
|
|
828
|
+
<a href="#" className="text-foreground-muted hover:text-foreground">Products</a>
|
|
829
|
+
<span className="text-foreground-muted">/</span>
|
|
830
|
+
<span className="text-foreground font-medium">Current Page</span>
|
|
831
|
+
</nav>`,
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
id: 'pagination',
|
|
835
|
+
name: 'Pagination',
|
|
836
|
+
category: 'Navigation',
|
|
837
|
+
description: 'Page navigation controls',
|
|
838
|
+
fileName: 'pagination',
|
|
839
|
+
code: `<nav data-sonance-name="pagination" className="flex items-center gap-1">
|
|
840
|
+
<button className="px-3 py-1.5 text-sm border border-border rounded-sm hover:bg-background-secondary">Prev</button>
|
|
841
|
+
<button className="px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded-sm">1</button>
|
|
842
|
+
<button className="px-3 py-1.5 text-sm border border-border rounded-sm hover:bg-background-secondary">2</button>
|
|
843
|
+
<button className="px-3 py-1.5 text-sm border border-border rounded-sm hover:bg-background-secondary">3</button>
|
|
844
|
+
<button className="px-3 py-1.5 text-sm border border-border rounded-sm hover:bg-background-secondary">Next</button>
|
|
845
|
+
</nav>`,
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
id: 'dropdown-menu',
|
|
849
|
+
name: 'Dropdown Menu',
|
|
850
|
+
category: 'Navigation',
|
|
851
|
+
description: 'Dropdown menu structure',
|
|
852
|
+
fileName: 'dropdown-menu',
|
|
853
|
+
code: `<div data-sonance-name="dropdown-menu" className="relative inline-block">
|
|
854
|
+
<button className="px-4 py-2 text-sm border border-border rounded-sm hover:bg-background-secondary">
|
|
855
|
+
Options ▼
|
|
856
|
+
</button>
|
|
857
|
+
<div className="absolute top-full left-0 mt-1 w-48 bg-card border border-card-border rounded-sm shadow-lg py-1 z-10">
|
|
858
|
+
<a href="#" className="block px-4 py-2 text-sm text-foreground hover:bg-background-secondary">Edit</a>
|
|
859
|
+
<a href="#" className="block px-4 py-2 text-sm text-foreground hover:bg-background-secondary">Duplicate</a>
|
|
860
|
+
<a href="#" className="block px-4 py-2 text-sm text-destructive hover:bg-background-secondary">Delete</a>
|
|
861
|
+
</div>
|
|
862
|
+
</div>`,
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
id: 'navigation-menu',
|
|
866
|
+
name: 'Navigation Menu',
|
|
867
|
+
category: 'Navigation',
|
|
868
|
+
description: 'Main navigation bar structure',
|
|
869
|
+
fileName: 'navigation-menu',
|
|
870
|
+
code: `<nav data-sonance-name="navigation-menu" className="flex items-center space-x-6 text-sm font-medium">
|
|
871
|
+
<a href="#" className="text-foreground transition-colors hover:text-foreground/80">Documentation</a>
|
|
872
|
+
<a href="#" className="text-foreground/60 transition-colors hover:text-foreground">Components</a>
|
|
873
|
+
<a href="#" className="text-foreground/60 transition-colors hover:text-foreground">Themes</a>
|
|
874
|
+
<a href="#" className="text-foreground/60 transition-colors hover:text-foreground">Examples</a>
|
|
875
|
+
</nav>`,
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
id: 'menubar',
|
|
879
|
+
name: 'Menubar',
|
|
880
|
+
category: 'Navigation',
|
|
881
|
+
description: 'Desktop application menu bar',
|
|
882
|
+
fileName: 'menubar',
|
|
883
|
+
code: `<div data-sonance-name="menubar" className="flex h-10 items-center space-x-1 border rounded-md border-border bg-background p-1">
|
|
884
|
+
<button className="px-3 py-1 text-sm font-medium hover:bg-background-secondary rounded-sm">File</button>
|
|
885
|
+
<button className="px-3 py-1 text-sm font-medium hover:bg-background-secondary rounded-sm">Edit</button>
|
|
886
|
+
<button className="px-3 py-1 text-sm font-medium hover:bg-background-secondary rounded-sm">View</button>
|
|
887
|
+
<button className="px-3 py-1 text-sm font-medium hover:bg-background-secondary rounded-sm">Profile</button>
|
|
888
|
+
</div>`,
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
id: 'sidebar',
|
|
892
|
+
name: 'Sidebar',
|
|
893
|
+
category: 'Navigation',
|
|
894
|
+
description: 'Vertical sidebar navigation',
|
|
895
|
+
fileName: 'sidebar',
|
|
896
|
+
code: `<div data-sonance-name="sidebar" className="w-64 h-full border-r border-border bg-card p-4">
|
|
897
|
+
<div className="mb-8">
|
|
898
|
+
<h2 className="px-2 text-lg font-semibold tracking-tight">Discover</h2>
|
|
899
|
+
<div className="space-y-1 mt-2">
|
|
900
|
+
<button className="w-full justify-start text-left px-2 py-1.5 text-sm font-medium bg-background-secondary rounded-sm text-foreground">Listen Now</button>
|
|
901
|
+
<button className="w-full justify-start text-left px-2 py-1.5 text-sm font-medium hover:bg-background-secondary rounded-sm text-foreground-muted hover:text-foreground">Browse</button>
|
|
902
|
+
<button className="w-full justify-start text-left px-2 py-1.5 text-sm font-medium hover:bg-background-secondary rounded-sm text-foreground-muted hover:text-foreground">Radio</button>
|
|
903
|
+
</div>
|
|
904
|
+
</div>
|
|
905
|
+
</div>`,
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
id: 'sheet',
|
|
909
|
+
name: 'Sheet/Drawer',
|
|
910
|
+
category: 'Navigation',
|
|
911
|
+
description: 'Slide-out panel',
|
|
912
|
+
fileName: 'sheet',
|
|
913
|
+
code: `<div data-sonance-name="sheet" className="fixed inset-y-0 right-0 z-50 w-3/4 gap-4 border-l border-border bg-background p-6 shadow-lg sm:max-w-sm">
|
|
914
|
+
<div className="flex flex-col space-y-2 text-center sm:text-left">
|
|
915
|
+
<h2 className="text-lg font-semibold text-foreground">Edit profile</h2>
|
|
916
|
+
<p className="text-sm text-foreground-muted">Make changes to your profile here. Click save when you're done.</p>
|
|
917
|
+
</div>
|
|
918
|
+
<div className="grid gap-4 py-4">
|
|
919
|
+
<div className="grid grid-cols-4 items-center gap-4">
|
|
920
|
+
<label className="text-right text-sm font-medium">Name</label>
|
|
921
|
+
<input className="col-span-3 px-3 py-2 border border-input-border rounded-sm bg-input" value="Pedro Duarte" />
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
<div className="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
|
925
|
+
<button className="bg-primary text-primary-foreground px-4 py-2 rounded-sm text-sm font-medium">Save changes</button>
|
|
926
|
+
</div>
|
|
927
|
+
</div>`,
|
|
928
|
+
},
|
|
929
|
+
|
|
930
|
+
// ============================================
|
|
931
|
+
// DATA DISPLAY
|
|
932
|
+
// ============================================
|
|
933
|
+
{
|
|
934
|
+
id: 'avatar',
|
|
935
|
+
name: 'Avatar',
|
|
936
|
+
category: 'Data Display',
|
|
937
|
+
description: 'User avatar with fallback',
|
|
938
|
+
fileName: 'avatar',
|
|
939
|
+
code: `<div data-sonance-name="avatar" className="flex items-center gap-3">
|
|
940
|
+
<div className="h-10 w-10 rounded-full bg-primary flex items-center justify-center text-primary-foreground font-medium">
|
|
941
|
+
JD
|
|
942
|
+
</div>
|
|
943
|
+
<div>
|
|
944
|
+
<p className="text-sm font-medium text-foreground">John Doe</p>
|
|
945
|
+
<p className="text-xs text-foreground-muted">john@example.com</p>
|
|
946
|
+
</div>
|
|
947
|
+
</div>`,
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
id: 'badge',
|
|
951
|
+
name: 'Badge',
|
|
952
|
+
category: 'Data Display',
|
|
953
|
+
description: 'Small status or label badge',
|
|
954
|
+
fileName: 'badge',
|
|
955
|
+
code: `<span data-sonance-name="badge" className="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full bg-primary text-primary-foreground">
|
|
956
|
+
Badge
|
|
957
|
+
</span>`,
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
id: 'badge-outline',
|
|
961
|
+
name: 'Badge (Outline)',
|
|
962
|
+
category: 'Data Display',
|
|
963
|
+
description: 'Outline style badge',
|
|
964
|
+
fileName: 'badge',
|
|
965
|
+
code: `<span data-sonance-name="badge-outline" className="inline-flex items-center px-2.5 py-0.5 text-xs font-medium rounded-full border border-border text-foreground">
|
|
966
|
+
Outline
|
|
967
|
+
</span>`,
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
id: 'table',
|
|
971
|
+
name: 'Table',
|
|
972
|
+
category: 'Data Display',
|
|
973
|
+
description: 'Data table structure',
|
|
974
|
+
fileName: 'table',
|
|
975
|
+
code: `<table data-sonance-name="table" className="w-full text-sm">
|
|
976
|
+
<thead>
|
|
977
|
+
<tr className="border-b border-border">
|
|
978
|
+
<th className="text-left py-3 px-4 font-medium text-foreground">Name</th>
|
|
979
|
+
<th className="text-left py-3 px-4 font-medium text-foreground">Status</th>
|
|
980
|
+
<th className="text-right py-3 px-4 font-medium text-foreground">Amount</th>
|
|
981
|
+
</tr>
|
|
982
|
+
</thead>
|
|
983
|
+
<tbody>
|
|
984
|
+
<tr className="border-b border-border hover:bg-background-secondary">
|
|
985
|
+
<td className="py-3 px-4 text-foreground">Item One</td>
|
|
986
|
+
<td className="py-3 px-4 text-foreground-secondary">Active</td>
|
|
987
|
+
<td className="py-3 px-4 text-foreground text-right">$100.00</td>
|
|
988
|
+
</tr>
|
|
989
|
+
</tbody>
|
|
990
|
+
</table>`,
|
|
991
|
+
},
|
|
992
|
+
|
|
993
|
+
{
|
|
994
|
+
id: 'carousel',
|
|
995
|
+
name: 'Carousel',
|
|
996
|
+
category: 'Data Display',
|
|
997
|
+
description: 'Image/content slider',
|
|
998
|
+
fileName: 'carousel',
|
|
999
|
+
code: `<div data-sonance-name="carousel" className="relative w-full max-w-xs mx-auto">
|
|
1000
|
+
<div className="overflow-hidden rounded-md border border-border">
|
|
1001
|
+
<div className="flex">
|
|
1002
|
+
<div className="min-w-full h-48 bg-background-secondary flex items-center justify-center">Slide 1</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
</div>
|
|
1005
|
+
<button className="absolute left-2 top-1/2 -translate-y-1/2 h-8 w-8 rounded-full bg-background/80 hover:bg-background border border-border flex items-center justify-center">←</button>
|
|
1006
|
+
<button className="absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 rounded-full bg-background/80 hover:bg-background border border-border flex items-center justify-center">→</button>
|
|
1007
|
+
</div>`,
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
id: 'chart',
|
|
1011
|
+
name: 'Chart (Bar)',
|
|
1012
|
+
category: 'Data Display',
|
|
1013
|
+
description: 'Basic bar chart visualization',
|
|
1014
|
+
fileName: 'chart',
|
|
1015
|
+
code: `<div data-sonance-name="chart" className="h-[200px] w-full border border-border rounded-md p-4 flex items-end justify-between gap-2">
|
|
1016
|
+
<div className="w-8 bg-primary/20 hover:bg-primary/30 rounded-t-sm h-[40%]" />
|
|
1017
|
+
<div className="w-8 bg-primary/20 hover:bg-primary/30 rounded-t-sm h-[70%]" />
|
|
1018
|
+
<div className="w-8 bg-primary rounded-t-sm h-[100%]" />
|
|
1019
|
+
<div className="w-8 bg-primary/20 hover:bg-primary/30 rounded-t-sm h-[50%]" />
|
|
1020
|
+
<div className="w-8 bg-primary/20 hover:bg-primary/30 rounded-t-sm h-[30%]" />
|
|
1021
|
+
</div>`,
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
id: 'code',
|
|
1025
|
+
name: 'Code Block',
|
|
1026
|
+
category: 'Data Display',
|
|
1027
|
+
description: 'Inline or block code',
|
|
1028
|
+
fileName: 'code',
|
|
1029
|
+
code: `<pre data-sonance-name="code" className="rounded-lg border border-border bg-background-secondary p-4 overflow-x-auto">
|
|
1030
|
+
<code className="text-sm font-mono text-foreground">
|
|
1031
|
+
{JSON.stringify({ hello: 'world' }, null, 2)}
|
|
1032
|
+
</code>
|
|
1033
|
+
</pre>`,
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
id: 'kbd',
|
|
1037
|
+
name: 'Keyboard Input',
|
|
1038
|
+
category: 'Data Display',
|
|
1039
|
+
description: 'Keyboard shortcut indicator',
|
|
1040
|
+
fileName: 'kbd',
|
|
1041
|
+
code: `<kbd data-sonance-name="kbd" className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-background-secondary px-1.5 font-mono text-[10px] font-medium text-foreground-muted opacity-100">
|
|
1042
|
+
<span className="text-xs">⌘</span>K
|
|
1043
|
+
</kbd>`,
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
id: 'command',
|
|
1047
|
+
name: 'Command Menu',
|
|
1048
|
+
category: 'Data Display',
|
|
1049
|
+
description: 'Command palette interface',
|
|
1050
|
+
fileName: 'command',
|
|
1051
|
+
code: `<div data-sonance-name="command" className="rounded-lg border border-border bg-popover text-popover-foreground shadow-md w-[400px]">
|
|
1052
|
+
<div className="flex items-center border-b border-border px-3">
|
|
1053
|
+
<span className="mr-2 opacity-50">🔍</span>
|
|
1054
|
+
<input className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-foreground-muted disabled:cursor-not-allowed disabled:opacity-50" placeholder="Type a command or search..." />
|
|
1055
|
+
</div>
|
|
1056
|
+
<div className="max-h-[300px] overflow-y-auto overflow-x-hidden p-1">
|
|
1057
|
+
<div className="px-2 py-1.5 text-xs font-medium text-foreground-muted">Suggestions</div>
|
|
1058
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground">Calendar</div>
|
|
1059
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground">Search Emoji</div>
|
|
1060
|
+
<div className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground">Calculator</div>
|
|
1061
|
+
</div>
|
|
1062
|
+
</div>`,
|
|
1063
|
+
},
|
|
1064
|
+
|
|
1065
|
+
{
|
|
1066
|
+
id: 'user',
|
|
1067
|
+
name: 'User',
|
|
1068
|
+
category: 'Data Display',
|
|
1069
|
+
description: 'User profile with avatar',
|
|
1070
|
+
fileName: 'user',
|
|
1071
|
+
code: `<div data-sonance-name="user" className="flex items-center gap-2">
|
|
1072
|
+
<div className="relative h-10 w-10 overflow-hidden rounded-full bg-background-secondary">
|
|
1073
|
+
<div className="flex h-full w-full items-center justify-center bg-primary text-primary-foreground text-sm font-medium">U</div>
|
|
1074
|
+
</div>
|
|
1075
|
+
<div className="flex flex-col">
|
|
1076
|
+
<p className="text-sm font-medium text-foreground">Username</p>
|
|
1077
|
+
<p className="text-xs text-foreground-muted">user@example.com</p>
|
|
1078
|
+
</div>
|
|
1079
|
+
</div>`,
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
id: 'image',
|
|
1083
|
+
name: 'Image',
|
|
1084
|
+
category: 'Data Display',
|
|
1085
|
+
description: 'Responsive image',
|
|
1086
|
+
fileName: 'image',
|
|
1087
|
+
code: `<img
|
|
1088
|
+
data-sonance-name="image"
|
|
1089
|
+
src="/placeholder.jpg"
|
|
1090
|
+
alt="Description"
|
|
1091
|
+
className="h-auto w-full max-w-sm rounded-md border border-border shadow-sm"
|
|
1092
|
+
loading="lazy"
|
|
1093
|
+
/>`,
|
|
1094
|
+
},
|
|
1095
|
+
|
|
1096
|
+
// ============================================
|
|
1097
|
+
// FEEDBACK
|
|
1098
|
+
// ============================================
|
|
1099
|
+
{
|
|
1100
|
+
id: 'alert',
|
|
1101
|
+
name: 'Alert',
|
|
1102
|
+
category: 'Feedback',
|
|
1103
|
+
description: 'Information alert box',
|
|
1104
|
+
fileName: 'alert',
|
|
1105
|
+
code: `<div data-sonance-name="alert" className="bg-info-light border border-info/20 rounded-sm p-4">
|
|
1106
|
+
<p className="text-sm text-info font-medium">Information</p>
|
|
1107
|
+
<p className="text-sm text-foreground-secondary mt-1">This is an informational message.</p>
|
|
1108
|
+
</div>`,
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
id: 'alert-destructive',
|
|
1112
|
+
name: 'Alert (Destructive)',
|
|
1113
|
+
category: 'Feedback',
|
|
1114
|
+
description: 'Error/danger alert box',
|
|
1115
|
+
fileName: 'alert',
|
|
1116
|
+
code: `<div data-sonance-name="alert-destructive" className="bg-destructive/10 border border-destructive/20 rounded-sm p-4">
|
|
1117
|
+
<p className="text-sm text-destructive font-medium">Error</p>
|
|
1118
|
+
<p className="text-sm text-foreground-secondary mt-1">Something went wrong. Please try again.</p>
|
|
1119
|
+
</div>`,
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
id: 'progress',
|
|
1123
|
+
name: 'Progress Bar',
|
|
1124
|
+
category: 'Feedback',
|
|
1125
|
+
description: 'Progress indicator',
|
|
1126
|
+
fileName: 'progress',
|
|
1127
|
+
code: `<div data-sonance-name="progress" className="space-y-2">
|
|
1128
|
+
<div className="flex justify-between text-sm">
|
|
1129
|
+
<span className="text-foreground">Progress</span>
|
|
1130
|
+
<span className="text-foreground-muted">60%</span>
|
|
1131
|
+
</div>
|
|
1132
|
+
<div className="h-2 bg-background-secondary rounded-full overflow-hidden">
|
|
1133
|
+
<div className="h-full bg-primary rounded-full" style={{ width: '60%' }} />
|
|
1134
|
+
</div>
|
|
1135
|
+
</div>`,
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
id: 'skeleton',
|
|
1139
|
+
name: 'Skeleton',
|
|
1140
|
+
category: 'Feedback',
|
|
1141
|
+
description: 'Loading placeholder',
|
|
1142
|
+
fileName: 'skeleton',
|
|
1143
|
+
code: `<div data-sonance-name="skeleton" className="space-y-3 animate-pulse">
|
|
1144
|
+
<div className="h-4 bg-background-secondary rounded w-3/4" />
|
|
1145
|
+
<div className="h-4 bg-background-secondary rounded w-1/2" />
|
|
1146
|
+
<div className="h-4 bg-background-secondary rounded w-5/6" />
|
|
1147
|
+
</div>`,
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
id: 'spinner',
|
|
1151
|
+
name: 'Spinner',
|
|
1152
|
+
category: 'Feedback',
|
|
1153
|
+
description: 'Loading spinner',
|
|
1154
|
+
fileName: 'spinner',
|
|
1155
|
+
code: `<div data-sonance-name="spinner" className="flex items-center justify-center">
|
|
1156
|
+
<div className="h-6 w-6 border-2 border-primary border-t-transparent rounded-full animate-spin" />
|
|
1157
|
+
</div>`,
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
id: 'tooltip',
|
|
1161
|
+
name: 'Tooltip',
|
|
1162
|
+
category: 'Feedback',
|
|
1163
|
+
description: 'Tooltip hint structure',
|
|
1164
|
+
fileName: 'tooltip',
|
|
1165
|
+
code: `<div data-sonance-name="tooltip" className="relative inline-block group">
|
|
1166
|
+
<button className="text-foreground underline">Hover me</button>
|
|
1167
|
+
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-3 py-1.5 bg-foreground text-background text-xs rounded-sm opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
|
|
1168
|
+
Tooltip text
|
|
1169
|
+
</div>
|
|
1170
|
+
</div>`,
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
id: 'dialog',
|
|
1174
|
+
name: 'Dialog/Modal',
|
|
1175
|
+
category: 'Feedback',
|
|
1176
|
+
description: 'Modal dialog structure',
|
|
1177
|
+
fileName: 'dialog',
|
|
1178
|
+
code: `<div data-sonance-name="dialog" className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
|
1179
|
+
<div className="bg-card border border-card-border rounded-sm p-6 w-full max-w-md shadow-xl">
|
|
1180
|
+
<h2 className="text-lg font-medium text-foreground">Dialog Title</h2>
|
|
1181
|
+
<p className="text-sm text-foreground-secondary mt-2">Dialog content goes here.</p>
|
|
1182
|
+
<div className="flex justify-end gap-2 mt-6">
|
|
1183
|
+
<button className="px-4 py-2 text-sm border border-border rounded-sm">Cancel</button>
|
|
1184
|
+
<button className="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-sm">Confirm</button>
|
|
1185
|
+
</div>
|
|
1186
|
+
</div>
|
|
1187
|
+
</div>`,
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
id: 'toast',
|
|
1191
|
+
name: 'Toast',
|
|
1192
|
+
category: 'Feedback',
|
|
1193
|
+
description: 'Toast notification',
|
|
1194
|
+
fileName: 'toast',
|
|
1195
|
+
code: `<div data-sonance-name="toast" className="fixed bottom-4 right-4 bg-card border border-card-border rounded-sm p-4 shadow-lg max-w-sm">
|
|
1196
|
+
<div className="flex items-start gap-3">
|
|
1197
|
+
<div className="flex-1">
|
|
1198
|
+
<p className="text-sm font-medium text-foreground">Success!</p>
|
|
1199
|
+
<p className="text-sm text-foreground-secondary mt-1">Your changes have been saved.</p>
|
|
1200
|
+
</div>
|
|
1201
|
+
<button className="text-foreground-muted hover:text-foreground">×</button>
|
|
1202
|
+
</div>
|
|
1203
|
+
</div>`,
|
|
1204
|
+
},
|
|
1205
|
+
|
|
1206
|
+
// ============================================
|
|
1207
|
+
// TYPOGRAPHY (No component files - these are base elements)
|
|
1208
|
+
// ============================================
|
|
1209
|
+
{
|
|
1210
|
+
id: 'section-header',
|
|
1211
|
+
name: 'Section Header',
|
|
1212
|
+
category: 'Typography',
|
|
1213
|
+
description: 'Standard section header with category label',
|
|
1214
|
+
code: `<div data-sonance-name="section-header" className="mb-8">
|
|
1215
|
+
<p className="text-xs font-medium uppercase tracking-widest text-foreground-muted mb-2">
|
|
1216
|
+
Category
|
|
1217
|
+
</p>
|
|
1218
|
+
<h2 className="text-4xl font-light text-foreground tracking-tight">
|
|
1219
|
+
Headline
|
|
1220
|
+
</h2>
|
|
1221
|
+
</div>`,
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
id: 'heading-display',
|
|
1225
|
+
name: 'Display Heading',
|
|
1226
|
+
category: 'Typography',
|
|
1227
|
+
description: 'Large display heading',
|
|
1228
|
+
code: `<h1 data-sonance-name="heading-display" className="text-5xl font-light text-foreground tracking-tight leading-tight">
|
|
1229
|
+
Display Heading
|
|
1230
|
+
</h1>`,
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
id: 'body-text',
|
|
1234
|
+
name: 'Body Text',
|
|
1235
|
+
category: 'Typography',
|
|
1236
|
+
description: 'Standard paragraph text',
|
|
1237
|
+
code: `<p data-sonance-name="body-text" className="text-base text-foreground leading-relaxed max-w-prose">
|
|
1238
|
+
This is body text. It uses the default font weight and is optimized for readability with proper line height and max width constraints.
|
|
1239
|
+
</p>`,
|
|
1240
|
+
},
|
|
1241
|
+
{
|
|
1242
|
+
id: 'link',
|
|
1243
|
+
name: 'Link',
|
|
1244
|
+
category: 'Typography',
|
|
1245
|
+
description: 'Inline text link',
|
|
1246
|
+
code: `<a data-sonance-name="link" href="#" className="text-primary hover:text-primary-hover underline underline-offset-2 transition-colors">
|
|
1247
|
+
Link text
|
|
1248
|
+
</a>`,
|
|
1249
|
+
},
|
|
1250
|
+
];
|
|
1251
|
+
|
|
1252
|
+
// ---- Preview Components (for component browser) ----
|
|
1253
|
+
|
|
1254
|
+
export const previewComponents = [
|
|
1255
|
+
{ id: 'button', name: 'Button', category: 'Forms' },
|
|
1256
|
+
{ id: 'input', name: 'Input', category: 'Forms' },
|
|
1257
|
+
{ id: 'checkbox', name: 'Checkbox', category: 'Forms' },
|
|
1258
|
+
{ id: 'switch', name: 'Switch', category: 'Forms' },
|
|
1259
|
+
{ id: 'select', name: 'Select', category: 'Forms' },
|
|
1260
|
+
{ id: 'card', name: 'Card', category: 'Data Display' },
|
|
1261
|
+
{ id: 'badge', name: 'Badge', category: 'Feedback' },
|
|
1262
|
+
{ id: 'alert', name: 'Alert', category: 'Feedback' },
|
|
1263
|
+
{ id: 'avatar', name: 'Avatar', category: 'Data Display' },
|
|
1264
|
+
{ id: 'tabs', name: 'Tabs', category: 'Navigation' },
|
|
1265
|
+
];
|