@squadbase/vantage 0.6.2-dev1.a7c4a3e → 0.6.2-dev1.b28a4df

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 (225) hide show
  1. package/dist/add-4GHF2TX2.js +6 -0
  2. package/dist/add-4GHF2TX2.js.map +1 -0
  3. package/dist/{build-JB4VOMUI.js → build-X5NVCQKT.js} +9 -9
  4. package/dist/{build-JB4VOMUI.js.map → build-X5NVCQKT.js.map} +1 -1
  5. package/dist/{check-ZJYK6RLG.js → check-ZBIH422T.js} +7 -7
  6. package/dist/{check-ZJYK6RLG.js.map → check-ZBIH422T.js.map} +1 -1
  7. package/dist/chunk-2ICNHUG6.js +1820 -0
  8. package/dist/chunk-2ICNHUG6.js.map +1 -0
  9. package/dist/{chunk-5ZOP4SQR.js → chunk-2N72FKLB.js} +12 -7
  10. package/dist/chunk-2N72FKLB.js.map +1 -0
  11. package/dist/{chunk-BCE22JSM.js → chunk-7DZGJQ3P.js} +33 -14
  12. package/dist/chunk-7DZGJQ3P.js.map +1 -0
  13. package/dist/{chunk-U2M6HGKQ.js → chunk-AABMKHEU.js} +4 -4
  14. package/dist/{chunk-U2M6HGKQ.js.map → chunk-AABMKHEU.js.map} +1 -1
  15. package/dist/{chunk-KLEIVDUV.js → chunk-CEXAQQ5W.js} +150 -11
  16. package/dist/chunk-CEXAQQ5W.js.map +1 -0
  17. package/dist/{chunk-QI3XQKHS.js → chunk-GNXCX4WE.js} +10 -3
  18. package/dist/chunk-GNXCX4WE.js.map +1 -0
  19. package/dist/{chunk-JGRMRXXZ.js → chunk-JKLLFVEU.js} +3 -3
  20. package/dist/{chunk-JGRMRXXZ.js.map → chunk-JKLLFVEU.js.map} +1 -1
  21. package/dist/{chunk-PXRX5PEC.js → chunk-PDOBHMUQ.js} +3 -3
  22. package/dist/chunk-PDOBHMUQ.js.map +1 -0
  23. package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
  24. package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
  25. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  26. package/dist/chunk-U736PVHY.js.map +1 -0
  27. package/dist/chunk-UNCSBSO4.js +7866 -0
  28. package/dist/chunk-UNCSBSO4.js.map +1 -0
  29. package/dist/{chunk-PVTHHV7X.js → chunk-V3LF7BE7.js} +27 -5
  30. package/dist/chunk-V3LF7BE7.js.map +1 -0
  31. package/dist/{chunk-EP6JHXSR.js → chunk-WAMZWZJB.js} +54 -9
  32. package/dist/chunk-WAMZWZJB.js.map +1 -0
  33. package/dist/{chunk-RPZAALCX.js → chunk-XPQSTZUU.js} +254 -164
  34. package/dist/chunk-XPQSTZUU.js.map +1 -0
  35. package/dist/{chunk-DTDVSFRY.js → chunk-XQUSGIDG.js} +17 -3
  36. package/dist/chunk-XQUSGIDG.js.map +1 -0
  37. package/dist/cli.js +12 -11
  38. package/dist/cli.js.map +1 -1
  39. package/dist/client/index.d.ts +32 -3
  40. package/dist/client/index.js +205 -12
  41. package/dist/client/index.js.map +1 -1
  42. package/dist/components/index.d.ts +1975 -28
  43. package/dist/components/index.js +4 -4
  44. package/dist/{dev-FCEC3UKQ.js → dev-4XEDTELV.js} +10 -10
  45. package/dist/dev-4XEDTELV.js.map +1 -0
  46. package/dist/doc/index.js +2 -2
  47. package/dist/doc/index.js.map +1 -1
  48. package/dist/{docs-EJJ3BECT.js → docs-JVP4RPKT.js} +3 -3
  49. package/dist/{docs-EJJ3BECT.js.map → docs-JVP4RPKT.js.map} +1 -1
  50. package/dist/{doctor-WHZXPERA.js → doctor-5E2VEZPK.js} +7 -7
  51. package/dist/{doctor-WHZXPERA.js.map → doctor-5E2VEZPK.js.map} +1 -1
  52. package/dist/markdown/index.js +1 -1
  53. package/dist/markdown/index.js.map +1 -1
  54. package/dist/{preview-OGMCNQUO.js → preview-T6CLSQVX.js} +3 -3
  55. package/dist/{preview-OGMCNQUO.js.map → preview-T6CLSQVX.js.map} +1 -1
  56. package/dist/query/index.d.ts +0 -11
  57. package/dist/query/index.js +2 -2
  58. package/dist/{routes-GTFO5PUF.js → routes-3SGAFDMC.js} +6 -6
  59. package/dist/{routes-GTFO5PUF.js.map → routes-3SGAFDMC.js.map} +1 -1
  60. package/dist/{search-6Y422SV6.js → search-5LC4XPB5.js} +3 -3
  61. package/dist/{search-6Y422SV6.js.map → search-5LC4XPB5.js.map} +1 -1
  62. package/dist/slide/index.js +49 -12
  63. package/dist/slide/index.js.map +1 -1
  64. package/dist/table/index.js +11 -10
  65. package/dist/table/index.js.map +1 -1
  66. package/dist/ui/index.d.ts +144 -11
  67. package/dist/ui/index.js +1339 -87
  68. package/dist/ui/index.js.map +1 -1
  69. package/dist/{upgrade-AL4KZZR4.js → upgrade-JHXZBGQS.js} +7 -7
  70. package/dist/{upgrade-AL4KZZR4.js.map → upgrade-JHXZBGQS.js.map} +1 -1
  71. package/dist/vite/index.d.ts +10 -0
  72. package/dist/vite/index.js +4 -4
  73. package/docs/en/components.md +29 -15
  74. package/docs/en/parts/data-table.md +22 -0
  75. package/docs/en/parts/delta.md +50 -0
  76. package/docs/en/parts/format.md +43 -0
  77. package/docs/en/parts/kpi-card.md +57 -0
  78. package/docs/en/parts/metric-value.md +3 -2
  79. package/docs/en/parts/sparkline.md +1 -1
  80. package/docs/en/parts/trend-indicator.md +17 -1
  81. package/docs/en/ui-and-theming.md +1 -1
  82. package/docs/index.json +366 -76
  83. package/docs/ja/changelog.md +31 -0
  84. package/docs/ja/components.md +57 -101
  85. package/docs/ja/page-types/csv.md +83 -0
  86. package/docs/ja/page-types/doc.md +83 -0
  87. package/docs/ja/page-types/excel.md +82 -0
  88. package/docs/ja/page-types/slide.md +132 -0
  89. package/docs/ja/page-types.md +47 -0
  90. package/docs/ja/parts/area-chart.md +61 -0
  91. package/docs/ja/parts/bar-chart.md +69 -0
  92. package/docs/ja/parts/bar-list.md +35 -0
  93. package/docs/ja/parts/category-bar.md +36 -0
  94. package/docs/ja/parts/data-table.md +22 -0
  95. package/docs/ja/parts/delta.md +50 -0
  96. package/docs/ja/parts/donut-chart.md +47 -0
  97. package/docs/ja/parts/echart.md +3 -0
  98. package/docs/ja/parts/format.md +44 -0
  99. package/docs/ja/parts/kpi-card.md +55 -0
  100. package/docs/ja/parts/line-chart.md +58 -0
  101. package/docs/ja/parts/metric-value.md +3 -2
  102. package/docs/ja/parts/progress-circle.md +34 -0
  103. package/docs/ja/parts/sparkline.md +2 -2
  104. package/docs/ja/parts/tracker.md +32 -0
  105. package/docs/ja/parts/trend-indicator.md +17 -1
  106. package/docs/ja/routing.md +8 -86
  107. package/docs/ja/ui/alert-dialog.md +41 -0
  108. package/docs/ja/ui/avatar.md +31 -0
  109. package/docs/ja/ui/combobox.md +74 -0
  110. package/docs/ja/ui/drawer.md +41 -0
  111. package/docs/ja/ui/field.md +42 -0
  112. package/docs/ja/ui/hover-card.md +21 -0
  113. package/docs/ja/ui/kbd.md +16 -0
  114. package/docs/ja/ui/pagination.md +36 -0
  115. package/docs/ja/ui/radio-group.md +21 -0
  116. package/docs/ja/ui/toast.md +46 -0
  117. package/docs/ja/ui-and-theming.md +14 -7
  118. package/package.json +43 -29
  119. package/registry/ui/accordion.tsx +76 -0
  120. package/registry/ui/alert-dialog.tsx +189 -0
  121. package/registry/ui/alert.tsx +80 -0
  122. package/registry/ui/app-shell.tsx +287 -0
  123. package/registry/ui/area-chart.tsx +3639 -0
  124. package/registry/ui/avatar.tsx +110 -0
  125. package/registry/ui/badge.tsx +56 -0
  126. package/registry/ui/bar-chart.tsx +3636 -0
  127. package/registry/ui/bar-list.tsx +3680 -0
  128. package/registry/ui/breadcrumb.tsx +128 -0
  129. package/registry/ui/button.tsx +62 -0
  130. package/registry/ui/calendar.tsx +223 -0
  131. package/registry/ui/card.tsx +107 -0
  132. package/registry/ui/category-bar.tsx +1255 -0
  133. package/registry/ui/chart-frame.tsx +1358 -0
  134. package/registry/ui/checkbox.tsx +30 -0
  135. package/registry/ui/collapsible.tsx +23 -0
  136. package/registry/ui/combobox.tsx +310 -0
  137. package/registry/ui/command.tsx +198 -0
  138. package/registry/ui/dashboard-card.tsx +217 -0
  139. package/registry/ui/data-table.tsx +693 -146
  140. package/registry/ui/date-range-picker.tsx +390 -0
  141. package/registry/ui/delta.tsx +188 -0
  142. package/registry/ui/dialog.tsx +161 -0
  143. package/registry/ui/donut-chart.tsx +3688 -0
  144. package/registry/ui/drawer.tsx +229 -0
  145. package/registry/ui/dropdown-menu.tsx +274 -0
  146. package/registry/ui/echart.tsx +890 -0
  147. package/registry/ui/field.tsx +240 -0
  148. package/registry/ui/filter-bar.tsx +392 -0
  149. package/registry/ui/funnel-steps.tsx +3541 -0
  150. package/registry/ui/heatmap.tsx +1752 -0
  151. package/registry/ui/hover-card.tsx +52 -0
  152. package/registry/ui/input-group.tsx +160 -0
  153. package/registry/ui/input.tsx +24 -0
  154. package/registry/ui/kbd.tsx +30 -0
  155. package/registry/ui/kpi-card.tsx +677 -0
  156. package/registry/ui/label.tsx +22 -0
  157. package/registry/ui/legend.tsx +3500 -0
  158. package/registry/ui/line-chart.tsx +3637 -0
  159. package/registry/ui/metric-value.tsx +62 -0
  160. package/registry/ui/multi-select.tsx +232 -0
  161. package/registry/ui/page-shell.tsx +282 -0
  162. package/registry/ui/pagination.tsx +140 -0
  163. package/registry/ui/placeholder.tsx +36 -0
  164. package/registry/ui/popover.tsx +92 -0
  165. package/registry/ui/progress-circle.tsx +867 -0
  166. package/registry/ui/progress.tsx +85 -0
  167. package/registry/ui/radio-group.tsx +39 -0
  168. package/registry/ui/sample-data.tsx +86 -0
  169. package/registry/ui/scatter-chart.tsx +4150 -0
  170. package/registry/ui/scroll-area.tsx +56 -0
  171. package/registry/ui/searchable-select.tsx +214 -0
  172. package/registry/ui/section-header.tsx +43 -0
  173. package/registry/ui/segmented-control.tsx +76 -0
  174. package/registry/ui/select.tsx +255 -0
  175. package/registry/ui/separator.tsx +27 -0
  176. package/registry/ui/sheet.tsx +139 -0
  177. package/registry/ui/sidebar.tsx +725 -0
  178. package/registry/ui/skeleton.tsx +17 -0
  179. package/registry/ui/slider.tsx +56 -0
  180. package/registry/ui/sparkline.tsx +230 -0
  181. package/registry/ui/spinner.tsx +14 -0
  182. package/registry/ui/states.tsx +90 -0
  183. package/registry/ui/status-badge.tsx +121 -0
  184. package/registry/ui/switch.tsx +34 -0
  185. package/registry/ui/table.tsx +118 -0
  186. package/registry/ui/tabs.tsx +84 -0
  187. package/registry/ui/textarea.tsx +22 -0
  188. package/registry/ui/toast.tsx +250 -0
  189. package/registry/ui/toggle-group.tsx +91 -0
  190. package/registry/ui/toggle.tsx +47 -0
  191. package/registry/ui/tooltip.tsx +68 -0
  192. package/registry/ui/tracker.tsx +843 -0
  193. package/registry/ui/trend-indicator.tsx +74 -0
  194. package/registry/ui/updated-at.tsx +122 -0
  195. package/registry/ui/waterfall-chart.tsx +4186 -0
  196. package/skills/vantage-add-feature/SKILL.md +9 -7
  197. package/skills/vantage-design/SKILL.md +12 -2
  198. package/skills/vantage-design/references/format.md +1 -1
  199. package/skills/vantage-pitfalls/SKILL.md +5 -1
  200. package/skills/vantage-slide/SKILL.md +17 -0
  201. package/templates/AGENTS.md +22 -1
  202. package/templates/agents/api.md +29 -0
  203. package/templates/agents/csv.md +2 -1
  204. package/templates/agents/doc.md +4 -3
  205. package/templates/agents/page.md +32 -8
  206. package/templates/agents/slide.md +13 -1
  207. package/templates/agents/xlsx.md +2 -1
  208. package/theme.css +241 -130
  209. package/dist/add-DY4AXANK.js +0 -6
  210. package/dist/add-DY4AXANK.js.map +0 -1
  211. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  212. package/dist/chunk-A2UUGASH.js.map +0 -1
  213. package/dist/chunk-BCE22JSM.js.map +0 -1
  214. package/dist/chunk-DTDVSFRY.js.map +0 -1
  215. package/dist/chunk-EP6JHXSR.js.map +0 -1
  216. package/dist/chunk-KLEIVDUV.js.map +0 -1
  217. package/dist/chunk-MP3QSOXL.js +0 -2232
  218. package/dist/chunk-MP3QSOXL.js.map +0 -1
  219. package/dist/chunk-PVTHHV7X.js.map +0 -1
  220. package/dist/chunk-PXRX5PEC.js.map +0 -1
  221. package/dist/chunk-QI3XQKHS.js.map +0 -1
  222. package/dist/chunk-RPZAALCX.js.map +0 -1
  223. package/dist/chunk-T3FLAGI6.js +0 -316
  224. package/dist/chunk-T3FLAGI6.js.map +0 -1
  225. package/dist/dev-FCEC3UKQ.js.map +0 -1
