tembro 3.1.7 → 3.1.9
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/showcase/package-meta.d.ts +2 -2
- package/dist/src/components/layout/app-sidebar.cjs +1 -1
- package/dist/src/components/layout/app-sidebar.js +10 -5
- package/dist/src/showcase/package-meta.cjs +1 -1
- package/dist/src/showcase/package-meta.js +1 -1
- package/dist/src/showcase/site-data.cjs +1 -1
- package/dist/src/showcase/site-data.js +1 -1
- package/dist/src/showcase/tembro-registry.json.cjs +1 -1
- package/dist/src/showcase/tembro-registry.json.js +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +116 -116
- package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +19 -14
- package/packages/cli/vendor/src/showcase/package-meta.ts +1 -1
- package/packages/cli/vendor/src/showcase/tembro-registry.json +1 -1
- package/packages/cli/vendor/templates/showcase/src/App.tsx +107 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/data/registry.ts +273 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/layout/HeroSection.tsx +41 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/layout/WorkbenchSidebar.tsx +82 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/CalendarSection.tsx +35 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/CategorySection.tsx +48 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentDetailSection.tsx +46 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/ComponentLivePreview.tsx +64 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/CoreUiSection.tsx +100 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/DataTableSection.tsx +45 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/FormsSection.tsx +26 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/InventorySection.tsx +38 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/KanbanSection.tsx +42 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/OverlaySection.tsx +62 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/PatternsSection.tsx +36 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/VerificationSection.tsx +42 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/sections/WizardSection.tsx +44 -0
- package/packages/cli/vendor/templates/showcase/src/showcase/shared/SectionTitle.tsx +13 -0
- 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
|
-
|
|
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
|
)
|
|
@@ -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.9 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.9" />
|
|
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.9",
|
|
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
|
+
}
|