tembro 3.1.7 → 3.1.8

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.
Files changed (32) hide show
  1. package/dist/showcase/package-meta.d.ts +2 -2
  2. package/dist/src/components/layout/app-sidebar.cjs +1 -1
  3. package/dist/src/components/layout/app-sidebar.js +10 -5
  4. package/dist/src/showcase/package-meta.cjs +1 -1
  5. package/dist/src/showcase/package-meta.js +1 -1
  6. package/dist/src/showcase/site-data.cjs +1 -1
  7. package/dist/src/showcase/site-data.js +1 -1
  8. package/dist/src/showcase/tembro-registry.json.cjs +1 -1
  9. package/dist/src/showcase/tembro-registry.json.js +1 -1
  10. package/package.json +1 -1
  11. package/packages/cli/dist/index.cjs +116 -116
  12. package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +19 -14
  13. package/packages/cli/vendor/src/showcase/package-meta.ts +1 -1
  14. package/packages/cli/vendor/src/showcase/tembro-registry.json +1 -1
  15. package/packages/cli/vendor/templates/showcase/src/App.tsx +107 -0
  16. package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +273 -0
  17. package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +41 -0
  18. package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +82 -0
  19. package/packages/cli/vendor/templates/showcase/src/showcase/sections/CalendarSection.tsx +35 -0
  20. package/packages/cli/vendor/templates/showcase/src/showcase/sections/CategorySection.tsx +48 -0
  21. package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentDetailSection.tsx +68 -0
  22. package/packages/cli/vendor/templates/showcase/src/showcase/sections/CoreUiSection.tsx +100 -0
  23. package/packages/cli/vendor/templates/showcase/src/showcase/sections/DataTableSection.tsx +45 -0
  24. package/packages/cli/vendor/templates/showcase/src/showcase/sections/FormsSection.tsx +26 -0
  25. package/packages/cli/vendor/templates/showcase/src/showcase/sections/InventorySection.tsx +38 -0
  26. package/packages/cli/vendor/templates/showcase/src/showcase/sections/KanbanSection.tsx +42 -0
  27. package/packages/cli/vendor/templates/showcase/src/showcase/sections/OverlaySection.tsx +62 -0
  28. package/packages/cli/vendor/templates/showcase/src/showcase/sections/PatternsSection.tsx +36 -0
  29. package/packages/cli/vendor/templates/showcase/src/showcase/sections/VerificationSection.tsx +42 -0
  30. package/packages/cli/vendor/templates/showcase/src/showcase/sections/WizardSection.tsx +44 -0
  31. package/packages/cli/vendor/templates/showcase/src/showcase/shared/SectionTitle.tsx +13 -0
  32. package/registry.json +1 -1
