azamat-ui-kit-cli 0.3.13 → 0.3.14

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 (30) hide show
  1. package/dist/index.cjs +807 -107
  2. package/package.json +1 -1
  3. package/vendor/src/components/data-table/data-table-pagination.tsx +1 -1
  4. package/vendor/src/components/data-table/data-table-toolbar.tsx +13 -12
  5. package/vendor/src/components/data-table/data-table.tsx +14 -14
  6. package/vendor/src/components/display/smart-card.tsx +17 -14
  7. package/vendor/src/components/form/form-input.tsx +3 -1
  8. package/vendor/src/components/form/form-textarea.tsx +15 -12
  9. package/vendor/src/components/inputs/async-select.tsx +106 -47
  10. package/vendor/src/components/inputs/clearable-input.tsx +1 -0
  11. package/vendor/src/components/inputs/input-chrome.tsx +1 -1
  12. package/vendor/src/components/inputs/input-decorator.tsx +16 -8
  13. package/vendor/src/components/inputs/simple-select.tsx +28 -28
  14. package/vendor/src/components/layout/app-sidebar.tsx +454 -154
  15. package/vendor/src/components/layout/breadcrumbs.tsx +67 -22
  16. package/vendor/src/components/layout/sidebar-nav.tsx +316 -128
  17. package/vendor/src/components/overlay/confirm-dialog.tsx +31 -20
  18. package/vendor/src/components/ui/badge.tsx +33 -32
  19. package/vendor/src/components/ui/button.tsx +15 -17
  20. package/vendor/src/components/ui/card.tsx +26 -25
  21. package/vendor/src/components/ui/dialog.tsx +6 -3
  22. package/vendor/src/components/ui/dropdown-menu.tsx +9 -9
  23. package/vendor/src/components/ui/input-primitive.tsx +1 -1
  24. package/vendor/src/components/ui/input.tsx +105 -2
  25. package/vendor/src/components/ui/popover.tsx +1 -1
  26. package/vendor/src/components/ui/select.tsx +3 -3
  27. package/vendor/src/components/ui/table.tsx +4 -4
  28. package/vendor/src/components/ui/tabs.tsx +2 -2
  29. package/vendor/src/families/member-metadata.ts +3 -3
  30. package/vendor/templates/styles/globals.css +706 -6
@@ -1,179 +1,479 @@
1
1
  import * as React from "react"
2
2
 
3
+ import { Tooltip } from "@/components/ui/tooltip"
3
4
  import { cn } from "@/lib/utils"
4
-
5
- export type AppSidebarNavItem = {
6
- key: string
7
- label: React.ReactNode
8
- icon?: React.ReactNode
9
- href?: string
10
- active?: boolean
11
- disabled?: boolean
12
- badge?: React.ReactNode
13
- hidden?: boolean
14
- onSelect?: () => void
15
- }
16
-
5
+
6
+ export type AppSidebarNavItem = {
7
+ key: string
8
+ label: React.ReactNode
9
+ icon?: React.ReactNode
10
+ href?: string
11
+ items?: AppSidebarNavItem[]
12
+ active?: boolean
13
+ disabled?: boolean
14
+ badge?: React.ReactNode
15
+ hidden?: boolean
16
+ sectionLabel?: React.ReactNode
17
+ defaultExpanded?: boolean
18
+ current?: React.AriaAttributes["aria-current"]
19
+ tooltip?: React.ReactNode
20
+ onSelect?: () => void
21
+ }
22
+
23
+ export type AppSidebarFooterAccount = {
24
+ label: React.ReactNode
25
+ description?: React.ReactNode
26
+ avatar?: React.ReactNode
27
+ href?: string
28
+ tooltip?: React.ReactNode
29
+ onSelect?: () => void
30
+ }
31
+
17
32
  export type AppSidebarProps = React.ComponentProps<"aside"> & {
18
33
  header?: React.ReactNode
19
34
  footer?: React.ReactNode
20
35
  items?: AppSidebarNavItem[]
21
36
  collapsed?: boolean
37
+ collapsedRail?: React.ReactNode
38
+ railItems?: AppSidebarNavItem[]
39
+ footerAccount?: AppSidebarFooterAccount
40
+ secondaryActions?: AppSidebarNavItem[]
41
+ footerSecondary?: React.ReactNode
42
+ tooltipOnCollapsed?: boolean
22
43
  onItemSelect?: (item: AppSidebarNavItem) => void
23
44
  renderItem?: (item: AppSidebarNavItem, state: { collapsed: boolean }) => React.ReactNode
24
45
  renderLink?: (props: React.ComponentProps<"a"> & { item: AppSidebarNavItem; [key: `data-${string}`]: string | boolean | undefined }) => React.ReactNode
25
46
  }