@@ -0,0 +1,287 @@
1
+ // Copied by `vantage add ui app-shell`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/components/app-shell.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ /**
6
+ * AppShell — the outermost application frame. `variant="sidebar"` (default)
7
+ * renders a collapsible sidebar with nested nav groups; `variant="header"`
8
+ * collapses the same nav into a single select in a top bar.
9
+ *
10
+ * Navigation is router-agnostic: pass `linkComponent` to render links with your
11
+ * router's Link, or leave it and `onNavigate` handles the header variant.
12
+ */
13
+ import { forwardRef, type ElementType, type ReactNode } from "react"
14
+ import { ChevronRight } from "lucide-react"
15
+
16
+ import { cn } from "@squadbase/vantage/ui"
17
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@squadbase/vantage/ui"
18
+ import { Separator } from "@squadbase/vantage/ui"
19
+ import {
20
+ Select,
21
+ SelectContent,
22
+ SelectGroup,
23
+ SelectItem,
24
+ SelectLabel,
25
+ SelectTrigger,
26
+ SelectValue,
27
+ } from "@squadbase/vantage/ui"
28
+ import {
29
+ Sidebar,
30
+ SidebarContent,
31
+ SidebarFooter,
32
+ SidebarGroup,
33
+ SidebarGroupLabel,
34
+ SidebarInset,
35
+ SidebarMenu,
36
+ SidebarMenuBadge,
37
+ SidebarMenuButton,
38
+ SidebarMenuItem,
39
+ SidebarMenuSub,
40
+ SidebarMenuSubButton,
41
+ SidebarMenuSubItem,
42
+ SidebarProvider,
43
+ SidebarRail,
44
+ SidebarTrigger,
45
+ } from "@squadbase/vantage/ui"
46
+ import type { NavGroup, NavItem } from "@squadbase/vantage/components"
47
+
48
+ export interface AppShellSidebarProps {
49
+ variant?: "sidebar"
50
+ groups: NavGroup[]
51
+ actions?: ReactNode
52
+ header?: ReactNode
53
+ children: ReactNode
54
+ defaultOpen?: boolean
55
+ className?: string
56
+ linkComponent?: ElementType
57
+ onNavigate?: (href: string) => void
58
+ }
59
+
60
+ export interface AppShellHeaderProps {
61
+ variant: "header"
62
+ groups: NavGroup[]
63
+ actions?: ReactNode
64
+ header?: ReactNode
65
+ children: ReactNode
66
+ className?: string
67
+ linkComponent?: ElementType
68
+ onNavigate?: (href: string) => void
69
+ }
70
+
71
+ export type AppShellProps = AppShellSidebarProps | AppShellHeaderProps
72
+
73
+ /** Nested groups collapse to their leaves — the select is a flat list. */
74
+ function flattenItems(item: NavItem): NavItem[] {
75
+ if (item.children && item.children.length > 0) {
76
+ return item.children.flatMap(flattenItems)
77
+ }
78
+ return [item]
79
+ }
80
+
81
+ function NavSelect({
82
+ groups,
83
+ onNavigate,
84
+ }: {
85
+ groups: NavGroup[]
86
+ onNavigate: (href: string) => void
87
+ }) {
88
+ const allItems = groups.flatMap((g) => g.items.flatMap(flattenItems))
89
+ const currentValue = allItems.find((item) => item.isActive)?.href ?? ""
90
+ // Base UI's SelectValue renders the raw value (the href) unless `items` maps
91
+ // it to a label, so pass the page names explicitly.
92
+ const selectItems = allItems.map((item) => ({ value: item.href, label: item.label }))
93
+
94
+ return (
95
+ <Select
96
+ items={selectItems}
97
+ value={currentValue}
98
+ onValueChange={(href) => {
99
+ // Base UI reports `null` when the selection is cleared; there is no
100
+ // page to navigate to in that case.
101
+ if (href !== null) onNavigate(href)
102
+ }}
103
+ >
104
+ <SelectTrigger size="sm" className="w-48">
105
+ <SelectValue placeholder="ページを選択" />
106
+ </SelectTrigger>
107
+ {/*
108
+ Page titles are author-written and often longer than the 12rem trigger,
109
+ so the list is allowed to grow past the anchor width (bounded by the
110
+ viewport) instead of clamping every title to the trigger's width.
111
+ */}
112
+ <SelectContent
113
+ align="start"
114
+ className="w-auto min-w-(--anchor-width) max-w-[min(24rem,var(--available-width))]"
115
+ >
116
+ {groups.map((group, index) => (
117
+ <SelectGroup key={group.label ?? index}>
118
+ {group.label && <SelectLabel>{group.label}</SelectLabel>}
119
+ {group.items.flatMap(flattenItems).map((item) => (
120
+ <SelectItem key={item.href} value={item.href} disabled={item.disabled}>
121
+ {item.label}
122
+ </SelectItem>
123
+ ))}
124
+ </SelectGroup>
125
+ ))}
126
+ </SelectContent>
127
+ </Select>
128
+ )
129
+ }
130
+
131
+ function NavItemWithChildren({
132
+ item,
133
+ linkComponent: LinkComponent = "a",
134
+ }: {
135
+ item: NavItem
136
+ linkComponent?: ElementType
137
+ }) {
138
+ return (
139
+ <Collapsible
140
+ defaultOpen={item.isActive}
141
+ className="group/collapsible"
142
+ render={<SidebarMenuItem />}
143
+ >
144
+ <CollapsibleTrigger
145
+ render={
146
+ <SidebarMenuButton
147
+ tooltip={item.label}
148
+ aria-disabled={item.disabled}
149
+ className={cn(item.disabled && "pointer-events-none")}
150
+ />
151
+ }
152
+ >
153
+ {item.icon && <item.icon />}
154
+ <span>{item.label}</span>
155
+ <ChevronRight className="ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90" />
156
+ </CollapsibleTrigger>
157
+ {item.badge && <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>}
158
+ <CollapsibleContent>
159
+ <SidebarMenuSub>
160
+ {item.children!.map((child) => (
161
+ <SidebarMenuSubItem key={child.href}>
162
+ <SidebarMenuSubButton
163
+ isActive={child.isActive}
164
+ render={
165
+ <LinkComponent
166
+ href={child.href}
167
+ aria-disabled={child.disabled}
168
+ tabIndex={child.disabled ? -1 : undefined}
169
+ className={cn(child.disabled && "pointer-events-none opacity-50")}
170
+ />
171
+ }
172
+ >
173
+ {child.icon && <child.icon />}
174
+ <span>{child.label}</span>
175
+ </SidebarMenuSubButton>
176
+ </SidebarMenuSubItem>
177
+ ))}
178
+ </SidebarMenuSub>
179
+ </CollapsibleContent>
180
+ </Collapsible>
181
+ )
182
+ }
183
+
184
+ function NavItemLink({
185
+ item,
186
+ linkComponent: LinkComponent = "a",
187
+ }: {
188
+ item: NavItem
189
+ linkComponent?: ElementType
190
+ }) {
191
+ return (
192
+ <SidebarMenuItem>
193
+ <SidebarMenuButton
194
+ tooltip={item.label}
195
+ isActive={item.isActive}
196
+ render={
197
+ <LinkComponent
198
+ href={item.href}
199
+ aria-disabled={item.disabled}
200
+ tabIndex={item.disabled ? -1 : undefined}
201
+ className={cn(item.disabled && "pointer-events-none")}
202
+ />
203
+ }
204
+ >
205
+ {item.icon && <item.icon />}
206
+ <span>{item.label}</span>
207
+ </SidebarMenuButton>
208
+ {item.badge && <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>}
209
+ </SidebarMenuItem>
210
+ )
211
+ }
212
+
213
+ const defaultNavigate = (href: string) => {
214
+ window.location.assign(href)
215
+ }
216
+
217
+ export const AppShell = forwardRef<HTMLDivElement, AppShellProps>((props, ref) => {
218
+ const {
219
+ variant = "sidebar",
220
+ groups,
221
+ actions,
222
+ header,
223
+ children,
224
+ className,
225
+ linkComponent,
226
+ onNavigate = defaultNavigate,
227
+ } = props
228
+
229
+ if (variant === "header") {
230
+ return (
231
+ <div ref={ref} data-slot="app-shell" className={cn("flex h-full flex-col", className)}>
232
+ {header !== undefined ? (
233
+ header
234
+ ) : (
235
+ <header className="flex h-14 shrink-0 items-center gap-3 border-b px-4">
236
+ {groups.length > 0 && <NavSelect groups={groups} onNavigate={onNavigate} />}
237
+ {actions && <div className="ml-auto flex items-center gap-2">{actions}</div>}
238
+ </header>
239
+ )}
240
+ <main className="flex-1 overflow-auto">{children}</main>
241
+ </div>
242
+ )
243
+ }
244
+
245
+ const { defaultOpen = true } = props as AppShellSidebarProps
246
+
247
+ return (
248
+ <SidebarProvider defaultOpen={defaultOpen}>
249
+ <Sidebar data-slot="app-sidebar" collapsible="offcanvas">
250
+ <SidebarContent>
251
+ {groups.map((group, index) => (
252
+ <SidebarGroup key={group.label ?? index}>
253
+ {group.label && <SidebarGroupLabel>{group.label}</SidebarGroupLabel>}
254
+ <SidebarMenu>
255
+ {group.items.map((item) =>
256
+ item.children && item.children.length > 0 ? (
257
+ <NavItemWithChildren
258
+ key={item.href}
259
+ item={item}
260
+ linkComponent={linkComponent}
261
+ />
262
+ ) : (
263
+ <NavItemLink key={item.href} item={item} linkComponent={linkComponent} />
264
+ ),
265
+ )}
266
+ </SidebarMenu>
267
+ </SidebarGroup>
268
+ ))}
269
+ </SidebarContent>
270
+ {actions && <SidebarFooter>{actions}</SidebarFooter>}
271
+ <SidebarRail />
272
+ </Sidebar>
273
+ <SidebarInset ref={ref} data-slot="app-shell" className={className}>
274
+ {header !== undefined ? (
275
+ header
276
+ ) : (
277
+ <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
278
+ <SidebarTrigger />
279
+ <Separator orientation="vertical" className="h-4" />
280
+ </header>
281
+ )}
282
+ <main className="flex-1 overflow-auto">{children}</main>
283
+ </SidebarInset>
284
+ </SidebarProvider>
285
+ )
286
+ })
287
+ AppShell.displayName = "AppShell"