create-lego-one 2.0.12 → 2.0.14
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/index.cjs +150 -15
- package/dist/index.cjs.map +1 -1
- package/package.json +1 -1
- package/template/.cursor/rules/rules.mdc +639 -0
- package/template/.dockerignore +58 -0
- package/template/.env.example +18 -0
- package/template/.eslintignore +5 -0
- package/template/.eslintrc.js +28 -0
- package/template/.prettierignore +6 -0
- package/template/.prettierrc +11 -0
- package/template/CLAUDE.md +634 -0
- package/template/Dockerfile +67 -0
- package/template/PROMPT.md +457 -0
- package/template/README.md +325 -0
- package/template/docker-compose.yml +48 -0
- package/template/docker-entrypoint.sh +23 -0
- package/template/docs/checkpoints/.template.md +64 -0
- package/template/docs/checkpoints/framework/01-infrastructure-setup.md +132 -0
- package/template/docs/checkpoints/framework/02-pocketbase-setup.md +155 -0
- package/template/docs/checkpoints/framework/03-host-kernel.md +170 -0
- package/template/docs/checkpoints/framework/04-auth-system.md +163 -0
- package/template/docs/checkpoints/framework/phase-05-multitenancy-rbac.md +223 -0
- package/template/docs/checkpoints/framework/phase-06-ui-components.md +260 -0
- package/template/docs/checkpoints/framework/phase-07-communication-system.md +276 -0
- package/template/docs/checkpoints/framework/phase-08-plugin-system.md +91 -0
- package/template/docs/checkpoints/framework/phase-09-dashboard-plugin.md +111 -0
- package/template/docs/checkpoints/framework/phase-10-todo-plugin.md +169 -0
- package/template/docs/checkpoints/framework/phase-11-testing.md +264 -0
- package/template/docs/checkpoints/framework/phase-12-deployment.md +294 -0
- package/template/docs/checkpoints/framework/phase-13-documentation.md +312 -0
- package/template/docs/framework/plans/00-index.md +164 -0
- package/template/docs/framework/plans/01-infrastructure-setup.md +855 -0
- package/template/docs/framework/plans/02-pocketbase-setup.md +1374 -0
- package/template/docs/framework/plans/03-host-kernel.md +1518 -0
- package/template/docs/framework/plans/04-auth-system.md +1466 -0
- package/template/docs/framework/plans/05-multitenancy-rbac.md +1527 -0
- package/template/docs/framework/plans/06-ui-components.md +1478 -0
- package/template/docs/framework/plans/07-communication-system.md +1106 -0
- package/template/docs/framework/plans/08-plugin-system.md +1179 -0
- package/template/docs/framework/plans/09-dashboard-plugin.md +1137 -0
- package/template/docs/framework/plans/10-todo-plugin.md +1343 -0
- package/template/docs/framework/plans/11-testing.md +935 -0
- package/template/docs/framework/plans/12-deployment.md +896 -0
- package/template/docs/framework/prompts/0-boilerplate-modernjs.md +151 -0
- package/template/docs/framework/research/00-modernjs-audit.md +488 -0
- package/template/docs/framework/research/01-system-blueprint.md +721 -0
- package/template/docs/framework/research/02-data-migration-protocol.md +699 -0
- package/template/docs/framework/research/03-host-setup.md +714 -0
- package/template/docs/framework/research/04-plugin-architecture.md +645 -0
- package/template/docs/framework/research/05-slot-injection-pattern.md +671 -0
- package/template/docs/framework/research/06-cli-strategy.md +615 -0
- package/template/docs/framework/research/07-deployment.md +629 -0
- package/template/docs/framework/research/README.md +282 -0
- package/template/docs/framework/setup/00-index.md +210 -0
- package/template/docs/framework/setup/01-framework-structure.md +308 -0
- package/template/docs/framework/setup/02-development-workflow.md +405 -0
- package/template/docs/framework/setup/03-environment-setup.md +215 -0
- package/template/docs/framework/setup/04-kernel-architecture.md +499 -0
- package/template/docs/framework/setup/05-plugin-system.md +620 -0
- package/template/docs/framework/setup/06-communication-patterns.md +451 -0
- package/template/docs/framework/setup/07-plugin-development.md +582 -0
- package/template/docs/framework/setup/08-component-library.md +658 -0
- package/template/docs/framework/setup/09-data-integration.md +609 -0
- package/template/docs/framework/setup/10-auth-rbac.md +497 -0
- package/template/docs/framework/setup/11-hooks-api.md +393 -0
- package/template/docs/framework/setup/12-components-api.md +665 -0
- package/template/docs/framework/setup/13-deployment-guide.md +566 -0
- package/template/docs/framework/setup/README.md +548 -0
- package/template/host/package.json +1 -1
- package/template/nginx.conf +72 -0
- package/template/package.json +1 -1
- package/template/packages/plugins/@lego/plugin-dashboard/package.json +1 -1
- package/template/packages/plugins/@lego/plugin-todo/package.json +1 -1
- package/template/pocketbase/CHANGELOG.md +911 -0
- package/template/pocketbase/LICENSE.md +17 -0
- package/template/scripts/create-plugin.js +221 -0
- package/template/scripts/deploy.sh +56 -0
- package/template/tsconfig.base.json +26 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
# Component Library
|
|
2
|
+
|
|
3
|
+
**UI Components, Styling, and Design System**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Lego-One uses **Radix UI primitives** styled with **Tailwind CSS** for accessible, customizable UI components. All components support dark mode and follow WCAG accessibility guidelines.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Design System
|
|
14
|
+
|
|
15
|
+
### Colors
|
|
16
|
+
|
|
17
|
+
CSS variables enable theming and dark mode:
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
:root {
|
|
21
|
+
--background: 0 0% 100%; /* White background */
|
|
22
|
+
--foreground: 222.2 84% 4.9%; /* Dark text */
|
|
23
|
+
--primary: 221.2 83.2% 53.3%; /* Primary blue */
|
|
24
|
+
--primary-foreground: 210 40% 98%;
|
|
25
|
+
--secondary: 210 40% 96.1%;
|
|
26
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
27
|
+
--muted: 210 40% 96.1%;
|
|
28
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
29
|
+
--accent: 210 40% 96.1%;
|
|
30
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
31
|
+
--destructive: 0 84.2% 60.2%;
|
|
32
|
+
--destructive-foreground: 210 40% 98%;
|
|
33
|
+
--border: 214.3 31.8% 91.4%;
|
|
34
|
+
--input: 214.3 31.8% 91.4%;
|
|
35
|
+
--ring: 221.2 83.2% 53.3%;
|
|
36
|
+
--radius: 0.5rem;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Usage:**
|
|
41
|
+
```tsx
|
|
42
|
+
<div className="bg-background text-foreground">
|
|
43
|
+
<h1 className="text-primary">Primary colored heading</h1>
|
|
44
|
+
<p className="text-muted-foreground">Muted text</p>
|
|
45
|
+
</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Dark Mode
|
|
49
|
+
|
|
50
|
+
Dark mode is automatic via the `dark:` class prefix:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<div className="bg-background dark:bg-gray-950">
|
|
54
|
+
<p className="text-foreground dark:text-gray-100">
|
|
55
|
+
Adapts to dark mode
|
|
56
|
+
</p>
|
|
57
|
+
</div>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Tailwind Config:**
|
|
61
|
+
```typescript
|
|
62
|
+
darkMode: ['class'], // Enables .dark class on html element
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Typography
|
|
66
|
+
|
|
67
|
+
**Font:** Inter (via system fonts)
|
|
68
|
+
|
|
69
|
+
**Scale:**
|
|
70
|
+
```tsx
|
|
71
|
+
<h1 className="text-3xl font-bold">Heading 1</h1>
|
|
72
|
+
<h2 className="text-2xl font-semibold">Heading 2</h2>
|
|
73
|
+
<h3 className="text-xl font-medium">Heading 3</h3>
|
|
74
|
+
<p className="text-sm">Body text</p>
|
|
75
|
+
<span className="text-xs">Small text</span>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Spacing
|
|
79
|
+
|
|
80
|
+
**Scale:** 4px base unit (Tailwind default)
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<div className="p-4"> /* 16px padding */
|
|
84
|
+
<div className="px-6"> /* 24px horizontal padding */
|
|
85
|
+
<div className="py-2"> /* 8px vertical padding */
|
|
86
|
+
<div className="m-8"> /* 32px margin */
|
|
87
|
+
<div className="gap-4"> /* 16px gap (flex/grid) */
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Available Components
|
|
93
|
+
|
|
94
|
+
### Form Components
|
|
95
|
+
|
|
96
|
+
#### Button
|
|
97
|
+
|
|
98
|
+
**Import:** `import { Button } from '@lego/kernel/components'`
|
|
99
|
+
|
|
100
|
+
**Variants:**
|
|
101
|
+
```tsx
|
|
102
|
+
<Button>Default</Button>
|
|
103
|
+
<Button variant="secondary">Secondary</Button>
|
|
104
|
+
<Button variant="destructive">Delete</Button>
|
|
105
|
+
<Button variant="outline">Outline</Button>
|
|
106
|
+
<Button variant="ghost">Ghost</Button>
|
|
107
|
+
<Button variant="link">Link</Button>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Sizes:**
|
|
111
|
+
```tsx
|
|
112
|
+
<Button size="default">Default</Button>
|
|
113
|
+
<Button size="sm">Small</Button>
|
|
114
|
+
<Button size="lg">Large</Button>
|
|
115
|
+
<Button size="icon"><Icon /></Button>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**States:**
|
|
119
|
+
```tsx
|
|
120
|
+
<Button disabled>Disabled</Button>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
#### Input
|
|
126
|
+
|
|
127
|
+
**Import:** `import { Input } from '@lego/kernel/components'`
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<Input placeholder="Enter text..." />
|
|
131
|
+
<Input type="password" placeholder="Password" />
|
|
132
|
+
<Input type="email" placeholder="Email" />
|
|
133
|
+
<Input disabled value="Disabled" />
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
#### Label
|
|
139
|
+
|
|
140
|
+
**Import:** `import { Label } from '@lego/kernel/components'`
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<Label htmlFor="email">Email</Label>
|
|
144
|
+
<Input id="email" type="email" />
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
#### Textarea
|
|
150
|
+
|
|
151
|
+
**Import:** `import { Textarea } from '@lego/kernel/components'`
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
<Textarea placeholder="Enter description..." rows={5} />
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
#### Select
|
|
160
|
+
|
|
161
|
+
**Import:** `import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue }`
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<Select>
|
|
165
|
+
<SelectTrigger>
|
|
166
|
+
<SelectValue placeholder="Select option" />
|
|
167
|
+
</SelectTrigger>
|
|
168
|
+
<SelectContent>
|
|
169
|
+
<SelectItem value="1">Option 1</SelectItem>
|
|
170
|
+
<SelectItem value="2">Option 2</SelectItem>
|
|
171
|
+
<SelectItem value="3">Option 3</SelectItem>
|
|
172
|
+
</SelectContent>
|
|
173
|
+
</Select>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
#### Checkbox
|
|
179
|
+
|
|
180
|
+
**Import:** `import { Checkbox } from '@lego/kernel/components'`
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
<Checkbox checked={checked} onCheckedChange={setChecked} />
|
|
184
|
+
<Checkbox disabled />
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
#### Switch
|
|
190
|
+
|
|
191
|
+
**Import:** `import { Switch } from '@lego/kernel/components'`
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
<Switch checked={enabled} onCheckedChange={setEnabled} />
|
|
195
|
+
<Switch disabled />
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### Layout Components
|
|
201
|
+
|
|
202
|
+
#### Card
|
|
203
|
+
|
|
204
|
+
**Import:** `import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }`
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
<Card>
|
|
208
|
+
<CardHeader>
|
|
209
|
+
<CardTitle>Card Title</CardTitle>
|
|
210
|
+
<CardDescription>Card description</CardDescription>
|
|
211
|
+
</CardHeader>
|
|
212
|
+
<CardContent>
|
|
213
|
+
<p>Card content</p>
|
|
214
|
+
</CardContent>
|
|
215
|
+
<CardFooter>
|
|
216
|
+
<Button>Action</Button>
|
|
217
|
+
</CardFooter>
|
|
218
|
+
</Card>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
#### Separator
|
|
224
|
+
|
|
225
|
+
**Import:** `import { Separator } from '@lego/kernel/components'`
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
<Separator /> {/* Horizontal */}
|
|
229
|
+
<Separator orientation="vertical" className="h-8" /> {/* Vertical */}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
#### ScrollArea
|
|
235
|
+
|
|
236
|
+
**Import:** `import { ScrollArea } from '@lego/kernel/components'`
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<ScrollArea className="h-96">
|
|
240
|
+
<div className="p-4">
|
|
241
|
+
{/* Long content */}
|
|
242
|
+
</div>
|
|
243
|
+
</ScrollArea>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Feedback Components
|
|
249
|
+
|
|
250
|
+
#### Alert
|
|
251
|
+
|
|
252
|
+
**Import:** `import { Alert, AlertDescription, AlertTitle }`
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
<Alert>
|
|
256
|
+
<AlertCircle className="h-4 w-4" />
|
|
257
|
+
<AlertTitle>Info</AlertTitle>
|
|
258
|
+
<AlertDescription>This is an informational message.</AlertDescription>
|
|
259
|
+
</Alert>
|
|
260
|
+
|
|
261
|
+
<Alert variant="destructive">
|
|
262
|
+
<AlertTitle>Error</AlertTitle>
|
|
263
|
+
<AlertDescription>Something went wrong.</AlertDescription>
|
|
264
|
+
</Alert>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
#### Badge
|
|
270
|
+
|
|
271
|
+
**Import:** `import { Badge } from '@lego/kernel/components'`
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
<Badge>Default</Badge>
|
|
275
|
+
<Badge variant="secondary">Secondary</Badge>
|
|
276
|
+
<Badge variant="destructive">Error</Badge>
|
|
277
|
+
<Badge variant="outline">Outline</Badge>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
#### Progress
|
|
283
|
+
|
|
284
|
+
**Import:** `import { Progress } from '@lego/kernel/components'`
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
<Progress value={33} />
|
|
288
|
+
<Progress value={66} className="w-96" />
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
#### Skeleton
|
|
294
|
+
|
|
295
|
+
**Import:** `import { Skeleton } from '@lego/kernel/components'`
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
<Skeleton className="h-12 w-12 rounded-full" />
|
|
299
|
+
<Skeleton className="h-4 w-64" />
|
|
300
|
+
<Skeleton className="h-96 w-full" />
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
#### Toast
|
|
306
|
+
|
|
307
|
+
**Import:** `import { useToast } from '@lego/kernel/components'`
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
// In root App.tsx
|
|
311
|
+
<Toaster />
|
|
312
|
+
|
|
313
|
+
// In component
|
|
314
|
+
function MyComponent() {
|
|
315
|
+
const { toast } = useToast();
|
|
316
|
+
|
|
317
|
+
return (
|
|
318
|
+
<Button onClick={() => {
|
|
319
|
+
toast({
|
|
320
|
+
title: 'Success',
|
|
321
|
+
description: 'Operation completed',
|
|
322
|
+
});
|
|
323
|
+
}}>
|
|
324
|
+
Show Toast
|
|
325
|
+
</Button>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### Navigation Components
|
|
333
|
+
|
|
334
|
+
#### Tabs
|
|
335
|
+
|
|
336
|
+
**Import:** `import { Tabs, TabsList, TabsTrigger, TabsContent }`
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
<Tabs defaultValue="tab1">
|
|
340
|
+
<TabsList>
|
|
341
|
+
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
342
|
+
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
343
|
+
</TabsList>
|
|
344
|
+
<TabsContent value="tab1">Content 1</TabsContent>
|
|
345
|
+
<TabsContent value="tab2">Content 2</TabsContent>
|
|
346
|
+
</Tabs>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
#### Dropdown Menu
|
|
352
|
+
|
|
353
|
+
**Import:** `import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator }`
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
<DropdownMenu>
|
|
357
|
+
<DropdownMenuTrigger asChild>
|
|
358
|
+
<Button variant="ghost">Menu</Button>
|
|
359
|
+
</DropdownMenuTrigger>
|
|
360
|
+
<DropdownMenuContent>
|
|
361
|
+
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
362
|
+
<DropdownMenuSeparator />
|
|
363
|
+
<DropdownMenuItem>Profile</DropdownMenuItem>
|
|
364
|
+
<DropdownMenuItem>Settings</DropdownMenuItem>
|
|
365
|
+
<DropdownMenuSeparator />
|
|
366
|
+
<DropdownMenuItem>Logout</DropdownMenuItem>
|
|
367
|
+
</DropdownMenuContent>
|
|
368
|
+
</DropdownMenu>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
### Display Components
|
|
374
|
+
|
|
375
|
+
#### Avatar
|
|
376
|
+
|
|
377
|
+
**Import:** `import { Avatar, AvatarImage, AvatarFallback }`
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
<Avatar>
|
|
381
|
+
<AvatarImage src="/avatar.jpg" alt="User" />
|
|
382
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
383
|
+
</Avatar>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
#### Table
|
|
389
|
+
|
|
390
|
+
**Import:** `import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell }`
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
<Table>
|
|
394
|
+
<TableHeader>
|
|
395
|
+
<TableRow>
|
|
396
|
+
<TableHead>Name</TableHead>
|
|
397
|
+
<TableHead>Email</TableHead>
|
|
398
|
+
</TableRow>
|
|
399
|
+
</TableHeader>
|
|
400
|
+
<TableBody>
|
|
401
|
+
<TableRow>
|
|
402
|
+
<TableCell>John Doe</TableCell>
|
|
403
|
+
<TableCell>john@example.com</TableCell>
|
|
404
|
+
</TableRow>
|
|
405
|
+
</TableBody>
|
|
406
|
+
</Table>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### Overlay Components
|
|
412
|
+
|
|
413
|
+
#### Dialog
|
|
414
|
+
|
|
415
|
+
**Import:** `import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger }`
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
<Dialog>
|
|
419
|
+
<DialogTrigger asChild>
|
|
420
|
+
<Button>Open Dialog</Button>
|
|
421
|
+
</DialogTrigger>
|
|
422
|
+
<DialogContent>
|
|
423
|
+
<DialogHeader>
|
|
424
|
+
<DialogTitle>Confirm Action</DialogTitle>
|
|
425
|
+
<DialogDescription>
|
|
426
|
+
This action cannot be undone.
|
|
427
|
+
</DialogDescription>
|
|
428
|
+
</DialogHeader>
|
|
429
|
+
<div className="flex justify-end gap-2">
|
|
430
|
+
<Button variant="outline">Cancel</Button>
|
|
431
|
+
<Button>Confirm</Button>
|
|
432
|
+
</div>
|
|
433
|
+
</DialogContent>
|
|
434
|
+
</Dialog>
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
#### Popover
|
|
440
|
+
|
|
441
|
+
**Import:** `import { Popover, PopoverContent, PopoverTrigger }`
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
<Popover>
|
|
445
|
+
<PopoverTrigger asChild>
|
|
446
|
+
<Button variant="ghost">Trigger</Button>
|
|
447
|
+
</PopoverTrigger>
|
|
448
|
+
<PopoverContent>
|
|
449
|
+
<div className="grid gap-4">
|
|
450
|
+
<h4 className="font-medium">Popover Content</h4>
|
|
451
|
+
<p className="text-sm text-muted-foreground">
|
|
452
|
+
Additional information
|
|
453
|
+
</p>
|
|
454
|
+
</div>
|
|
455
|
+
</PopoverContent>
|
|
456
|
+
</Popover>
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
#### Tooltip
|
|
462
|
+
|
|
463
|
+
**Import:** `import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }`
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
// Wrap app with TooltipProvider once
|
|
467
|
+
<TooltipProvider>
|
|
468
|
+
<App />
|
|
469
|
+
</TooltipProvider>
|
|
470
|
+
|
|
471
|
+
// Use tooltips
|
|
472
|
+
<Tooltip>
|
|
473
|
+
<TooltipTrigger>Hover me</TooltipTrigger>
|
|
474
|
+
<TooltipContent>
|
|
475
|
+
<p>Additional information</p>
|
|
476
|
+
</TooltipContent>
|
|
477
|
+
</Tooltip>
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Utility Functions
|
|
483
|
+
|
|
484
|
+
### cn() - Class Name Merger
|
|
485
|
+
|
|
486
|
+
**Import:** `import { cn } from '@lego/kernel/lib/utils'`
|
|
487
|
+
|
|
488
|
+
Merges Tailwind classes with conditional logic:
|
|
489
|
+
|
|
490
|
+
```tsx
|
|
491
|
+
import { cn } from '@lego/kernel/lib/utils';
|
|
492
|
+
|
|
493
|
+
function MyComponent({ isActive }: { isActive: boolean }) {
|
|
494
|
+
return (
|
|
495
|
+
<div className={cn(
|
|
496
|
+
'base-classes',
|
|
497
|
+
isActive && 'active-classes',
|
|
498
|
+
'always-applied'
|
|
499
|
+
)}>
|
|
500
|
+
Content
|
|
501
|
+
</div>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## Using Components in Plugins
|
|
509
|
+
|
|
510
|
+
Plugins can use kernel components via the window bridge or by importing if bundled:
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
// In plugin (bundled production)
|
|
514
|
+
import { Button, Card, Dialog } from '@lego/kernel/components';
|
|
515
|
+
|
|
516
|
+
function MyPluginComponent() {
|
|
517
|
+
return (
|
|
518
|
+
<Card>
|
|
519
|
+
<CardHeader>
|
|
520
|
+
<CardTitle>My Plugin</CardTitle>
|
|
521
|
+
</CardHeader>
|
|
522
|
+
<CardContent>
|
|
523
|
+
<Button>Click me</Button>
|
|
524
|
+
</CardContent>
|
|
525
|
+
</Card>
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Component Patterns
|
|
533
|
+
|
|
534
|
+
### Form with Validation
|
|
535
|
+
|
|
536
|
+
```tsx
|
|
537
|
+
import { useForm } from 'react-hook-form';
|
|
538
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
539
|
+
import { z } from 'zod';
|
|
540
|
+
import { Button, Input, Label } from '@lego/kernel/components';
|
|
541
|
+
|
|
542
|
+
const schema = z.object({
|
|
543
|
+
email: z.string().email(),
|
|
544
|
+
password: z.string().min(8),
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
function LoginForm() {
|
|
548
|
+
const { register, handleSubmit, formState: { errors } } = useForm({
|
|
549
|
+
resolver: zodResolver(schema),
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
return (
|
|
553
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
554
|
+
<div>
|
|
555
|
+
<Label htmlFor="email">Email</Label>
|
|
556
|
+
<Input {...register('email')} />
|
|
557
|
+
{errors.email && <span className="text-destructive">{errors.email.message}</span>}
|
|
558
|
+
</div>
|
|
559
|
+
<Button type="submit">Submit</Button>
|
|
560
|
+
</form>
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Data Table with Actions
|
|
566
|
+
|
|
567
|
+
```tsx
|
|
568
|
+
import { Button, DropdownMenu, Table } from '@lego/kernel/components';
|
|
569
|
+
import { MoreHorizontal } from 'lucide-react';
|
|
570
|
+
|
|
571
|
+
function DataTable({ data }: { data: Item[] }) {
|
|
572
|
+
return (
|
|
573
|
+
<Table>
|
|
574
|
+
<TableHeader>
|
|
575
|
+
<TableRow>
|
|
576
|
+
<TableHead>Name</TableHead>
|
|
577
|
+
<TableHead>Actions</TableHead>
|
|
578
|
+
</TableRow>
|
|
579
|
+
</TableHeader>
|
|
580
|
+
<TableBody>
|
|
581
|
+
{data.map((item) => (
|
|
582
|
+
<TableRow key={item.id}>
|
|
583
|
+
<TableCell>{item.name}</TableCell>
|
|
584
|
+
<TableCell>
|
|
585
|
+
<DropdownMenu>
|
|
586
|
+
<DropdownMenuTrigger asChild>
|
|
587
|
+
<Button size="icon" variant="ghost">
|
|
588
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
589
|
+
</Button>
|
|
590
|
+
</DropdownMenuTrigger>
|
|
591
|
+
<DropdownMenuContent>
|
|
592
|
+
<DropdownMenuItem>Edit</DropdownMenuItem>
|
|
593
|
+
<DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
|
|
594
|
+
</DropdownMenuContent>
|
|
595
|
+
</DropdownMenu>
|
|
596
|
+
</TableCell>
|
|
597
|
+
</TableRow>
|
|
598
|
+
))}
|
|
599
|
+
</TableBody>
|
|
600
|
+
</Table>
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Loading States
|
|
606
|
+
|
|
607
|
+
```tsx
|
|
608
|
+
import { Skeleton, Card, CardHeader, CardContent } from '@lego/kernel/components';
|
|
609
|
+
|
|
610
|
+
function LoadingCard() {
|
|
611
|
+
return (
|
|
612
|
+
<Card>
|
|
613
|
+
<CardHeader>
|
|
614
|
+
<Skeleton className="h-6 w-48" />
|
|
615
|
+
</CardHeader>
|
|
616
|
+
<CardContent>
|
|
617
|
+
<Skeleton className="h-4 w-full mb-2" />
|
|
618
|
+
<Skeleton className="h-4 w-3/4" />
|
|
619
|
+
</CardContent>
|
|
620
|
+
</Card>
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## Icons (Lucide React)
|
|
628
|
+
|
|
629
|
+
**Import:** `import { IconName } from 'lucide-react'`
|
|
630
|
+
|
|
631
|
+
```tsx
|
|
632
|
+
import { Home, Settings, User, Search, Plus, Trash } from 'lucide-react';
|
|
633
|
+
|
|
634
|
+
<Home className="h-5 w-5" />
|
|
635
|
+
<Settings className="h-6 w-6" />
|
|
636
|
+
<User className="h-4 w-4" />
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
**Common Icons:**
|
|
640
|
+
- **Navigation:** `Home`, `Settings`, `LayoutDashboard`, `CheckSquare`
|
|
641
|
+
- **Actions:** `Plus`, `Trash`, `Edit`, `Save`, `X`
|
|
642
|
+
- **UI:** `Menu`, `Bell`, `Search`, `ChevronDown`, `ChevronRight`
|
|
643
|
+
- **Status:** `Check`, `XCircle`, `AlertCircle`, `Loader2`
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## Best Practices
|
|
648
|
+
|
|
649
|
+
1. **Use existing components** - Don't recreate what exists
|
|
650
|
+
2. **Follow accessibility** - All Radix components are accessible by default
|
|
651
|
+
3. **Support dark mode** - Use `dark:` prefix for dark mode styles
|
|
652
|
+
4. **Use semantic HTML** - Button, Dialog, etc. render proper elements
|
|
653
|
+
5. **Handle loading/error states** - Use Skeleton, Alert for feedback
|
|
654
|
+
6. **Responsive design** - Mobile-first approach with Tailwind breakpoints
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
**Next:** Read [`09-data-integration.md`](./09-data-integration.md) for PocketBase and data fetching patterns.
|