@@ -0,0 +1,48 @@
1
+ import { Button } from "@/components/ui/button"
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
3
+ import { Badge } from "@/components/ui/badge"
4
+ import { getModuleKey, getModuleLabel, getModuleSourcePath, type RegistryGroup } from "@/showcase/data/registry"
5
+
6
+ type CategorySectionProps = {
7
+ group: RegistryGroup
8
+ onSelect: (key: string) => void
9
+ }
10
+
11
+ export function CategorySection({ group, onSelect }: CategorySectionProps) {
12
+ return (
13
+ <section className="grid gap-4">
14
+ <Card>
15
+ <CardHeader>
16
+ <div className="flex flex-wrap items-start justify-between gap-3">
17
+ <div>
18
+ <CardTitle>{group.name}</CardTitle>
19
+ <CardDescription>{group.components.length} registry component. Sidebar ichidan bittasini tanlab alohida test qilasiz.</CardDescription>
20
+ </div>
21
+ <Badge label={`${group.components.length} components`} variant="secondary" />
22
+ </div>
23
+ </CardHeader>
24
+ <CardContent>
25
+ <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
26
+ {group.components.map((component) => (
27
+ <button
28
+ key={component.name}
29
+ type="button"
30
+ className="rounded-lg border bg-card p-4 text-left transition hover:border-primary/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
31
+ onClick={() => onSelect(getModuleKey(group.name, component.name))}
32
+ >
33
+ <div className="flex items-center justify-between gap-3">
34
+ <div className="font-medium">{getModuleLabel(component.name)}</div>
35
+ <Badge label={component.status} status={component.status === "stable" ? "success" : "info"} variant="soft" />
36
+ </div>
37
+ <div className="mt-1 text-xs text-muted-foreground">{getModuleSourcePath(component)}</div>
38
+ </button>
39
+ ))}
40
+ </div>
41
+ </CardContent>
42
+ </Card>
43
+ <div className="flex justify-end">
44
+ <Button variant="outline" onClick={() => onSelect("overview")}>Back to overview</Button>
45
+ </div>
46
+ </section>
47
+ )
48
+ }
@@ -0,0 +1,68 @@
1
+ import { FolderOpenIcon } from "lucide-react"
2
+
3
+ import { Badge } from "@/components/ui/badge"
4
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
5
+ import { getModuleLabel, getModuleSourcePath, type RegistryComponent, type RegistryGroup } from "@/showcase/data/registry"
6
+ import { CalendarSection } from "@/showcase/sections/CalendarSection"
7
+ import { CoreUiSection } from "@/showcase/sections/CoreUiSection"
8
+ import { DataTableSection } from "@/showcase/sections/DataTableSection"
9
+ import { FormsSection } from "@/showcase/sections/FormsSection"
10
+ import { KanbanSection } from "@/showcase/sections/KanbanSection"
11
+ import { OverlaySection } from "@/showcase/sections/OverlaySection"
12
+ import { PatternsSection } from "@/showcase/sections/PatternsSection"
13
+ import { WizardSection } from "@/showcase/sections/WizardSection"
14
+
15
+ type ComponentDetailSectionProps = {
16
+ group: RegistryGroup
17
+ component: RegistryComponent
18
+ }
19
+
20
+ function RelatedPreview({ groupName, componentName }: { groupName: string; componentName: string }) {
21
+ if (groupName === "ui" || ["actions", "command"].includes(groupName)) return <CoreUiSection />
22
+ if (groupName === "inputs" || groupName === "form" || groupName === "feedback") return <FormsSection />
23
+ if (groupName === "data-table") return <DataTableSection />
24
+ if (groupName === "display" && componentName === "kanban") return <KanbanSection />
25
+ if (groupName === "calendar" || groupName === "navigation") return <CalendarSection />
26
+ if (groupName === "overlay") return <OverlaySection />
27
+ if (groupName === "wizard") return <WizardSection />
28
+ if (["patterns", "layout", "modern", "notifications", "filters", "upload", "charts", "dnd", "display"].includes(groupName)) {
29
+ return <PatternsSection />
30
+ }
31
+
32
+ return <PatternsSection />
33
+ }
34
+
35
+ export function ComponentDetailSection({ group, component }: ComponentDetailSectionProps) {
36
+ const sourcePath = getModuleSourcePath(component)
37
+
38
+ return (
39
+ <section className="grid gap-5">
40
+ <Card>
41
+ <CardHeader>
42
+ <div className="flex flex-wrap items-start justify-between gap-3">
43
+ <div>
44
+ <CardTitle>{getModuleLabel(component.name)}</CardTitle>
45
+ <CardDescription>Tanlangan registry component test paneli.</CardDescription>
46
+ </div>
47
+ <div className="flex flex-wrap gap-2">
48
+ <Badge label={group.name} status="info" />
49
+ <Badge label={component.status} status={component.status === "stable" ? "success" : "info"} />
50
+ <Badge label="local source" status="success" />
51
+ </div>
52
+ </div>
53
+ </CardHeader>
54
+ <CardContent className="grid gap-3 text-sm">
55
+ <div className="flex items-center gap-2 rounded-lg border bg-muted/30 p-3">
56
+ <FolderOpenIcon className="size-4 text-muted-foreground" />
57
+ <code className="min-w-0 break-all">{sourcePath}</code>
58
+ </div>
59
+ <p className="text-muted-foreground">
60
+ Sidebar orqali har bir registry component alohida tanlanadi. Quyidagi preview shu component tegishli category test surfaceini ko‘rsatadi.
61
+ </p>
62
+ </CardContent>
63
+ </Card>
64
+
65
+ <RelatedPreview groupName={group.name} componentName={component.name} />
66
+ </section>
67
+ )
68
+ }
@@ -0,0 +1,100 @@
1
+ import { ChevronRightIcon, CommandIcon, SearchIcon, SparklesIcon } from "lucide-react"
2
+
3
+ import { AvatarGroup } from "@/components/display/avatar"
4
+ import { Progress } from "@/components/display/progress"
5
+ import { Tag, TagGroup } from "@/components/display/tag"
6
+ import { Alert } from "@/components/feedback/alert"
7
+ import { Badge } from "@/components/ui/badge"
8
+ import { Button } from "@/components/ui/button"
9
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
10
+ import { Checkbox } from "@/components/ui/checkbox"
11
+ import { Input } from "@/components/ui/input"
12
+ import { Select } from "@/components/ui/select"
13
+ import { Switch } from "@/components/ui/switch"
14
+ import { Textarea } from "@/components/ui/textarea"
15
+ import { registryGroups } from "@/showcase/data/registry"
16
+
17
+ export function CoreUiSection() {
18
+ return (
19
+ <div className="grid gap-4 xl:grid-cols-[1.35fr_0.65fr]">
20
+ <Card>
21
+ <CardHeader>
22
+ <CardTitle>UI controls and variants</CardTitle>
23
+ <CardDescription>Button, Badge, Card, Input, Select, Checkbox, Switch, Tabs, Textarea.</CardDescription>
24
+ </CardHeader>
25
+ <CardContent className="grid gap-5">
26
+ <div className="flex flex-wrap gap-2">
27
+ <Button leftIcon={<SparklesIcon className="size-4" />}>Default</Button>
28
+ <Button variant="secondary">Secondary</Button>
29
+ <Button variant="outline">Outline</Button>
30
+ <Button variant="ghost">Ghost</Button>
31
+ <Button variant="warning">Warning</Button>
32
+ <Button variant="destructive">Destructive</Button>
33
+ <Button iconOnly aria-label="Command"><CommandIcon className="size-4" /></Button>
34
+ </div>
35
+ <div className="flex flex-wrap gap-2">
36
+ <Badge label="default" />
37
+ <Badge label="info" status="info" />
38
+ <Badge label="success" status="success" />
39
+ <Badge label="warning" status="warning" />
40
+ <Badge label="danger" status="danger" removable />
41
+ </div>
42
+ <div className="grid gap-3 md:grid-cols-3">
43
+ <Input kind="search" placeholder="Search components" searchIcon={<SearchIcon className="size-4" />} />
44
+ <Input kind="password" placeholder="Password input" />
45
+ <Select
46
+ placeholder="Pick category"
47
+ searchable
48
+ clearable
49
+ options={registryGroups.slice(0, 8).map((group) => ({
50
+ label: group.name,
51
+ value: group.name,
52
+ description: `${group.components.length} components`,
53
+ }))}
54
+ />
55
+ </div>
56
+ <div className="grid gap-4 md:grid-cols-2">
57
+ <Textarea defaultValue="Textarea with helper text, counter and Tembro theme." helperText="Textarea helper text" maxLength={140} showCharacterCount />
58
+ <div className="grid content-start gap-4 rounded-lg border bg-muted/25 p-4">
59
+ <Switch defaultChecked label="Enable preview" description="Switch with label and description" />
60
+ <div className="flex items-center gap-3">
61
+ <Checkbox defaultChecked />
62
+ <span className="text-sm">Checkbox selected state</span>
63
+ </div>
64
+ <AvatarGroup
65
+ items={[
66
+ { key: "az", name: "Azamat Jurayev", status: "online" },
67
+ { key: "qa", name: "QA Tester", status: "busy" },
68
+ { key: "ux", name: "UX Review", status: "away" },
69
+ { key: "tm", name: "Tembro Maintainer", status: "offline" },
70
+ ]}
71
+ max={3}
72
+ />
73
+ </div>
74
+ </div>
75
+ </CardContent>
76
+ </Card>
77
+ <Card
78
+ variant="elevated"
79
+ tone="info"
80
+ eyebrow="Card surface props"
81
+ title="Surface API"
82
+ description="title, description, badge, action, content, footer props."
83
+ badge={<Badge label="styled" status="info" />}
84
+ action={<Button size="sm" variant="outline" rightIcon={<ChevronRightIcon className="size-4" />}>Open</Button>}
85
+ content={
86
+ <div className="grid gap-4">
87
+ <Progress value={78} label="Style coverage" showValue tone="info" />
88
+ <TagGroup>
89
+ <Tag tone="success" selected>Selected</Tag>
90
+ <Tag tone="info">Info</Tag>
91
+ <Tag tone="warning" removable>Removable</Tag>
92
+ </TagGroup>
93
+ <Alert tone="success" title="Styled by Tembro tokens" description="This card uses copied local component code." />
94
+ </div>
95
+ }
96
+ footer={<span className="text-sm text-muted-foreground">No Vite starter component here.</span>}
97
+ />
98
+ </div>
99
+ )
100
+ }
@@ -0,0 +1,45 @@
1
+ import type { ColumnDef } from "@tanstack/react-table"
2
+
3
+ import { DataTable } from "@/components/data-table/data-table"
4
+ import { Badge } from "@/components/ui/badge"
5
+ import { componentRows, type ComponentRow } from "@/showcase/data/registry"
6
+
7
+ const columns: ColumnDef<ComponentRow>[] = [
8
+ { accessorKey: "component", header: "Component" },
9
+ { accessorKey: "category", header: "Category" },
10
+ {
11
+ accessorKey: "status",
12
+ header: "Status",
13
+ cell: ({ row }) => {
14
+ const status = row.original.status
15
+ return (
16
+ <Badge
17
+ status={status === "Ready" ? "success" : status === "Testing" ? "info" : "warning"}
18
+ label={status}
19
+ variant="soft"
20
+ />
21
+ )
22
+ },
23
+ },
24
+ { accessorKey: "props", header: "Props shown" },
25
+ ]
26
+
27
+ export function DataTableSection() {
28
+ return (
29
+ <DataTable
30
+ columns={columns}
31
+ data={componentRows}
32
+ title="Component audit"
33
+ description="DataTable with search, column visibility, row actions, refresh, export and pagination features."
34
+ features={{ search: true, columnVisibility: true, rowActions: true, refresh: true, export: true }}
35
+ search={{ placeholder: "Search table", clearable: true }}
36
+ pagination={{ pageIndex: 0, pageSize: 5, rowCount: componentRows.length, showPageSize: true }}
37
+ rowActions={() => [
38
+ { key: "inspect", label: "Inspect", onSelect: () => undefined },
39
+ { key: "mark-ready", label: "Mark ready", onSelect: () => undefined },
40
+ ]}
41
+ onRefresh={() => undefined}
42
+ onExport={() => undefined}
43
+ />
44
+ )
45
+ }
@@ -0,0 +1,26 @@
1
+ import { ProgressCard } from "@/components/display/progress"
2
+ import { LoadingState } from "@/components/feedback/loading-state"
3
+ import { Rating } from "@/components/inputs/rating"
4
+ import { RangeSlider, Slider } from "@/components/inputs/slider"
5
+ import { Badge } from "@/components/ui/badge"
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
7
+
8
+ export function FormsSection() {
9
+ return (
10
+ <div className="grid gap-4 lg:grid-cols-3">
11
+ <Card>
12
+ <CardHeader>
13
+ <CardTitle>Advanced inputs</CardTitle>
14
+ <CardDescription>Rating and sliders.</CardDescription>
15
+ </CardHeader>
16
+ <CardContent className="grid gap-5">
17
+ <Rating defaultValue={4} />
18
+ <Slider defaultValue={72} label="Quality" showValue formatValue={(value) => `${value}%`} />
19
+ <RangeSlider defaultValue={[20, 80]} label="Range" showValue />
20
+ </CardContent>
21
+ </Card>
22
+ <ProgressCard title="Form completeness" description="input, select, switch, textarea" value={86} tone="success" footer={<Badge label="forms" status="success" />} />
23
+ <LoadingState label="Loading state" description="Spinner/skeleton/progress state component." />
24
+ </div>
25
+ )
26
+ }
@@ -0,0 +1,38 @@
1
+ import { Badge } from "@/components/ui/badge"
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
3
+ import { Tag } from "@/components/display/tag"
4
+ import { registryGroups } from "@/showcase/data/registry"
5
+ import { SectionTitle } from "@/showcase/shared/SectionTitle"
6
+
7
+ export function InventorySection() {
8
+ return (
9
+ <section>
10
+ <SectionTitle
11
+ title="Complete Registry Component Inventory"
12
+ description="Bu yerda `tembro add <name>` bilan chaqiriladigan aniq component nomlari ko‘rinadi."
13
+ />
14
+ <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
15
+ {registryGroups.map((group) => (
16
+ <Card key={group.name} variant="outline" className="min-w-0">
17
+ <CardHeader>
18
+ <div className="flex items-center justify-between gap-3">
19
+ <CardTitle>{group.name}</CardTitle>
20
+ <Badge label={group.components.length} variant="secondary" />
21
+ </div>
22
+ <CardDescription>src/components/{group.name}</CardDescription>
23
+ </CardHeader>
24
+ <CardContent>
25
+ <div className="flex flex-wrap gap-2">
26
+ {group.components.map((component) => (
27
+ <Tag key={component.name} size="sm" tone="neutral">
28
+ {component.name}
29
+ </Tag>
30
+ ))}
31
+ </div>
32
+ </CardContent>
33
+ </Card>
34
+ ))}
35
+ </div>
36
+ </section>
37
+ )
38
+ }
@@ -0,0 +1,42 @@
1
+ import { useMemo } from "react"
2
+
3
+ import { KanbanBoard, type KanbanColumn } from "@/components/display/kanban"
4
+ import { Badge } from "@/components/ui/badge"
5
+
6
+ export function KanbanSection() {
7
+ const kanbanColumns = useMemo<KanbanColumn[]>(
8
+ () => [
9
+ {
10
+ key: "todo",
11
+ title: "Todo",
12
+ count: 2,
13
+ cards: [
14
+ { key: "sidebar", title: "Sidebar", description: "Navigation, badges, collapsed state", meta: <Badge label="layout" /> },
15
+ { key: "upload", title: "Upload", description: "file-upload and image-upload components", meta: <Badge label="upload" /> },
16
+ ],
17
+ },
18
+ {
19
+ key: "doing",
20
+ title: "Doing",
21
+ count: 2,
22
+ cards: [
23
+ { key: "kanban", title: "Kanban board", description: "Drag cards between columns", meta: <Badge status="info" label="dnd" /> },
24
+ { key: "wizard", title: "Wizard flow", description: "Stepper and wizard controls", meta: <Badge status="warning" label="flow" /> },
25
+ ],
26
+ },
27
+ {
28
+ key: "done",
29
+ title: "Done",
30
+ count: 3,
31
+ cards: [
32
+ { key: "ui", title: "UI controls", description: "Button, input, select, tabs, card", meta: <Badge status="success" label="ready" /> },
33
+ { key: "calendar", title: "Calendar", description: "Calendar and DatePicker", meta: <Badge status="success" label="ready" /> },
34
+ { key: "table", title: "DataTable", description: "Search, actions, pagination", meta: <Badge status="success" label="ready" /> },
35
+ ],
36
+ },
37
+ ],
38
+ []
39
+ )
40
+
41
+ return <KanbanBoard defaultColumns={kanbanColumns} />
42
+ }
@@ -0,0 +1,62 @@
1
+ import { useState } from "react"
2
+
3
+ import { StatusLegend } from "@/components/display/status-legend"
4
+ import { Alert } from "@/components/feedback/alert"
5
+ import { ConfirmDialog } from "@/components/overlay/confirm-dialog"
6
+ import { Drawer, DrawerCloseButton } from "@/components/overlay/drawer"
7
+ import { Button } from "@/components/ui/button"
8
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
9
+
10
+ export function OverlaySection() {
11
+ const [drawerOpen, setDrawerOpen] = useState(false)
12
+ const [confirmOpen, setConfirmOpen] = useState(false)
13
+
14
+ return (
15
+ <div className="grid gap-4 lg:grid-cols-3">
16
+ <Card>
17
+ <CardHeader>
18
+ <CardTitle>Drawer</CardTitle>
19
+ <CardDescription>Right-side overlay component.</CardDescription>
20
+ </CardHeader>
21
+ <CardContent>
22
+ <Drawer
23
+ open={drawerOpen}
24
+ onOpenChange={setDrawerOpen}
25
+ trigger={<Button onClick={() => setDrawerOpen(true)}>Open drawer</Button>}
26
+ title="Drawer preview"
27
+ description="Overlay/drawer module rendered from local Tembro code."
28
+ footer={<DrawerCloseButton>Close drawer</DrawerCloseButton>}
29
+ >
30
+ <StatusLegend
31
+ title="Drawer content"
32
+ items={[
33
+ { key: "one", label: "Overlay API", count: 3, tone: "info" },
34
+ { key: "two", label: "Dialog base", count: 1, tone: "success" },
35
+ ]}
36
+ />
37
+ </Drawer>
38
+ </CardContent>
39
+ </Card>
40
+ <Card>
41
+ <CardHeader>
42
+ <CardTitle>ConfirmDialog</CardTitle>
43
+ <CardDescription>Controlled confirm modal.</CardDescription>
44
+ </CardHeader>
45
+ <CardContent>
46
+ <ConfirmDialog
47
+ open={confirmOpen}
48
+ onOpenChange={setConfirmOpen}
49
+ trigger={<Button variant="outline" onClick={() => setConfirmOpen(true)}>Open confirm</Button>}
50
+ title="Confirm action"
51
+ description="This is a Tembro ConfirmDialog."
52
+ confirmText="Confirm"
53
+ cancelText="Cancel"
54
+ >
55
+ <p className="text-sm text-muted-foreground">Dialog content area is rendered and styled by the component.</p>
56
+ </ConfirmDialog>
57
+ </CardContent>
58
+ </Card>
59
+ <Alert tone="warning" title="Overlay components" description="alert-dialog, confirm-dialog and drawer are installed. Dialog primitives are under ui/dialog." />
60
+ </div>
61
+ )
62
+ }
@@ -0,0 +1,36 @@
1
+ import { StatusLegend } from "@/components/display/status-legend"
2
+ import { Timeline } from "@/components/display/timeline"
3
+ import { EmptyState } from "@/components/patterns/empty-state"
4
+
5
+ export function PatternsSection() {
6
+ return (
7
+ <div className="grid gap-4 lg:grid-cols-3">
8
+ <EmptyState
9
+ title="EmptyState pattern"
10
+ description="Pattern components are installed: resource pages, settings pages, page toolbar, data view and form builder."
11
+ primaryAction={{ label: "Primary action" }}
12
+ secondaryAction={{ label: "Secondary action", variant: "outline" }}
13
+ />
14
+ <StatusLegend
15
+ title="StatusLegend"
16
+ description="Display module with counts."
17
+ orientation="grid"
18
+ items={[
19
+ { key: "ready", label: "Ready", description: "Can be tested", count: 62, tone: "success" },
20
+ { key: "large", label: "Large components", description: "sidebar, kanban, data-table", count: 8, tone: "info" },
21
+ { key: "forms", label: "Form components", description: "inputs and shells", count: 18, tone: "warning" },
22
+ { key: "overlay", label: "Overlay components", description: "dialog, drawer", count: 3, tone: "default" },
23
+ ]}
24
+ />
25
+ <Timeline
26
+ items={[
27
+ { key: "init", title: "tembro init", description: "Project initialized", time: "done", tone: "success" },
28
+ { key: "add", title: "tembro add", description: "All registry entries copied", time: "done", tone: "success" },
29
+ { key: "show", title: "Workbench", description: "Visible app surface", time: "now", tone: "info" },
30
+ ]}
31
+ pending
32
+ pendingLabel="Manual component QA"
33
+ />
34
+ </div>
35
+ )
36
+ }
@@ -0,0 +1,42 @@
1
+ import { CheckCircle2Icon, Layers3Icon, ShieldCheckIcon } from "lucide-react"
2
+
3
+ import { Card, CardContent } from "@/components/ui/card"
4
+ import { moduleCount, registryGroups } from "@/showcase/data/registry"
5
+ import { SectionTitle } from "@/showcase/shared/SectionTitle"
6
+
7
+ export function VerificationSection() {
8
+ return (
9
+ <section>
10
+ <SectionTitle title="Verification" description="Package va project setup holati." />
11
+ <div className="grid gap-4 md:grid-cols-3">
12
+ <Card>
13
+ <CardContent className="flex items-start gap-3 pt-6">
14
+ <CheckCircle2Icon className="mt-1 size-5 text-emerald-600" />
15
+ <div>
16
+ <div className="font-medium">Doctor passed</div>
17
+ <p className="text-sm text-muted-foreground">Tembro theme tokens recognized.</p>
18
+ </div>
19
+ </CardContent>
20
+ </Card>
21
+ <Card>
22
+ <CardContent className="flex items-start gap-3 pt-6">
23
+ <Layers3Icon className="mt-1 size-5 text-blue-600" />
24
+ <div>
25
+ <div className="font-medium">All categories listed</div>
26
+ <p className="text-sm text-muted-foreground">{registryGroups.length} groups and {moduleCount} registry components.</p>
27
+ </div>
28
+ </CardContent>
29
+ </Card>
30
+ <Card>
31
+ <CardContent className="flex items-start gap-3 pt-6">
32
+ <ShieldCheckIcon className="mt-1 size-5 text-amber-600" />
33
+ <div>
34
+ <div className="font-medium">Build checked</div>
35
+ <p className="text-sm text-muted-foreground">Vite starter screen removed.</p>
36
+ </div>
37
+ </CardContent>
38
+ </Card>
39
+ </div>
40
+ </section>
41
+ )
42
+ }
@@ -0,0 +1,44 @@
1
+ import { useState } from "react"
2
+
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
4
+ import { Stepper } from "@/components/wizard/stepper"
5
+ import { Wizard } from "@/components/wizard/wizard"
6
+ import { wizardSteps } from "@/showcase/data/registry"
7
+
8
+ export function WizardSection() {
9
+ const [step, setStep] = useState("test")
10
+
11
+ return (
12
+ <div className="grid gap-4 lg:grid-cols-[1fr_0.8fr]">
13
+ <Card>
14
+ <CardHeader>
15
+ <CardTitle>Stepper</CardTitle>
16
+ <CardDescription>Horizontal and clickable stepper.</CardDescription>
17
+ </CardHeader>
18
+ <CardContent>
19
+ <Stepper steps={wizardSteps} currentStep={step} onStepChange={setStep} />
20
+ </CardContent>
21
+ </Card>
22
+ <Card>
23
+ <CardHeader>
24
+ <CardTitle>Wizard</CardTitle>
25
+ <CardDescription>Wizard footer, previous/next and content slot.</CardDescription>
26
+ </CardHeader>
27
+ <CardContent>
28
+ <Wizard
29
+ steps={wizardSteps}
30
+ currentStep={step}
31
+ onStepChange={setStep}
32
+ onPrevious={() => setStep("add")}
33
+ onNext={() => setStep("test")}
34
+ onFinish={() => setStep("test")}
35
+ >
36
+ <div className="rounded-lg border bg-muted/25 p-4 text-sm">
37
+ Current step: <span className="font-semibold">{step}</span>
38
+ </div>
39
+ </Wizard>
40
+ </CardContent>
41
+ </Card>
42
+ </div>
43
+ )
44
+ }
@@ -0,0 +1,13 @@
1
+ type SectionTitleProps = {
2
+ title: string
3
+ description: string
4
+ }
5
+
6
+ export function SectionTitle({ title, description }: SectionTitleProps) {
7
+ return (
8
+ <div className="mb-4">
9
+ <h2 className="text-xl font-semibold tracking-tight">{title}</h2>
10
+ <p className="mt-1 max-w-3xl text-sm leading-6 text-muted-foreground">{description}</p>
11
+ </div>
12
+ )
13
+ }
package/registry.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://tembro.dev/registry.schema.json",
3
3
  "name": "tembro",
4
- "version": "3.1.7",
4
+ "version": "3.1.8",
5
5
  "description": "Reusable React + TypeScript UI kit registry",
6
6
  "groups": {
7
7
  "ui": [