26
-
27
- function AppSidebar({
28
- className,
29
- header,
30
- footer,
31
- items = [],
47
+
48
+ function hasVisibleSidebarChildren(item: AppSidebarNavItem) {
49
+ return item.items?.some((child) => !child.hidden) ?? false
50
+ }
51
+
52
+ function isSidebarItemActive(item: AppSidebarNavItem): boolean {
53
+ if (item.active) return true
54
+ return item.items?.some((child) => isSidebarItemActive(child)) ?? false
55
+ }
56
+
57
+ function SidebarLeafItem({
58
+ item,
59
+ collapsed,
60
+ depth,
61
+ onItemSelect,
62
+ renderLink,
63
+ }: {
64
+ item: AppSidebarNavItem
65
+ collapsed: boolean
66
+ depth: number
67
+ onItemSelect?: (item: AppSidebarNavItem) => void
68
+ renderLink?: AppSidebarProps["renderLink"]
69
+ }) {
70
+ const currentValue: React.AriaAttributes["aria-current"] = item.current ?? (item.active ? "page" : undefined)
71
+ const commonProps = {
72
+ "aria-current": currentValue,
73
+ "aria-disabled": item.disabled || undefined,
74
+ "data-slot": "app-sidebar-item" as const,
75
+ "data-active": item.active || undefined,
76
+ "data-disabled": item.disabled || undefined,
77
+ "data-depth": String(depth),
78
+ className: cn(
79
+ "flex min-h-9 items-center gap-2 rounded-lg border border-transparent px-2.5 text-sm font-medium outline-none transition-[background-color,border-color,color,box-shadow] data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
80
+ collapsed && "justify-center px-2"
81
+ ),
82
+ }
83
+
84
+ const content = (
85
+ <>
86
+ {item.icon && <span className="shrink-0">{item.icon}</span>}
87
+ {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
88
+ {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
89
+ </>
90
+ )
91
+
92
+ const wrapCollapsedContent = (node: React.ReactNode) =>
93
+ collapsed ? (
94
+ <Tooltip content={item.tooltip ?? item.label} side="right">
95
+ <span className="block">{node}</span>
96
+ </Tooltip>
97
+ ) : (
98
+ node
99
+ )
100
+
101
+ if (item.href?.startsWith("/")) {
102
+ if (renderLink) {
103
+ return wrapCollapsedContent(
104
+ <>
105
+ {renderLink({
106
+ item,
107
+ href: item.href,
108
+ ...commonProps,
109
+ onClick: (event) => {
110
+ if (item.disabled) {
111
+ event.preventDefault()
112
+ return
113
+ }
114
+ item.onSelect?.()
115
+ onItemSelect?.(item)
116
+ },
117
+ children: content,
118
+ })}
119
+ </>
120
+ )
121
+ }
122
+
123
+ return wrapCollapsedContent(
124
+ <a
125
+ href={item.href}
126
+ {...commonProps}
127
+ onClick={(event) => {
128
+ if (item.disabled) {
129
+ event.preventDefault()
130
+ return
131
+ }
132
+ item.onSelect?.()
133
+ onItemSelect?.(item)
134
+ }}
135
+ >
136
+ {content}
137
+ </a>
138
+ )
139
+ }
140
+
141
+ if (item.href) {
142
+ return wrapCollapsedContent(
143
+ <button
144
+ type="button"
145
+ {...commonProps}
146
+ className={cn(commonProps.className, "w-full")}
147
+ onClick={() => {
148
+ if (item.disabled) return
149
+ const href = item.href
150
+ if (!href) return
151
+ item.onSelect?.()
152
+ onItemSelect?.(item)
153
+ if (href.startsWith("http")) {
154
+ window.open(href, "_blank", "noopener,noreferrer")
155
+ return
156
+ }
157
+ window.location.assign(href)
158
+ }}
159
+ >
160
+ {content}
161
+ </button>
162
+ )
163
+ }
164
+
165
+ return wrapCollapsedContent(
166
+ <button
167
+ type="button"
168
+ disabled={item.disabled}
169
+ {...commonProps}
170
+ onClick={() => {
171
+ item.onSelect?.()
172
+ onItemSelect?.(item)
173
+ }}
174
+ >
175
+ {content}
176
+ </button>
177
+ )
178
+ }
179
+
180
+ function SidebarTree({
181
+ items,
182
+ collapsed,
183
+ depth,
184
+ onItemSelect,
185
+ renderLink,
186
+ }: {
187
+ items: AppSidebarNavItem[]
188
+ collapsed: boolean
189
+ depth: number
190
+ onItemSelect?: (item: AppSidebarNavItem) => void
191
+ renderLink?: AppSidebarProps["renderLink"]
192
+ }) {
193
+ return items.map((item) => {
194
+ if (item.hidden) return null
195
+
196
+ const hasChildren = hasVisibleSidebarChildren(item)
197
+ const active = isSidebarItemActive(item)
198
+ const showSectionLabel = !collapsed && depth === 0 && item.sectionLabel
199
+
200
+ if (!hasChildren) {
201
+ return (
202
+ <React.Fragment key={item.key}>
203
+ {showSectionLabel ? (
204
+ <div
205
+ data-slot="app-sidebar-group-label"
206
+ className="px-2.5 pb-1 pt-3 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground first:pt-0"
207
+ >
208
+ {item.sectionLabel}
209
+ </div>
210
+ ) : null}
211
+ <SidebarLeafItem
212
+ item={item}
213
+ collapsed={collapsed}
214
+ depth={depth}
215
+ onItemSelect={onItemSelect}
216
+ renderLink={renderLink}
217
+ />
218
+ </React.Fragment>
219
+ )
220
+ }
221
+
222
+ const defaultExpanded = item.defaultExpanded ?? active
223
+
224
+ return (
225
+ <div key={item.key} data-slot="app-sidebar-group" data-depth={depth}>
226
+ {showSectionLabel && (
227
+ <div
228
+ data-slot="app-sidebar-group-label"
229
+ className="px-2.5 pb-1 pt-3 text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground first:pt-0"
230
+ >
231
+ {item.sectionLabel}
232
+ </div>
233
+ )}
234
+ <details data-slot="app-sidebar-group-details" open={defaultExpanded} className="group/app-sidebar-details">
235
+ <summary
236
+ data-slot="app-sidebar-group-trigger"
237
+ className={cn(
238
+ "flex min-h-9 list-none items-center gap-2 rounded-lg border border-transparent text-sm font-medium outline-none transition-[background-color,border-color,color,box-shadow]",
239
+ collapsed ? "justify-center px-2" : "px-2.5"
240
+ )}
241
+ >
242
+ {item.icon ? (
243
+ collapsed ? (
244
+ <Tooltip content={item.tooltip ?? item.label} side="right">
245
+ <span className="shrink-0">{item.icon}</span>
246
+ </Tooltip>
247
+ ) : (
248
+ <span className="shrink-0">{item.icon}</span>
249
+ )
250
+ ) : null}
251
+ {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
252
+ {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
253
+ {!collapsed && <span data-slot="app-sidebar-group-chevron" className="ml-auto text-xs text-muted-foreground transition-transform group-open/app-sidebar-details:rotate-90">›</span>}
254
+ </summary>
255
+ <div data-slot="app-sidebar-group-content" className={cn("mt-1 space-y-1", !collapsed && "pl-3")}>
256
+ <SidebarTree
257
+ items={item.items ?? []}
258
+ collapsed={collapsed}
259
+ depth={depth + 1}
260
+ onItemSelect={onItemSelect}
261
+ renderLink={renderLink}
262
+ />
263
+ </div>
264
+ </details>
265
+ </div>
266
+ )
267
+ })
268
+ }
269
+
270
+ function SidebarActionButton({
271
+ item,
272
+ collapsed,
273
+ onItemSelect,
274
+ }: {
275
+ item: AppSidebarNavItem
276
+ collapsed: boolean
277
+ onItemSelect?: (item: AppSidebarNavItem) => void
278
+ }) {
279
+ const content = (
280
+ <button
281
+ type="button"
282
+ data-slot="app-sidebar-action"
283
+ data-active={item.active || undefined}
284
+ data-disabled={item.disabled || undefined}
285
+ className={cn(
286
+ "flex min-h-9 items-center gap-2 rounded-lg border border-transparent px-2.5 text-sm font-medium outline-none transition-[background-color,border-color,color,box-shadow] data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
287
+ collapsed && "justify-center px-2"
288
+ )}
289
+ disabled={item.disabled}
290
+ onClick={() => {
291
+ if (item.disabled) return
292
+ item.onSelect?.()
293
+ onItemSelect?.(item)
294
+ }}
295
+ >
296
+ {item.icon ? <span className="shrink-0">{item.icon}</span> : null}
297
+ {!collapsed ? <span className="min-w-0 flex-1 truncate">{item.label}</span> : null}
298
+ {!collapsed && item.badge ? <span className="shrink-0">{item.badge}</span> : null}
299
+ </button>
300
+ )
301
+
302
+ return collapsed ? (
303
+ <Tooltip content={item.tooltip ?? item.label} side="right">
304
+ <span className="block">{content}</span>
305
+ </Tooltip>
306
+ ) : (
307
+ content
308
+ )
309
+ }
310
+
311
+ function SidebarFooterAccount({
312
+ account,
313
+ collapsed,
314
+ }: {
315
+ account: AppSidebarFooterAccount
316
+ collapsed: boolean
317
+ }) {
318
+ const body = (
319
+ <button
320
+ type="button"
321
+ data-slot="app-sidebar-account"
322
+ className={cn(
323
+ "flex w-full items-center gap-3 rounded-[min(var(--radius-xl),16px)] border border-transparent text-left transition-[background-color,border-color,color,box-shadow]",
324
+ collapsed ? "justify-center px-2 py-2.5" : "px-3 py-2.5"
325
+ )}
326
+ onClick={() => {
327
+ account.onSelect?.()
328
+ if (!account.href) return
329
+ if (account.href.startsWith("http")) {
330
+ window.open(account.href, "_blank", "noopener,noreferrer")
331
+ return
332
+ }
333
+ window.location.assign(account.href)
334
+ }}
335
+ >
336
+ {account.avatar ? (
337
+ <span
338
+ data-slot="app-sidebar-account-avatar"
339
+ className="inline-flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full border border-border/65 bg-muted/45 text-sm font-semibold"
340
+ >
341
+ {account.avatar}
342
+ </span>
343
+ ) : null}
344
+ {!collapsed ? (
345
+ <span className="min-w-0 flex-1">
346
+ <span data-slot="app-sidebar-account-label" className="block truncate text-sm font-semibold text-foreground">
347
+ {account.label}
348
+ </span>
349
+ {account.description ? (
350
+ <span data-slot="app-sidebar-account-description" className="block truncate text-xs text-muted-foreground">
351
+ {account.description}
352
+ </span>
353
+ ) : null}
354
+ </span>
355
+ ) : null}
356
+ </button>
357
+ )
358
+
359
+ return collapsed ? (
360
+ <Tooltip content={account.tooltip ?? account.label} side="right">
361
+ <span className="block">{body}</span>
362
+ </Tooltip>
363
+ ) : (
364
+ body
365
+ )
366
+ }
367
+
368
+ function AppSidebar({
369
+ className,
370
+ header,
371
+ footer,
372
+ items = [],
32
373
  collapsed = false,
374
+ collapsedRail,
375
+ railItems = [],
376
+ footerAccount,
377
+ secondaryActions = [],
378
+ footerSecondary,
379
+ tooltipOnCollapsed = true,
33
380
  onItemSelect,
34
381
  renderItem,
35
382
  renderLink,
36
383
  children,
37
384
  ...props
38
385
  }: AppSidebarProps) {
39
- const visibleItems = items.filter((item) => !item.hidden)
40
-
41
- return (
42
- <aside
43
- data-slot="app-sidebar"
44
- data-collapsed={collapsed || undefined}
45
- className={cn("flex h-full min-h-0 flex-col bg-sidebar text-sidebar-foreground", className)}
46
- {...props}
47
- >
48
- {header && <div className="shrink-0 border-b p-3">{header}</div>}
49
-
386
+ const visibleItems = items.filter((item) => !item.hidden)
387
+ const visibleRailItems = railItems.filter((item) => !item.hidden)
388
+ const visibleSecondaryActions = secondaryActions.filter((item) => !item.hidden)
389
+
390
+ return (
391
+ <aside
392
+ data-slot="app-sidebar"
393
+ data-collapsed={collapsed || undefined}
394
+ className={cn("flex h-full min-h-0 flex-col", className)}
395
+ {...props}
396
+ >
397
+ {header && <div data-slot="app-sidebar-header" className="shrink-0 border-b p-3">{header}</div>}
398
+
50
399
  <nav data-slot="app-sidebar-nav" className="min-h-0 flex-1 space-y-1 overflow-y-auto p-2">
51
400
  {children ??
52
- visibleItems.map((item) =>
53
- renderItem ? (
54
- <React.Fragment key={item.key}>{renderItem(item, { collapsed })}</React.Fragment>
55
- ) : (
56
- item.href?.startsWith("/") ? (
57
- renderLink ? (
58
- <React.Fragment key={item.key}>
59
- {renderLink({
60
- item,
61
- href: item.href,
62
- "aria-current": item.active ? "page" : undefined,
63
- "aria-disabled": item.disabled || undefined,
64
- "data-active": item.active || undefined,
65
- "data-disabled": item.disabled || undefined,
66
- className: cn(
67
- "flex min-h-9 items-center gap-2 rounded-lg px-2.5 text-sm font-medium outline-none transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 focus-visible:ring-sidebar-ring data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
68
- collapsed && "justify-center px-2"
69
- ),
70
- onClick: (event) => {
71
- if (item.disabled) {
72
- event.preventDefault()
73
- return
74
- }
75
-
76
- item.onSelect?.()
77
- onItemSelect?.(item)
78
- },
79
- children: (
80
- <>
81
- {item.icon && <span className="shrink-0">{item.icon}</span>}
82
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
83
- {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
84
- </>
85
- ),
86
- })}
87
- </React.Fragment>
88
- ) : (
89
- <a
90
- key={item.key}
91
- href={item.href}
92
- aria-current={item.active ? "page" : undefined}
93
- aria-disabled={item.disabled || undefined}
94
- data-active={item.active || undefined}
95
- data-disabled={item.disabled || undefined}
96
- className={cn(
97
- "flex min-h-9 items-center gap-2 rounded-lg px-2.5 text-sm font-medium outline-none transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 focus-visible:ring-sidebar-ring data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
98
- collapsed && "justify-center px-2"
99
- )}
100
- onClick={(event) => {
101
- if (item.disabled) {
102
- event.preventDefault()
103
- return
104
- }
105
-
106
- item.onSelect?.()
107
- onItemSelect?.(item)
108
- }}
109
- >
110
- {item.icon && <span className="shrink-0">{item.icon}</span>}
111
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
112
- {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
113
- </a>
114
- )
115
- ) : item.href ? (
116
- <button
117
- key={item.key}
118
- type="button"
119
- aria-current={item.active ? "page" : undefined}
120
- aria-disabled={item.disabled || undefined}
121
- data-active={item.active || undefined}
122
- data-disabled={item.disabled || undefined}
123
- className={cn(
124
- "flex min-h-9 w-full items-center gap-2 rounded-lg px-2.5 text-sm font-medium outline-none transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 focus-visible:ring-sidebar-ring data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
125
- collapsed && "justify-center px-2"
126
- )}
127
- onClick={() => {
128
- if (item.disabled) return
129
- const href = item.href
130
- if (!href) return
131
-
132
- item.onSelect?.()
133
- onItemSelect?.(item)
134
-
135
- if (href.startsWith("http")) {
136
- window.open(href, "_blank", "noopener,noreferrer")
137
- return
138
- }
139
-
140
- window.location.assign(href)
141
- }}
142
- >
143
- {item.icon && <span className="shrink-0">{item.icon}</span>}
144
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
145
- {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
146
- </button>
147
- ) : (
148
- <button
149
- key={item.key}
150
- type="button"
151
- disabled={item.disabled}
152
- aria-current={item.active ? "page" : undefined}
153
- aria-disabled={item.disabled || undefined}
154
- data-active={item.active || undefined}
155
- data-disabled={item.disabled || undefined}
156
- className={cn(
157
- "flex min-h-9 items-center gap-2 rounded-lg px-2.5 text-sm font-medium outline-none transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 focus-visible:ring-sidebar-ring data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
158
- collapsed && "justify-center px-2"
159
- )}
160
- onClick={() => {
161
- item.onSelect?.()
162
- onItemSelect?.(item)
163
- }}
164
- >
165
- {item.icon && <span className="shrink-0">{item.icon}</span>}
166
- {!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
167
- {!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
168
- </button>
169
- )
401
+ visibleItems.map((item) => {
402
+ if (!renderItem) return null
403
+
404
+ const renderedItem = renderItem(item, { collapsed })
405
+ if (!collapsed || !tooltipOnCollapsed) {
406
+ return <React.Fragment key={item.key}>{renderedItem}</React.Fragment>
407
+ }
408
+
409
+ return (
410
+ <Tooltip key={item.key} content={item.tooltip ?? item.label} side="right">
411
+ <span className="block">{renderedItem}</span>
412
+ </Tooltip>
170
413
  )
171
- )}
414
+ })}
415
+ {!children && !renderItem && (
416
+ <SidebarTree
417
+ items={visibleItems}
418
+ collapsed={collapsed}
419
+ depth={0}
420
+ onItemSelect={onItemSelect}
421
+ renderLink={renderLink}
422
+ />
423
+ )}
172
424
  </nav>
173
-
174
- {footer && <div className="shrink-0 border-t p-3">{footer}</div>}
175
- </aside>
176
- )
177
- }
425
+
426
+ {(footerAccount || footerSecondary || footer || visibleSecondaryActions.length > 0 || (collapsed && (collapsedRail || visibleRailItems.length > 0))) && (
427
+ <div data-slot="app-sidebar-footer" className="shrink-0 border-t p-3">
428
+ {collapsed ? (
429
+ <>
430
+ {visibleRailItems.length > 0 ? (
431
+ <div data-slot="app-sidebar-rail-actions" className="grid gap-2">
432
+ {visibleRailItems.map((item) => (
433
+ <SidebarActionButton
434
+ key={item.key}
435
+ item={item}
436
+ collapsed
437
+ onItemSelect={onItemSelect}
438
+ />
439
+ ))}
440
+ </div>
441
+ ) : null}
442
+ {collapsedRail ? <div data-slot="app-sidebar-rail">{collapsedRail}</div> : null}
443
+ </>
444
+ ) : null}
445
+ {!collapsed && footerAccount ? (
446
+ <div data-slot="app-sidebar-account-wrap" className="mb-3">
447
+ <SidebarFooterAccount account={footerAccount} collapsed={false} />
448
+ </div>
449
+ ) : null}
450
+ {!collapsed && visibleSecondaryActions.length > 0 ? (
451
+ <div data-slot="app-sidebar-secondary-actions" className="mb-3 grid gap-2">
452
+ {visibleSecondaryActions.map((item) => (
453
+ <SidebarActionButton
454
+ key={item.key}
455
+ item={item}
456
+ collapsed={false}
457
+ onItemSelect={onItemSelect}
458
+ />
459
+ ))}
460
+ </div>
461
+ ) : null}
462
+ {!collapsed && footerSecondary ? (
463
+ <div data-slot="app-sidebar-footer-secondary" className="mb-3">
464
+ {footerSecondary}
465
+ </div>
466
+ ) : null}
467
+ {collapsed && footerAccount ? (
468
+ <div data-slot="app-sidebar-account-wrap">
469
+ <SidebarFooterAccount account={footerAccount} collapsed />
470
+ </div>
471
+ ) : null}
472
+ {!collapsed && footer}
473
+ </div>
474
+ )}
475
+ </aside>
476
+ )
477
+ }
178
478
 
179
479
  export { AppSidebar }