@mbao01/common 0.0.48 → 0.0.50
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/types/components/Breadcrumb/Breadcrumb.d.ts +20 -0
- package/dist/types/components/Breadcrumb/constants.d.ts +6 -0
- package/dist/types/components/Breadcrumb/index.d.ts +1 -0
- package/dist/types/components/Breadcrumb/types.d.ts +12 -0
- package/dist/types/components/Command/Command.d.ts +6 -6
- package/dist/types/components/Form/MultiSelect/MultiSelect.d.ts +2 -2
- package/dist/types/components/Sidebar/Sidebar.d.ts +39 -0
- package/dist/types/components/Sidebar/SidebarContext.d.ts +2 -0
- package/dist/types/components/Sidebar/SidebarGroup.d.ts +13 -0
- package/dist/types/components/Sidebar/SidebarMenu.d.ts +30 -0
- package/dist/types/components/Sidebar/constants.d.ts +48 -0
- package/dist/types/components/Sidebar/hooks/index.d.ts +1 -0
- package/dist/types/components/Sidebar/hooks/useSidebar/index.d.ts +1 -0
- package/dist/types/components/Sidebar/hooks/useSidebar/useSidebar.d.ts +1 -0
- package/dist/types/components/Sidebar/index.d.ts +4 -0
- package/dist/types/components/Sidebar/stories/examples/Sidebar.example.d.ts +57 -0
- package/dist/types/components/Sidebar/stories/examples/components/AppMain.d.ts +3 -0
- package/dist/types/components/Sidebar/stories/examples/components/AppSidebar.d.ts +6 -0
- package/dist/types/components/Sidebar/stories/examples/components/SearchForm.d.ts +1 -0
- package/dist/types/components/Sidebar/stories/examples/components/VersionSwitcher.d.ts +4 -0
- package/dist/types/components/Sidebar/types.d.ts +55 -0
- package/dist/types/hooks/index.d.ts +1 -0
- package/dist/types/hooks/useIsMobile/index.d.ts +1 -0
- package/dist/types/hooks/useIsMobile/useIsMobile.d.ts +1 -0
- package/dist/types/index.d.ts +3 -1
- package/package.json +3 -3
- package/src/components/Anchor/Anchor.tsx +2 -2
- package/src/components/Breadcrumb/Breadcrumb.tsx +99 -0
- package/src/components/Breadcrumb/constants.ts +15 -0
- package/src/components/Breadcrumb/index.ts +1 -0
- package/src/components/Breadcrumb/types.ts +19 -0
- package/src/components/Calendar/Calendar.tsx +1 -1
- package/src/components/Carousel/Carousel.tsx +1 -1
- package/src/components/Chart/stories/examples/LineChart.tsx +2 -2
- package/src/components/Combobox/Combobox.tsx +2 -2
- package/src/components/Command/Command.tsx +2 -2
- package/src/components/DatePicker/DatePicker.tsx +2 -2
- package/src/components/DatePicker/DateRangePicker.tsx +2 -2
- package/src/components/DatePicker/MultipleDatesPicker.tsx +2 -2
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/FileUploader/FileUploader.tsx +2 -2
- package/src/components/Form/DatetimeInput/DatetimeCalendar.tsx +2 -2
- package/src/components/Form/MultiSelect/MultiSelect.tsx +2 -2
- package/src/components/Form/Select/Select.tsx +1 -1
- package/src/components/Form/TagsInput/TagsInput.tsx +2 -2
- package/src/components/Menu/ContextMenu/ContextMenu.tsx +2 -2
- package/src/components/Menu/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/components/Menu/Menubar/Menubar.tsx +2 -2
- package/src/components/Menu/NavigationMenu/NavigationMenu.tsx +1 -1
- package/src/components/Pagination/Pagination.tsx +2 -2
- package/src/components/Sidebar/Sidebar.tsx +326 -0
- package/src/components/Sidebar/SidebarContext.tsx +6 -0
- package/src/components/Sidebar/SidebarGroup.tsx +72 -0
- package/src/components/Sidebar/SidebarMenu.tsx +205 -0
- package/src/components/Sidebar/constants.ts +206 -0
- package/src/components/Sidebar/hooks/index.ts +1 -0
- package/src/components/Sidebar/hooks/useSidebar/index.ts +1 -0
- package/src/components/Sidebar/hooks/useSidebar/useSidebar.ts +11 -0
- package/src/components/Sidebar/index.ts +4 -0
- package/src/components/Sidebar/stories/examples/Sidebar.example.tsx +155 -0
- package/src/components/Sidebar/stories/examples/components/AppMain.tsx +35 -0
- package/src/components/Sidebar/stories/examples/components/AppSidebar.tsx +531 -0
- package/src/components/Sidebar/stories/examples/components/SearchForm.tsx +26 -0
- package/src/components/Sidebar/stories/examples/components/VersionSwitcher.tsx +45 -0
- package/src/components/Sidebar/types.ts +74 -0
- package/src/components/Widget/Widgets.example.tsx +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useIsMobile/index.ts +1 -0
- package/src/hooks/useIsMobile/useIsMobile.ts +19 -0
- package/src/index.ts +4 -1
- package/dist/types/components/Breadcrumbs/Breadcrumbs.d.ts +0 -3
- package/dist/types/components/Breadcrumbs/index.d.ts +0 -1
- package/dist/types/components/Breadcrumbs/types.d.ts +0 -2
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +0 -13
- package/src/components/Breadcrumbs/index.ts +0 -1
- package/src/components/Breadcrumbs/types.ts +0 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { HTMLAttributes } from "react";
|
|
2
|
+
import { Breadcrumb } from "../../../../Breadcrumb";
|
|
3
|
+
import { Sidebar } from "../../../Sidebar";
|
|
4
|
+
import { type SidebarProps } from "../../../types";
|
|
5
|
+
|
|
6
|
+
export const AppMain = ({
|
|
7
|
+
side,
|
|
8
|
+
...props
|
|
9
|
+
}: HTMLAttributes<HTMLDivElement> & Pick<SidebarProps, "side">) => {
|
|
10
|
+
return (
|
|
11
|
+
<Sidebar.Inset {...props}>
|
|
12
|
+
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
|
13
|
+
{side !== "right" ? <Sidebar.Trigger className="-ml-1" /> : null}
|
|
14
|
+
<Breadcrumb>
|
|
15
|
+
<Breadcrumb.List>
|
|
16
|
+
<Breadcrumb.Link asChild className="hidden md:block">
|
|
17
|
+
<a href="#">Building Your Application</a>
|
|
18
|
+
</Breadcrumb.Link>
|
|
19
|
+
<Breadcrumb.Separator />
|
|
20
|
+
<Breadcrumb.Page>Data Fetching</Breadcrumb.Page>
|
|
21
|
+
</Breadcrumb.List>
|
|
22
|
+
</Breadcrumb>
|
|
23
|
+
{side === "right" ? <Sidebar.Trigger className="-mr-1 ml-auto !rotate-180" /> : null}
|
|
24
|
+
</header>
|
|
25
|
+
<div className="flex flex-1 flex-col gap-4 p-4">
|
|
26
|
+
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
|
27
|
+
<div className="aspect-video rounded-xl bg-base-200/50" />
|
|
28
|
+
<div className="aspect-video rounded-xl bg-base-200/50" />
|
|
29
|
+
<div className="aspect-video rounded-xl bg-base-200/50" />
|
|
30
|
+
</div>
|
|
31
|
+
<div className="min-h-[100vh] flex-1 rounded-xl bg-base-200/50 md:min-h-min" />
|
|
32
|
+
</div>
|
|
33
|
+
</Sidebar.Inset>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AudioWaveform,
|
|
3
|
+
BookOpen,
|
|
4
|
+
Bot,
|
|
5
|
+
ChevronRight,
|
|
6
|
+
Command,
|
|
7
|
+
File,
|
|
8
|
+
Folder,
|
|
9
|
+
Frame,
|
|
10
|
+
GalleryVerticalEnd,
|
|
11
|
+
Map,
|
|
12
|
+
Minus,
|
|
13
|
+
MoreHorizontal,
|
|
14
|
+
PieChart,
|
|
15
|
+
Plus,
|
|
16
|
+
Settings2,
|
|
17
|
+
Share,
|
|
18
|
+
SquareTerminal,
|
|
19
|
+
Trash2,
|
|
20
|
+
} from "lucide-react";
|
|
21
|
+
import { Collapsible } from "../../../../Collapsible";
|
|
22
|
+
import { DropdownMenu } from "../../../../Menu";
|
|
23
|
+
import { useSidebar } from "../../../hooks";
|
|
24
|
+
import { Sidebar } from "../../../Sidebar";
|
|
25
|
+
import { SidebarGroup } from "../../../SidebarGroup";
|
|
26
|
+
import { SidebarMenu } from "../../../SidebarMenu";
|
|
27
|
+
import { type SidebarProps } from "../../../types";
|
|
28
|
+
import { SearchForm } from "./SearchForm";
|
|
29
|
+
import { VersionSwitcher } from "./VersionSwitcher";
|
|
30
|
+
|
|
31
|
+
// This is sample data.
|
|
32
|
+
const data = {
|
|
33
|
+
versions: ["1.0.1", "1.1.0-alpha", "2.0.0-beta1"],
|
|
34
|
+
user: {
|
|
35
|
+
name: "shadcn",
|
|
36
|
+
email: "m@example.com",
|
|
37
|
+
avatar: "/avatars/shadcn.jpg",
|
|
38
|
+
},
|
|
39
|
+
teams: [
|
|
40
|
+
{
|
|
41
|
+
name: "Acme Inc",
|
|
42
|
+
logo: GalleryVerticalEnd,
|
|
43
|
+
plan: "Enterprise",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "Acme Corp.",
|
|
47
|
+
logo: AudioWaveform,
|
|
48
|
+
plan: "Startup",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "Evil Corp.",
|
|
52
|
+
logo: Command,
|
|
53
|
+
plan: "Free",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
navMain: [
|
|
57
|
+
{
|
|
58
|
+
title: "Playground",
|
|
59
|
+
url: "#",
|
|
60
|
+
icon: SquareTerminal,
|
|
61
|
+
isActive: true,
|
|
62
|
+
items: [
|
|
63
|
+
{
|
|
64
|
+
title: "History",
|
|
65
|
+
url: "#",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
title: "Starred",
|
|
69
|
+
url: "#",
|
|
70
|
+
isActive: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: "Settings",
|
|
74
|
+
url: "#",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: "Models",
|
|
80
|
+
url: "#",
|
|
81
|
+
icon: Bot,
|
|
82
|
+
isActive: false,
|
|
83
|
+
items: [
|
|
84
|
+
{
|
|
85
|
+
title: "Genesis",
|
|
86
|
+
url: "#",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
title: "Explorer",
|
|
90
|
+
url: "#",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: "Quantum",
|
|
94
|
+
url: "#",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
title: "Documentation",
|
|
100
|
+
url: "#",
|
|
101
|
+
icon: BookOpen,
|
|
102
|
+
isActive: false,
|
|
103
|
+
items: [
|
|
104
|
+
{
|
|
105
|
+
title: "Introduction",
|
|
106
|
+
url: "#",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
title: "Get Started",
|
|
110
|
+
url: "#",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
title: "Tutorials",
|
|
114
|
+
url: "#",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
title: "Changelog",
|
|
118
|
+
url: "#",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
title: "Settings",
|
|
124
|
+
url: "#",
|
|
125
|
+
icon: Settings2,
|
|
126
|
+
isActive: false,
|
|
127
|
+
items: [
|
|
128
|
+
{
|
|
129
|
+
title: "General",
|
|
130
|
+
url: "#",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: "Team",
|
|
134
|
+
url: "#",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
title: "Billing",
|
|
138
|
+
url: "#",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
title: "Limits",
|
|
142
|
+
url: "#",
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
projects: [
|
|
148
|
+
{
|
|
149
|
+
name: "Design Engineering",
|
|
150
|
+
url: "#",
|
|
151
|
+
icon: Frame,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "Sales & Marketing",
|
|
155
|
+
url: "#",
|
|
156
|
+
icon: PieChart,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "Travel",
|
|
160
|
+
url: "#",
|
|
161
|
+
icon: Map,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const AppSidebar = (props: SidebarProps) => {
|
|
167
|
+
return (
|
|
168
|
+
<Sidebar {...props}>
|
|
169
|
+
<Sidebar.Header>
|
|
170
|
+
<VersionSwitcher versions={data.versions} defaultVersion={data.versions[0]} />
|
|
171
|
+
<SearchForm />
|
|
172
|
+
</Sidebar.Header>
|
|
173
|
+
<Sidebar.Content>
|
|
174
|
+
{/* We create a SidebarGroup for each parent. */}
|
|
175
|
+
{data.navMain.map((item) => (
|
|
176
|
+
<SidebarGroup key={item.title}>
|
|
177
|
+
<SidebarGroup.Label>{item.title}</SidebarGroup.Label>
|
|
178
|
+
<SidebarGroup.Content>
|
|
179
|
+
<SidebarMenu>
|
|
180
|
+
{item.items.map((item) => (
|
|
181
|
+
<SidebarMenu.Item key={item.title}>
|
|
182
|
+
<SidebarMenu.Button asChild isActive={item.isActive}>
|
|
183
|
+
<a href={item.url}>{item.title}</a>
|
|
184
|
+
</SidebarMenu.Button>
|
|
185
|
+
</SidebarMenu.Item>
|
|
186
|
+
))}
|
|
187
|
+
</SidebarMenu>
|
|
188
|
+
</SidebarGroup.Content>
|
|
189
|
+
</SidebarGroup>
|
|
190
|
+
))}
|
|
191
|
+
</Sidebar.Content>
|
|
192
|
+
<Sidebar.Rail />
|
|
193
|
+
</Sidebar>
|
|
194
|
+
);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const AppSidebarWithCollapsibleGroup = (props: SidebarProps) => {
|
|
198
|
+
return (
|
|
199
|
+
<Sidebar {...props}>
|
|
200
|
+
<Sidebar.Header>
|
|
201
|
+
<VersionSwitcher versions={data.versions} defaultVersion={data.versions[0]} />
|
|
202
|
+
<SearchForm />
|
|
203
|
+
</Sidebar.Header>
|
|
204
|
+
<Sidebar.Content className="gap-0">
|
|
205
|
+
{/* We create a collapsible SidebarGroup for each parent. */}
|
|
206
|
+
{data.navMain.map((item) => (
|
|
207
|
+
<Collapsible
|
|
208
|
+
key={item.title}
|
|
209
|
+
title={item.title}
|
|
210
|
+
defaultOpen
|
|
211
|
+
className="group/collapsible"
|
|
212
|
+
>
|
|
213
|
+
<SidebarGroup>
|
|
214
|
+
<SidebarGroup.Label
|
|
215
|
+
asChild
|
|
216
|
+
className="group/label text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
217
|
+
>
|
|
218
|
+
<Collapsible.Trigger>
|
|
219
|
+
{item.title}{" "}
|
|
220
|
+
<ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
|
|
221
|
+
</Collapsible.Trigger>
|
|
222
|
+
</SidebarGroup.Label>
|
|
223
|
+
<Collapsible.Content>
|
|
224
|
+
<SidebarGroup.Content>
|
|
225
|
+
<SidebarMenu>
|
|
226
|
+
{item.items.map((item) => (
|
|
227
|
+
<SidebarMenu.Item key={item.title}>
|
|
228
|
+
<SidebarMenu.Button asChild isActive={item.isActive}>
|
|
229
|
+
<a href={item.url}>{item.title}</a>
|
|
230
|
+
</SidebarMenu.Button>
|
|
231
|
+
</SidebarMenu.Item>
|
|
232
|
+
))}
|
|
233
|
+
</SidebarMenu>
|
|
234
|
+
</SidebarGroup.Content>
|
|
235
|
+
</Collapsible.Content>
|
|
236
|
+
</SidebarGroup>
|
|
237
|
+
</Collapsible>
|
|
238
|
+
))}
|
|
239
|
+
</Sidebar.Content>
|
|
240
|
+
<Sidebar.Rail />
|
|
241
|
+
</Sidebar>
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
export const AppSidebarWithSubMenu = (props: SidebarProps) => {
|
|
246
|
+
return (
|
|
247
|
+
<Sidebar {...props}>
|
|
248
|
+
<Sidebar.Header>
|
|
249
|
+
<SidebarMenu>
|
|
250
|
+
<SidebarMenu.Item>
|
|
251
|
+
<SidebarMenu.Button size="lg" asChild>
|
|
252
|
+
<a href="#">
|
|
253
|
+
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
254
|
+
<GalleryVerticalEnd className="size-4" />
|
|
255
|
+
</div>
|
|
256
|
+
<div className="flex flex-col gap-0.5 leading-none">
|
|
257
|
+
<span className="font-semibold">Documentation</span>
|
|
258
|
+
<span className="">v1.0.0</span>
|
|
259
|
+
</div>
|
|
260
|
+
</a>
|
|
261
|
+
</SidebarMenu.Button>
|
|
262
|
+
</SidebarMenu.Item>
|
|
263
|
+
</SidebarMenu>
|
|
264
|
+
</Sidebar.Header>
|
|
265
|
+
<Sidebar.Content>
|
|
266
|
+
<SidebarGroup>
|
|
267
|
+
<SidebarMenu>
|
|
268
|
+
{data.navMain.map((item) => (
|
|
269
|
+
<Collapsible
|
|
270
|
+
key={item.title}
|
|
271
|
+
asChild
|
|
272
|
+
defaultOpen={item.isActive}
|
|
273
|
+
className="group/collapsible"
|
|
274
|
+
>
|
|
275
|
+
<SidebarMenu.Item key={item.title}>
|
|
276
|
+
<Collapsible.Trigger asChild>
|
|
277
|
+
<SidebarMenu.Button tooltip={item.title}>
|
|
278
|
+
{item.icon && <item.icon />}
|
|
279
|
+
<a href={item.url} className="font-medium">
|
|
280
|
+
{item.title}
|
|
281
|
+
</a>
|
|
282
|
+
<Plus className="ml-auto group-data-[state=open]/collapsible:hidden" />
|
|
283
|
+
<Minus className="ml-auto group-data-[state=closed]/collapsible:hidden" />
|
|
284
|
+
</SidebarMenu.Button>
|
|
285
|
+
</Collapsible.Trigger>
|
|
286
|
+
<Collapsible.Content>
|
|
287
|
+
{item.items?.length ? (
|
|
288
|
+
<SidebarMenu.Sub>
|
|
289
|
+
{item.items.map((item) => (
|
|
290
|
+
<SidebarMenu.SubItem key={item.title}>
|
|
291
|
+
<SidebarMenu.SubButton asChild isActive={item.isActive}>
|
|
292
|
+
<a href={item.url}>{item.title}</a>
|
|
293
|
+
</SidebarMenu.SubButton>
|
|
294
|
+
</SidebarMenu.SubItem>
|
|
295
|
+
))}
|
|
296
|
+
</SidebarMenu.Sub>
|
|
297
|
+
) : null}
|
|
298
|
+
</Collapsible.Content>
|
|
299
|
+
</SidebarMenu.Item>
|
|
300
|
+
</Collapsible>
|
|
301
|
+
))}
|
|
302
|
+
</SidebarMenu>
|
|
303
|
+
</SidebarGroup>
|
|
304
|
+
</Sidebar.Content>
|
|
305
|
+
<Sidebar.Rail />
|
|
306
|
+
</Sidebar>
|
|
307
|
+
);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export const AppSidebarWithSecondaryNavigation = (props: SidebarProps) => {
|
|
311
|
+
const { isMobile } = useSidebar();
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<Sidebar {...props}>
|
|
315
|
+
<Sidebar.Header>
|
|
316
|
+
<SidebarMenu>
|
|
317
|
+
<SidebarMenu.Item>
|
|
318
|
+
<SidebarMenu.Button size="lg" asChild>
|
|
319
|
+
<a href="#">
|
|
320
|
+
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
321
|
+
<GalleryVerticalEnd className="size-4" />
|
|
322
|
+
</div>
|
|
323
|
+
<div className="flex flex-col gap-0.5 leading-none">
|
|
324
|
+
<span className="font-semibold">Documentation</span>
|
|
325
|
+
<span className="">v1.0.0</span>
|
|
326
|
+
</div>
|
|
327
|
+
</a>
|
|
328
|
+
</SidebarMenu.Button>
|
|
329
|
+
</SidebarMenu.Item>
|
|
330
|
+
</SidebarMenu>
|
|
331
|
+
</Sidebar.Header>
|
|
332
|
+
<Sidebar.Content>
|
|
333
|
+
<SidebarGroup>
|
|
334
|
+
<SidebarMenu>
|
|
335
|
+
{data.navMain.map((item) => (
|
|
336
|
+
<Collapsible
|
|
337
|
+
key={item.title}
|
|
338
|
+
asChild
|
|
339
|
+
defaultOpen={item.isActive}
|
|
340
|
+
className="group/collapsible"
|
|
341
|
+
>
|
|
342
|
+
<SidebarMenu.Item key={item.title}>
|
|
343
|
+
<Collapsible.Trigger asChild>
|
|
344
|
+
<SidebarMenu.Button tooltip={item.title}>
|
|
345
|
+
{item.icon && <item.icon />}
|
|
346
|
+
<a href={item.url} className="font-medium">
|
|
347
|
+
{item.title}
|
|
348
|
+
</a>
|
|
349
|
+
<Plus className="ml-auto group-data-[state=open]/collapsible:hidden" />
|
|
350
|
+
<Minus className="ml-auto group-data-[state=closed]/collapsible:hidden" />
|
|
351
|
+
</SidebarMenu.Button>
|
|
352
|
+
</Collapsible.Trigger>
|
|
353
|
+
<Collapsible.Content>
|
|
354
|
+
{item.items?.length ? (
|
|
355
|
+
<SidebarMenu.Sub>
|
|
356
|
+
{item.items.map((item) => (
|
|
357
|
+
<SidebarMenu.SubItem key={item.title}>
|
|
358
|
+
<SidebarMenu.SubButton asChild isActive={item.isActive}>
|
|
359
|
+
<a href={item.url}>{item.title}</a>
|
|
360
|
+
</SidebarMenu.SubButton>
|
|
361
|
+
</SidebarMenu.SubItem>
|
|
362
|
+
))}
|
|
363
|
+
</SidebarMenu.Sub>
|
|
364
|
+
) : null}
|
|
365
|
+
</Collapsible.Content>
|
|
366
|
+
</SidebarMenu.Item>
|
|
367
|
+
</Collapsible>
|
|
368
|
+
))}
|
|
369
|
+
</SidebarMenu>
|
|
370
|
+
</SidebarGroup>
|
|
371
|
+
|
|
372
|
+
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
|
373
|
+
<SidebarGroup.Label>Projects</SidebarGroup.Label>
|
|
374
|
+
<SidebarMenu>
|
|
375
|
+
{data.projects.map((item) => (
|
|
376
|
+
<SidebarMenu.Item key={item.name}>
|
|
377
|
+
<SidebarMenu.Button asChild>
|
|
378
|
+
<a href={item.url}>
|
|
379
|
+
<item.icon />
|
|
380
|
+
<span>{item.name}</span>
|
|
381
|
+
</a>
|
|
382
|
+
</SidebarMenu.Button>
|
|
383
|
+
<DropdownMenu>
|
|
384
|
+
<DropdownMenu.Trigger asChild>
|
|
385
|
+
<SidebarMenu.Action showOnHover>
|
|
386
|
+
<MoreHorizontal />
|
|
387
|
+
<span className="sr-only">More</span>
|
|
388
|
+
</SidebarMenu.Action>
|
|
389
|
+
</DropdownMenu.Trigger>
|
|
390
|
+
<DropdownMenu.Content
|
|
391
|
+
className="w-48"
|
|
392
|
+
side={isMobile ? "bottom" : "right"}
|
|
393
|
+
align={isMobile ? "end" : "start"}
|
|
394
|
+
>
|
|
395
|
+
<DropdownMenu.Item>
|
|
396
|
+
<Folder className="text-muted-foreground" />
|
|
397
|
+
<span>View Project</span>
|
|
398
|
+
</DropdownMenu.Item>
|
|
399
|
+
<DropdownMenu.Item>
|
|
400
|
+
<Share className="text-muted-foreground" />
|
|
401
|
+
<span>Share Project</span>
|
|
402
|
+
</DropdownMenu.Item>
|
|
403
|
+
<DropdownMenu.Separator />
|
|
404
|
+
<DropdownMenu.Item>
|
|
405
|
+
<Trash2 className="text-muted-foreground" />
|
|
406
|
+
<span>Delete Project</span>
|
|
407
|
+
</DropdownMenu.Item>
|
|
408
|
+
</DropdownMenu.Content>
|
|
409
|
+
</DropdownMenu>
|
|
410
|
+
</SidebarMenu.Item>
|
|
411
|
+
))}
|
|
412
|
+
<SidebarMenu.Item>
|
|
413
|
+
<SidebarMenu.Button>
|
|
414
|
+
<MoreHorizontal />
|
|
415
|
+
<span>More</span>
|
|
416
|
+
</SidebarMenu.Button>
|
|
417
|
+
</SidebarMenu.Item>
|
|
418
|
+
</SidebarMenu>
|
|
419
|
+
</SidebarGroup>
|
|
420
|
+
</Sidebar.Content>
|
|
421
|
+
<Sidebar.Rail />
|
|
422
|
+
</Sidebar>
|
|
423
|
+
);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// This is sample data.
|
|
427
|
+
const treeData = {
|
|
428
|
+
changes: [
|
|
429
|
+
{
|
|
430
|
+
file: "README.md",
|
|
431
|
+
state: "M",
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
file: "api/hello/route.ts",
|
|
435
|
+
state: "U",
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
file: "app/layout.tsx",
|
|
439
|
+
state: "M",
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
tree: [
|
|
443
|
+
["app", ["api", ["hello", ["route.ts"]], "page.tsx", "layout.tsx", ["blog", ["page.tsx"]]]],
|
|
444
|
+
["components", ["ui", "button.tsx", "card.tsx"], "header.tsx", "footer.tsx"],
|
|
445
|
+
["lib", ["util.ts"]],
|
|
446
|
+
["public", "favicon.ico", "vercel.svg"],
|
|
447
|
+
".eslintrc.json",
|
|
448
|
+
".gitignore",
|
|
449
|
+
"next.config.js",
|
|
450
|
+
"tailwind.config.js",
|
|
451
|
+
"package.json",
|
|
452
|
+
"README.md",
|
|
453
|
+
],
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
type TreeType = string | TreeType[];
|
|
457
|
+
const Tree = ({ item }: { item: TreeType }) => {
|
|
458
|
+
const [name, ...items] = Array.isArray(item) ? item : [item];
|
|
459
|
+
|
|
460
|
+
if (!items.length) {
|
|
461
|
+
return (
|
|
462
|
+
<SidebarMenu.Button
|
|
463
|
+
isActive={name === "button.tsx"}
|
|
464
|
+
className="data-[active=true]:bg-transparent"
|
|
465
|
+
>
|
|
466
|
+
<File />
|
|
467
|
+
{name}
|
|
468
|
+
</SidebarMenu.Button>
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return (
|
|
473
|
+
<SidebarMenu.Item>
|
|
474
|
+
<Collapsible
|
|
475
|
+
className="group/collapsible [&[data-state=open]>button>svg:first-child]:rotate-90"
|
|
476
|
+
defaultOpen={name === "components" || name === "ui"}
|
|
477
|
+
>
|
|
478
|
+
<Collapsible.Trigger asChild>
|
|
479
|
+
<SidebarMenu.Button>
|
|
480
|
+
<ChevronRight className="transition-transform" />
|
|
481
|
+
<Folder />
|
|
482
|
+
{name}
|
|
483
|
+
</SidebarMenu.Button>
|
|
484
|
+
</Collapsible.Trigger>
|
|
485
|
+
<Collapsible.Content>
|
|
486
|
+
<SidebarMenu.Sub>
|
|
487
|
+
{items.map((subItem, index) => (
|
|
488
|
+
<Tree key={index} item={subItem} />
|
|
489
|
+
))}
|
|
490
|
+
</SidebarMenu.Sub>
|
|
491
|
+
</Collapsible.Content>
|
|
492
|
+
</Collapsible>
|
|
493
|
+
</SidebarMenu.Item>
|
|
494
|
+
);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
export const AppSidebarCollapsibleTree = (props: SidebarProps) => {
|
|
498
|
+
return (
|
|
499
|
+
<Sidebar {...props}>
|
|
500
|
+
<Sidebar.Content>
|
|
501
|
+
<SidebarGroup>
|
|
502
|
+
<SidebarGroup.Label>Changes</SidebarGroup.Label>
|
|
503
|
+
<SidebarGroup.Content>
|
|
504
|
+
<SidebarMenu>
|
|
505
|
+
{treeData.changes.map((item, index) => (
|
|
506
|
+
<SidebarMenu.Item key={index}>
|
|
507
|
+
<SidebarMenu.Button>
|
|
508
|
+
<File />
|
|
509
|
+
{item.file}
|
|
510
|
+
</SidebarMenu.Button>
|
|
511
|
+
<SidebarMenu.Badge>{item.state}</SidebarMenu.Badge>
|
|
512
|
+
</SidebarMenu.Item>
|
|
513
|
+
))}
|
|
514
|
+
</SidebarMenu>
|
|
515
|
+
</SidebarGroup.Content>
|
|
516
|
+
</SidebarGroup>
|
|
517
|
+
<SidebarGroup>
|
|
518
|
+
<SidebarGroup.Label>Files</SidebarGroup.Label>
|
|
519
|
+
<SidebarGroup.Content>
|
|
520
|
+
<SidebarMenu>
|
|
521
|
+
{treeData.tree.map((item, index) => (
|
|
522
|
+
<Tree key={index} item={item} />
|
|
523
|
+
))}
|
|
524
|
+
</SidebarMenu>
|
|
525
|
+
</SidebarGroup.Content>
|
|
526
|
+
</SidebarGroup>
|
|
527
|
+
</Sidebar.Content>
|
|
528
|
+
<Sidebar.Rail />
|
|
529
|
+
</Sidebar>
|
|
530
|
+
);
|
|
531
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Search } from "lucide-react";
|
|
2
|
+
import { Label } from "../../../../Form";
|
|
3
|
+
import { Sidebar } from "../../../Sidebar";
|
|
4
|
+
import { SidebarGroup } from "../../../SidebarGroup";
|
|
5
|
+
|
|
6
|
+
export const SearchForm = ({ ...props }: React.ComponentProps<"form">) => {
|
|
7
|
+
return (
|
|
8
|
+
<form {...props}>
|
|
9
|
+
<SidebarGroup className="py-0">
|
|
10
|
+
<SidebarGroup.Content className="relative">
|
|
11
|
+
<Label htmlFor="search" className="sr-only">
|
|
12
|
+
Search
|
|
13
|
+
</Label>
|
|
14
|
+
<Sidebar.Input
|
|
15
|
+
size="sm"
|
|
16
|
+
outline
|
|
17
|
+
id="search"
|
|
18
|
+
placeholder="Search the docs..."
|
|
19
|
+
className="pl-8"
|
|
20
|
+
/>
|
|
21
|
+
<Search className="pointer-events-none absolute left-2 top-1/2 size-4 -translate-y-1/2 select-none opacity-50" />
|
|
22
|
+
</SidebarGroup.Content>
|
|
23
|
+
</SidebarGroup>
|
|
24
|
+
</form>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Check, ChevronsUpDown, GalleryVerticalEnd } from "lucide-react";
|
|
3
|
+
import { DropdownMenu } from "../../../../Menu";
|
|
4
|
+
import { SidebarMenu } from "../../../SidebarMenu";
|
|
5
|
+
|
|
6
|
+
export const VersionSwitcher = ({
|
|
7
|
+
versions,
|
|
8
|
+
defaultVersion,
|
|
9
|
+
}: {
|
|
10
|
+
versions: string[];
|
|
11
|
+
defaultVersion: string;
|
|
12
|
+
}) => {
|
|
13
|
+
const [selectedVersion, setSelectedVersion] = useState(defaultVersion);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<SidebarMenu>
|
|
17
|
+
<SidebarMenu.Item>
|
|
18
|
+
<DropdownMenu>
|
|
19
|
+
<DropdownMenu.Trigger asChild>
|
|
20
|
+
<SidebarMenu.Button
|
|
21
|
+
size="lg"
|
|
22
|
+
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
23
|
+
>
|
|
24
|
+
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
25
|
+
<GalleryVerticalEnd className="size-4" />
|
|
26
|
+
</div>
|
|
27
|
+
<div className="flex flex-col gap-0.5 leading-none">
|
|
28
|
+
<span className="font-semibold">Documentation</span>
|
|
29
|
+
<span className="">v{selectedVersion}</span>
|
|
30
|
+
</div>
|
|
31
|
+
<ChevronsUpDown className="ml-auto" />
|
|
32
|
+
</SidebarMenu.Button>
|
|
33
|
+
</DropdownMenu.Trigger>
|
|
34
|
+
<DropdownMenu.Content className="w-[--radix-dropdown-menu-trigger-width]" align="start">
|
|
35
|
+
{versions.map((version) => (
|
|
36
|
+
<DropdownMenu.Item key={version} onSelect={() => setSelectedVersion(version)}>
|
|
37
|
+
v{version} {version === selectedVersion && <Check className="ml-auto" />}
|
|
38
|
+
</DropdownMenu.Item>
|
|
39
|
+
))}
|
|
40
|
+
</DropdownMenu.Content>
|
|
41
|
+
</DropdownMenu>
|
|
42
|
+
</SidebarMenu.Item>
|
|
43
|
+
</SidebarMenu>
|
|
44
|
+
);
|
|
45
|
+
};
|