radtools 0.1.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 +108 -0
- package/bin/radtools.js +5 -0
- package/dist/cli/index.js +427 -0
- package/package.json +55 -0
- package/templates/api-routes/assets/optimize/route.ts +94 -0
- package/templates/api-routes/assets/route.ts +159 -0
- package/templates/api-routes/components/create-folder/route.ts +55 -0
- package/templates/api-routes/components/route.ts +156 -0
- package/templates/api-routes/fonts/route.ts +96 -0
- package/templates/api-routes/fonts/upload/route.ts +79 -0
- package/templates/api-routes/read-css/route.ts +29 -0
- package/templates/api-routes/write-css/route.ts +423 -0
- package/templates/components/Rad_os/AppWindow.tsx +423 -0
- package/templates/components/Rad_os/MobileAppModal.tsx +76 -0
- package/templates/components/Rad_os/WindowTitleBar.tsx +290 -0
- package/templates/components/icons/Icon.tsx +224 -0
- package/templates/components/icons/README.md +85 -0
- package/templates/components/icons/index.ts +20 -0
- package/templates/components/icons.tsx +164 -0
- package/templates/components/ui/Accordion.tsx +268 -0
- package/templates/components/ui/Alert.tsx +111 -0
- package/templates/components/ui/Badge.tsx +87 -0
- package/templates/components/ui/Breadcrumbs.tsx +88 -0
- package/templates/components/ui/Button.tsx +249 -0
- package/templates/components/ui/Card.tsx +137 -0
- package/templates/components/ui/Checkbox.tsx +137 -0
- package/templates/components/ui/ContextMenu.tsx +220 -0
- package/templates/components/ui/Dialog.tsx +264 -0
- package/templates/components/ui/Divider.tsx +70 -0
- package/templates/components/ui/DropdownMenu.tsx +301 -0
- package/templates/components/ui/HelpPanel.tsx +119 -0
- package/templates/components/ui/Input.tsx +176 -0
- package/templates/components/ui/Popover.tsx +211 -0
- package/templates/components/ui/Progress.tsx +158 -0
- package/templates/components/ui/Select.tsx +134 -0
- package/templates/components/ui/Sheet.tsx +316 -0
- package/templates/components/ui/Slider.tsx +223 -0
- package/templates/components/ui/Switch.tsx +155 -0
- package/templates/components/ui/Tabs.tsx +253 -0
- package/templates/components/ui/Toast.tsx +192 -0
- package/templates/components/ui/Tooltip.tsx +129 -0
- package/templates/components/ui/hooks/useModalBehavior.ts +66 -0
- package/templates/components/ui/index.ts +84 -0
- package/templates/devtools/DevToolsPanel.tsx +261 -0
- package/templates/devtools/DevToolsProvider.tsx +43 -0
- package/templates/devtools/components/BreakpointIndicator.tsx +49 -0
- package/templates/devtools/components/ColorPicker.tsx +33 -0
- package/templates/devtools/components/ComponentsSecondaryNav.tsx +44 -0
- package/templates/devtools/components/ContextualFooter.tsx +56 -0
- package/templates/devtools/components/DraggablePanel.tsx +43 -0
- package/templates/devtools/components/PrimaryNavigationFooter.tsx +254 -0
- package/templates/devtools/components/SearchableColorDropdown.tsx +253 -0
- package/templates/devtools/components/SecondaryNavigation.tsx +36 -0
- package/templates/devtools/components/TokenDropdown.tsx +47 -0
- package/templates/devtools/components/TypographyFooter.tsx +145 -0
- package/templates/devtools/hooks/useMockState.ts +16 -0
- package/templates/devtools/index.ts +17 -0
- package/templates/devtools/lib/componentScanner.ts +78 -0
- package/templates/devtools/lib/cssParser.ts +465 -0
- package/templates/devtools/lib/searchIndexes.ts +45 -0
- package/templates/devtools/lib/selectorGenerator.ts +86 -0
- package/templates/devtools/store/index.ts +66 -0
- package/templates/devtools/store/slices/assetsSlice.ts +106 -0
- package/templates/devtools/store/slices/componentsSlice.ts +59 -0
- package/templates/devtools/store/slices/mockStatesSlice.ts +77 -0
- package/templates/devtools/store/slices/panelSlice.ts +17 -0
- package/templates/devtools/store/slices/typographySlice.ts +538 -0
- package/templates/devtools/store/slices/variablesSlice.ts +167 -0
- package/templates/devtools/tabs/AssetsTab/AssetGrid.tsx +76 -0
- package/templates/devtools/tabs/AssetsTab/FolderTree.tsx +53 -0
- package/templates/devtools/tabs/AssetsTab/UploadDropzone.tsx +76 -0
- package/templates/devtools/tabs/AssetsTab/index.tsx +182 -0
- package/templates/devtools/tabs/ComponentsTab/AddTabButton.tsx +63 -0
- package/templates/devtools/tabs/ComponentsTab/ComponentList.tsx +153 -0
- package/templates/devtools/tabs/ComponentsTab/DesignSystemTab.tsx +1515 -0
- package/templates/devtools/tabs/ComponentsTab/DynamicFolderTab.tsx +113 -0
- package/templates/devtools/tabs/ComponentsTab/PropDisplay.tsx +55 -0
- package/templates/devtools/tabs/ComponentsTab/index.tsx +167 -0
- package/templates/devtools/tabs/ComponentsTab/previews/.gitkeep +4 -0
- package/templates/devtools/tabs/ComponentsTab/previews/Rad_os.tsx +262 -0
- package/templates/devtools/tabs/ComponentsTab/tabConfig.ts +53 -0
- package/templates/devtools/tabs/MockStatesTab/index.tsx +29 -0
- package/templates/devtools/tabs/TypographyTab/FontManager.tsx +421 -0
- package/templates/devtools/tabs/TypographyTab/TypographyStylesDisplay.tsx +290 -0
- package/templates/devtools/tabs/TypographyTab/index.tsx +98 -0
- package/templates/devtools/tabs/VariablesTab/BaseColorEditor.tsx +267 -0
- package/templates/devtools/tabs/VariablesTab/BorderRadiusEditor.tsx +37 -0
- package/templates/devtools/tabs/VariablesTab/ColorModeSelector.tsx +235 -0
- package/templates/devtools/tabs/VariablesTab/index.tsx +100 -0
- package/templates/devtools/types/index.ts +99 -0
- package/templates/globals.css +574 -0
- package/templates/hooks/index.ts +1 -0
- package/templates/hooks/useWindowManager.ts +212 -0
- package/templates/public/assets/icons/avatar.svg +18 -0
- package/templates/public/assets/icons/checkmark-filled.svg +14 -0
- package/templates/public/assets/icons/checkmark.svg +14 -0
- package/templates/public/assets/icons/chevron-down.svg +14 -0
- package/templates/public/assets/icons/close.svg +14 -0
- package/templates/public/assets/icons/copy.svg +14 -0
- package/templates/public/assets/icons/download.svg +14 -0
- package/templates/public/assets/icons/expand.svg +31 -0
- package/templates/public/assets/icons/file-blank.svg +17 -0
- package/templates/public/assets/icons/file-image.svg +19 -0
- package/templates/public/assets/icons/file-written.svg +17 -0
- package/templates/public/assets/icons/folder-closed.svg +17 -0
- package/templates/public/assets/icons/folder-open.svg +17 -0
- package/templates/public/assets/icons/hamburger.svg +18 -0
- package/templates/public/assets/icons/home-outline.svg +28 -0
- package/templates/public/assets/icons/home.svg +30 -0
- package/templates/public/assets/icons/hourglass.svg +25 -0
- package/templates/public/assets/icons/information-circle.svg +14 -0
- package/templates/public/assets/icons/information.svg +17 -0
- package/templates/public/assets/icons/lightning.svg +14 -0
- package/templates/public/assets/icons/locked.svg +17 -0
- package/templates/public/assets/icons/not-allowed.svg +14 -0
- package/templates/public/assets/icons/plus.svg +5 -0
- package/templates/public/assets/icons/power-thin.svg +17 -0
- package/templates/public/assets/icons/power.svg +17 -0
- package/templates/public/assets/icons/question-block.svg +14 -0
- package/templates/public/assets/icons/question.svg +17 -0
- package/templates/public/assets/icons/refresh-block.svg +14 -0
- package/templates/public/assets/icons/refresh.svg +17 -0
- package/templates/public/assets/icons/save.svg +14 -0
- package/templates/public/assets/icons/search.svg +25 -0
- package/templates/public/assets/icons/settings.svg +14 -0
- package/templates/public/assets/icons/trash-full.svg +21 -0
- package/templates/public/assets/icons/trash-open.svg +23 -0
- package/templates/public/assets/icons/trash.svg +18 -0
- package/templates/public/assets/icons/unlocked.svg +17 -0
- package/templates/public/assets/icons/waring-triangle-filled.svg +17 -0
- package/templates/public/assets/icons/warning-triangle-filled-2.svg +30 -0
- package/templates/public/assets/icons/warning-triangle-lines.svg +29 -0
- package/templates/public/assets/icons/wrench.svg +17 -0
|
@@ -0,0 +1,1515 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Card,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardBody,
|
|
9
|
+
CardFooter,
|
|
10
|
+
Tabs,
|
|
11
|
+
TabList,
|
|
12
|
+
TabTrigger,
|
|
13
|
+
TabContent,
|
|
14
|
+
Input,
|
|
15
|
+
TextArea,
|
|
16
|
+
Label,
|
|
17
|
+
Select,
|
|
18
|
+
Checkbox,
|
|
19
|
+
Radio,
|
|
20
|
+
Badge,
|
|
21
|
+
Progress,
|
|
22
|
+
Spinner,
|
|
23
|
+
Tooltip,
|
|
24
|
+
Divider,
|
|
25
|
+
ContextMenu,
|
|
26
|
+
ContextMenuContent,
|
|
27
|
+
ContextMenuItem,
|
|
28
|
+
ContextMenuSeparator,
|
|
29
|
+
Alert,
|
|
30
|
+
Breadcrumbs,
|
|
31
|
+
Switch,
|
|
32
|
+
Slider,
|
|
33
|
+
ToastProvider,
|
|
34
|
+
useToast,
|
|
35
|
+
HelpPanel,
|
|
36
|
+
} from '@/components/ui';
|
|
37
|
+
import {
|
|
38
|
+
Dialog,
|
|
39
|
+
DialogTrigger,
|
|
40
|
+
DialogContent,
|
|
41
|
+
DialogHeader,
|
|
42
|
+
DialogTitle,
|
|
43
|
+
DialogDescription,
|
|
44
|
+
DialogBody,
|
|
45
|
+
DialogFooter,
|
|
46
|
+
DialogClose,
|
|
47
|
+
} from '@/components/ui/Dialog';
|
|
48
|
+
import {
|
|
49
|
+
DropdownMenu,
|
|
50
|
+
DropdownMenuTrigger,
|
|
51
|
+
DropdownMenuContent,
|
|
52
|
+
DropdownMenuItem,
|
|
53
|
+
DropdownMenuSeparator,
|
|
54
|
+
DropdownMenuLabel,
|
|
55
|
+
} from '@/components/ui/DropdownMenu';
|
|
56
|
+
import {
|
|
57
|
+
Popover,
|
|
58
|
+
PopoverTrigger,
|
|
59
|
+
PopoverContent,
|
|
60
|
+
} from '@/components/ui/Popover';
|
|
61
|
+
import {
|
|
62
|
+
Sheet,
|
|
63
|
+
SheetTrigger,
|
|
64
|
+
SheetContent,
|
|
65
|
+
SheetHeader,
|
|
66
|
+
SheetTitle,
|
|
67
|
+
SheetDescription,
|
|
68
|
+
SheetBody,
|
|
69
|
+
SheetFooter,
|
|
70
|
+
SheetClose,
|
|
71
|
+
} from '@/components/ui/Sheet';
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Section Component
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
function Section({
|
|
78
|
+
title,
|
|
79
|
+
children,
|
|
80
|
+
variant = 'h3',
|
|
81
|
+
subsectionId,
|
|
82
|
+
className,
|
|
83
|
+
'data-edit-scope': editScope,
|
|
84
|
+
'data-component': component,
|
|
85
|
+
...rest
|
|
86
|
+
}: {
|
|
87
|
+
title: string;
|
|
88
|
+
children: React.ReactNode;
|
|
89
|
+
variant?: 'h3' | 'h4';
|
|
90
|
+
subsectionId?: string;
|
|
91
|
+
className?: string;
|
|
92
|
+
'data-edit-scope'?: string;
|
|
93
|
+
'data-component'?: string;
|
|
94
|
+
}) {
|
|
95
|
+
const HeadingTag = variant === 'h4' ? 'h4' : 'h3';
|
|
96
|
+
const hasMarginOverride = className?.includes('mb-');
|
|
97
|
+
const isSubsection = variant === 'h4';
|
|
98
|
+
const subsectionClasses = isSubsection ? 'p-4 border border-black bg-[var(--color-cream)]' : '';
|
|
99
|
+
const baseClasses = `${hasMarginOverride ? '' : 'mb-4'} ${subsectionClasses} rounded flex flex-col gap-4`.trim();
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
className={`${baseClasses} ${className || ''}`}
|
|
103
|
+
data-subsection-id={subsectionId}
|
|
104
|
+
data-edit-scope={editScope}
|
|
105
|
+
data-component={component}
|
|
106
|
+
{...rest}
|
|
107
|
+
>
|
|
108
|
+
<HeadingTag>
|
|
109
|
+
{title}
|
|
110
|
+
</HeadingTag>
|
|
111
|
+
<div className="flex flex-col gap-4">
|
|
112
|
+
{children}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function PropsDisplay({ props }: { props: string }) {
|
|
119
|
+
return (
|
|
120
|
+
<code className="bg-black/5 px-2 py-1 rounded-sm block mt-2">
|
|
121
|
+
{props}
|
|
122
|
+
</code>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function Row({ children, props }: {
|
|
127
|
+
children: React.ReactNode;
|
|
128
|
+
props?: string;
|
|
129
|
+
}) {
|
|
130
|
+
return (
|
|
131
|
+
<div>
|
|
132
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
133
|
+
{children}
|
|
134
|
+
</div>
|
|
135
|
+
{props && <PropsDisplay props={props} />}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// Accordion Content Components
|
|
142
|
+
// ============================================================================
|
|
143
|
+
|
|
144
|
+
// Loading button demo component
|
|
145
|
+
function LoadingButtonDemo() {
|
|
146
|
+
const [loading1, setLoading1] = useState(false);
|
|
147
|
+
const [loading2, setLoading2] = useState(false);
|
|
148
|
+
const [loading3, setLoading3] = useState(false);
|
|
149
|
+
|
|
150
|
+
const handleClick1 = () => {
|
|
151
|
+
setLoading1(true);
|
|
152
|
+
setTimeout(() => setLoading1(false), 2000);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleClick2 = () => {
|
|
156
|
+
setLoading2(true);
|
|
157
|
+
setTimeout(() => setLoading2(false), 2000);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const handleClick3 = () => {
|
|
161
|
+
setLoading3(true);
|
|
162
|
+
setTimeout(() => setLoading3(false), 2000);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<>
|
|
167
|
+
<Button
|
|
168
|
+
variant="primary"
|
|
169
|
+
size="md"
|
|
170
|
+
iconOnly={true}
|
|
171
|
+
iconName="refresh"
|
|
172
|
+
loading={loading1}
|
|
173
|
+
onClick={handleClick1}
|
|
174
|
+
data-edit-scope="component-definition"
|
|
175
|
+
data-component="Button"
|
|
176
|
+
>
|
|
177
|
+
{''}
|
|
178
|
+
</Button>
|
|
179
|
+
<Button
|
|
180
|
+
variant="secondary"
|
|
181
|
+
size="md"
|
|
182
|
+
iconOnly={true}
|
|
183
|
+
iconName="download"
|
|
184
|
+
loading={loading2}
|
|
185
|
+
onClick={handleClick2}
|
|
186
|
+
data-edit-scope="component-definition"
|
|
187
|
+
data-component="Button"
|
|
188
|
+
data-edit-variant="secondary"
|
|
189
|
+
>
|
|
190
|
+
{''}
|
|
191
|
+
</Button>
|
|
192
|
+
<Button
|
|
193
|
+
variant="primary"
|
|
194
|
+
size="md"
|
|
195
|
+
iconName="copy"
|
|
196
|
+
loading={loading3}
|
|
197
|
+
onClick={handleClick3}
|
|
198
|
+
data-edit-scope="component-definition"
|
|
199
|
+
data-component="Button"
|
|
200
|
+
>
|
|
201
|
+
Copy
|
|
202
|
+
</Button>
|
|
203
|
+
</>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function ButtonsContent() {
|
|
208
|
+
return (
|
|
209
|
+
<div className="space-y-6">
|
|
210
|
+
<Section title="Button Variants" variant="h4" subsectionId="button-variants" className="mb-4">
|
|
211
|
+
<Row props='variant="primary" | "secondary" | "outline" | "ghost"'>
|
|
212
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button">Primary</Button>
|
|
213
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button">Disabled</Button>
|
|
214
|
+
</Row>
|
|
215
|
+
<Row props='variant="secondary"'>
|
|
216
|
+
<Button variant="secondary" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">Secondary</Button>
|
|
217
|
+
<Button variant="secondary" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">Disabled</Button>
|
|
218
|
+
</Row>
|
|
219
|
+
<Row props='variant="outline"'>
|
|
220
|
+
<Button variant="outline" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="outline">Outline</Button>
|
|
221
|
+
<Button variant="outline" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="outline">Disabled</Button>
|
|
222
|
+
</Row>
|
|
223
|
+
<Row props='variant="ghost"'>
|
|
224
|
+
<Button variant="ghost" size="md" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="ghost">Ghost</Button>
|
|
225
|
+
<Button variant="ghost" size="md" fullWidth={false} iconOnly={false} disabled data-edit-scope="component-definition" data-component="Button" data-edit-variant="ghost">Disabled</Button>
|
|
226
|
+
</Row>
|
|
227
|
+
</Section>
|
|
228
|
+
|
|
229
|
+
<Section title="Button Sizes" variant="h4" subsectionId="button-sizes">
|
|
230
|
+
<Row props='size="sm" | "md" | "lg"'>
|
|
231
|
+
<Button variant="primary" size="sm" fullWidth={false} iconOnly={false}>Small</Button>
|
|
232
|
+
</Row>
|
|
233
|
+
<Row props='size="md"'>
|
|
234
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Medium</Button>
|
|
235
|
+
</Row>
|
|
236
|
+
<Row props='size="lg"'>
|
|
237
|
+
<Button variant="primary" size="lg" fullWidth={false} iconOnly={false}>Large</Button>
|
|
238
|
+
</Row>
|
|
239
|
+
</Section>
|
|
240
|
+
|
|
241
|
+
<Section title="Button with Icon" variant="h4" subsectionId="button-with-icon">
|
|
242
|
+
<Row props='iconName="..."'>
|
|
243
|
+
<Button variant="primary" size="md" iconName="copy" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button">
|
|
244
|
+
Download
|
|
245
|
+
</Button>
|
|
246
|
+
<Button variant="secondary" size="md" iconName="copy" fullWidth={false} iconOnly={false} data-edit-scope="component-definition" data-component="Button" data-edit-variant="secondary">
|
|
247
|
+
Copy
|
|
248
|
+
</Button>
|
|
249
|
+
</Row>
|
|
250
|
+
<Row props='iconOnly={true} iconName="..."'>
|
|
251
|
+
<Button variant="primary" size="md" iconOnly={true} iconName="close" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
|
|
252
|
+
<Button variant="primary" size="md" iconOnly={true} iconName="copy" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
|
|
253
|
+
<Button variant="primary" size="lg" iconOnly={true} iconName="copy" fullWidth={false} data-edit-scope="component-definition" data-component="Button">{''}</Button>
|
|
254
|
+
</Row>
|
|
255
|
+
<Row props='loading={boolean} (only applies to buttons with icons)'>
|
|
256
|
+
<LoadingButtonDemo />
|
|
257
|
+
</Row>
|
|
258
|
+
<Row props='fullWidth={true}'>
|
|
259
|
+
<div className="w-64">
|
|
260
|
+
<Button variant="primary" size="md" fullWidth={true} iconOnly={false} data-edit-scope="component-definition" data-component="Button">Full Width Button</Button>
|
|
261
|
+
</div>
|
|
262
|
+
</Row>
|
|
263
|
+
</Section>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function CardsContent() {
|
|
269
|
+
return (
|
|
270
|
+
<div className="space-y-6">
|
|
271
|
+
<Section title="Card Variants" variant="h4" subsectionId="card-variants">
|
|
272
|
+
<Row props='variant="default" | "dark" | "raised"'>
|
|
273
|
+
<div className="grid grid-cols-3 gap-4 w-full">
|
|
274
|
+
<Card variant="default" noPadding={false} data-edit-scope="component-definition" data-component="Card">
|
|
275
|
+
<p className="font-joystix text-xs mb-2">Default Card</p>
|
|
276
|
+
<p>
|
|
277
|
+
Cream background with black border
|
|
278
|
+
</p>
|
|
279
|
+
</Card>
|
|
280
|
+
<Card variant="dark" noPadding={false} data-edit-scope="component-definition" data-component="Card" data-edit-variant="dark">
|
|
281
|
+
<p className="mb-2">Dark Card</p>
|
|
282
|
+
<p>
|
|
283
|
+
Black background with cream text
|
|
284
|
+
</p>
|
|
285
|
+
</Card>
|
|
286
|
+
<Card variant="raised" noPadding={false} data-edit-scope="component-definition" data-component="Card" data-edit-variant="raised">
|
|
287
|
+
<p className="mb-2">Raised Card</p>
|
|
288
|
+
<p>
|
|
289
|
+
Pixel shadow effect
|
|
290
|
+
</p>
|
|
291
|
+
</Card>
|
|
292
|
+
</div>
|
|
293
|
+
</Row>
|
|
294
|
+
</Section>
|
|
295
|
+
|
|
296
|
+
<Section title="Card with Header/Footer" variant="h4" subsectionId="card-with-header-footer">
|
|
297
|
+
<Row props='noPadding={true} className="max-w-md"'>
|
|
298
|
+
<Card variant="default" noPadding={true} className="max-w-md" data-edit-scope="component-definition" data-component="Card">
|
|
299
|
+
<CardHeader>
|
|
300
|
+
<h4>Card Header</h4>
|
|
301
|
+
</CardHeader>
|
|
302
|
+
<CardBody>
|
|
303
|
+
<p>
|
|
304
|
+
This is the card body content. It can contain any elements.
|
|
305
|
+
</p>
|
|
306
|
+
</CardBody>
|
|
307
|
+
<CardFooter className="flex justify-end gap-2">
|
|
308
|
+
<Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>Cancel</Button>
|
|
309
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Confirm</Button>
|
|
310
|
+
</CardFooter>
|
|
311
|
+
</Card>
|
|
312
|
+
</Row>
|
|
313
|
+
</Section>
|
|
314
|
+
</div>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function FormsContent() {
|
|
319
|
+
const [selectValue, setSelectValue] = useState('');
|
|
320
|
+
const [checkboxChecked, setCheckboxChecked] = useState(false);
|
|
321
|
+
const [radioValue, setRadioValue] = useState('option1');
|
|
322
|
+
const [switchChecked, setSwitchChecked] = useState(false);
|
|
323
|
+
const [sliderValue, setSliderValue] = useState(50);
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div className="space-y-6">
|
|
327
|
+
<Section title="Text Inputs" variant="h4" subsectionId="text-inputs">
|
|
328
|
+
<Row props='size="md" error={false} fullWidth={true}'>
|
|
329
|
+
<div className="max-w-md w-full">
|
|
330
|
+
<Label htmlFor="input-default">Default Input</Label>
|
|
331
|
+
<Input id="input-default" size="md" error={false} fullWidth={true} placeholder="Enter text..." data-edit-scope="component-definition" data-component="Input" />
|
|
332
|
+
</div>
|
|
333
|
+
</Row>
|
|
334
|
+
<Row props='error={true} fullWidth={true}'>
|
|
335
|
+
<div className="max-w-md w-full">
|
|
336
|
+
<Label htmlFor="input-error" required>Error State</Label>
|
|
337
|
+
<Input id="input-error" size="md" error={true} fullWidth={true} placeholder="Invalid input" data-edit-scope="component-definition" data-component="Input" />
|
|
338
|
+
</div>
|
|
339
|
+
</Row>
|
|
340
|
+
<Row props='disabled fullWidth={true}'>
|
|
341
|
+
<div className="max-w-md w-full">
|
|
342
|
+
<Label htmlFor="input-disabled">Disabled</Label>
|
|
343
|
+
<Input id="input-disabled" size="md" error={false} fullWidth={true} disabled placeholder="Disabled" data-edit-scope="component-definition" data-component="Input" />
|
|
344
|
+
</div>
|
|
345
|
+
</Row>
|
|
346
|
+
</Section>
|
|
347
|
+
|
|
348
|
+
<Section title="Input Sizes" variant="h4" subsectionId="input-sizes">
|
|
349
|
+
<Row props='size="sm" | "md" | "lg"'>
|
|
350
|
+
<div className="max-w-md w-full">
|
|
351
|
+
<Label htmlFor="input-sm">Small</Label>
|
|
352
|
+
<Input id="input-sm" size="sm" error={false} fullWidth={true} placeholder="Small" data-edit-scope="component-definition" data-component="Input" />
|
|
353
|
+
</div>
|
|
354
|
+
</Row>
|
|
355
|
+
<Row props='size="md"'>
|
|
356
|
+
<div className="max-w-md w-full">
|
|
357
|
+
<Label htmlFor="input-md">Medium</Label>
|
|
358
|
+
<Input id="input-md" size="md" error={false} fullWidth={true} placeholder="Medium" data-edit-scope="component-definition" data-component="Input" />
|
|
359
|
+
</div>
|
|
360
|
+
</Row>
|
|
361
|
+
<Row props='size="lg"'>
|
|
362
|
+
<div className="max-w-md w-full">
|
|
363
|
+
<Label htmlFor="input-lg">Large</Label>
|
|
364
|
+
<Input id="input-lg" size="lg" error={false} fullWidth={true} placeholder="Large" data-edit-scope="component-definition" data-component="Input" />
|
|
365
|
+
</div>
|
|
366
|
+
</Row>
|
|
367
|
+
</Section>
|
|
368
|
+
|
|
369
|
+
<Section title="TextArea" variant="h4" subsectionId="textarea">
|
|
370
|
+
<Row props='error={false} fullWidth={true} rows={4}'>
|
|
371
|
+
<div className="max-w-md w-full">
|
|
372
|
+
<Label htmlFor="textarea">Description</Label>
|
|
373
|
+
<TextArea id="textarea" error={false} fullWidth={true} rows={4} placeholder="Enter description..." data-edit-scope="component-definition" data-component="TextArea" />
|
|
374
|
+
</div>
|
|
375
|
+
</Row>
|
|
376
|
+
</Section>
|
|
377
|
+
|
|
378
|
+
<Section title="Select" variant="h4" subsectionId="select">
|
|
379
|
+
<Row props='options={[...]} value={string} onChange={fn} placeholder="..." fullWidth={true}'>
|
|
380
|
+
<div className="max-w-xs w-full">
|
|
381
|
+
<Label htmlFor="select">Choose an option</Label>
|
|
382
|
+
<Select
|
|
383
|
+
options={[
|
|
384
|
+
{ value: 'option1', label: 'Option One' },
|
|
385
|
+
{ value: 'option2', label: 'Option Two' },
|
|
386
|
+
{ value: 'option3', label: 'Option Three' },
|
|
387
|
+
{ value: 'disabled', label: 'Disabled Option', disabled: true },
|
|
388
|
+
]}
|
|
389
|
+
value={selectValue}
|
|
390
|
+
onChange={setSelectValue}
|
|
391
|
+
placeholder="Select..."
|
|
392
|
+
fullWidth={true}
|
|
393
|
+
data-edit-scope="component-definition"
|
|
394
|
+
data-component="Select"
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
397
|
+
</Row>
|
|
398
|
+
</Section>
|
|
399
|
+
|
|
400
|
+
<Section title="Checkbox & Radio" variant="h4" subsectionId="checkbox-radio">
|
|
401
|
+
<Row props='label="..." checked={boolean} onChange={fn} disabled={boolean}'>
|
|
402
|
+
<Checkbox
|
|
403
|
+
label="Check me"
|
|
404
|
+
checked={checkboxChecked}
|
|
405
|
+
onChange={(e) => setCheckboxChecked(e.target.checked)}
|
|
406
|
+
disabled={false}
|
|
407
|
+
data-edit-scope="component-definition"
|
|
408
|
+
data-component="Checkbox"
|
|
409
|
+
/>
|
|
410
|
+
<Checkbox label="Disabled" checked={false} onChange={() => {}} disabled={true} data-edit-scope="component-definition" data-component="Checkbox" />
|
|
411
|
+
<Checkbox label="Checked & Disabled" checked={true} onChange={() => {}} disabled={true} data-edit-scope="component-definition" data-component="Checkbox" />
|
|
412
|
+
</Row>
|
|
413
|
+
<Row props='name="..." value="..." label="..." checked={boolean} onChange={fn}'>
|
|
414
|
+
<Radio
|
|
415
|
+
name="radio-group"
|
|
416
|
+
value="option1"
|
|
417
|
+
label="Option 1"
|
|
418
|
+
checked={radioValue === 'option1'}
|
|
419
|
+
onChange={() => setRadioValue('option1')}
|
|
420
|
+
data-edit-scope="component-definition"
|
|
421
|
+
data-component="Radio"
|
|
422
|
+
/>
|
|
423
|
+
<Radio
|
|
424
|
+
name="radio-group"
|
|
425
|
+
value="option2"
|
|
426
|
+
label="Option 2"
|
|
427
|
+
checked={radioValue === 'option2'}
|
|
428
|
+
onChange={() => setRadioValue('option2')}
|
|
429
|
+
data-edit-scope="component-definition"
|
|
430
|
+
data-component="Radio"
|
|
431
|
+
/>
|
|
432
|
+
<Radio
|
|
433
|
+
name="radio-group"
|
|
434
|
+
value="option3"
|
|
435
|
+
label="Option 3"
|
|
436
|
+
checked={radioValue === 'option3'}
|
|
437
|
+
onChange={() => setRadioValue('option3')}
|
|
438
|
+
data-edit-scope="component-definition"
|
|
439
|
+
data-component="Radio"
|
|
440
|
+
/>
|
|
441
|
+
</Row>
|
|
442
|
+
</Section>
|
|
443
|
+
|
|
444
|
+
<Section title="Switch" variant="h4" subsectionId="switch">
|
|
445
|
+
<Row props='checked={boolean} onChange={fn} size="sm" | "md" | "lg" label="..." labelPosition="left" | "right"'>
|
|
446
|
+
<Switch
|
|
447
|
+
checked={switchChecked}
|
|
448
|
+
onChange={setSwitchChecked}
|
|
449
|
+
size="md"
|
|
450
|
+
label="Enable notifications"
|
|
451
|
+
labelPosition="right"
|
|
452
|
+
data-edit-scope="component-definition"
|
|
453
|
+
data-component="Switch"
|
|
454
|
+
/>
|
|
455
|
+
<Switch
|
|
456
|
+
checked={!switchChecked}
|
|
457
|
+
onChange={() => setSwitchChecked(!switchChecked)}
|
|
458
|
+
size="md"
|
|
459
|
+
label="Disabled"
|
|
460
|
+
labelPosition="right"
|
|
461
|
+
disabled={true}
|
|
462
|
+
data-edit-scope="component-definition"
|
|
463
|
+
data-component="Switch"
|
|
464
|
+
/>
|
|
465
|
+
</Row>
|
|
466
|
+
<Row props='size="sm" | "md" | "lg"'>
|
|
467
|
+
<Switch checked={true} onChange={() => {}} size="sm" data-edit-scope="component-definition" data-component="Switch" />
|
|
468
|
+
<Switch checked={true} onChange={() => {}} size="md" data-edit-scope="component-definition" data-component="Switch" />
|
|
469
|
+
<Switch checked={true} onChange={() => {}} size="lg" data-edit-scope="component-definition" data-component="Switch" />
|
|
470
|
+
</Row>
|
|
471
|
+
<Row props='labelPosition="left"'>
|
|
472
|
+
<Switch
|
|
473
|
+
checked={switchChecked}
|
|
474
|
+
onChange={setSwitchChecked}
|
|
475
|
+
size="md"
|
|
476
|
+
label="Label on left"
|
|
477
|
+
labelPosition="left"
|
|
478
|
+
data-edit-scope="component-definition"
|
|
479
|
+
data-component="Switch"
|
|
480
|
+
/>
|
|
481
|
+
</Row>
|
|
482
|
+
</Section>
|
|
483
|
+
|
|
484
|
+
<Section title="Slider" variant="h4" subsectionId="slider">
|
|
485
|
+
<Row props='value={number} onChange={fn} min={number} max={number} step={number} size="sm" | "md" | "lg" showValue={boolean} label="..."'>
|
|
486
|
+
<div className="max-w-md w-full">
|
|
487
|
+
<Slider
|
|
488
|
+
value={sliderValue}
|
|
489
|
+
onChange={setSliderValue}
|
|
490
|
+
min={0}
|
|
491
|
+
max={100}
|
|
492
|
+
step={1}
|
|
493
|
+
size="md"
|
|
494
|
+
label="Volume"
|
|
495
|
+
showValue={true}
|
|
496
|
+
data-edit-scope="component-definition"
|
|
497
|
+
data-component="Slider"
|
|
498
|
+
/>
|
|
499
|
+
</div>
|
|
500
|
+
</Row>
|
|
501
|
+
<Row props='size="sm" | "md" | "lg"'>
|
|
502
|
+
<div className="max-w-md w-full">
|
|
503
|
+
<Slider value={30} onChange={() => {}} size="sm" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
|
|
504
|
+
</div>
|
|
505
|
+
</Row>
|
|
506
|
+
<Row props='size="md"'>
|
|
507
|
+
<div className="max-w-md w-full">
|
|
508
|
+
<Slider value={60} onChange={() => {}} size="md" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
|
|
509
|
+
</div>
|
|
510
|
+
</Row>
|
|
511
|
+
<Row props='size="lg"'>
|
|
512
|
+
<div className="max-w-md w-full">
|
|
513
|
+
<Slider value={80} onChange={() => {}} size="lg" showValue={true} data-edit-scope="component-definition" data-component="Slider" />
|
|
514
|
+
</div>
|
|
515
|
+
</Row>
|
|
516
|
+
<Row props='disabled'>
|
|
517
|
+
<div className="max-w-md w-full">
|
|
518
|
+
<Slider value={50} onChange={() => {}} disabled={true} showValue={true} data-edit-scope="component-definition" data-component="Slider" />
|
|
519
|
+
</div>
|
|
520
|
+
</Row>
|
|
521
|
+
</Section>
|
|
522
|
+
</div>
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function FeedbackContent() {
|
|
527
|
+
const { addToast } = useToast();
|
|
528
|
+
|
|
529
|
+
return (
|
|
530
|
+
<div className="space-y-6">
|
|
531
|
+
<Section title="Alert" variant="h4" subsectionId="alert">
|
|
532
|
+
<Row props='variant="default" | "success" | "warning" | "error" | "info" title="..." iconName="..." closable={boolean} onClose={fn}'>
|
|
533
|
+
<div className="max-w-md w-full">
|
|
534
|
+
<Alert variant="default" title="Default Alert" data-edit-scope="component-definition" data-component="Alert">
|
|
535
|
+
This is a default alert message.
|
|
536
|
+
</Alert>
|
|
537
|
+
</div>
|
|
538
|
+
</Row>
|
|
539
|
+
<Row props='variant="success"'>
|
|
540
|
+
<div className="max-w-md w-full">
|
|
541
|
+
<Alert variant="success" title="Success" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="success">
|
|
542
|
+
Operation completed successfully!
|
|
543
|
+
</Alert>
|
|
544
|
+
</div>
|
|
545
|
+
</Row>
|
|
546
|
+
<Row props='variant="warning"'>
|
|
547
|
+
<div className="max-w-md w-full">
|
|
548
|
+
<Alert variant="warning" title="Warning" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="warning">
|
|
549
|
+
Please review this information carefully.
|
|
550
|
+
</Alert>
|
|
551
|
+
</div>
|
|
552
|
+
</Row>
|
|
553
|
+
<Row props='variant="error"'>
|
|
554
|
+
<div className="max-w-md w-full">
|
|
555
|
+
<Alert variant="error" title="Error" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="error">
|
|
556
|
+
Something went wrong. Please try again.
|
|
557
|
+
</Alert>
|
|
558
|
+
</div>
|
|
559
|
+
</Row>
|
|
560
|
+
<Row props='variant="info"'>
|
|
561
|
+
<div className="max-w-md w-full">
|
|
562
|
+
<Alert variant="info" title="Info" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="info">
|
|
563
|
+
Here's some helpful information for you.
|
|
564
|
+
</Alert>
|
|
565
|
+
</div>
|
|
566
|
+
</Row>
|
|
567
|
+
<Row props='iconName="..." (overrides variant default)'>
|
|
568
|
+
<div className="max-w-md w-full">
|
|
569
|
+
<Alert variant="success" title="Custom Icon" iconName="checkmark" data-edit-scope="component-definition" data-component="Alert" data-edit-variant="success">
|
|
570
|
+
Using a custom icon instead of the variant default.
|
|
571
|
+
</Alert>
|
|
572
|
+
</div>
|
|
573
|
+
</Row>
|
|
574
|
+
<Row props='closable={true} onClose={fn}'>
|
|
575
|
+
<div className="max-w-md w-full">
|
|
576
|
+
<Alert
|
|
577
|
+
variant="default"
|
|
578
|
+
title="Closable Alert"
|
|
579
|
+
closable={true}
|
|
580
|
+
onClose={() => alert('Alert closed!')}
|
|
581
|
+
data-edit-scope="component-definition"
|
|
582
|
+
data-component="Alert"
|
|
583
|
+
>
|
|
584
|
+
This alert can be closed by clicking the X button.
|
|
585
|
+
</Alert>
|
|
586
|
+
</div>
|
|
587
|
+
</Row>
|
|
588
|
+
<Row props='No title'>
|
|
589
|
+
<div className="max-w-md w-full">
|
|
590
|
+
<Alert variant="default" data-edit-scope="component-definition" data-component="Alert">
|
|
591
|
+
Alert without a title - just the message content.
|
|
592
|
+
</Alert>
|
|
593
|
+
</div>
|
|
594
|
+
</Row>
|
|
595
|
+
</Section>
|
|
596
|
+
|
|
597
|
+
<Section title="Badge Variants" variant="h4" subsectionId="badge-variants">
|
|
598
|
+
<Row props='variant="default" | "success" | "warning" | "error" | "info" size="md"'>
|
|
599
|
+
<Badge variant="default" size="md" data-edit-scope="component-definition" data-component="Badge">Default</Badge>
|
|
600
|
+
<Badge variant="success" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="success">Success</Badge>
|
|
601
|
+
<Badge variant="warning" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="warning">Warning</Badge>
|
|
602
|
+
<Badge variant="error" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="error">Error</Badge>
|
|
603
|
+
<Badge variant="info" size="md" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="info">Info</Badge>
|
|
604
|
+
</Row>
|
|
605
|
+
<Row props='size="sm" | "md"'>
|
|
606
|
+
<Badge variant="default" size="sm" data-edit-scope="component-definition" data-component="Badge">Small</Badge>
|
|
607
|
+
<Badge variant="success" size="sm" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="success">Success</Badge>
|
|
608
|
+
<Badge variant="error" size="sm" data-edit-scope="component-definition" data-component="Badge" data-edit-variant="error">Error</Badge>
|
|
609
|
+
</Row>
|
|
610
|
+
</Section>
|
|
611
|
+
|
|
612
|
+
<Section title="Progress" variant="h4" subsectionId="progress">
|
|
613
|
+
<Row props='value={number} variant="default" size="md" showLabel={false}'>
|
|
614
|
+
<div className="max-w-md w-full">
|
|
615
|
+
<Label htmlFor="progress-default">Default (50%)</Label>
|
|
616
|
+
<Progress value={50} variant="default" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" />
|
|
617
|
+
</div>
|
|
618
|
+
</Row>
|
|
619
|
+
<Row props='variant="success"'>
|
|
620
|
+
<div className="max-w-md w-full">
|
|
621
|
+
<Label htmlFor="progress-success">Success (75%)</Label>
|
|
622
|
+
<Progress value={75} variant="success" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="success" />
|
|
623
|
+
</div>
|
|
624
|
+
</Row>
|
|
625
|
+
<Row props='variant="warning"'>
|
|
626
|
+
<div className="max-w-md w-full">
|
|
627
|
+
<Label htmlFor="progress-warning">Warning (25%)</Label>
|
|
628
|
+
<Progress value={25} variant="warning" size="md" showLabel={false} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="warning" />
|
|
629
|
+
</div>
|
|
630
|
+
</Row>
|
|
631
|
+
<Row props='showLabel={true}'>
|
|
632
|
+
<div className="max-w-md w-full">
|
|
633
|
+
<Label htmlFor="progress-label">Error with Label</Label>
|
|
634
|
+
<Progress value={90} variant="error" size="md" showLabel={true} data-edit-scope="component-definition" data-component="Progress" data-edit-variant="error" />
|
|
635
|
+
</div>
|
|
636
|
+
</Row>
|
|
637
|
+
</Section>
|
|
638
|
+
|
|
639
|
+
<Section title="Progress Sizes" variant="h4" subsectionId="progress-sizes">
|
|
640
|
+
<Row props='size="sm" | "md" | "lg"'>
|
|
641
|
+
<div className="max-w-md w-full">
|
|
642
|
+
<Label htmlFor="progress-sm">Small</Label>
|
|
643
|
+
<Progress value={60} variant="default" size="sm" showLabel={false} />
|
|
644
|
+
</div>
|
|
645
|
+
</Row>
|
|
646
|
+
<Row props='size="md"'>
|
|
647
|
+
<div className="max-w-md w-full">
|
|
648
|
+
<Label htmlFor="progress-md">Medium</Label>
|
|
649
|
+
<Progress value={60} variant="default" size="md" showLabel={false} />
|
|
650
|
+
</div>
|
|
651
|
+
</Row>
|
|
652
|
+
<Row props='size="lg"'>
|
|
653
|
+
<div className="max-w-md w-full">
|
|
654
|
+
<Label htmlFor="progress-lg">Large</Label>
|
|
655
|
+
<Progress value={60} variant="default" size="lg" showLabel={false} />
|
|
656
|
+
</div>
|
|
657
|
+
</Row>
|
|
658
|
+
</Section>
|
|
659
|
+
|
|
660
|
+
<Section title="Spinner" variant="h4" subsectionId="spinner">
|
|
661
|
+
<Row props='size={number}'>
|
|
662
|
+
<Spinner size={16} data-edit-scope="component-definition" data-component="Spinner" />
|
|
663
|
+
<Spinner size={24} data-edit-scope="component-definition" data-component="Spinner" />
|
|
664
|
+
<Spinner size={32} data-edit-scope="component-definition" data-component="Spinner" />
|
|
665
|
+
</Row>
|
|
666
|
+
</Section>
|
|
667
|
+
|
|
668
|
+
<Section title="Toast" variant="h4" subsectionId="toast">
|
|
669
|
+
<Row props='useToast() hook - addToast({ title, description?, variant?, duration? })'>
|
|
670
|
+
<div className="flex flex-wrap gap-2">
|
|
671
|
+
<Button
|
|
672
|
+
variant="primary"
|
|
673
|
+
size="md"
|
|
674
|
+
|
|
675
|
+
fullWidth={false}
|
|
676
|
+
iconOnly={false}
|
|
677
|
+
onClick={() => addToast({ title: 'Default Toast', variant: 'default' })}
|
|
678
|
+
>
|
|
679
|
+
Default Toast
|
|
680
|
+
</Button>
|
|
681
|
+
<Button
|
|
682
|
+
variant="primary"
|
|
683
|
+
size="md"
|
|
684
|
+
|
|
685
|
+
fullWidth={false}
|
|
686
|
+
iconOnly={false}
|
|
687
|
+
onClick={() => addToast({ title: 'Success!', description: 'Operation completed successfully.', variant: 'success' })}
|
|
688
|
+
>
|
|
689
|
+
Success Toast
|
|
690
|
+
</Button>
|
|
691
|
+
<Button
|
|
692
|
+
variant="primary"
|
|
693
|
+
size="md"
|
|
694
|
+
|
|
695
|
+
fullWidth={false}
|
|
696
|
+
iconOnly={false}
|
|
697
|
+
onClick={() => addToast({ title: 'Warning', description: 'Please review this carefully.', variant: 'warning' })}
|
|
698
|
+
>
|
|
699
|
+
Warning Toast
|
|
700
|
+
</Button>
|
|
701
|
+
<Button
|
|
702
|
+
variant="primary"
|
|
703
|
+
size="md"
|
|
704
|
+
|
|
705
|
+
fullWidth={false}
|
|
706
|
+
iconOnly={false}
|
|
707
|
+
onClick={() => addToast({ title: 'Error', description: 'Something went wrong.', variant: 'error' })}
|
|
708
|
+
>
|
|
709
|
+
Error Toast
|
|
710
|
+
</Button>
|
|
711
|
+
<Button
|
|
712
|
+
variant="primary"
|
|
713
|
+
size="md"
|
|
714
|
+
|
|
715
|
+
fullWidth={false}
|
|
716
|
+
iconOnly={false}
|
|
717
|
+
onClick={() => addToast({ title: 'Info', description: 'Here\'s some helpful information.', variant: 'info' })}
|
|
718
|
+
>
|
|
719
|
+
Info Toast
|
|
720
|
+
</Button>
|
|
721
|
+
</div>
|
|
722
|
+
</Row>
|
|
723
|
+
</Section>
|
|
724
|
+
|
|
725
|
+
<Section title="Tooltip" variant="h4" subsectionId="tooltip">
|
|
726
|
+
<Row props='content="..." position="top" | "bottom" | "left" | "right" size="sm" | "md" | "lg"'>
|
|
727
|
+
<Tooltip content="Top tooltip" position="top" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
|
|
728
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Top</Button>
|
|
729
|
+
</Tooltip>
|
|
730
|
+
<Tooltip content="Bottom tooltip" position="bottom" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
|
|
731
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Bottom</Button>
|
|
732
|
+
</Tooltip>
|
|
733
|
+
<Tooltip content="Left tooltip" position="left" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
|
|
734
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Left</Button>
|
|
735
|
+
</Tooltip>
|
|
736
|
+
<Tooltip content="Right tooltip" position="right" size="sm" data-edit-scope="component-definition" data-component="Tooltip">
|
|
737
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>Right</Button>
|
|
738
|
+
</Tooltip>
|
|
739
|
+
</Row>
|
|
740
|
+
</Section>
|
|
741
|
+
</div>
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function NavigationContent() {
|
|
746
|
+
return (
|
|
747
|
+
<div className="space-y-6">
|
|
748
|
+
<Section title="Breadcrumbs" variant="h4" subsectionId="breadcrumbs">
|
|
749
|
+
<Row props='items={[{ label: string, href?: string }]} separator={string}'>
|
|
750
|
+
<Breadcrumbs
|
|
751
|
+
items={[
|
|
752
|
+
{ label: 'Home', href: '#' },
|
|
753
|
+
{ label: 'Products', href: '#' },
|
|
754
|
+
{ label: 'Electronics', href: '#' },
|
|
755
|
+
{ label: 'Current Page' },
|
|
756
|
+
]}
|
|
757
|
+
data-edit-scope="component-definition"
|
|
758
|
+
data-component="Breadcrumbs"
|
|
759
|
+
/>
|
|
760
|
+
</Row>
|
|
761
|
+
<Row props='separator="→"'>
|
|
762
|
+
<Breadcrumbs
|
|
763
|
+
items={[
|
|
764
|
+
{ label: 'Home', href: '#' },
|
|
765
|
+
{ label: 'About', href: '#' },
|
|
766
|
+
{ label: 'Team' },
|
|
767
|
+
]}
|
|
768
|
+
separator="→"
|
|
769
|
+
/>
|
|
770
|
+
</Row>
|
|
771
|
+
<Row props='separator="•"'>
|
|
772
|
+
<Breadcrumbs
|
|
773
|
+
items={[
|
|
774
|
+
{ label: 'Dashboard', href: '#' },
|
|
775
|
+
{ label: 'Settings', href: '#' },
|
|
776
|
+
{ label: 'Profile' },
|
|
777
|
+
]}
|
|
778
|
+
separator="•"
|
|
779
|
+
/>
|
|
780
|
+
</Row>
|
|
781
|
+
<Row props='Single item'>
|
|
782
|
+
<Breadcrumbs items={[{ label: 'Home' }]} />
|
|
783
|
+
</Row>
|
|
784
|
+
</Section>
|
|
785
|
+
|
|
786
|
+
<Section title="Tabs - Pill Variant" variant="h4" subsectionId="tabs-pill-variant">
|
|
787
|
+
<Row props='variant="pill" | "line" defaultValue="tab1" iconName="..."'>
|
|
788
|
+
<Card variant="default" noPadding={false} className="max-w-lg">
|
|
789
|
+
<Tabs defaultValue="tab1" variant="pill" data-edit-scope="component-definition" data-component="Tabs">
|
|
790
|
+
<TabList className="">
|
|
791
|
+
<TabTrigger value="tab1" iconName="home" className="">Tab One</TabTrigger>
|
|
792
|
+
<TabTrigger value="tab2" iconName="settings" className="">Tab Two</TabTrigger>
|
|
793
|
+
<TabTrigger value="tab3" iconName="information-circle" className="">Tab Three</TabTrigger>
|
|
794
|
+
</TabList>
|
|
795
|
+
<TabContent value="tab1" className="mt-4">
|
|
796
|
+
<p>Content for Tab One</p>
|
|
797
|
+
</TabContent>
|
|
798
|
+
<TabContent value="tab2" className="mt-4">
|
|
799
|
+
<p>Content for Tab Two</p>
|
|
800
|
+
</TabContent>
|
|
801
|
+
<TabContent value="tab3" className="mt-4">
|
|
802
|
+
<p>Content for Tab Three</p>
|
|
803
|
+
</TabContent>
|
|
804
|
+
</Tabs>
|
|
805
|
+
</Card>
|
|
806
|
+
</Row>
|
|
807
|
+
</Section>
|
|
808
|
+
|
|
809
|
+
<Section title="Tabs - Line Variant" variant="h4" subsectionId="tabs-line-variant">
|
|
810
|
+
<Row props='variant="line" iconName="..."'>
|
|
811
|
+
<Card variant="default" noPadding={false} className="max-w-lg">
|
|
812
|
+
<Tabs defaultValue="tab1" variant="line" data-edit-scope="component-definition" data-component="Tabs" data-edit-variant="line">
|
|
813
|
+
<TabList className="">
|
|
814
|
+
<TabTrigger value="tab1" iconName="home" className="">First</TabTrigger>
|
|
815
|
+
<TabTrigger value="tab2" iconName="settings" className="">Second</TabTrigger>
|
|
816
|
+
<TabTrigger value="tab3" iconName="information-circle" className="">Third</TabTrigger>
|
|
817
|
+
</TabList>
|
|
818
|
+
<TabContent value="tab1" className="mt-4">
|
|
819
|
+
<p>First tab content</p>
|
|
820
|
+
</TabContent>
|
|
821
|
+
<TabContent value="tab2" className="mt-4">
|
|
822
|
+
<p>Second tab content</p>
|
|
823
|
+
</TabContent>
|
|
824
|
+
<TabContent value="tab3" className="mt-4">
|
|
825
|
+
<p>Third tab content</p>
|
|
826
|
+
</TabContent>
|
|
827
|
+
</Tabs>
|
|
828
|
+
</Card>
|
|
829
|
+
</Row>
|
|
830
|
+
</Section>
|
|
831
|
+
|
|
832
|
+
<Section title="Dividers" variant="h4" subsectionId="dividers">
|
|
833
|
+
<Row props='variant="solid" | "dashed" | "decorated" orientation="horizontal"'>
|
|
834
|
+
<div className="w-full max-w-md">
|
|
835
|
+
<Label htmlFor="divider-solid">Solid</Label>
|
|
836
|
+
<Divider orientation="horizontal" variant="solid" data-edit-scope="component-definition" data-component="Divider" />
|
|
837
|
+
</div>
|
|
838
|
+
</Row>
|
|
839
|
+
<Row props='variant="dashed"'>
|
|
840
|
+
<div className="w-full max-w-md">
|
|
841
|
+
<Label htmlFor="divider-dashed">Dashed</Label>
|
|
842
|
+
<Divider orientation="horizontal" variant="dashed" data-edit-scope="component-definition" data-component="Divider" data-edit-variant="dashed" />
|
|
843
|
+
</div>
|
|
844
|
+
</Row>
|
|
845
|
+
<Row props='variant="decorated"'>
|
|
846
|
+
<div className="w-full max-w-md">
|
|
847
|
+
<Label htmlFor="divider-decorated">Decorated</Label>
|
|
848
|
+
<Divider orientation="horizontal" variant="decorated" data-edit-scope="component-definition" data-component="Divider" data-edit-variant="decorated" />
|
|
849
|
+
</div>
|
|
850
|
+
</Row>
|
|
851
|
+
</Section>
|
|
852
|
+
|
|
853
|
+
<Section title="Vertical Divider" variant="h4" subsectionId="vertical-divider">
|
|
854
|
+
<Row props='orientation="vertical"'>
|
|
855
|
+
<div className="flex items-center h-12 gap-4">
|
|
856
|
+
<span className="font-mondwest text-base">Left</span>
|
|
857
|
+
<Divider orientation="vertical" variant="solid" />
|
|
858
|
+
<span className="font-mondwest text-base">Right</span>
|
|
859
|
+
</div>
|
|
860
|
+
</Row>
|
|
861
|
+
</Section>
|
|
862
|
+
</div>
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function OverlaysContent() {
|
|
867
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
868
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
869
|
+
const [helpPanelOpen, setHelpPanelOpen] = useState(false);
|
|
870
|
+
|
|
871
|
+
return (
|
|
872
|
+
<div className="space-y-6">
|
|
873
|
+
<Section title="Dialog" variant="h4" subsectionId="dialog">
|
|
874
|
+
<Row props='open={boolean} onOpenChange={fn} defaultOpen={boolean}'>
|
|
875
|
+
<Dialog open={dialogOpen} onOpenChange={setDialogOpen} data-edit-scope="component-definition" data-component="Dialog">
|
|
876
|
+
<DialogTrigger asChild>
|
|
877
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
878
|
+
Open Dialog
|
|
879
|
+
</Button>
|
|
880
|
+
</DialogTrigger>
|
|
881
|
+
<DialogContent>
|
|
882
|
+
<DialogHeader>
|
|
883
|
+
<DialogTitle>Dialog Title</DialogTitle>
|
|
884
|
+
<DialogDescription>
|
|
885
|
+
This is a description of what the dialog does.
|
|
886
|
+
</DialogDescription>
|
|
887
|
+
</DialogHeader>
|
|
888
|
+
<DialogBody>
|
|
889
|
+
<p>
|
|
890
|
+
Dialog content goes here. You can put any content in the body.
|
|
891
|
+
</p>
|
|
892
|
+
</DialogBody>
|
|
893
|
+
<DialogFooter>
|
|
894
|
+
<DialogClose asChild>
|
|
895
|
+
<Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>
|
|
896
|
+
Cancel
|
|
897
|
+
</Button>
|
|
898
|
+
</DialogClose>
|
|
899
|
+
<DialogClose asChild>
|
|
900
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
901
|
+
Confirm
|
|
902
|
+
</Button>
|
|
903
|
+
</DialogClose>
|
|
904
|
+
</DialogFooter>
|
|
905
|
+
</DialogContent>
|
|
906
|
+
</Dialog>
|
|
907
|
+
</Row>
|
|
908
|
+
</Section>
|
|
909
|
+
|
|
910
|
+
<Section title="Dropdown Menu" variant="h4" subsectionId="dropdown-menu">
|
|
911
|
+
<Row props='open={boolean} onOpenChange={fn} position="bottom-start" | "bottom-end" | "top-start" | "top-end"'>
|
|
912
|
+
<DropdownMenu data-edit-scope="component-definition" data-component="DropdownMenu">
|
|
913
|
+
<DropdownMenuTrigger asChild>
|
|
914
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
915
|
+
Open Menu ▼
|
|
916
|
+
</Button>
|
|
917
|
+
</DropdownMenuTrigger>
|
|
918
|
+
<DropdownMenuContent>
|
|
919
|
+
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
|
920
|
+
<DropdownMenuItem onClick={() => alert('Copy clicked!')} destructive={false} disabled={false}>
|
|
921
|
+
Copy
|
|
922
|
+
</DropdownMenuItem>
|
|
923
|
+
<DropdownMenuItem onClick={() => alert('Cut clicked!')} destructive={false} disabled={false}>
|
|
924
|
+
Cut
|
|
925
|
+
</DropdownMenuItem>
|
|
926
|
+
<DropdownMenuItem onClick={() => alert('Paste clicked!')} destructive={false} disabled={false}>
|
|
927
|
+
Paste
|
|
928
|
+
</DropdownMenuItem>
|
|
929
|
+
<DropdownMenuSeparator />
|
|
930
|
+
<DropdownMenuItem onClick={() => alert('Delete clicked!')} destructive={true} disabled={false}>
|
|
931
|
+
Delete
|
|
932
|
+
</DropdownMenuItem>
|
|
933
|
+
<DropdownMenuItem onClick={() => alert('Disabled item')} destructive={false} disabled={true}>
|
|
934
|
+
Disabled Item
|
|
935
|
+
</DropdownMenuItem>
|
|
936
|
+
</DropdownMenuContent>
|
|
937
|
+
</DropdownMenu>
|
|
938
|
+
</Row>
|
|
939
|
+
</Section>
|
|
940
|
+
|
|
941
|
+
<Section title="Popover" variant="h4" subsectionId="popover">
|
|
942
|
+
<Row props='open={boolean} onOpenChange={fn} position="top" | "bottom" | "left" | "right" align="start" | "center" | "end"'>
|
|
943
|
+
<Popover data-edit-scope="component-definition" data-component="Popover">
|
|
944
|
+
<PopoverTrigger asChild>
|
|
945
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
946
|
+
Open Popover
|
|
947
|
+
</Button>
|
|
948
|
+
</PopoverTrigger>
|
|
949
|
+
<PopoverContent>
|
|
950
|
+
<p className="font-joystix text-xs uppercase mb-2">Popover Title</p>
|
|
951
|
+
<p className="font-mondwest text-base text-black/70">
|
|
952
|
+
This is popover content. It can contain any elements.
|
|
953
|
+
</p>
|
|
954
|
+
</PopoverContent>
|
|
955
|
+
</Popover>
|
|
956
|
+
</Row>
|
|
957
|
+
<Row props='position="top"'>
|
|
958
|
+
<Popover position="top" data-edit-scope="component-definition" data-component="Popover">
|
|
959
|
+
<PopoverTrigger asChild>
|
|
960
|
+
<Button variant="outline" size="md" fullWidth={false} iconOnly={false}>
|
|
961
|
+
Top Popover
|
|
962
|
+
</Button>
|
|
963
|
+
</PopoverTrigger>
|
|
964
|
+
<PopoverContent>
|
|
965
|
+
<p>Popover appears above</p>
|
|
966
|
+
</PopoverContent>
|
|
967
|
+
</Popover>
|
|
968
|
+
</Row>
|
|
969
|
+
</Section>
|
|
970
|
+
|
|
971
|
+
<Section title="Sheet" variant="h4" subsectionId="sheet">
|
|
972
|
+
<Row props='open={boolean} onOpenChange={fn} side="left" | "right" | "top" | "bottom"'>
|
|
973
|
+
<Sheet open={sheetOpen} onOpenChange={setSheetOpen} side="right" data-edit-scope="component-definition" data-component="Sheet">
|
|
974
|
+
<SheetTrigger asChild>
|
|
975
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
976
|
+
Open Sheet (Right)
|
|
977
|
+
</Button>
|
|
978
|
+
</SheetTrigger>
|
|
979
|
+
<SheetContent>
|
|
980
|
+
<SheetHeader>
|
|
981
|
+
<SheetTitle>Sheet Title</SheetTitle>
|
|
982
|
+
<SheetDescription>
|
|
983
|
+
This is a description of the sheet content.
|
|
984
|
+
</SheetDescription>
|
|
985
|
+
</SheetHeader>
|
|
986
|
+
<SheetBody>
|
|
987
|
+
<p>
|
|
988
|
+
Sheet content goes here. This is a slide-in panel from the right side.
|
|
989
|
+
</p>
|
|
990
|
+
</SheetBody>
|
|
991
|
+
<SheetFooter>
|
|
992
|
+
<SheetClose asChild>
|
|
993
|
+
<Button variant="ghost" size="md" fullWidth={false} iconOnly={false}>
|
|
994
|
+
Cancel
|
|
995
|
+
</Button>
|
|
996
|
+
</SheetClose>
|
|
997
|
+
<SheetClose asChild>
|
|
998
|
+
<Button variant="primary" size="md" fullWidth={false} iconOnly={false}>
|
|
999
|
+
Save
|
|
1000
|
+
</Button>
|
|
1001
|
+
</SheetClose>
|
|
1002
|
+
</SheetFooter>
|
|
1003
|
+
</SheetContent>
|
|
1004
|
+
</Sheet>
|
|
1005
|
+
</Row>
|
|
1006
|
+
<Row props='side="left"'>
|
|
1007
|
+
<Sheet side="left" data-edit-scope="component-definition" data-component="Sheet">
|
|
1008
|
+
<SheetTrigger asChild>
|
|
1009
|
+
<Button variant="outline" size="md" fullWidth={false} iconOnly={false}>
|
|
1010
|
+
Open Sheet (Left)
|
|
1011
|
+
</Button>
|
|
1012
|
+
</SheetTrigger>
|
|
1013
|
+
<SheetContent>
|
|
1014
|
+
<SheetHeader>
|
|
1015
|
+
<SheetTitle>Left Side Sheet</SheetTitle>
|
|
1016
|
+
</SheetHeader>
|
|
1017
|
+
<SheetBody>
|
|
1018
|
+
<p>Sheet slides in from the left</p>
|
|
1019
|
+
</SheetBody>
|
|
1020
|
+
</SheetContent>
|
|
1021
|
+
</Sheet>
|
|
1022
|
+
</Row>
|
|
1023
|
+
</Section>
|
|
1024
|
+
|
|
1025
|
+
<Section title="Help Panel" variant="h4" subsectionId="help-panel">
|
|
1026
|
+
<Row props='isOpen={boolean} onClose={fn} title={string}'>
|
|
1027
|
+
<div className="relative w-full max-w-md h-64 border border-black rounded-sm bg-warm-cloud overflow-hidden">
|
|
1028
|
+
<div className="p-4">
|
|
1029
|
+
<Button
|
|
1030
|
+
variant="primary"
|
|
1031
|
+
size="md"
|
|
1032
|
+
|
|
1033
|
+
fullWidth={false}
|
|
1034
|
+
iconOnly={false}
|
|
1035
|
+
onClick={() => setHelpPanelOpen(true)}
|
|
1036
|
+
>
|
|
1037
|
+
Open Help Panel
|
|
1038
|
+
</Button>
|
|
1039
|
+
</div>
|
|
1040
|
+
<HelpPanel
|
|
1041
|
+
isOpen={helpPanelOpen}
|
|
1042
|
+
onClose={() => setHelpPanelOpen(false)}
|
|
1043
|
+
title="Help"
|
|
1044
|
+
data-edit-scope="component-definition"
|
|
1045
|
+
data-component="HelpPanel"
|
|
1046
|
+
>
|
|
1047
|
+
<div>
|
|
1048
|
+
<p className="font-joystix text-xs uppercase mb-2">Help Content</p>
|
|
1049
|
+
<p className="mb-4">
|
|
1050
|
+
This is a contextual help panel that slides in from the right side of its container.
|
|
1051
|
+
</p>
|
|
1052
|
+
<p>
|
|
1053
|
+
It's useful for providing contextual help within app windows or modals.
|
|
1054
|
+
</p>
|
|
1055
|
+
</div>
|
|
1056
|
+
</HelpPanel>
|
|
1057
|
+
</div>
|
|
1058
|
+
</Row>
|
|
1059
|
+
</Section>
|
|
1060
|
+
|
|
1061
|
+
<Section title="Context Menu" variant="h4" subsectionId="context-menu">
|
|
1062
|
+
<Row props='onClick={fn} destructive={boolean} disabled={boolean}'>
|
|
1063
|
+
<p className="mb-4 w-full">
|
|
1064
|
+
Right-click on the card below to see the context menu:
|
|
1065
|
+
</p>
|
|
1066
|
+
<ContextMenu data-edit-scope="component-definition" data-component="ContextMenu">
|
|
1067
|
+
<Card variant="default" noPadding={false} className="max-w-xs cursor-context-menu">
|
|
1068
|
+
<p className="font-joystix text-xs mb-2">Right-click me!</p>
|
|
1069
|
+
<p className="font-mondwest text-base text-black/70">
|
|
1070
|
+
This card has a context menu attached.
|
|
1071
|
+
</p>
|
|
1072
|
+
</Card>
|
|
1073
|
+
<ContextMenuContent>
|
|
1074
|
+
<ContextMenuItem onClick={() => alert('Copy clicked!')} destructive={false} disabled={false}>
|
|
1075
|
+
Copy
|
|
1076
|
+
</ContextMenuItem>
|
|
1077
|
+
<ContextMenuItem onClick={() => alert('Paste clicked!')} destructive={false} disabled={false}>
|
|
1078
|
+
Paste
|
|
1079
|
+
</ContextMenuItem>
|
|
1080
|
+
<ContextMenuItem onClick={() => alert('Duplicate clicked!')} destructive={false} disabled={false}>
|
|
1081
|
+
Duplicate
|
|
1082
|
+
</ContextMenuItem>
|
|
1083
|
+
<ContextMenuSeparator />
|
|
1084
|
+
<ContextMenuItem onClick={() => alert('Delete clicked!')} destructive={true} disabled={false}>
|
|
1085
|
+
Delete
|
|
1086
|
+
</ContextMenuItem>
|
|
1087
|
+
</ContextMenuContent>
|
|
1088
|
+
</ContextMenu>
|
|
1089
|
+
</Row>
|
|
1090
|
+
</Section>
|
|
1091
|
+
</div>
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// ============================================================================
|
|
1096
|
+
// Search Index
|
|
1097
|
+
// ============================================================================
|
|
1098
|
+
|
|
1099
|
+
export interface SearchableItem {
|
|
1100
|
+
text: string;
|
|
1101
|
+
sectionId: string;
|
|
1102
|
+
subsectionTitle?: string;
|
|
1103
|
+
type: 'section' | 'subsection' | 'button' | 'label' | 'checkbox' | 'radio' | 'switch' | 'slider' | 'badge' | 'alert' | 'toast' | 'tooltip' | 'breadcrumb' | 'tab' | 'divider' | 'menu';
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
export const SEARCH_INDEX: SearchableItem[] = [
|
|
1107
|
+
// Buttons section
|
|
1108
|
+
{ text: 'Buttons', sectionId: 'buttons', type: 'section' },
|
|
1109
|
+
{ text: 'Button Variants', sectionId: 'buttons', subsectionTitle: 'Button Variants', type: 'subsection' },
|
|
1110
|
+
{ text: 'Button Sizes', sectionId: 'buttons', subsectionTitle: 'Button Sizes', type: 'subsection' },
|
|
1111
|
+
{ text: 'Button with Icon', sectionId: 'buttons', subsectionTitle: 'Button with Icon', type: 'subsection' },
|
|
1112
|
+
{ text: 'Primary', sectionId: 'buttons', type: 'button' },
|
|
1113
|
+
{ text: 'Secondary', sectionId: 'buttons', type: 'button' },
|
|
1114
|
+
{ text: 'Outline', sectionId: 'buttons', type: 'button' },
|
|
1115
|
+
{ text: 'Ghost', sectionId: 'buttons', type: 'button' },
|
|
1116
|
+
{ text: 'Disabled', sectionId: 'buttons', type: 'button' },
|
|
1117
|
+
{ text: 'Small', sectionId: 'buttons', type: 'button' },
|
|
1118
|
+
{ text: 'Medium', sectionId: 'buttons', type: 'button' },
|
|
1119
|
+
{ text: 'Large', sectionId: 'buttons', type: 'button' },
|
|
1120
|
+
{ text: 'Download', sectionId: 'buttons', type: 'button' },
|
|
1121
|
+
{ text: 'Copy', sectionId: 'buttons', type: 'button' },
|
|
1122
|
+
{ text: 'Full Width Button', sectionId: 'buttons', type: 'button' },
|
|
1123
|
+
|
|
1124
|
+
// Cards section
|
|
1125
|
+
{ text: 'Cards', sectionId: 'cards', type: 'section' },
|
|
1126
|
+
{ text: 'Card Variants', sectionId: 'cards', subsectionTitle: 'Card Variants', type: 'subsection' },
|
|
1127
|
+
{ text: 'Card with Header/Footer', sectionId: 'cards', subsectionTitle: 'Card with Header/Footer', type: 'subsection' },
|
|
1128
|
+
{ text: 'Default Card', sectionId: 'cards', type: 'label' },
|
|
1129
|
+
{ text: 'Dark Card', sectionId: 'cards', type: 'label' },
|
|
1130
|
+
{ text: 'Raised Card', sectionId: 'cards', type: 'label' },
|
|
1131
|
+
{ text: 'Card Header', sectionId: 'cards', type: 'label' },
|
|
1132
|
+
{ text: 'Cancel', sectionId: 'cards', type: 'button' },
|
|
1133
|
+
{ text: 'Confirm', sectionId: 'cards', type: 'button' },
|
|
1134
|
+
|
|
1135
|
+
// Forms section
|
|
1136
|
+
{ text: 'Forms', sectionId: 'forms', type: 'section' },
|
|
1137
|
+
{ text: 'Text Inputs', sectionId: 'forms', subsectionTitle: 'Text Inputs', type: 'subsection' },
|
|
1138
|
+
{ text: 'Input Sizes', sectionId: 'forms', subsectionTitle: 'Input Sizes', type: 'subsection' },
|
|
1139
|
+
{ text: 'TextArea', sectionId: 'forms', subsectionTitle: 'TextArea', type: 'subsection' },
|
|
1140
|
+
{ text: 'Select', sectionId: 'forms', subsectionTitle: 'Select', type: 'subsection' },
|
|
1141
|
+
{ text: 'Checkbox & Radio', sectionId: 'forms', subsectionTitle: 'Checkbox & Radio', type: 'subsection' },
|
|
1142
|
+
{ text: 'Switch', sectionId: 'forms', subsectionTitle: 'Switch', type: 'subsection' },
|
|
1143
|
+
{ text: 'Slider', sectionId: 'forms', subsectionTitle: 'Slider', type: 'subsection' },
|
|
1144
|
+
{ text: 'Default Input', sectionId: 'forms', type: 'label' },
|
|
1145
|
+
{ text: 'Error State', sectionId: 'forms', type: 'label' },
|
|
1146
|
+
{ text: 'Description', sectionId: 'forms', type: 'label' },
|
|
1147
|
+
{ text: 'Choose an option', sectionId: 'forms', type: 'label' },
|
|
1148
|
+
{ text: 'Check me', sectionId: 'forms', type: 'checkbox' },
|
|
1149
|
+
{ text: 'Checked & Disabled', sectionId: 'forms', type: 'checkbox' },
|
|
1150
|
+
{ text: 'Option 1', sectionId: 'forms', type: 'radio' },
|
|
1151
|
+
{ text: 'Option 2', sectionId: 'forms', type: 'radio' },
|
|
1152
|
+
{ text: 'Option 3', sectionId: 'forms', type: 'radio' },
|
|
1153
|
+
{ text: 'Enable notifications', sectionId: 'forms', type: 'switch' },
|
|
1154
|
+
{ text: 'Label on left', sectionId: 'forms', type: 'switch' },
|
|
1155
|
+
{ text: 'Volume', sectionId: 'forms', type: 'slider' },
|
|
1156
|
+
{ text: 'Default (50%)', sectionId: 'forms', type: 'label' },
|
|
1157
|
+
{ text: 'Success (75%)', sectionId: 'forms', type: 'label' },
|
|
1158
|
+
{ text: 'Warning (25%)', sectionId: 'forms', type: 'label' },
|
|
1159
|
+
{ text: 'Error with Label', sectionId: 'forms', type: 'label' },
|
|
1160
|
+
|
|
1161
|
+
// Feedback section
|
|
1162
|
+
{ text: 'Feedback', sectionId: 'feedback', type: 'section' },
|
|
1163
|
+
{ text: 'Alert', sectionId: 'feedback', subsectionTitle: 'Alert', type: 'subsection' },
|
|
1164
|
+
{ text: 'Badge Variants', sectionId: 'feedback', subsectionTitle: 'Badge Variants', type: 'subsection' },
|
|
1165
|
+
{ text: 'Progress', sectionId: 'feedback', subsectionTitle: 'Progress', type: 'subsection' },
|
|
1166
|
+
{ text: 'Progress Sizes', sectionId: 'feedback', subsectionTitle: 'Progress Sizes', type: 'subsection' },
|
|
1167
|
+
{ text: 'Spinner', sectionId: 'feedback', subsectionTitle: 'Spinner', type: 'subsection' },
|
|
1168
|
+
{ text: 'Toast', sectionId: 'feedback', subsectionTitle: 'Toast', type: 'subsection' },
|
|
1169
|
+
{ text: 'Tooltip', sectionId: 'feedback', subsectionTitle: 'Tooltip', type: 'subsection' },
|
|
1170
|
+
{ text: 'Default Alert', sectionId: 'feedback', type: 'alert' },
|
|
1171
|
+
{ text: 'Success', sectionId: 'feedback', type: 'alert' },
|
|
1172
|
+
{ text: 'Warning', sectionId: 'feedback', type: 'alert' },
|
|
1173
|
+
{ text: 'Error', sectionId: 'feedback', type: 'alert' },
|
|
1174
|
+
{ text: 'Info', sectionId: 'feedback', type: 'alert' },
|
|
1175
|
+
{ text: 'Closable Alert', sectionId: 'feedback', type: 'alert' },
|
|
1176
|
+
{ text: 'Default Toast', sectionId: 'feedback', type: 'toast' },
|
|
1177
|
+
{ text: 'Success Toast', sectionId: 'feedback', type: 'toast' },
|
|
1178
|
+
{ text: 'Warning Toast', sectionId: 'feedback', type: 'toast' },
|
|
1179
|
+
{ text: 'Error Toast', sectionId: 'feedback', type: 'toast' },
|
|
1180
|
+
{ text: 'Info Toast', sectionId: 'feedback', type: 'toast' },
|
|
1181
|
+
{ text: 'Top', sectionId: 'feedback', type: 'tooltip' },
|
|
1182
|
+
{ text: 'Bottom', sectionId: 'feedback', type: 'tooltip' },
|
|
1183
|
+
{ text: 'Left', sectionId: 'feedback', type: 'tooltip' },
|
|
1184
|
+
{ text: 'Right', sectionId: 'feedback', type: 'tooltip' },
|
|
1185
|
+
|
|
1186
|
+
// Navigation section
|
|
1187
|
+
{ text: 'Navigation', sectionId: 'navigation', type: 'section' },
|
|
1188
|
+
{ text: 'Breadcrumbs', sectionId: 'navigation', subsectionTitle: 'Breadcrumbs', type: 'subsection' },
|
|
1189
|
+
{ text: 'Tabs - Pill Variant', sectionId: 'navigation', subsectionTitle: 'Tabs - Pill Variant', type: 'subsection' },
|
|
1190
|
+
{ text: 'Tabs - Line Variant', sectionId: 'navigation', subsectionTitle: 'Tabs - Line Variant', type: 'subsection' },
|
|
1191
|
+
{ text: 'Dividers', sectionId: 'navigation', subsectionTitle: 'Dividers', type: 'subsection' },
|
|
1192
|
+
{ text: 'Vertical Divider', sectionId: 'navigation', subsectionTitle: 'Vertical Divider', type: 'subsection' },
|
|
1193
|
+
{ text: 'Home', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1194
|
+
{ text: 'Products', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1195
|
+
{ text: 'Electronics', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1196
|
+
{ text: 'Current Page', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1197
|
+
{ text: 'About', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1198
|
+
{ text: 'Team', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1199
|
+
{ text: 'Dashboard', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1200
|
+
{ text: 'Settings', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1201
|
+
{ text: 'Profile', sectionId: 'navigation', type: 'breadcrumb' },
|
|
1202
|
+
{ text: 'Tab One', sectionId: 'navigation', type: 'tab' },
|
|
1203
|
+
{ text: 'Tab Two', sectionId: 'navigation', type: 'tab' },
|
|
1204
|
+
{ text: 'Tab Three', sectionId: 'navigation', type: 'tab' },
|
|
1205
|
+
{ text: 'First', sectionId: 'navigation', type: 'tab' },
|
|
1206
|
+
{ text: 'Second', sectionId: 'navigation', type: 'tab' },
|
|
1207
|
+
{ text: 'Third', sectionId: 'navigation', type: 'tab' },
|
|
1208
|
+
{ text: 'Solid', sectionId: 'navigation', type: 'divider' },
|
|
1209
|
+
{ text: 'Dashed', sectionId: 'navigation', type: 'divider' },
|
|
1210
|
+
{ text: 'Decorated', sectionId: 'navigation', type: 'divider' },
|
|
1211
|
+
|
|
1212
|
+
// Overlays section
|
|
1213
|
+
{ text: 'Overlays', sectionId: 'overlays', type: 'section' },
|
|
1214
|
+
{ text: 'Dialog', sectionId: 'overlays', subsectionTitle: 'Dialog', type: 'subsection' },
|
|
1215
|
+
{ text: 'Dropdown Menu', sectionId: 'overlays', subsectionTitle: 'Dropdown Menu', type: 'subsection' },
|
|
1216
|
+
{ text: 'Popover', sectionId: 'overlays', subsectionTitle: 'Popover', type: 'subsection' },
|
|
1217
|
+
{ text: 'Sheet', sectionId: 'overlays', subsectionTitle: 'Sheet', type: 'subsection' },
|
|
1218
|
+
{ text: 'Help Panel', sectionId: 'overlays', subsectionTitle: 'Help Panel', type: 'subsection' },
|
|
1219
|
+
{ text: 'Context Menu', sectionId: 'overlays', subsectionTitle: 'Context Menu', type: 'subsection' },
|
|
1220
|
+
{ text: 'Open Dialog', sectionId: 'overlays', type: 'button' },
|
|
1221
|
+
{ text: 'Open Menu', sectionId: 'overlays', type: 'button' },
|
|
1222
|
+
{ text: 'Open Popover', sectionId: 'overlays', type: 'button' },
|
|
1223
|
+
{ text: 'Top Popover', sectionId: 'overlays', type: 'button' },
|
|
1224
|
+
{ text: 'Open Sheet (Right)', sectionId: 'overlays', type: 'button' },
|
|
1225
|
+
{ text: 'Open Sheet (Left)', sectionId: 'overlays', type: 'button' },
|
|
1226
|
+
{ text: 'Open Help Panel', sectionId: 'overlays', type: 'button' },
|
|
1227
|
+
{ text: 'Save', sectionId: 'overlays', type: 'button' },
|
|
1228
|
+
{ text: 'Actions', sectionId: 'overlays', type: 'menu' },
|
|
1229
|
+
{ text: 'Cut', sectionId: 'overlays', type: 'menu' },
|
|
1230
|
+
{ text: 'Paste', sectionId: 'overlays', type: 'menu' },
|
|
1231
|
+
{ text: 'Duplicate', sectionId: 'overlays', type: 'menu' },
|
|
1232
|
+
{ text: 'Disabled Item', sectionId: 'overlays', type: 'menu' },
|
|
1233
|
+
];
|
|
1234
|
+
|
|
1235
|
+
// Section title lookup map
|
|
1236
|
+
const SECTION_TITLES: Record<string, string> = {
|
|
1237
|
+
buttons: 'Buttons',
|
|
1238
|
+
cards: 'Cards',
|
|
1239
|
+
forms: 'Forms',
|
|
1240
|
+
feedback: 'Feedback',
|
|
1241
|
+
navigation: 'Navigation',
|
|
1242
|
+
overlays: 'Overlays',
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
// Subsection title to ID mapping
|
|
1246
|
+
const SUBSECTION_ID_MAP: Record<string, string> = {
|
|
1247
|
+
'Button Variants': 'button-variants',
|
|
1248
|
+
'Button Sizes': 'button-sizes',
|
|
1249
|
+
'Button with Icon': 'button-with-icon',
|
|
1250
|
+
'Card Variants': 'card-variants',
|
|
1251
|
+
'Card with Header/Footer': 'card-with-header-footer',
|
|
1252
|
+
'Text Inputs': 'text-inputs',
|
|
1253
|
+
'Input Sizes': 'input-sizes',
|
|
1254
|
+
'TextArea': 'textarea',
|
|
1255
|
+
'Select': 'select',
|
|
1256
|
+
'Checkbox & Radio': 'checkbox-radio',
|
|
1257
|
+
'Switch': 'switch',
|
|
1258
|
+
'Slider': 'slider',
|
|
1259
|
+
'Alert': 'alert',
|
|
1260
|
+
'Badge Variants': 'badge-variants',
|
|
1261
|
+
'Progress': 'progress',
|
|
1262
|
+
'Progress Sizes': 'progress-sizes',
|
|
1263
|
+
'Spinner': 'spinner',
|
|
1264
|
+
'Toast': 'toast',
|
|
1265
|
+
'Tooltip': 'tooltip',
|
|
1266
|
+
'Breadcrumbs': 'breadcrumbs',
|
|
1267
|
+
'Tabs - Pill Variant': 'tabs-pill-variant',
|
|
1268
|
+
'Tabs - Line Variant': 'tabs-line-variant',
|
|
1269
|
+
'Dividers': 'dividers',
|
|
1270
|
+
'Vertical Divider': 'vertical-divider',
|
|
1271
|
+
'Dialog': 'dialog',
|
|
1272
|
+
'Dropdown Menu': 'dropdown-menu',
|
|
1273
|
+
'Popover': 'popover',
|
|
1274
|
+
'Sheet': 'sheet',
|
|
1275
|
+
'Help Panel': 'help-panel',
|
|
1276
|
+
'Context Menu': 'context-menu',
|
|
1277
|
+
};
|
|
1278
|
+
|
|
1279
|
+
// ============================================================================
|
|
1280
|
+
// Autocomplete Component
|
|
1281
|
+
// ============================================================================
|
|
1282
|
+
|
|
1283
|
+
interface AutocompleteProps {
|
|
1284
|
+
query: string;
|
|
1285
|
+
suggestions: SearchableItem[];
|
|
1286
|
+
selectedIndex: number;
|
|
1287
|
+
onSelect: (item: SearchableItem) => void;
|
|
1288
|
+
onClose: () => void;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
function Autocomplete({ query, suggestions, selectedIndex, onSelect, onClose }: AutocompleteProps) {
|
|
1292
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
1293
|
+
|
|
1294
|
+
useEffect(() => {
|
|
1295
|
+
if (listRef.current && selectedIndex >= 0 && selectedIndex < suggestions.length) {
|
|
1296
|
+
const selectedElement = listRef.current.children[selectedIndex] as HTMLElement;
|
|
1297
|
+
if (selectedElement) {
|
|
1298
|
+
selectedElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}, [selectedIndex, suggestions.length]);
|
|
1302
|
+
|
|
1303
|
+
if (suggestions.length === 0 || !query) {
|
|
1304
|
+
return null;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
const highlightText = (text: string, query: string) => {
|
|
1308
|
+
const index = text.toLowerCase().indexOf(query.toLowerCase());
|
|
1309
|
+
if (index === -1) return text;
|
|
1310
|
+
return (
|
|
1311
|
+
<>
|
|
1312
|
+
{text.substring(0, index)}
|
|
1313
|
+
<span className="bg-sun-yellow">{text.substring(index, index + query.length)}</span>
|
|
1314
|
+
{text.substring(index + query.length)}
|
|
1315
|
+
</>
|
|
1316
|
+
);
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
return (
|
|
1320
|
+
<div
|
|
1321
|
+
ref={listRef}
|
|
1322
|
+
className="absolute z-50 w-full mt-1 bg-warm-cloud border border-black rounded-sm shadow-[4px_4px_0_0_var(--color-black)] max-h-64 overflow-y-auto"
|
|
1323
|
+
>
|
|
1324
|
+
{suggestions.map((item, index) => {
|
|
1325
|
+
const sectionTitle = SECTION_TITLES[item.sectionId];
|
|
1326
|
+
const isSubsection = item.subsectionTitle !== undefined;
|
|
1327
|
+
const displayTitle = isSubsection ? item.subsectionTitle : sectionTitle;
|
|
1328
|
+
|
|
1329
|
+
return (
|
|
1330
|
+
<button
|
|
1331
|
+
key={`${item.sectionId}-${item.text}-${index}`}
|
|
1332
|
+
type="button"
|
|
1333
|
+
onClick={() => onSelect(item)}
|
|
1334
|
+
className={`w-full text-left px-3 py-2 font-mondwest text-sm transition-colors ${
|
|
1335
|
+
index === selectedIndex
|
|
1336
|
+
? 'bg-sun-yellow text-black'
|
|
1337
|
+
: 'bg-warm-cloud text-black hover:bg-black/5'
|
|
1338
|
+
} ${isSubsection ? 'pl-6' : ''}`}
|
|
1339
|
+
>
|
|
1340
|
+
<div className="flex items-center justify-between">
|
|
1341
|
+
<div className="flex flex-col gap-0.5">
|
|
1342
|
+
{displayTitle && (
|
|
1343
|
+
<span className="font-joystix text-xs font-bold text-black/60 uppercase">
|
|
1344
|
+
{displayTitle}
|
|
1345
|
+
</span>
|
|
1346
|
+
)}
|
|
1347
|
+
<span>{highlightText(item.text, query)}</span>
|
|
1348
|
+
</div>
|
|
1349
|
+
<span className="text-xs text-black/40 uppercase">{item.type}</span>
|
|
1350
|
+
</div>
|
|
1351
|
+
</button>
|
|
1352
|
+
);
|
|
1353
|
+
})}
|
|
1354
|
+
</div>
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// ============================================================================
|
|
1359
|
+
// Main Component
|
|
1360
|
+
// ============================================================================
|
|
1361
|
+
|
|
1362
|
+
// Component sections for search filtering
|
|
1363
|
+
const COMPONENT_SECTIONS = [
|
|
1364
|
+
{ id: 'buttons', title: 'Buttons', content: <ButtonsContent /> },
|
|
1365
|
+
{ id: 'cards', title: 'Cards', content: <CardsContent /> },
|
|
1366
|
+
{ id: 'forms', title: 'Forms', content: <FormsContent /> },
|
|
1367
|
+
{ id: 'feedback', title: 'Feedback', content: <FeedbackContent /> },
|
|
1368
|
+
{ id: 'navigation', title: 'Navigation', content: <NavigationContent /> },
|
|
1369
|
+
{ id: 'overlays', title: 'Overlays', content: <OverlaysContent /> },
|
|
1370
|
+
];
|
|
1371
|
+
|
|
1372
|
+
interface DesignSystemTabProps {
|
|
1373
|
+
searchQuery?: string;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
export function DesignSystemTab({ searchQuery: propSearchQuery = '' }: DesignSystemTabProps) {
|
|
1377
|
+
const searchQuery = propSearchQuery;
|
|
1378
|
+
|
|
1379
|
+
// Get matching suggestions (for autocomplete in footer)
|
|
1380
|
+
const suggestions = searchQuery
|
|
1381
|
+
? SEARCH_INDEX.filter((item) =>
|
|
1382
|
+
item.text.toLowerCase().includes(searchQuery.toLowerCase())
|
|
1383
|
+
).slice(0, 10)
|
|
1384
|
+
: [];
|
|
1385
|
+
|
|
1386
|
+
// Filter sections based on search query
|
|
1387
|
+
const filteredSections = searchQuery
|
|
1388
|
+
? (() => {
|
|
1389
|
+
const queryLower = searchQuery.toLowerCase().trim();
|
|
1390
|
+
|
|
1391
|
+
// Check for exact match first (case-insensitive)
|
|
1392
|
+
const exactMatch = SEARCH_INDEX.find(
|
|
1393
|
+
(item) => item.text.toLowerCase() === queryLower
|
|
1394
|
+
);
|
|
1395
|
+
|
|
1396
|
+
if (exactMatch) {
|
|
1397
|
+
// If exact match is a subsection, we'll filter subsections via CSS
|
|
1398
|
+
if (exactMatch.subsectionTitle) {
|
|
1399
|
+
// Show the section containing this subsection
|
|
1400
|
+
return COMPONENT_SECTIONS.filter(
|
|
1401
|
+
(section) => section.id === exactMatch.sectionId
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
// If exact match is a section title, show all subsections in that section
|
|
1405
|
+
if (exactMatch.type === 'section') {
|
|
1406
|
+
return COMPONENT_SECTIONS.filter(
|
|
1407
|
+
(section) => section.id === exactMatch.sectionId
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
// Otherwise, only show the section containing that item
|
|
1411
|
+
return COMPONENT_SECTIONS.filter(
|
|
1412
|
+
(section) => section.id === exactMatch.sectionId
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// Check if query matches a subsection title
|
|
1417
|
+
const subsectionMatch = Object.keys(SUBSECTION_ID_MAP).find(
|
|
1418
|
+
(title) => title.toLowerCase() === queryLower
|
|
1419
|
+
);
|
|
1420
|
+
|
|
1421
|
+
if (subsectionMatch) {
|
|
1422
|
+
const subsectionId = SUBSECTION_ID_MAP[subsectionMatch];
|
|
1423
|
+
// Find which section contains this subsection
|
|
1424
|
+
const subsectionItem = SEARCH_INDEX.find(
|
|
1425
|
+
(item) => item.subsectionTitle === subsectionMatch
|
|
1426
|
+
);
|
|
1427
|
+
if (subsectionItem) {
|
|
1428
|
+
return COMPONENT_SECTIONS.filter(
|
|
1429
|
+
(section) => section.id === subsectionItem.sectionId
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// Check if query matches a section title
|
|
1435
|
+
const sectionMatch = Object.values(SECTION_TITLES).find(
|
|
1436
|
+
(title) => title.toLowerCase() === queryLower
|
|
1437
|
+
);
|
|
1438
|
+
|
|
1439
|
+
if (sectionMatch) {
|
|
1440
|
+
// Show all subsections in that section
|
|
1441
|
+
const sectionId = Object.keys(SECTION_TITLES).find(
|
|
1442
|
+
(id) => SECTION_TITLES[id] === sectionMatch
|
|
1443
|
+
);
|
|
1444
|
+
if (sectionId) {
|
|
1445
|
+
return COMPONENT_SECTIONS.filter(
|
|
1446
|
+
(section) => section.id === sectionId
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// Otherwise, use the existing fuzzy matching logic
|
|
1452
|
+
return COMPONENT_SECTIONS.filter((section) => {
|
|
1453
|
+
// Check if section title matches
|
|
1454
|
+
if (section.title.toLowerCase().includes(queryLower)) {
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
// Check if any searchable item in this section matches
|
|
1458
|
+
return SEARCH_INDEX.some(
|
|
1459
|
+
(item) =>
|
|
1460
|
+
item.sectionId === section.id &&
|
|
1461
|
+
item.text.toLowerCase().includes(queryLower)
|
|
1462
|
+
);
|
|
1463
|
+
});
|
|
1464
|
+
})()
|
|
1465
|
+
: COMPONENT_SECTIONS;
|
|
1466
|
+
|
|
1467
|
+
// Determine which subsection to show (if any)
|
|
1468
|
+
const activeSubsectionId = searchQuery
|
|
1469
|
+
? (() => {
|
|
1470
|
+
const queryLower = searchQuery.toLowerCase().trim();
|
|
1471
|
+
const exactMatch = SEARCH_INDEX.find(
|
|
1472
|
+
(item) => item.text.toLowerCase() === queryLower
|
|
1473
|
+
);
|
|
1474
|
+
if (exactMatch?.subsectionTitle) {
|
|
1475
|
+
return SUBSECTION_ID_MAP[exactMatch.subsectionTitle];
|
|
1476
|
+
}
|
|
1477
|
+
const subsectionMatch = Object.keys(SUBSECTION_ID_MAP).find(
|
|
1478
|
+
(title) => title.toLowerCase() === queryLower
|
|
1479
|
+
);
|
|
1480
|
+
if (subsectionMatch) {
|
|
1481
|
+
return SUBSECTION_ID_MAP[subsectionMatch];
|
|
1482
|
+
}
|
|
1483
|
+
return null;
|
|
1484
|
+
})()
|
|
1485
|
+
: null;
|
|
1486
|
+
|
|
1487
|
+
|
|
1488
|
+
return (
|
|
1489
|
+
<ToastProvider>
|
|
1490
|
+
<div className="flex flex-col h-full overflow-auto pt-4 pb-4 pl-4 pr-2 bg-[var(--color-white)] border border-black rounded">
|
|
1491
|
+
{/* Component Sections */}
|
|
1492
|
+
{activeSubsectionId && (
|
|
1493
|
+
<style>{`
|
|
1494
|
+
div[data-subsection-id]:not([data-subsection-id="${activeSubsectionId}"]) {
|
|
1495
|
+
display: none !important;
|
|
1496
|
+
}
|
|
1497
|
+
`}</style>
|
|
1498
|
+
)}
|
|
1499
|
+
<div className="space-y-0">
|
|
1500
|
+
{filteredSections.length > 0 ? (
|
|
1501
|
+
filteredSections.map((section) => (
|
|
1502
|
+
<div key={section.id} className="mb-6">
|
|
1503
|
+
<Section title={section.title}>{section.content}</Section>
|
|
1504
|
+
</div>
|
|
1505
|
+
))
|
|
1506
|
+
) : (
|
|
1507
|
+
<div className="text-center py-8 text-black/60 font-mondwest text-base">
|
|
1508
|
+
No components match "{searchQuery}"
|
|
1509
|
+
</div>
|
|
1510
|
+
)}
|
|
1511
|
+
</div>
|
|
1512
|
+
</div>
|
|
1513
|
+
</ToastProvider>
|
|
1514
|
+
);
|
|
1515
|
+
}
|