@mbao01/common 0.0.48 → 0.0.49
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/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 +2 -0
- package/package.json +3 -3
- package/src/components/Anchor/Anchor.tsx +2 -2
- 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 +36 -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 +3 -0
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { TooltipProviderProps } from "@radix-ui/react-tooltip";
|
|
2
|
+
import type { HTMLAttributes } from "react";
|
|
3
|
+
import type { VariantProps } from "../../libs";
|
|
4
|
+
import type { TooltipContentProps } from "../Tooltip/types";
|
|
5
|
+
import { getSidebarMenuButtonClasses } from "./constants";
|
|
6
|
+
|
|
7
|
+
export type SidebarContextProps = {
|
|
8
|
+
state: "expanded" | "collapsed";
|
|
9
|
+
open: boolean;
|
|
10
|
+
setOpen: (open: boolean) => void;
|
|
11
|
+
openMobile: boolean;
|
|
12
|
+
setOpenMobile: (open: boolean) => void;
|
|
13
|
+
isMobile: boolean;
|
|
14
|
+
toggleSidebar: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type SidebarProps = HTMLAttributes<HTMLDivElement> &
|
|
18
|
+
Partial<{
|
|
19
|
+
side: "left" | "right";
|
|
20
|
+
variant: "sidebar" | "floating" | "inset";
|
|
21
|
+
collapsible: "offcanvas" | "icon" | "none";
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
export type SidebarProviderProps = HTMLAttributes<HTMLDivElement> & {
|
|
25
|
+
defaultOpen?: boolean;
|
|
26
|
+
open?: boolean;
|
|
27
|
+
onOpenChange?: (open: boolean) => void;
|
|
28
|
+
tooltipProvider?: TooltipProviderProps;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type SidebarGroupProps = HTMLAttributes<HTMLDivElement>;
|
|
32
|
+
|
|
33
|
+
export type SidebarGroupLabelProps = HTMLAttributes<HTMLDivElement> & Partial<{ asChild: boolean }>;
|
|
34
|
+
|
|
35
|
+
export type SidebarGroupActionProps = HTMLAttributes<HTMLButtonElement> &
|
|
36
|
+
Partial<{ asChild: boolean }>;
|
|
37
|
+
|
|
38
|
+
export type SidebarGroupContentProps = HTMLAttributes<HTMLDivElement>;
|
|
39
|
+
|
|
40
|
+
export type SidebarMenuProps = HTMLAttributes<HTMLUListElement>;
|
|
41
|
+
|
|
42
|
+
export type SidebarMenuItemProps = HTMLAttributes<HTMLLIElement>;
|
|
43
|
+
|
|
44
|
+
export type SidebarMenuButtonProps = HTMLAttributes<HTMLButtonElement> &
|
|
45
|
+
Partial<{
|
|
46
|
+
asChild: boolean;
|
|
47
|
+
isActive: boolean;
|
|
48
|
+
tooltip: string | TooltipContentProps;
|
|
49
|
+
}> &
|
|
50
|
+
VariantProps<typeof getSidebarMenuButtonClasses>;
|
|
51
|
+
|
|
52
|
+
export type SidebarMenuActionProps = HTMLAttributes<HTMLButtonElement> &
|
|
53
|
+
Partial<{
|
|
54
|
+
asChild: boolean;
|
|
55
|
+
showOnHover: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
|
|
58
|
+
export type SidebarMenuBadgeProps = HTMLAttributes<HTMLDivElement>;
|
|
59
|
+
|
|
60
|
+
export type SidebarMenuSkeletonProps = HTMLAttributes<HTMLDivElement> &
|
|
61
|
+
Partial<{
|
|
62
|
+
showIcon: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
|
|
65
|
+
export type SidebarMenuSubProps = HTMLAttributes<HTMLUListElement>;
|
|
66
|
+
|
|
67
|
+
export type SidebarMenuSubItemProps = HTMLAttributes<HTMLLIElement>;
|
|
68
|
+
|
|
69
|
+
export type SidebarMenuSubButtonProps = HTMLAttributes<HTMLAnchorElement> &
|
|
70
|
+
Partial<{
|
|
71
|
+
asChild: boolean;
|
|
72
|
+
size: "sm" | "md";
|
|
73
|
+
isActive: boolean;
|
|
74
|
+
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { MoveIcon,
|
|
2
|
+
import { MoveIcon, OctagonXIcon } from "lucide-react";
|
|
3
3
|
import { Draggable } from "../DragAndDrop";
|
|
4
4
|
import { useWidgets } from "./hooks/useWidgets/useWidgets";
|
|
5
5
|
import { Widget } from "./Widget";
|
|
@@ -103,7 +103,7 @@ const Widgets = () => {
|
|
|
103
103
|
aria-label={`Delete widget ${widget.id}`}
|
|
104
104
|
className="transition-all hover:text-error"
|
|
105
105
|
>
|
|
106
|
-
<
|
|
106
|
+
<OctagonXIcon />
|
|
107
107
|
</Draggable.Action>
|
|
108
108
|
</div>
|
|
109
109
|
)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useIsMobile } from "./useIsMobile";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useIsMobile } from "./useIsMobile";
|