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
@@ -560,7 +560,7 @@ function SidebarSurface({
560
560
  type="button"
561
561
  aria-label={mobileCloseLabel}
562
562
  data-slot="app-sidebar-mobile-close"
563
- className="inline-flex size-9 shrink-0 items-center justify-center rounded-xl border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg-alt)] text-[color:var(--aui-page-foreground)] transition hover:bg-[color:var(--aui-control-bg)]"
563
+ className="inline-flex size-9 shrink-0 items-center justify-center rounded-xl border border-[color:var(--aui-divider,var(--border))] bg-[color:var(--aui-page-bg-alt,var(--muted))] text-[color:var(--aui-page-foreground,var(--foreground))] transition hover:bg-[color:var(--aui-control-bg,var(--muted))]"
564
564
  onClick={onRequestClose}
565
565
  >
566
566
  <XIcon className="size-4" />
@@ -781,12 +781,12 @@ function Sidebar({
781
781
  data-slot="app-sidebar-mobile-trigger"
782
782
  data-state={mobileOpen ? "open" : "closed"}
783
783
  className={cn(
784
- "inline-flex min-h-10 items-center gap-2 rounded-xl border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg)] px-3 text-sm font-medium text-[color:var(--aui-page-foreground)] shadow-sm transition hover:bg-[color:var(--aui-page-bg-alt)]",
784
+ "inline-flex min-h-10 items-center gap-2 rounded-xl border border-[color:var(--aui-divider,var(--border))] bg-[color:var(--aui-page-bg,var(--background))] px-3 text-sm font-medium text-[color:var(--aui-page-foreground,var(--foreground))] shadow-sm transition hover:bg-[color:var(--aui-page-bg-alt,var(--muted))]",
785
785
  mobileToggleClassName
786
786
  )}
787
787
  onClick={() => setMobileOpen(!mobileOpen)}
788
788
  >
789
- <span className="inline-flex size-8 items-center justify-center rounded-lg bg-[color:var(--aui-page-bg-alt)]">
789
+ <span className="inline-flex size-8 items-center justify-center rounded-lg bg-[color:var(--aui-page-bg-alt,var(--muted))]">
790
790
  {mobileToggleIcon ?? <MenuIcon className="size-4" />}
791
791
  </span>
792
792
  <span>{mobileOpen ? mobileCloseLabel : mobileToggleLabel}</span>
@@ -808,11 +808,15 @@ function Sidebar({
808
808
  data-state={mobileOpen ? "open" : "closed"}
809
809
  className={cn(
810
810
  "fixed inset-0 z-40 bg-black/45 transition-opacity duration-200",
811
- mobileOpen ? "opacity-100" : "pointer-events-none opacity-0",
812
- mobileOverlayClassName
813
- )}
814
- onClick={() => setMobileOpen(false)}
815
- />
811
+ mobileOpen ? "opacity-100" : "pointer-events-none opacity-0",
812
+ mobileOverlayClassName
813
+ )}
814
+ style={{
815
+ opacity: mobileOpen ? 1 : 0,
816
+ pointerEvents: mobileOpen ? "auto" : "none",
817
+ }}
818
+ onClick={() => setMobileOpen(false)}
819
+ />
816
820
  <SidebarSurface
817
821
  {...baseProps}
818
822
  mobile
@@ -825,16 +829,17 @@ function Sidebar({
825
829
  aria-modal="true"
826
830
  aria-label={typeof mobileTitle === "string" ? mobileTitle : "Navigation"}
827
831
  className={cn(
828
- "fixed inset-y-0 left-0 z-50 max-w-[22rem] border-r border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg)] shadow-2xl transition-transform duration-200 ease-out",
832
+ "fixed inset-y-0 left-0 z-50 max-w-[22rem] border-r border-[color:var(--aui-divider,var(--border))] bg-[color:var(--aui-page-bg,var(--background))] shadow-2xl transition-transform duration-200 ease-out",
829
833
  mobileOpen ? "translate-x-0" : "-translate-x-full",
830
834
  mobilePanelClassName,
831
835
  className
832
836
  )}
833
- style={{
834
- width: mobileWidth,
835
- minWidth: mobileWidth,
836
- }}
837
- />
837
+ style={{
838
+ width: mobileWidth,
839
+ minWidth: mobileWidth,
840
+ translate: mobileOpen ? "0 0" : "-100% 0",
841
+ }}
842
+ />
838
843
  </div>
839
844
  </>
840
845
  )
@@ -1,4 +1,4 @@
1
- export const PACKAGE_LATEST_VERSION = "3.1.7"
1
+ export const PACKAGE_LATEST_VERSION = "3.1.8"
2
2
  export const PACKAGE_LATEST_RELEASE_DATE = "July 15, 2026"
3
3
  export const PACKAGE_DEPENDENCY_RANGE = PACKAGE_LATEST_VERSION
4
4
 
@@ -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": [
@@ -0,0 +1,107 @@
1
+ import { useState } from "react"
2
+ import { BellIcon } from "lucide-react"
3
+
4
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
5
+ import { resolveWorkbenchSelection } from "@/showcase/data/registry"
6
+ import { HeroSection } from "@/showcase/layout/HeroSection"
7
+ import { WorkbenchSidebar } from "@/showcase/layout/WorkbenchSidebar"
8
+ import { CalendarSection } from "@/showcase/sections/CalendarSection"
9
+ import { CategorySection } from "@/showcase/sections/CategorySection"
10
+ import { ComponentDetailSection } from "@/showcase/sections/ComponentDetailSection"
11
+ import { CoreUiSection } from "@/showcase/sections/CoreUiSection"
12
+ import { DataTableSection } from "@/showcase/sections/DataTableSection"
13
+ import { FormsSection } from "@/showcase/sections/FormsSection"
14
+ import { InventorySection } from "@/showcase/sections/InventorySection"
15
+ import { KanbanSection } from "@/showcase/sections/KanbanSection"
16
+ import { OverlaySection } from "@/showcase/sections/OverlaySection"
17
+ import { PatternsSection } from "@/showcase/sections/PatternsSection"
18
+ import { VerificationSection } from "@/showcase/sections/VerificationSection"
19
+ import { WizardSection } from "@/showcase/sections/WizardSection"
20
+ import { SectionTitle } from "@/showcase/shared/SectionTitle"
21
+
22
+ function OverviewContent() {
23
+ return (
24
+ <>
25
+ <section>
26
+ <SectionTitle
27
+ title="Live Component Sections"
28
+ description="Har bir katta category o‘z faylida: sidebar, kanban, data-table, calendar, overlay, wizard, UI controls va style variantlar."
29
+ />
30
+ <Tabs defaultValue="ui">
31
+ <TabsList overflow="wrap">
32
+ <TabsTrigger value="ui">UI</TabsTrigger>
33
+ <TabsTrigger value="forms">Forms</TabsTrigger>
34
+ <TabsTrigger value="data">Data</TabsTrigger>
35
+ <TabsTrigger value="kanban">Kanban</TabsTrigger>
36
+ <TabsTrigger value="calendar">Calendar</TabsTrigger>
37
+ <TabsTrigger value="overlay">Overlay</TabsTrigger>
38
+ <TabsTrigger value="patterns">Patterns</TabsTrigger>
39
+ <TabsTrigger value="wizard">Wizard</TabsTrigger>
40
+ </TabsList>
41
+
42
+ <TabsContent value="ui" className="mt-5">
43
+ <CoreUiSection />
44
+ </TabsContent>
45
+ <TabsContent value="forms" className="mt-5">
46
+ <FormsSection />
47
+ </TabsContent>
48
+ <TabsContent value="data" className="mt-5">
49
+ <DataTableSection />
50
+ </TabsContent>
51
+ <TabsContent value="kanban" className="mt-5">
52
+ <KanbanSection />
53
+ </TabsContent>
54
+ <TabsContent value="calendar" className="mt-5">
55
+ <CalendarSection />
56
+ </TabsContent>
57
+ <TabsContent value="overlay" className="mt-5">
58
+ <OverlaySection />
59
+ </TabsContent>
60
+ <TabsContent value="patterns" className="mt-5">
61
+ <PatternsSection />
62
+ </TabsContent>
63
+ <TabsContent value="wizard" className="mt-5">
64
+ <WizardSection />
65
+ </TabsContent>
66
+ </Tabs>
67
+ </section>
68
+
69
+ <InventorySection />
70
+ <VerificationSection />
71
+ </>
72
+ )
73
+ }
74
+
75
+ function App() {
76
+ const [selectedKey, setSelectedKey] = useState("overview")
77
+ const selection = resolveWorkbenchSelection(selectedKey)
78
+
79
+ return (
80
+ <main className="min-h-screen bg-background text-foreground">
81
+ <div className="grid min-h-screen lg:grid-cols-[280px_1fr]">
82
+ <WorkbenchSidebar selectedKey={selectedKey} onSelect={setSelectedKey} />
83
+
84
+ <div className="min-w-0">
85
+ <HeroSection />
86
+
87
+ <div className="mx-auto grid max-w-7xl gap-10 px-6 py-10 lg:px-8">
88
+ {selection.type === "overview" ? <OverviewContent /> : null}
89
+ {selection.type === "category" ? (
90
+ <CategorySection group={selection.group} onSelect={setSelectedKey} />
91
+ ) : null}
92
+ {selection.type === "module" ? (
93
+ <ComponentDetailSection group={selection.group} component={selection.component} />
94
+ ) : null}
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <div className="fixed bottom-4 right-4 hidden rounded-full border bg-card px-4 py-2 text-sm shadow-lg md:flex md:items-center md:gap-2">
100
+ <BellIcon className="size-4 text-primary" />
101
+ <span>Local Tembro workbench active</span>
102
+ </div>
103
+ </main>
104
+ )
105
+ }
106
+
107
+ export default App
@@ -0,0 +1,273 @@
1
+ export type ComponentStatus = "stable" | "preview" | "experimental" | "internal"
2
+
3
+ export type RegistryComponent = {
4
+ name: string
5
+ status: ComponentStatus
6
+ sourcePath: string
7
+ }
8
+
9
+ export type RegistryGroup = {
10
+ name: string
11
+ components: RegistryComponent[]
12
+ }
13
+
14
+ export type ComponentRow = {
15
+ id: string
16
+ component: string
17
+ category: string
18
+ status: "Ready" | "Testing" | "Review"
19
+ props: number
20
+ }
21
+
22
+ const component = (name: string, status: ComponentStatus, sourcePath: string): RegistryComponent => ({
23
+ name,
24
+ status,
25
+ sourcePath,
26
+ })
27
+
28
+ export const registryGroups: RegistryGroup[] = [
29
+ {
30
+ name: "ui",
31
+ components: [
32
+ component("button", "stable", "src/components/ui/button"),
33
+ component("input", "stable", "src/components/ui/input"),
34
+ component("textarea", "stable", "src/components/ui/textarea"),
35
+ component("checkbox", "stable", "src/components/ui/checkbox"),
36
+ component("switch", "stable", "src/components/ui/switch"),
37
+ component("badge", "stable", "src/components/ui/badge"),
38
+ component("card", "stable", "src/components/ui/card"),
39
+ component("skeleton", "preview", "src/components/ui/skeleton"),
40
+ component("tabs", "preview", "src/components/ui/tabs"),
41
+ component("dialog", "stable", "src/components/ui/dialog"),
42
+ component("dropdown-menu", "stable", "src/components/ui/dropdown-menu"),
43
+ component("popover", "stable", "src/components/ui/popover"),
44
+ component("tooltip", "preview", "src/components/ui/tooltip"),
45
+ component("select", "stable", "src/components/ui/select"),
46
+ component("table", "stable", "src/components/ui/table"),
47
+ component("segmented-control", "preview", "src/components/ui/segmented-control"),
48
+ component("radio-group", "stable", "src/components/ui/radio-group"),
49
+ component("accordion", "stable", "src/components/ui/accordion"),
50
+ component("kbd", "stable", "src/components/ui/kbd"),
51
+ component("scroll-box", "stable", "src/components/ui/scroll-box"),
52
+ component("right-click-menu", "stable", "src/components/ui/right-click-menu"),
53
+ component("collapse", "preview", "src/components/ui/collapse"),
54
+ component("command", "preview", "src/components/ui/command"),
55
+ component("divider", "preview", "src/components/ui/divider"),
56
+ component("spinner", "preview", "src/components/ui/spinner"),
57
+ ],
58
+ },
59
+ {
60
+ name: "actions",
61
+ components: [
62
+ component("action-menu", "stable", "src/components/actions/action-menu.tsx"),
63
+ component("button-group", "preview", "src/components/actions/button-group.tsx"),
64
+ component("copy-button", "preview", "src/components/actions/copy-button.tsx"),
65
+ component("quick-action-grid", "preview", "src/components/actions/quick-action-grid.tsx"),
66
+ ],
67
+ },
68
+ {
69
+ name: "inputs",
70
+ components: [
71
+ component("tag-input", "preview", "src/components/inputs/tag-input.tsx"),
72
+ component("async-select", "preview", "src/components/inputs/async-select.tsx"),
73
+ component("otp-input", "preview", "src/components/inputs/otp-input.tsx"),
74
+ component("color-picker", "stable", "src/components/inputs/color-picker.tsx"),
75
+ component("signature-pad", "preview", "src/components/inputs/signature-pad.tsx"),
76
+ component("rating", "preview", "src/components/inputs/rating.tsx"),
77
+ component("slider", "preview", "src/components/inputs/slider.tsx"),
78
+ component("inline-editable", "preview", "src/components/inputs/inline-editable.tsx"),
79
+ component("json-input", "preview", "src/components/inputs/json-input.tsx"),
80
+ component("time-picker", "preview", "src/components/inputs/time-picker.tsx"),
81
+ ],
82
+ },
83
+ {
84
+ name: "form",
85
+ components: [
86
+ component("form-field-shell", "preview", "src/components/form/form-field-shell.tsx"),
87
+ component("form-input", "preview", "src/components/form/form-input.tsx"),
88
+ component("form-select", "preview", "src/components/form/form-select.tsx"),
89
+ component("form-textarea", "preview", "src/components/form/form-textarea.tsx"),
90
+ component("form-switch", "preview", "src/components/form/form-switch.tsx"),
91
+ component("form-date-range-input", "preview", "src/components/form/form-date-range-input.tsx"),
92
+ component("form-date-picker", "preview", "src/components/form/form-date-picker.tsx"),
93
+ component("form-date-range-picker", "preview", "src/components/form/form-date-range-picker.tsx"),
94
+ ],
95
+ },
96
+ {
97
+ name: "display",
98
+ components: [
99
+ component("activity-feed", "stable", "src/components/display/activity-feed.tsx"),
100
+ component("avatar", "preview", "src/components/display/avatar.tsx"),
101
+ component("code-block", "preview", "src/components/display/code-block.tsx"),
102
+ component("carousel", "preview", "src/components/display/carousel.tsx"),
103
+ component("tag", "preview", "src/components/display/tag.tsx"),
104
+ component("typography", "preview", "src/components/display/typography.tsx"),
105
+ component("data-state", "preview", "src/components/display/data-state.tsx"),
106
+ component("description-list", "stable", "src/components/display/description-list.tsx"),
107
+ component("kanban", "preview", "src/components/display/kanban.tsx"),
108
+ component("list", "preview", "src/components/display/list.tsx"),
109
+ component("progress", "stable", "src/components/display/progress.tsx"),
110
+ component("info-card", "stable", "src/components/display/info-card.tsx"),
111
+ component("statistic", "preview", "src/components/display/statistic.tsx"),
112
+ component("status-dot", "preview", "src/components/display/status-dot.tsx"),
113
+ component("status-legend", "preview", "src/components/display/status-legend.tsx"),
114
+ component("timeline", "stable", "src/components/display/timeline.tsx"),
115
+ component("tree-view", "preview", "src/components/display/tree-view.tsx"),
116
+ component("qr-code", "stable", "src/components/display/qr-code.tsx"),
117
+ component("virtual-list", "preview", "src/components/display/virtual-list.tsx"),
118
+ ],
119
+ },
120
+ { name: "data-table", components: [component("data-table", "preview", "src/components/data-table/data-table.tsx")] },
121
+ {
122
+ name: "calendar",
123
+ components: [
124
+ component("calendar", "preview", "src/components/calendar/calendar.tsx"),
125
+ component("date-picker", "preview", "src/components/calendar/date-picker.tsx"),
126
+ component("date-range-picker", "preview", "src/components/calendar/date-range-picker.tsx"),
127
+ ],
128
+ },
129
+ {
130
+ name: "overlay",
131
+ components: [
132
+ component("confirm-dialog", "stable", "src/components/overlay/confirm-dialog.tsx"),
133
+ component("alert-dialog", "stable", "src/components/overlay/alert-dialog.tsx"),
134
+ component("drawer", "stable", "src/components/overlay/drawer.tsx"),
135
+ ],
136
+ },
137
+ {
138
+ name: "feedback",
139
+ components: [
140
+ component("loading-state", "stable", "src/components/feedback/loading-state.tsx"),
141
+ component("page-state", "preview", "src/components/feedback/page-state.tsx"),
142
+ component("alert", "preview", "src/components/feedback/alert.tsx"),
143
+ ],
144
+ },
145
+ {
146
+ name: "layout",
147
+ components: [
148
+ component("sidebar", "stable", "src/components/layout/app-sidebar.tsx"),
149
+ component("breadcrumbs", "stable", "src/components/layout/breadcrumbs.tsx"),
150
+ component("section", "preview", "src/components/layout/section.tsx"),
151
+ ],
152
+ },
153
+ {
154
+ name: "patterns",
155
+ components: [
156
+ component("bulk-action-bar", "preview", "src/components/patterns/bulk-action-bar.tsx"),
157
+ component("data-view", "preview", "src/components/patterns/data-view.tsx"),
158
+ component("detail-layout", "preview", "src/components/patterns/detail-layout.tsx"),
159
+ component("empty-state", "preview", "src/components/patterns/empty-state.tsx"),
160
+ component("form-builder", "preview", "src/components/patterns/form-builder.tsx"),
161
+ component("resource-detail-page", "preview", "src/components/patterns/resource-detail-page.tsx"),
162
+ component("resource-page", "preview", "src/components/patterns/resource-page.tsx"),
163
+ component("page-toolbar", "preview", "src/components/patterns/page-toolbar.tsx"),
164
+ component("settings-page", "preview", "src/components/patterns/settings-page.tsx"),
165
+ ],
166
+ },
167
+ {
168
+ name: "modern",
169
+ components: [
170
+ component("calendar-scheduler", "preview", "src/components/modern/calendar-scheduler.tsx"),
171
+ component("dual-list-picker", "preview", "src/components/modern/dual-list-picker.tsx"),
172
+ component("resizable-panel", "preview", "src/components/modern/resizable-panel.tsx"),
173
+ component("rich-text-editor", "preview", "src/components/modern/rich-text-editor.tsx"),
174
+ component("image-cropper", "preview", "src/components/modern/image-cropper.tsx"),
175
+ ],
176
+ },
177
+ {
178
+ name: "upload",
179
+ components: [
180
+ component("file-upload", "preview", "src/components/upload/file-upload.tsx"),
181
+ component("image-upload", "preview", "src/components/upload/image-upload.tsx"),
182
+ ],
183
+ },
184
+ {
185
+ name: "filters",
186
+ components: [
187
+ component("filter-bar", "stable", "src/components/filters/filter-bar.tsx"),
188
+ component("saved-filter-select", "preview", "src/components/filters/saved-filter-select.tsx"),
189
+ ],
190
+ },
191
+ { name: "navigation", components: [component("pagination", "stable", "src/components/navigation/pagination.tsx")] },
192
+ { name: "charts", components: [component("progress-circle", "stable", "src/components/charts/progress-circle.tsx")] },
193
+ {
194
+ name: "wizard",
195
+ components: [
196
+ component("stepper", "preview", "src/components/wizard/stepper.tsx"),
197
+ component("wizard", "preview", "src/components/wizard/wizard.tsx"),
198
+ ],
199
+ },
200
+ {
201
+ name: "notifications",
202
+ components: [
203
+ component("toast", "preview", "src/components/notifications/toast.tsx"),
204
+ component("notification-center", "preview", "src/components/notifications/notification-center.tsx"),
205
+ ],
206
+ },
207
+ { name: "command", components: [component("command-palette", "preview", "src/components/command/command-palette.tsx")] },
208
+ { name: "dnd", components: [component("sortable-list", "preview", "src/components/dnd/sortable-list.tsx")] },
209
+ ]
210
+
211
+ export const componentRows: ComponentRow[] = [
212
+ { id: "cmp-001", component: "sidebar", category: "layout", status: "Ready", props: 34 },
213
+ { id: "cmp-002", component: "kanban", category: "display", status: "Ready", props: 13 },
214
+ { id: "cmp-003", component: "data-table", category: "data-table", status: "Testing", props: 50 },
215
+ { id: "cmp-004", component: "calendar", category: "calendar", status: "Ready", props: 22 },
216
+ { id: "cmp-005", component: "drawer", category: "overlay", status: "Ready", props: 14 },
217
+ { id: "cmp-006", component: "wizard", category: "wizard", status: "Review", props: 12 },
218
+ { id: "cmp-007", component: "button", category: "ui", status: "Ready", props: 9 },
219
+ { id: "cmp-008", component: "input", category: "ui", status: "Ready", props: 11 },
220
+ ]
221
+
222
+ export const wizardSteps = [
223
+ { id: "setup", title: "Setup", description: "init + theme", completed: true },
224
+ { id: "add", title: "Add", description: "105 registry components", completed: true },
225
+ { id: "test", title: "Test", description: "visible workbench" },
226
+ ]
227
+
228
+ export const moduleCount = registryGroups.reduce((sum, group) => sum + group.components.length, 0)
229
+
230
+ export type WorkbenchSelection =
231
+ | { type: "overview"; key: "overview" }
232
+ | { type: "category"; key: string; group: RegistryGroup }
233
+ | { type: "module"; key: string; group: RegistryGroup; component: RegistryComponent }
234
+
235
+ export function getCategoryKey(groupName: string) {
236
+ return `category:${groupName}`
237
+ }
238
+
239
+ export function getModuleKey(groupName: string, componentName: string) {
240
+ return `component:${groupName}/${componentName}`
241
+ }
242
+
243
+ export function getModuleLabel(componentName: string) {
244
+ return componentName
245
+ }
246
+
247
+ export function getModuleSourcePath(component: RegistryComponent) {
248
+ return component.sourcePath
249
+ }
250
+
251
+ export function resolveWorkbenchSelection(key: string): WorkbenchSelection {
252
+ if (key === "overview") return { type: "overview", key: "overview" }
253
+
254
+ if (key.startsWith("category:")) {
255
+ const groupName = key.slice("category:".length)
256
+ const group = registryGroups.find((item) => item.name === groupName)
257
+ if (group) return { type: "category", key, group }
258
+ }
259
+
260
+ if (key.startsWith("component:")) {
261
+ const value = key.slice("component:".length)
262
+ const slashIndex = value.indexOf("/")
263
+ const groupName = value.slice(0, slashIndex)
264
+ const componentName = value.slice(slashIndex + 1)
265
+ const group = registryGroups.find((item) => item.name === groupName)
266
+ const selectedComponent = group?.components.find((item) => item.name === componentName)
267
+ if (group && selectedComponent) {
268
+ return { type: "module", key, group, component: selectedComponent }
269
+ }
270
+ }
271
+
272
+ return { type: "overview", key: "overview" }
273
+ }
@@ -0,0 +1,41 @@
1
+ import { PlusIcon, SettingsIcon } from "lucide-react"
2
+
3
+ import { CopyButton } from "@/components/actions/copy-button"
4
+ import { StatisticCard, StatisticGrid } from "@/components/display/statistic"
5
+ import { Badge } from "@/components/ui/badge"
6
+ import { Button } from "@/components/ui/button"
7
+ import { moduleCount, registryGroups } from "@/showcase/data/registry"
8
+
9
+ export function HeroSection() {
10
+ return (
11
+ <section className="border-b bg-card">
12
+ <div className="mx-auto max-w-7xl px-6 py-8 lg:px-8">
13
+ <div className="flex flex-wrap items-start justify-between gap-6">
14
+ <div className="max-w-3xl">
15
+ <div className="mb-3 flex flex-wrap gap-2">
16
+ <Badge status="success" label="tembro init done" variant="soft" />
17
+ <Badge status="info" label={`${moduleCount} registry components`} variant="soft" />
18
+ <Badge status="warning" label="real local components" variant="soft" />
19
+ </div>
20
+ <h1 className="text-4xl font-semibold tracking-tight">All Tembro Components Test Surface</h1>
21
+ <p className="mt-3 text-base leading-7 text-muted-foreground">
22
+ Vite starter olib tashlandi. Bu ekran `tembro add showcase` orqali o‘rnatilgan aniq registry componentlardan qurildi.
23
+ </p>
24
+ </div>
25
+ <div className="flex flex-wrap gap-2">
26
+ <Button leftIcon={<PlusIcon className="size-4" />}>Create</Button>
27
+ <Button variant="outline" leftIcon={<SettingsIcon className="size-4" />}>Settings</Button>
28
+ <CopyButton value="npx tembro@3.1.8 list --json">Copy list command</CopyButton>
29
+ </div>
30
+ </div>
31
+
32
+ <StatisticGrid columns={4} className="mt-8">
33
+ <StatisticCard label="Registry components" value={moduleCount} change="visible below" trend="up" description="tembro add <name>" />
34
+ <StatisticCard label="Local source files" value="152" change="with hooks/lib" trend="up" description="installed by CLI" />
35
+ <StatisticCard label="Categories" value={registryGroups.length} change="all shown" trend="up" description="actions to wizard" />
36
+ <StatisticCard label="Build" value="Pass" change="doctor pass" trend="up" description="tembro@3.1.8" />
37
+ </StatisticGrid>
38
+ </div>
39
+ </section>
40
+ )
41
+ }
@@ -0,0 +1,82 @@
1
+ import {
2
+ CalendarDaysIcon,
3
+ ClipboardListIcon,
4
+ DatabaseIcon,
5
+ FolderKanbanIcon,
6
+ Layers3Icon,
7
+ LayoutDashboardIcon,
8
+ SparklesIcon,
9
+ UploadCloudIcon,
10
+ WandSparklesIcon,
11
+ } from "lucide-react"
12
+
13
+ import { Sidebar } from "@/components/layout/app-sidebar"
14
+ import { Badge } from "@/components/ui/badge"
15
+ import { getCategoryKey, getModuleKey, getModuleLabel, moduleCount, registryGroups } from "@/showcase/data/registry"
16
+
17
+ type WorkbenchSidebarProps = {
18
+ selectedKey: string
19
+ onSelect: (key: string) => void
20
+ }
21
+
22
+ export function WorkbenchSidebar({ selectedKey, onSelect }: WorkbenchSidebarProps) {
23
+ return (
24
+ <aside className="border-r bg-sidebar p-3 lg:sticky lg:top-0 lg:h-screen lg:overflow-y-auto">
25
+ <Sidebar
26
+ width="100%"
27
+ header={
28
+ <div className="flex items-center gap-3 rounded-xl border bg-card p-3">
29
+ <div className="flex size-10 items-center justify-center rounded-lg bg-primary text-primary-foreground">
30
+ <WandSparklesIcon className="size-5" />
31
+ </div>
32
+ <div className="min-w-0">
33
+ <div className="truncate font-semibold">Tembro Workbench</div>
34
+ <div className="text-xs text-muted-foreground">local copied components</div>
35
+ </div>
36
+ </div>
37
+ }
38
+ items={[
39
+ { key: "overview", label: "Overview", icon: <LayoutDashboardIcon className="size-4" />, active: selectedKey === "overview", badge: <Badge label="live" status="success" />, onSelect: () => onSelect("overview") },
40
+ ...registryGroups.map((group) => {
41
+ const categoryKey = getCategoryKey(group.name)
42
+ return {
43
+ key: categoryKey,
44
+ label: group.name,
45
+ icon: group.name === "ui"
46
+ ? <SparklesIcon className="size-4" />
47
+ : group.name === "data-table"
48
+ ? <DatabaseIcon className="size-4" />
49
+ : group.name === "display"
50
+ ? <FolderKanbanIcon className="size-4" />
51
+ : group.name === "calendar"
52
+ ? <CalendarDaysIcon className="size-4" />
53
+ : group.name === "overlay"
54
+ ? <Layers3Icon className="size-4" />
55
+ : group.name === "upload"
56
+ ? <UploadCloudIcon className="size-4" />
57
+ : <ClipboardListIcon className="size-4" />,
58
+ active: selectedKey === categoryKey || selectedKey.startsWith(`component:${group.name}/`),
59
+ badge: <Badge label={group.components.length} variant="secondary" />,
60
+ defaultExpanded: ["ui", "display", "data-table", "inputs", "layout", "overlay"].includes(group.name),
61
+ onSelect: () => onSelect(categoryKey),
62
+ items: group.components.map((component) => {
63
+ const moduleKey = getModuleKey(group.name, component.name)
64
+ return {
65
+ key: moduleKey,
66
+ label: getModuleLabel(component.name),
67
+ active: selectedKey === moduleKey,
68
+ onSelect: () => onSelect(moduleKey),
69
+ }
70
+ }),
71
+ }
72
+ }),
73
+ ]}
74
+ footerAccount={{
75
+ label: "tembro@3.1.8",
76
+ description: `${moduleCount} registry components`,
77
+ }}
78
+ activeIndicator="bar"
79
+ />
80
+ </aside>
81
+ )
82
+ }
@@ -0,0 +1,35 @@
1
+ import { useState } from "react"
2
+
3
+ import { Calendar } from "@/components/calendar/calendar"
4
+ import { DatePicker } from "@/components/calendar/date-picker"
5
+ import { Pagination } from "@/components/navigation/pagination"
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
7
+
8
+ export function CalendarSection() {
9
+ const [date, setDate] = useState("2026-07-15")
10
+ const [page, setPage] = useState(2)
11
+
12
+ return (
13
+ <div className="grid gap-4 lg:grid-cols-[1fr_0.8fr]">
14
+ <Card>
15
+ <CardHeader>
16
+ <CardTitle>Calendar</CardTitle>
17
+ <CardDescription>Single/range capable calendar module.</CardDescription>
18
+ </CardHeader>
19
+ <CardContent>
20
+ <Calendar value={date} onValueChange={setDate} showTodayShortcut showClearShortcut showSelectionSummary />
21
+ </CardContent>
22
+ </Card>
23
+ <Card>
24
+ <CardHeader>
25
+ <CardTitle>DatePicker and pagination</CardTitle>
26
+ <CardDescription>Popover date picker plus navigation pagination.</CardDescription>
27
+ </CardHeader>
28
+ <CardContent className="grid gap-5">
29
+ <DatePicker value={date} onValueChange={setDate} />
30
+ <Pagination page={page} pageCount={9} onPageChange={setPage} showSummary totalCount={90} pageSize={10} />
31
+ </CardContent>
32
+ </Card>
33
+ </div>
34
+ )
35
+ }