@loykin/designkit 0.0.1-dev.1 → 0.0.1-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  React page template library. Provides ready-to-use page layouts for admin and dashboard applications.
4
4
 
5
+ For AI-assisted implementation in consuming applications, see the
6
+ [DesignKit Consumer Agent Guide](docs/consumer-guide.md).
7
+
5
8
  ## Installation
6
9
 
7
10
  ```bash
8
- npm install @loykin/designkit @loykin/gridkit
11
+ npm install @loykin/designkit
9
12
  ```
10
13
 
11
- Requires React 19 and Tailwind CSS v4. UI components are based on [shadcn/ui](https://ui.shadcn.com) — if your app has shadcn set up, theming integrates automatically via shared CSS variables (`--primary`, `--background`, `--radius`, etc.). You can customize every token through shadcn's theme without touching designkit directly.
14
+ Requires React 19 and Tailwind CSS v4. UI components are based on [shadcn/ui](https://ui.shadcn.com) — if your app has shadcn set up, theming integrates automatically via shared CSS variables (`--primary`, `--background`, `--radius`, etc.).
12
15
 
13
16
  Import the styles in your global CSS:
14
17
 
@@ -17,29 +20,24 @@ Import the styles in your global CSS:
17
20
  @import "@loykin/designkit/styles";
18
21
  ```
19
22
 
20
- This handles Tailwind class scanning automatically — no additional `@source` configuration needed.
23
+ The styles file includes pre-built Tailwind utility classes — no `@source` configuration required. You can also import the stylesheet from your app entry, as shown below.
21
24
 
22
25
  ## Quick Start
23
26
 
24
27
  ```tsx
25
- import { DataBodyTemplate, DataGridView, PageTopBar, type DataGridColumnDef } from '@loykin/designkit'
28
+ import { DataBodyTemplate, PageTopBar, Button } from '@loykin/designkit'
26
29
  import '@loykin/designkit/styles'
27
30
 
28
- type User = { id: string; name: string; email: string }
29
-
30
- const columns: DataGridColumnDef<User>[] = [
31
- { id: 'name', accessorKey: 'name', header: 'Name' },
32
- { id: 'email', accessorKey: 'email', header: 'Email' },
33
- ]
34
-
35
31
  export function UsersPage() {
36
32
  return (
37
33
  <DataBodyTemplate
38
34
  topBar={<PageTopBar left="Admin / Users" />}
39
35
  title="Users"
36
+ description="Manage your team members."
37
+ actions={<Button>Add User</Button>}
40
38
  >
41
39
  <DataBodyTemplate.Body>
42
- <DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
40
+ {/* your content */}
43
41
  </DataBodyTemplate.Body>
44
42
  </DataBodyTemplate>
45
43
  )
@@ -52,7 +50,7 @@ export function UsersPage() {
52
50
 
53
51
  ### DataBodyTemplate
54
52
 
55
- The general-purpose page shell. Accepts three kinds of child slots — `.Body`, `.Tab`, and `.Section` which determine the layout mode automatically.
53
+ General-purpose page shell. Accepts `.Body`, `.Tab`, and `.Section` child slots which determine the layout mode automatically.
56
54
 
57
55
  ```tsx
58
56
  <DataBodyTemplate
@@ -70,33 +68,33 @@ The general-purpose page shell. Accepts three kinds of child slots — `.Body`,
70
68
  | `topBar` | `ReactNode` | Top breadcrumb bar. Pass `<PageTopBar left="..." />` or omit. |
71
69
  | `title` | `ReactNode` | Page title |
72
70
  | `description` | `ReactNode` | Subtitle below the title |
73
- | `actions` | `ReactNode` | Page-level actions (Add, Export, etc.) next to the title. Not for form Save buttons. |
71
+ | `actions` | `ReactNode` | Page-level actions (Add, Export, etc.) next to the title |
74
72
  | `toolbarLeft` / `toolbarRight` | `ReactNode` | Toolbar slots above the content area |
75
73
  | `theme` | `CSSProperties` | Inline CSS variable overrides |
76
74
  | `className` | `string` | Class applied to the page root |
77
75
 
78
76
  #### DataBodyTemplate.Body
79
77
 
80
- Single-pane content. No navigation. Use for full-height grid or custom layouts.
78
+ Single-pane content. Use for full-height layouts.
81
79
 
82
80
  ```tsx
83
81
  <DataBodyTemplate title="Users">
84
82
  <DataBodyTemplate.Body>
85
- <DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
83
+ {/* your content */}
86
84
  </DataBodyTemplate.Body>
87
85
  </DataBodyTemplate>
88
86
  ```
89
87
 
90
- > Passing children directly without any slot wrapper also renders as a body, but `.Body` makes the layout intent explicit.
88
+ > Passing children directly without a slot wrapper also renders as a body, but `.Body` makes the intent explicit.
91
89
 
92
90
  #### DataBodyTemplate.Tab
93
91
 
94
- Creates a tabbed page layout. Add multiple `.Tab` children to enable the tab bar.
92
+ Creates a tabbed page layout.
95
93
 
96
94
  ```tsx
97
95
  <DataBodyTemplate title="Users">
98
96
  <DataBodyTemplate.Tab id="list" label="List" count={42}>
99
- <DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
97
+ {/* list content */}
100
98
  </DataBodyTemplate.Tab>
101
99
  <DataBodyTemplate.Tab id="settings" label="Settings">
102
100
  <SettingsForm />
@@ -106,7 +104,7 @@ Creates a tabbed page layout. Add multiple `.Tab` children to enable the tab bar
106
104
 
107
105
  #### DataBodyTemplate.Section
108
106
 
109
- Settings-style layout with left navigation and right content panel. Add multiple `.Section` children to enable the side nav.
107
+ Settings-style layout with left navigation and right content panel.
110
108
 
111
109
  ```tsx
112
110
  <DataBodyTemplate title="Settings">
@@ -129,12 +127,22 @@ Settings-style layout with left navigation and right content panel. Add multiple
129
127
 
130
128
  Groups content within a tab or section. The `layout` prop controls the visual structure.
131
129
 
132
- | layout | Use case | Default wrapper |
130
+ | layout | Use case |
131
+ |---|---|
132
+ | `horizontal` | Label on left, input on right (settings form) |
133
+ | `stacked` | Label above, input below |
134
+ | `inline` | Table-style rows (detail view) |
135
+ | `split` | Left list + right detail |
136
+
137
+ | Prop | Type | Description |
133
138
  |---|---|---|
134
- | `horizontal` | Label on left, input on right (settings form) | Card |
135
- | `stacked` | Label above, input below | plain |
136
- | `inline` | Table-style rows (detail view, inline form) | bordered |
137
- | `split` | Left list + right detail | bordered |
139
+ | `layout` | `GroupLayout` | Visual structure see table above |
140
+ | `variant` | `'card' \| 'plain' \| 'bordered'` | Wrapper style (defaults per layout) |
141
+ | `title` | `ReactNode` | Group heading |
142
+ | `description` | `ReactNode` | Subtitle below the heading |
143
+ | `actions` | `ReactNode` | Action slot next to the heading |
144
+ | `danger` | `boolean` | Renders title in destructive color |
145
+ | `className` | `string` | Class applied to the group root element |
138
146
 
139
147
  ```tsx
140
148
  <DataBodyTemplate.Tab id="settings" label="Settings">
@@ -151,7 +159,7 @@ Groups content within a tab or section. The `layout` prop controls the visual st
151
159
 
152
160
  #### DataBodyTemplate.Field
153
161
 
154
- Read-only key-value display. Use with `Group layout="inline"` for detail pages.
162
+ Read-only key-value display.
155
163
 
156
164
  ```tsx
157
165
  <DataBodyTemplate.Group layout="inline" title="Identity">
@@ -162,7 +170,7 @@ Read-only key-value display. Use with `Group layout="inline"` for detail pages.
162
170
 
163
171
  #### DataBodyTemplate.Summary
164
172
 
165
- A pinned summary area below the header, above tabs.
173
+ Pinned summary area below the header, above tabs.
166
174
 
167
175
  ```tsx
168
176
  <DataBodyTemplate title="Overview">
@@ -175,49 +183,170 @@ A pinned summary area below the header, above tabs.
175
183
 
176
184
  ---
177
185
 
178
- ### DataGridView
186
+ ### DashboardBodyTemplate
179
187
 
180
- Data table component. Use inside `DataBodyTemplate.Body` or any `.Tab` / `.Section`.
188
+ Dashboard page shell. Provides the chrome top bar, variable bar, panel grid area — while the app owns panel content and the data engine.
181
189
 
182
- | variant | Description |
183
- |---|---|
184
- | `standard` (default) | Standard data table with pagination |
185
- | `infinity` | Infinite scroll |
186
- | `drag` | Row drag-to-reorder |
187
- | `card` | Card grid |
188
- | `card-list` | Card list |
190
+ Requires [`@loykin/dashboardkit`](https://github.com/loykin/dashboardkit) 0.0.6 or newer for the grid and variable system:
191
+
192
+ ```bash
193
+ npm install @loykin/dashboardkit@^0.0.6 react-grid-layout
194
+ ```
195
+
196
+ Also import DashboardKit's grid CSS in your app:
197
+
198
+ ```ts
199
+ import '@loykin/dashboardkit/styles'
200
+ ```
201
+
202
+ For rounded design systems, tune DashboardKit's resize handle variables so the
203
+ handle stays inside the clipped panel corner:
204
+
205
+ ```css
206
+ .layout-dashboard .react-grid-item:not(.react-grid-placeholder) {
207
+ --dk-resize-handle-size: clamp(20px, calc(var(--radius) * 1.6), 40px);
208
+ --dk-resize-handle-inset: clamp(4px, calc(var(--radius) * 0.45), 16px);
209
+ --dk-resize-handle-mark-size: clamp(6px, calc(var(--radius) * 0.55), 12px);
210
+ --dk-resize-handle-color: rgba(0, 0, 0, 0.35);
211
+ --dk-resize-handle-mark-radius: min(var(--radius), var(--dk-resize-handle-mark-size));
212
+ }
213
+
214
+ .dark .layout-dashboard .react-grid-item:not(.react-grid-placeholder) {
215
+ --dk-resize-handle-color: rgba(255, 255, 255, 0.4);
216
+ }
217
+ ```
189
218
 
190
219
  ```tsx
191
- import { DataBodyTemplate, DataGridView, PageTopBar, type DataGridColumnDef } from '@loykin/designkit'
220
+ import React, { useState, useMemo } from 'react'
221
+ import { DashboardBodyTemplate, DashboardPanel, PageTopBar } from '@loykin/designkit'
222
+ import { createDashboardEngine, definePanel } from '@loykin/dashboardkit'
223
+ import { useLoadDashboard, useVariable, DashboardGrid } from '@loykin/dashboardkit/react'
224
+ import type { PanelViewerProps } from '@loykin/dashboardkit'
225
+
226
+ // Register panel types once at module level
227
+ const engine = createDashboardEngine()
228
+ engine.registerPanel(definePanel({
229
+ id: 'stat',
230
+ name: 'Stat',
231
+ optionsSchema: {},
232
+ viewer({ data, loading }: PanelViewerProps<unknown, unknown>) {
233
+ if (loading) return null
234
+ return <div className="text-2xl font-bold">{String(data ?? '—')}</div>
235
+ },
236
+ }))
237
+
238
+ export function MyDashboard() {
239
+ useLoadDashboard(engine, config)
240
+ const envVar = useVariable(engine, 'env')
241
+ const variables = useMemo(() => ({ env: (envVar.value as string) ?? 'production' }), [envVar.value])
242
+ const [editable, setEditable] = useState(false)
192
243
 
193
- type User = { id: string; name: string; email: string }
244
+ return (
245
+ <DashboardBodyTemplate
246
+ topBar={<PageTopBar left="My Dashboard" right={/* controls */} />}
247
+ variableBar={/* <VariableSelect> components */}
248
+ >
249
+ <DashboardGrid engine={engine} editable={editable}>
250
+ {({ panelType, config, data, rawData, loading, error, ref }) => {
251
+ const Viewer = engine.getPanelPlugin(panelType)?.viewer as React.FC<PanelViewerProps<unknown, unknown>> | undefined
252
+ return (
253
+ <DashboardPanel
254
+ ref={ref}
255
+ title={config.title}
256
+ loading={loading}
257
+ error={error ?? undefined}
258
+ editable={editable}
259
+ style={{ height: '100%' }}
260
+ >
261
+ {Viewer && (
262
+ <Viewer
263
+ panel={config} options={config.options}
264
+ data={data} rawData={rawData}
265
+ width={0} height={0}
266
+ loading={loading} error={error}
267
+ variables={variables}
268
+ />
269
+ )}
270
+ </DashboardPanel>
271
+ )
272
+ }}
273
+ </DashboardGrid>
274
+ </DashboardBodyTemplate>
275
+ )
276
+ }
277
+ ```
194
278
 
195
- const columns: DataGridColumnDef<User>[] = [
196
- { id: 'name', accessorKey: 'name', header: 'Name' },
197
- { id: 'email', accessorKey: 'email', header: 'Email' },
198
- ]
279
+ **DashboardBodyTemplate props:**
199
280
 
200
- export function UsersPage() {
281
+ | Prop | Type | Description |
282
+ |---|---|---|
283
+ | `topBar` | `ReactNode` | Top bar — breadcrumb, edit/refresh controls |
284
+ | `variableBar` | `ReactNode` | Variable dropdown strip between top bar and panels |
285
+ | `title` | `ReactNode` | Dashboard title (omit if topBar covers it) |
286
+ | `description` | `ReactNode` | Subtitle |
287
+ | `toolbar` | `ReactNode` | Toolbar slot next to the title |
288
+ | `theme` | `CSSProperties` | Inline CSS variable overrides |
289
+ | `className` | `string` | Class applied to the page root |
290
+ | `contentClassName` | `string` | Class applied to the panel grid area |
291
+
292
+ **DashboardPanel props:**
293
+
294
+ Panel card component. Wrap your panel viewer in `DashboardPanel` for consistent chrome across all panels.
295
+
296
+ | Prop | Type | Description |
297
+ |---|---|---|
298
+ | `title` | `string` | Panel title |
299
+ | `description` | `string` | Panel subtitle |
300
+ | `loading` | `boolean` | Shows loading spinner overlay |
301
+ | `error` | `string` | Shows error state, hides children |
302
+ | `editable` | `boolean` | Shows drag handle and edit ring |
303
+ | `headerRight` | `ReactNode` | Action slot in panel header — hidden until hover |
304
+ | `transparent` | `boolean` | Removes card border and background |
305
+ | `ref` | forwarded | Attach `DashboardGrid`'s `ref` for viewport virtualization |
306
+
307
+ ---
308
+
309
+ ### WorkbenchBodyTemplate
310
+
311
+ Resizable editor/workbench shell for products like panel editors, SQL editors, log explorers, and data workspaces. The template owns the pane chrome and resize handles; the app owns editor, preview, inspector, schema, and result content.
312
+
313
+ ```tsx
314
+ import { WorkbenchBodyTemplate, PageTopBar, Button } from '@loykin/designkit'
315
+
316
+ export function SqlEditorPage() {
201
317
  return (
202
- <DataBodyTemplate topBar={<PageTopBar left="Admin / Users" />} title="Users">
203
- <DataBodyTemplate.Body>
204
- <DataGridView
205
- data={data}
206
- columns={columns}
207
- getRowId={(row) => row.id}
208
- tableHeight={420}
209
- />
210
- </DataBodyTemplate.Body>
211
- </DataBodyTemplate>
318
+ <WorkbenchBodyTemplate
319
+ topBar={<PageTopBar left="Data / Query editor" />}
320
+ title="SQL editor"
321
+ headerRight={<Button variant="outline" size="sm">Run</Button>}
322
+ leftPane={<SchemaBrowser />}
323
+ mainPane={<SqlEditor />}
324
+ bottomPane={<ResultsGrid />}
325
+ resizable
326
+ />
212
327
  )
213
328
  }
214
329
  ```
215
330
 
331
+ **WorkbenchBodyTemplate props:**
332
+
333
+ | Prop | Type | Description |
334
+ |---|---|---|
335
+ | `topBar` | `ReactNode` | Top bar above the workbench |
336
+ | `title` / `description` | `ReactNode` | Header copy above the panes |
337
+ | `headerRight` / `actions` | `ReactNode` | Header action slots |
338
+ | `leftPane` / `rightPane` | `ReactNode` | Optional side panes |
339
+ | `mainPane` | `ReactNode` | Primary editor or preview area |
340
+ | `bottomPane` | `ReactNode` | Optional result, query, or logs pane |
341
+ | `resizable` | `boolean` | Enables pane drag handles |
342
+ | `leftPaneCollapsed` / `rightPaneCollapsed` / `bottomPaneCollapsed` | `boolean` | Hides optional panes while preserving the template layout model |
343
+ | `leftPaneWidth` / `rightPaneWidth` / `bottomPaneHeight` | `number` | Initial pane sizes in pixels |
344
+
216
345
  ---
217
346
 
218
347
  ### FormWizardBodyTemplate
219
348
 
220
- Multi-step input wizard. The template wraps each step's `content` in a `<form>` element automatically, so the Continue / Finish button acts as a submit trigger. Press Enter or click Continue to advance.
349
+ Multi-step input wizard. Wraps each step's `content` in a `<form>` element automatically.
221
350
 
222
351
  ```tsx
223
352
  import { useState } from 'react'
@@ -244,7 +373,7 @@ export function OnboardingPage() {
244
373
  }
245
374
  ```
246
375
 
247
- For per-step validation with `react-hook-form`, call `trigger()` inside `onNext` before advancing:
376
+ For per-step validation with `react-hook-form`:
248
377
 
249
378
  ```tsx
250
379
  onNext={async () => {
@@ -253,13 +382,13 @@ onNext={async () => {
253
382
  }}
254
383
  ```
255
384
 
256
- The `variant` prop switches between `'plain'` (default) and `'card'` to wrap each step in a Card.
385
+ The `variant` prop switches between `'plain'` (default) and `'card'`.
257
386
 
258
387
  ---
259
388
 
260
389
  ### LoginBodyTemplate
261
390
 
262
- Authentication page shell. Renders centered or split-panel login layouts.
391
+ Authentication page shell.
263
392
 
264
393
  ```tsx
265
394
  import { LoginBodyTemplate } from '@loykin/designkit'
@@ -286,39 +415,46 @@ export function SignInPage() {
286
415
  | Prop | Type | Default | Description |
287
416
  |---|---|---|---|
288
417
  | `layout` | `'centered' \| 'split'` | `'centered'` | Centered card or split-panel with brand side |
289
- | `card` | `'card' \| 'plain'` | `'plain'` | Wrap the form content in a card border |
290
- | `cardWidth` | `'sm' \| 'md' \| 'lg'` | `'md'` | Width of the form card |
418
+ | `card` | `'card' \| 'plain'` | `'plain'` | Wrap form content in a card border |
419
+ | `cardWidth` | `'sm' \| 'md' \| 'lg'` | `'md'` | Form card width |
291
420
  | `bg` | `'default' \| 'subtle' \| 'none'` | `'default'` | Background style |
292
- | `side` | `'left' \| 'right'` | `'left'` | Side the brand panel appears on (split layout only) |
421
+ | `side` | `'left' \| 'right'` | `'left'` | Brand panel side (split layout only) |
293
422
  | `brand` | `ReactNode` | built-in | Custom brand/logo panel content |
294
423
 
295
424
  ---
296
425
 
297
426
  ## UI Components
298
427
 
299
- Base components for use within page templates.
300
-
301
428
  ```tsx
302
429
  import {
303
- Badge, Button, Card, CardContent,
304
- Input, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
305
- Switch, Checkbox, Slider,
430
+ Avatar, AvatarFallback, AvatarImage,
431
+ Badge,
432
+ Button,
433
+ Card, CardContent, CardHeader, CardTitle,
434
+ Checkbox,
435
+ DropdownMenu,
306
436
  EmptyState,
307
- Tabs, TabsList, TabsTrigger, TabsContent,
437
+ Input,
438
+ Label,
439
+ NavigationMenu,
440
+ Popover,
441
+ ScrollArea,
442
+ Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
443
+ Separator,
308
444
  Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger,
445
+ Sidebar,
446
+ Skeleton,
447
+ Slider,
448
+ Switch,
449
+ Table,
450
+ Tabs, TabsList, TabsTrigger, TabsContent,
309
451
  Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
310
- Avatar, AvatarFallback, AvatarImage,
311
- Separator, Skeleton,
312
- Breadcrumb, DropdownMenu, NavigationMenu,
313
- Popover, ScrollArea, Sidebar, Table,
314
452
  PageTopBar,
315
453
  } from '@loykin/designkit'
316
454
  ```
317
455
 
318
456
  ### EmptyState
319
457
 
320
- Displays empty data, no search results, or error states.
321
-
322
458
  ```tsx
323
459
  import { EmptyState } from '@loykin/designkit'
324
460
  import { Users } from 'lucide-react'
@@ -335,13 +471,7 @@ import { Users } from 'lucide-react'
335
471
 
336
472
  ## Theming
337
473
 
338
- Designkit maps shadcn/ui CSS variables (`--primary`, `--background`, `--radius`, etc.) onto its own `--dk-*` tokens. Changing your shadcn theme automatically updates all designkit components.
339
-
340
- For additional control, override `--dk-*` variables directly in `globals.css`.
341
-
342
- ### Customization scope
343
-
344
- CSS variables are the customization layer. The library is opinionated about structure and ships its own UI components — visual appearance is controlled entirely through tokens.
474
+ Designkit maps shadcn/ui CSS variables onto its own `--dk-*` tokens. Changing your shadcn theme automatically updates all designkit components.
345
475
 
346
476
  | What | How |
347
477
  |---|---|
@@ -351,48 +481,53 @@ CSS variables are the customization layer. The library is opinionated about stru
351
481
 
352
482
  ```css
353
483
  :root {
354
- --dk-radius: 0.375rem;
355
- --dk-primary: oklch(0.52 0.2 250);
356
-
357
484
  --dk-density: 1; /* 0.85 compact / 1 default / 1.15 comfortable */
358
485
  --dk-page-padding-x: 1.5rem;
359
486
  --dk-page-padding-y: 1rem;
360
487
  --dk-panel-gap: 1rem;
361
- --dk-toolbar-height: 2.75rem;
362
488
  }
363
489
  ```
364
490
 
365
- To override per page, combine with `className`:
491
+ Per-page override via `className`:
366
492
 
367
493
  ```css
368
- .layout-settings {
369
- --dk-radius: 0.5rem;
370
- --dk-density: 1.15;
494
+ .layout-dashboard {
495
+ --dk-density: 0.85;
371
496
  }
372
497
  ```
373
498
 
374
499
  ```tsx
375
- <DataBodyTemplate className="layout-settings" title="Settings">
376
- ...
377
- </DataBodyTemplate>
500
+ <DashboardBodyTemplate className="layout-dashboard" ...>
378
501
  ```
379
502
 
380
- Or use the `theme` prop for inline overrides:
503
+ Or via `theme` prop:
381
504
 
382
505
  ```tsx
383
506
  <DataBodyTemplate
384
- theme={{ '--dk-radius': '0.5rem', '--dk-density': '1.15' } as React.CSSProperties}
507
+ theme={{ '--dk-density': '1.15' } as React.CSSProperties}
385
508
  title="Settings"
386
509
  >
387
- ...
388
- </DataBodyTemplate>
389
510
  ```
390
511
 
391
512
  ---
392
513
 
514
+ ## Using with gridkit
515
+
516
+ If your app also uses `@loykin/gridkit`, import its styles **after** designkit:
517
+
518
+ ```css
519
+ @import "tailwindcss";
520
+ @import "@loykin/designkit/styles";
521
+ @import "@loykin/gridkit/styles"; /* must come last — uses @layer gridkit */
522
+ ```
523
+
524
+ gridkit registers a named `@layer gridkit`. Importing it before `tailwindcss` or `designkit/styles` causes layer ordering conflicts where utility overrides resolve incorrectly.
525
+
526
+ ---
527
+
393
528
  ## Playground
394
529
 
395
- An interactive development tool to preview templates and generate CSS/component code.
530
+ Interactive development tool to preview templates and generate code.
396
531
 
397
532
  ```bash
398
533
  git clone https://github.com/loykin/designkit
@@ -401,8 +536,6 @@ pnpm install
401
536
  pnpm dev
402
537
  ```
403
538
 
404
- Open `http://localhost:5173` to browse templates and export code.
405
-
406
539
  ---
407
540
 
408
541
  ## License