tembro 2.0.1 → 2.0.3
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/CHANGELOG.md +14 -0
- package/dist/components/calendar/calendar.cjs +1 -1
- package/dist/components/calendar/calendar.js +5 -5
- package/dist/components/inputs/clearable-input.cjs +1 -1
- package/dist/components/inputs/clearable-input.js +1 -1
- package/dist/components/inputs/input-chrome.cjs +1 -1
- package/dist/components/inputs/input-chrome.js +1 -1
- package/dist/components/layout/app-sidebar.cjs +1 -1
- package/dist/components/layout/app-sidebar.d.ts +19 -1
- package/dist/components/layout/app-sidebar.js +253 -126
- package/dist/components/ui/button/index.cjs +1 -1
- package/dist/components/ui/button/index.js +2 -2
- package/dist/components/ui/input/primitive.cjs +1 -1
- package/dist/components/ui/input/primitive.js +1 -1
- package/dist/components/ui/select/index.cjs +1 -1
- package/dist/components/ui/select/index.js +3 -3
- package/dist/hooks/index.cjs +1 -1
- package/dist/hooks/index.js +4 -4
- package/dist/index.cjs +1 -1
- package/dist/index.js +134 -134
- package/dist/showcase/package-meta.cjs +1 -1
- package/dist/showcase/package-meta.d.ts +3 -3
- package/dist/showcase/package-meta.js +1 -1
- package/dist/showcase/premium/app-shell/showcase.cjs +1 -1
- package/dist/showcase/premium/app-shell/showcase.js +5 -1
- package/dist/showcase/premium/app-sidebar/showcase.cjs +1 -1
- package/dist/showcase/premium/app-sidebar/showcase.js +91 -70
- package/dist/showcase/site-data.cjs +1 -1
- package/dist/showcase/site-data.js +1 -1
- package/dist/showcase/tembro-registry.json.cjs +1 -1
- package/dist/showcase/tembro-registry.json.js +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +6 -6
- package/packages/cli/vendor/src/components/calendar/calendar.tsx +5 -5
- package/packages/cli/vendor/src/components/inputs/clearable-input.tsx +1 -1
- package/packages/cli/vendor/src/components/inputs/input-chrome.tsx +1 -1
- package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +259 -21
- package/packages/cli/vendor/src/components/ui/button/index.tsx +2 -2
- package/packages/cli/vendor/src/components/ui/input/primitive.tsx +1 -1
- package/packages/cli/vendor/src/components/ui/select/index.tsx +3 -3
- package/packages/cli/vendor/src/showcase/package-meta.ts +2 -2
- package/packages/cli/vendor/src/showcase/premium/app-shell/showcase.tsx +5 -1
- package/packages/cli/vendor/src/showcase/premium/app-sidebar/showcase.tsx +18 -4
- package/packages/cli/vendor/src/showcase/tembro-registry.json +1 -1
- package/packages/cli/vendor/templates/styles/globals.css +5 -5
- package/registry.json +1 -1
|
@@ -269,7 +269,7 @@ function Calendar({
|
|
|
269
269
|
data-slot="calendar"
|
|
270
270
|
data-months={resolvedNumberOfMonths}
|
|
271
271
|
className={cn(
|
|
272
|
-
"w-fit rounded-[var(--aui-card-radius,var(--radius-lg))] border border-[color:var(--aui-card-border,var(--border))] bg-popover p-3 text-popover-foreground shadow-[var(--aui-control-panel-shadow,0_18px_40px_rgba(15,23,42,0.14))]
|
|
272
|
+
"w-fit rounded-[var(--aui-card-radius,var(--radius-lg))] border border-[color:var(--aui-card-border,var(--border))] bg-popover p-3 text-popover-foreground shadow-[var(--aui-control-panel-shadow,0_18px_40px_rgba(15,23,42,0.14))]",
|
|
273
273
|
className
|
|
274
274
|
)}
|
|
275
275
|
{...props}
|
|
@@ -279,7 +279,7 @@ function Calendar({
|
|
|
279
279
|
type="button"
|
|
280
280
|
variant="outline"
|
|
281
281
|
size="icon-sm"
|
|
282
|
-
className="rounded-
|
|
282
|
+
className="rounded-[var(--radius-md)] border-border/70 bg-background text-foreground shadow-none hover:border-border hover:bg-accent hover:text-accent-foreground"
|
|
283
283
|
aria-label={labels?.previousMonth ?? "Previous month"}
|
|
284
284
|
onClick={() => setMonth(addMonths(currentMonth, -navigationStep))}
|
|
285
285
|
>
|
|
@@ -293,7 +293,7 @@ function Calendar({
|
|
|
293
293
|
type="button"
|
|
294
294
|
variant="outline"
|
|
295
295
|
size="icon-sm"
|
|
296
|
-
className="rounded-
|
|
296
|
+
className="rounded-[var(--radius-md)] border-border/70 bg-background text-foreground shadow-none hover:border-border hover:bg-accent hover:text-accent-foreground"
|
|
297
297
|
aria-label={labels?.nextMonth ?? "Next month"}
|
|
298
298
|
onClick={() => setMonth(addMonths(currentMonth, navigationStep))}
|
|
299
299
|
>
|
|
@@ -310,7 +310,7 @@ function Calendar({
|
|
|
310
310
|
}
|
|
311
311
|
>
|
|
312
312
|
{monthDaysByMonth.map(({ month: visibleMonth, days }) => (
|
|
313
|
-
<div key={toDateKey(visibleMonth)} className="min-w-[16.5rem] rounded-[var(--radius-
|
|
313
|
+
<div key={toDateKey(visibleMonth)} className="min-w-[16.5rem] rounded-[var(--radius-md)] bg-transparent p-1">
|
|
314
314
|
{shouldShowMonthHeaders && (
|
|
315
315
|
<div className="mb-2 text-center text-sm font-semibold capitalize tracking-tight text-foreground">
|
|
316
316
|
{getMonthLabel(visibleMonth, locale)}
|
|
@@ -354,7 +354,7 @@ function Calendar({
|
|
|
354
354
|
data-in-range={inRange || undefined}
|
|
355
355
|
data-disabled-reason={disabledReason}
|
|
356
356
|
className={cn(
|
|
357
|
-
"flex h-9 items-center justify-center rounded-[var(--radius-
|
|
357
|
+
"flex h-9 items-center justify-center rounded-[var(--radius-sm)] border border-transparent text-sm font-medium outline-none transition-[background-color,color,border-color,box-shadow,transform] hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-30",
|
|
358
358
|
outside && "text-muted-foreground/34",
|
|
359
359
|
dateKey === todayKey && "border-border/70 bg-muted/60 text-foreground",
|
|
360
360
|
inRange && "bg-primary/10 text-foreground",
|
|
@@ -96,7 +96,7 @@ const ClearableInput = React.forwardRef<HTMLInputElement, ClearableInputProps>(
|
|
|
96
96
|
type="button"
|
|
97
97
|
data-slot="clearable-input-clear"
|
|
98
98
|
aria-label={clearLabel}
|
|
99
|
-
className="inline-flex size-7 items-center justify-center rounded-
|
|
99
|
+
className="inline-flex size-7 items-center justify-center rounded-[var(--radius-sm)] border border-transparent bg-transparent text-muted-foreground/74 transition hover:border-border/60 hover:bg-muted/58 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30"
|
|
100
100
|
onClick={handleClearClick}
|
|
101
101
|
onMouseDown={handleClearMouseDown}
|
|
102
102
|
onDoubleClick={handleClearMouseDown}
|
|
@@ -22,7 +22,7 @@ function InputChrome({
|
|
|
22
22
|
<div
|
|
23
23
|
data-slot="input-chrome"
|
|
24
24
|
className={cn(
|
|
25
|
-
"flex h-
|
|
25
|
+
"flex h-11 w-full min-w-0 items-center rounded-[var(--aui-control-radius,var(--radius-md))] border border-[color:var(--aui-control-border-strong,var(--input))] bg-[color:var(--aui-control-surface,var(--background))] shadow-[var(--aui-control-shadow,none)] transition-[background-color,border-color,box-shadow] hover:border-[color:var(--aui-control-hover-border,var(--ring))] hover:bg-[color:var(--aui-control-surface-hover,var(--background))] focus-within:border-[color:var(--ring)] focus-within:shadow-[var(--aui-control-shadow,none),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_4px_var(--aui-focus-ring-soft,transparent)]",
|
|
26
26
|
className
|
|
27
27
|
)}
|
|
28
28
|
{...props}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
+
import { MenuIcon, XIcon } from "lucide-react"
|
|
2
3
|
|
|
4
|
+
import { useIsMobile } from "@/hooks/use-is-mobile"
|
|
3
5
|
import { Tooltip } from "@/components/ui/tooltip"
|
|
4
6
|
import { cn } from "@/lib/utils"
|
|
5
7
|
|
|
@@ -40,11 +42,28 @@ export type AppSidebarProps = React.ComponentProps<"aside"> & {
|
|
|
40
42
|
secondaryActions?: AppSidebarNavItem[]
|
|
41
43
|
footerSecondary?: React.ReactNode
|
|
42
44
|
tooltipOnCollapsed?: boolean
|
|
45
|
+
responsive?: boolean
|
|
46
|
+
mobileBreakpoint?: number
|
|
47
|
+
mobileOpen?: boolean
|
|
48
|
+
defaultMobileOpen?: boolean
|
|
49
|
+
onMobileOpenChange?: (open: boolean) => void
|
|
50
|
+
mobileTitle?: React.ReactNode
|
|
51
|
+
mobileDescription?: React.ReactNode
|
|
52
|
+
mobileToggleLabel?: string
|
|
53
|
+
mobileToggleIcon?: React.ReactNode
|
|
54
|
+
showMobileToggle?: boolean
|
|
55
|
+
closeOnSelect?: boolean
|
|
56
|
+
mobileToggleClassName?: string
|
|
57
|
+
mobilePanelClassName?: string
|
|
58
|
+
mobileOverlayClassName?: string
|
|
59
|
+
renderMobileToggle?: (state: { open: boolean; setOpen: (open: boolean) => void }) => React.ReactNode
|
|
43
60
|
onItemSelect?: (item: AppSidebarNavItem) => void
|
|
44
61
|
renderItem?: (item: AppSidebarNavItem, state: { collapsed: boolean }) => React.ReactNode
|
|
45
62
|
renderLink?: (props: React.ComponentProps<"a"> & { item: AppSidebarNavItem; [key: `data-${string}`]: string | boolean | undefined }) => React.ReactNode
|
|
46
63
|
}
|
|
47
64
|
|
|
65
|
+
const DEFAULT_APP_SIDEBAR_BREAKPOINT = 1024
|
|
66
|
+
|
|
48
67
|
function hasVisibleSidebarChildren(item: AppSidebarNavItem) {
|
|
49
68
|
return item.items?.some((child) => !child.hidden) ?? false
|
|
50
69
|
}
|
|
@@ -54,6 +73,11 @@ function isSidebarItemActive(item: AppSidebarNavItem): boolean {
|
|
|
54
73
|
return item.items?.some((child) => isSidebarItemActive(child)) ?? false
|
|
55
74
|
}
|
|
56
75
|
|
|
76
|
+
function triggerSidebarItem(item: AppSidebarNavItem, onItemSelect?: (item: AppSidebarNavItem) => void) {
|
|
77
|
+
item.onSelect?.()
|
|
78
|
+
onItemSelect?.(item)
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
function SidebarLeafItem({
|
|
58
82
|
item,
|
|
59
83
|
collapsed,
|
|
@@ -111,8 +135,7 @@ function SidebarLeafItem({
|
|
|
111
135
|
event.preventDefault()
|
|
112
136
|
return
|
|
113
137
|
}
|
|
114
|
-
item
|
|
115
|
-
onItemSelect?.(item)
|
|
138
|
+
triggerSidebarItem(item, onItemSelect)
|
|
116
139
|
},
|
|
117
140
|
children: content,
|
|
118
141
|
})}
|
|
@@ -129,8 +152,7 @@ function SidebarLeafItem({
|
|
|
129
152
|
event.preventDefault()
|
|
130
153
|
return
|
|
131
154
|
}
|
|
132
|
-
item
|
|
133
|
-
onItemSelect?.(item)
|
|
155
|
+
triggerSidebarItem(item, onItemSelect)
|
|
134
156
|
}}
|
|
135
157
|
>
|
|
136
158
|
{content}
|
|
@@ -148,8 +170,7 @@ function SidebarLeafItem({
|
|
|
148
170
|
if (item.disabled) return
|
|
149
171
|
const href = item.href
|
|
150
172
|
if (!href) return
|
|
151
|
-
item
|
|
152
|
-
onItemSelect?.(item)
|
|
173
|
+
triggerSidebarItem(item, onItemSelect)
|
|
153
174
|
if (href.startsWith("http")) {
|
|
154
175
|
window.open(href, "_blank", "noopener,noreferrer")
|
|
155
176
|
return
|
|
@@ -168,8 +189,8 @@ function SidebarLeafItem({
|
|
|
168
189
|
disabled={item.disabled}
|
|
169
190
|
{...commonProps}
|
|
170
191
|
onClick={() => {
|
|
171
|
-
item.
|
|
172
|
-
|
|
192
|
+
if (item.disabled) return
|
|
193
|
+
triggerSidebarItem(item, onItemSelect)
|
|
173
194
|
}}
|
|
174
195
|
>
|
|
175
196
|
{content}
|
|
@@ -250,7 +271,14 @@ function SidebarTree({
|
|
|
250
271
|
) : null}
|
|
251
272
|
{!collapsed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
|
|
252
273
|
{!collapsed && item.badge && <span className="shrink-0">{item.badge}</span>}
|
|
253
|
-
{!collapsed &&
|
|
274
|
+
{!collapsed && (
|
|
275
|
+
<span
|
|
276
|
+
data-slot="app-sidebar-group-chevron"
|
|
277
|
+
className="ml-auto text-xs text-muted-foreground transition-transform group-open/app-sidebar-details:rotate-90"
|
|
278
|
+
>
|
|
279
|
+
›
|
|
280
|
+
</span>
|
|
281
|
+
)}
|
|
254
282
|
</summary>
|
|
255
283
|
<div data-slot="app-sidebar-group-content" className={cn("mt-1 space-y-1", !collapsed && "pl-3")}>
|
|
256
284
|
<SidebarTree
|
|
@@ -289,8 +317,7 @@ function SidebarActionButton({
|
|
|
289
317
|
disabled={item.disabled}
|
|
290
318
|
onClick={() => {
|
|
291
319
|
if (item.disabled) return
|
|
292
|
-
item
|
|
293
|
-
onItemSelect?.(item)
|
|
320
|
+
triggerSidebarItem(item, onItemSelect)
|
|
294
321
|
}}
|
|
295
322
|
>
|
|
296
323
|
{item.icon ? <span className="shrink-0">{item.icon}</span> : null}
|
|
@@ -311,9 +338,11 @@ function SidebarActionButton({
|
|
|
311
338
|
function SidebarFooterAccount({
|
|
312
339
|
account,
|
|
313
340
|
collapsed,
|
|
341
|
+
onAfterSelect,
|
|
314
342
|
}: {
|
|
315
343
|
account: AppSidebarFooterAccount
|
|
316
344
|
collapsed: boolean
|
|
345
|
+
onAfterSelect?: () => void
|
|
317
346
|
}) {
|
|
318
347
|
const body = (
|
|
319
348
|
<button
|
|
@@ -325,6 +354,7 @@ function SidebarFooterAccount({
|
|
|
325
354
|
)}
|
|
326
355
|
onClick={() => {
|
|
327
356
|
account.onSelect?.()
|
|
357
|
+
onAfterSelect?.()
|
|
328
358
|
if (!account.href) return
|
|
329
359
|
if (account.href.startsWith("http")) {
|
|
330
360
|
window.open(account.href, "_blank", "noopener,noreferrer")
|
|
@@ -365,7 +395,7 @@ function SidebarFooterAccount({
|
|
|
365
395
|
)
|
|
366
396
|
}
|
|
367
397
|
|
|
368
|
-
function
|
|
398
|
+
function SidebarSurface({
|
|
369
399
|
className,
|
|
370
400
|
header,
|
|
371
401
|
footer,
|
|
@@ -376,25 +406,70 @@ function AppSidebar({
|
|
|
376
406
|
footerAccount,
|
|
377
407
|
secondaryActions = [],
|
|
378
408
|
footerSecondary,
|
|
379
|
-
tooltipOnCollapsed
|
|
409
|
+
tooltipOnCollapsed,
|
|
380
410
|
onItemSelect,
|
|
381
411
|
renderItem,
|
|
382
412
|
renderLink,
|
|
383
413
|
children,
|
|
414
|
+
mobile,
|
|
415
|
+
mobileTitle,
|
|
416
|
+
mobileDescription,
|
|
417
|
+
onRequestClose,
|
|
418
|
+
closeOnSelect = true,
|
|
384
419
|
...props
|
|
385
|
-
}: AppSidebarProps
|
|
420
|
+
}: Omit<AppSidebarProps, "responsive" | "mobileBreakpoint" | "mobileOpen" | "defaultMobileOpen" | "onMobileOpenChange" | "mobileToggleLabel" | "mobileToggleIcon" | "showMobileToggle" | "mobileToggleClassName" | "mobilePanelClassName" | "mobileOverlayClassName" | "renderMobileToggle"> & {
|
|
421
|
+
mobile?: boolean
|
|
422
|
+
onRequestClose?: () => void
|
|
423
|
+
}) {
|
|
386
424
|
const visibleItems = items.filter((item) => !item.hidden)
|
|
387
425
|
const visibleRailItems = railItems.filter((item) => !item.hidden)
|
|
388
426
|
const visibleSecondaryActions = secondaryActions.filter((item) => !item.hidden)
|
|
389
427
|
|
|
428
|
+
const handleSelect = React.useCallback((item: AppSidebarNavItem) => {
|
|
429
|
+
onItemSelect?.(item)
|
|
430
|
+
if (mobile && closeOnSelect) onRequestClose?.()
|
|
431
|
+
}, [closeOnSelect, mobile, onItemSelect, onRequestClose])
|
|
432
|
+
|
|
433
|
+
const showMobileHeader = mobile && (mobileTitle || mobileDescription || onRequestClose)
|
|
434
|
+
|
|
390
435
|
return (
|
|
391
436
|
<aside
|
|
392
437
|
data-slot="app-sidebar"
|
|
393
438
|
data-collapsed={collapsed || undefined}
|
|
439
|
+
data-mobile={mobile || undefined}
|
|
394
440
|
className={cn("flex h-full min-h-0 flex-col overflow-hidden", className)}
|
|
395
441
|
{...props}
|
|
396
442
|
>
|
|
397
|
-
{header
|
|
443
|
+
{(header || showMobileHeader) && (
|
|
444
|
+
<div data-slot="app-sidebar-header" className="shrink-0 border-b p-3">
|
|
445
|
+
<div className="flex items-start gap-3">
|
|
446
|
+
<div className="min-w-0 flex-1">
|
|
447
|
+
{header ?? null}
|
|
448
|
+
{showMobileHeader ? (
|
|
449
|
+
<div className={cn(header && "mt-3")}>
|
|
450
|
+
{mobileTitle ? (
|
|
451
|
+
<p className="text-sm font-semibold text-foreground">{mobileTitle}</p>
|
|
452
|
+
) : null}
|
|
453
|
+
{mobileDescription ? (
|
|
454
|
+
<p className="mt-1 text-xs leading-5 text-muted-foreground">{mobileDescription}</p>
|
|
455
|
+
) : null}
|
|
456
|
+
</div>
|
|
457
|
+
) : null}
|
|
458
|
+
</div>
|
|
459
|
+
{mobile && onRequestClose ? (
|
|
460
|
+
<button
|
|
461
|
+
type="button"
|
|
462
|
+
aria-label="Close navigation"
|
|
463
|
+
data-slot="app-sidebar-mobile-close"
|
|
464
|
+
className="inline-flex size-9 shrink-0 items-center justify-center rounded-xl border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg-alt)] text-[color:var(--aui-page-foreground)] transition hover:bg-[color:var(--aui-control-bg)]"
|
|
465
|
+
onClick={onRequestClose}
|
|
466
|
+
>
|
|
467
|
+
<XIcon className="size-4" />
|
|
468
|
+
</button>
|
|
469
|
+
) : null}
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
)}
|
|
398
473
|
|
|
399
474
|
<nav data-slot="app-sidebar-nav" className="min-h-0 flex-1 space-y-1 overflow-y-auto overscroll-contain p-2">
|
|
400
475
|
{children ??
|
|
@@ -417,7 +492,7 @@ function AppSidebar({
|
|
|
417
492
|
items={visibleItems}
|
|
418
493
|
collapsed={collapsed}
|
|
419
494
|
depth={0}
|
|
420
|
-
onItemSelect={
|
|
495
|
+
onItemSelect={handleSelect}
|
|
421
496
|
renderLink={renderLink}
|
|
422
497
|
/>
|
|
423
498
|
)}
|
|
@@ -434,7 +509,7 @@ function AppSidebar({
|
|
|
434
509
|
key={item.key}
|
|
435
510
|
item={item}
|
|
436
511
|
collapsed
|
|
437
|
-
onItemSelect={
|
|
512
|
+
onItemSelect={handleSelect}
|
|
438
513
|
/>
|
|
439
514
|
))}
|
|
440
515
|
</div>
|
|
@@ -444,7 +519,9 @@ function AppSidebar({
|
|
|
444
519
|
) : null}
|
|
445
520
|
{!collapsed && footerAccount ? (
|
|
446
521
|
<div data-slot="app-sidebar-account-wrap" className="mb-3">
|
|
447
|
-
<SidebarFooterAccount account={footerAccount} collapsed={false}
|
|
522
|
+
<SidebarFooterAccount account={footerAccount} collapsed={false} onAfterSelect={() => {
|
|
523
|
+
if (mobile && closeOnSelect) onRequestClose?.()
|
|
524
|
+
}} />
|
|
448
525
|
</div>
|
|
449
526
|
) : null}
|
|
450
527
|
{!collapsed && visibleSecondaryActions.length > 0 ? (
|
|
@@ -454,7 +531,7 @@ function AppSidebar({
|
|
|
454
531
|
key={item.key}
|
|
455
532
|
item={item}
|
|
456
533
|
collapsed={false}
|
|
457
|
-
onItemSelect={
|
|
534
|
+
onItemSelect={handleSelect}
|
|
458
535
|
/>
|
|
459
536
|
))}
|
|
460
537
|
</div>
|
|
@@ -466,7 +543,13 @@ function AppSidebar({
|
|
|
466
543
|
) : null}
|
|
467
544
|
{collapsed && footerAccount ? (
|
|
468
545
|
<div data-slot="app-sidebar-account-wrap">
|
|
469
|
-
<SidebarFooterAccount
|
|
546
|
+
<SidebarFooterAccount
|
|
547
|
+
account={footerAccount}
|
|
548
|
+
collapsed
|
|
549
|
+
onAfterSelect={() => {
|
|
550
|
+
if (mobile && closeOnSelect) onRequestClose?.()
|
|
551
|
+
}}
|
|
552
|
+
/>
|
|
470
553
|
</div>
|
|
471
554
|
) : null}
|
|
472
555
|
{!collapsed && footer}
|
|
@@ -475,7 +558,162 @@ function AppSidebar({
|
|
|
475
558
|
</aside>
|
|
476
559
|
)
|
|
477
560
|
}
|
|
478
|
-
|
|
561
|
+
|
|
562
|
+
function AppSidebar({
|
|
563
|
+
className,
|
|
564
|
+
header,
|
|
565
|
+
footer,
|
|
566
|
+
items = [],
|
|
567
|
+
collapsed = false,
|
|
568
|
+
collapsedRail,
|
|
569
|
+
railItems = [],
|
|
570
|
+
footerAccount,
|
|
571
|
+
secondaryActions = [],
|
|
572
|
+
footerSecondary,
|
|
573
|
+
tooltipOnCollapsed = true,
|
|
574
|
+
responsive = true,
|
|
575
|
+
mobileBreakpoint = DEFAULT_APP_SIDEBAR_BREAKPOINT,
|
|
576
|
+
mobileOpen: mobileOpenProp,
|
|
577
|
+
defaultMobileOpen = false,
|
|
578
|
+
onMobileOpenChange,
|
|
579
|
+
mobileTitle,
|
|
580
|
+
mobileDescription,
|
|
581
|
+
mobileToggleLabel = "Open navigation",
|
|
582
|
+
mobileToggleIcon,
|
|
583
|
+
showMobileToggle = true,
|
|
584
|
+
closeOnSelect = true,
|
|
585
|
+
mobileToggleClassName,
|
|
586
|
+
mobilePanelClassName,
|
|
587
|
+
mobileOverlayClassName,
|
|
588
|
+
renderMobileToggle,
|
|
589
|
+
onItemSelect,
|
|
590
|
+
renderItem,
|
|
591
|
+
renderLink,
|
|
592
|
+
children,
|
|
593
|
+
...props
|
|
594
|
+
}: AppSidebarProps) {
|
|
595
|
+
const isMobile = responsive ? useIsMobile(mobileBreakpoint) : false
|
|
596
|
+
const [uncontrolledMobileOpen, setUncontrolledMobileOpen] = React.useState(defaultMobileOpen)
|
|
597
|
+
const mobileOpen = mobileOpenProp ?? uncontrolledMobileOpen
|
|
598
|
+
|
|
599
|
+
const setMobileOpen = React.useCallback((nextOpen: boolean) => {
|
|
600
|
+
if (mobileOpenProp == null) {
|
|
601
|
+
setUncontrolledMobileOpen(nextOpen)
|
|
602
|
+
}
|
|
603
|
+
onMobileOpenChange?.(nextOpen)
|
|
604
|
+
}, [mobileOpenProp, onMobileOpenChange])
|
|
605
|
+
|
|
606
|
+
React.useEffect(() => {
|
|
607
|
+
if (!isMobile && mobileOpen) {
|
|
608
|
+
setMobileOpen(false)
|
|
609
|
+
}
|
|
610
|
+
}, [isMobile, mobileOpen, setMobileOpen])
|
|
611
|
+
|
|
612
|
+
React.useEffect(() => {
|
|
613
|
+
if (!isMobile || !mobileOpen) return
|
|
614
|
+
|
|
615
|
+
const previousOverflow = document.body.style.overflow
|
|
616
|
+
document.body.style.overflow = "hidden"
|
|
617
|
+
|
|
618
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
619
|
+
if (event.key === "Escape") {
|
|
620
|
+
setMobileOpen(false)
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
window.addEventListener("keydown", handleKeyDown)
|
|
625
|
+
return () => {
|
|
626
|
+
document.body.style.overflow = previousOverflow
|
|
627
|
+
window.removeEventListener("keydown", handleKeyDown)
|
|
628
|
+
}
|
|
629
|
+
}, [isMobile, mobileOpen, setMobileOpen])
|
|
630
|
+
|
|
631
|
+
const baseProps = {
|
|
632
|
+
className,
|
|
633
|
+
header,
|
|
634
|
+
footer,
|
|
635
|
+
items,
|
|
636
|
+
collapsed,
|
|
637
|
+
collapsedRail,
|
|
638
|
+
railItems,
|
|
639
|
+
footerAccount,
|
|
640
|
+
secondaryActions,
|
|
641
|
+
footerSecondary,
|
|
642
|
+
tooltipOnCollapsed,
|
|
643
|
+
closeOnSelect,
|
|
644
|
+
onItemSelect,
|
|
645
|
+
renderItem,
|
|
646
|
+
renderLink,
|
|
647
|
+
children,
|
|
648
|
+
...props,
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (!responsive || !isMobile) {
|
|
652
|
+
return <SidebarSurface {...baseProps} />
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
const defaultTrigger = (
|
|
656
|
+
<button
|
|
657
|
+
type="button"
|
|
658
|
+
aria-label={mobileOpen ? "Close navigation" : mobileToggleLabel}
|
|
659
|
+
data-slot="app-sidebar-mobile-trigger"
|
|
660
|
+
data-state={mobileOpen ? "open" : "closed"}
|
|
661
|
+
className={cn(
|
|
662
|
+
"inline-flex min-h-10 items-center gap-2 rounded-xl border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg)] px-3 text-sm font-medium text-[color:var(--aui-page-foreground)] shadow-sm transition hover:bg-[color:var(--aui-page-bg-alt)]",
|
|
663
|
+
mobileToggleClassName
|
|
664
|
+
)}
|
|
665
|
+
onClick={() => setMobileOpen(!mobileOpen)}
|
|
666
|
+
>
|
|
667
|
+
<span className="inline-flex size-8 items-center justify-center rounded-lg bg-[color:var(--aui-page-bg-alt)]">
|
|
668
|
+
{mobileToggleIcon ?? <MenuIcon className="size-4" />}
|
|
669
|
+
</span>
|
|
670
|
+
<span>{mobileOpen ? "Close navigation" : mobileToggleLabel}</span>
|
|
671
|
+
</button>
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
return (
|
|
675
|
+
<>
|
|
676
|
+
{showMobileToggle
|
|
677
|
+
? renderMobileToggle
|
|
678
|
+
? renderMobileToggle({ open: mobileOpen, setOpen: setMobileOpen })
|
|
679
|
+
: defaultTrigger
|
|
680
|
+
: null}
|
|
681
|
+
<div data-slot="app-sidebar-mobile-root" className="relative z-40">
|
|
682
|
+
<button
|
|
683
|
+
type="button"
|
|
684
|
+
aria-label="Dismiss navigation"
|
|
685
|
+
data-slot="app-sidebar-mobile-overlay"
|
|
686
|
+
data-state={mobileOpen ? "open" : "closed"}
|
|
687
|
+
className={cn(
|
|
688
|
+
"fixed inset-0 z-40 bg-black/45 transition-opacity duration-200",
|
|
689
|
+
mobileOpen ? "opacity-100" : "pointer-events-none opacity-0",
|
|
690
|
+
mobileOverlayClassName
|
|
691
|
+
)}
|
|
692
|
+
onClick={() => setMobileOpen(false)}
|
|
693
|
+
/>
|
|
694
|
+
<SidebarSurface
|
|
695
|
+
{...baseProps}
|
|
696
|
+
mobile
|
|
697
|
+
collapsed={false}
|
|
698
|
+
mobileTitle={mobileTitle}
|
|
699
|
+
mobileDescription={mobileDescription}
|
|
700
|
+
onRequestClose={() => setMobileOpen(false)}
|
|
701
|
+
data-state={mobileOpen ? "open" : "closed"}
|
|
702
|
+
role="dialog"
|
|
703
|
+
aria-modal="true"
|
|
704
|
+
aria-label={typeof mobileTitle === "string" ? mobileTitle : "Navigation"}
|
|
705
|
+
className={cn(
|
|
706
|
+
"fixed inset-y-0 left-0 z-50 w-[min(88vw,22rem)] max-w-[22rem] border-r border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg)] shadow-2xl transition-transform duration-200 ease-out",
|
|
707
|
+
mobileOpen ? "translate-x-0" : "-translate-x-full",
|
|
708
|
+
mobilePanelClassName,
|
|
709
|
+
className
|
|
710
|
+
)}
|
|
711
|
+
/>
|
|
712
|
+
</div>
|
|
713
|
+
</>
|
|
714
|
+
)
|
|
715
|
+
}
|
|
716
|
+
|
|
479
717
|
/**
|
|
480
718
|
* Canonical sidebar surface for new usage.
|
|
481
719
|
*/
|
|
@@ -5,11 +5,11 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
|
5
5
|
import { cn } from "@/lib/utils"
|
|
6
6
|
|
|
7
7
|
const buttonVariants = cva(
|
|
8
|
-
"group/button inline-flex shrink-0 items-center justify-center rounded-[var(--aui-control-radius,var(--radius-
|
|
8
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-[var(--aui-control-radius,var(--radius-md))] border border-[color:var(--aui-control-border-strong,var(--border))] bg-[color:var(--aui-control-surface,var(--background))] bg-clip-padding text-sm font-semibold text-foreground whitespace-nowrap shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04))] transition-[transform,background-color,border-color,color,box-shadow,opacity] outline-none select-none hover:border-[color:var(--aui-control-hover-border,var(--ring))] hover:bg-[color:var(--aui-control-surface-hover,var(--muted))] focus-visible:ring-0 focus-visible:shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_4px_var(--aui-focus-ring-soft,transparent)] active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:cursor-not-allowed disabled:translate-y-0 disabled:border-[color:color-mix(in_oklch,var(--border),transparent_24%)] disabled:bg-[color:var(--aui-control-surface-disabled,var(--muted))] disabled:text-muted-foreground disabled:shadow-none disabled:opacity-100 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:translate-y-0 aria-disabled:opacity-100 aria-invalid:border-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
|
-
default: "border-[color:color-mix(in_oklch,var(--primary),black_10%)] bg-primary text-primary-foreground shadow-[var(--aui-button-primary-shadow,0_10px_24px_rgba(16,185,129,0.18))] hover:border-[color:color-mix(in_oklch,var(--primary),black_18%)] hover:bg-[color:color-mix(in_oklch,var(--primary),white_8%)]",
|
|
12
|
+
default: "border-[color:color-mix(in_oklch,var(--primary),black_10%)] bg-primary text-primary-foreground shadow-[var(--aui-button-primary-shadow,0_10px_24px_rgba(16,185,129,0.18))] hover:border-[color:color-mix(in_oklch,var(--primary),black_18%)] hover:bg-[color:color-mix(in_oklch,var(--primary),white_8%)] hover:text-primary-foreground",
|
|
13
13
|
outline: "bg-[color:var(--aui-control-surface,var(--background))] text-foreground shadow-none",
|
|
14
14
|
secondary: "border-[color:color-mix(in_oklch,var(--border),var(--foreground)_6%)] bg-secondary text-secondary-foreground shadow-none",
|
|
15
15
|
ghost: "border-transparent bg-transparent shadow-none",
|
|
@@ -13,7 +13,7 @@ function InputPrimitive({ className, type, ...props }: InputPrimitiveProps) {
|
|
|
13
13
|
type={type}
|
|
14
14
|
data-slot="input"
|
|
15
15
|
className={cn(
|
|
16
|
-
"h-11 w-full min-w-0 rounded-[var(--aui-control-radius,var(--radius-
|
|
16
|
+
"h-11 w-full min-w-0 rounded-[var(--aui-control-radius,var(--radius-md))] border border-[color:color-mix(in_oklch,var(--aui-control-border-strong,var(--input)),var(--foreground)_6%)] bg-[color:var(--aui-control-surface,var(--background))] px-3.5 py-2.5 text-sm font-normal text-foreground shadow-[var(--aui-shadow-xs,0_1px_2px_rgba(15,23,42,0.04))] transition-[background-color,border-color,box-shadow,color] outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground/74 hover:border-[color:color-mix(in_oklch,var(--aui-control-hover-border,var(--ring)),var(--foreground)_10%)] hover:bg-[color:var(--aui-control-surface-hover,var(--background))] focus-visible:border-[color:var(--ring)] focus-visible:ring-0 focus-visible:shadow-[var(--aui-shadow-xs,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_4px_var(--aui-focus-ring-soft,transparent)] disabled:pointer-events-none disabled:cursor-not-allowed disabled:border-[color:color-mix(in_oklch,var(--border),transparent_18%)] disabled:bg-[color:var(--aui-control-surface-disabled,var(--muted))] disabled:text-muted-foreground disabled:shadow-none disabled:opacity-100 read-only:bg-[color:var(--aui-control-surface-readonly,var(--muted))]",
|
|
17
17
|
className
|
|
18
18
|
)}
|
|
19
19
|
{...props}
|
|
@@ -54,7 +54,7 @@ function SelectTrigger({
|
|
|
54
54
|
data-slot="select-trigger"
|
|
55
55
|
data-size={size}
|
|
56
56
|
className={cn(
|
|
57
|
-
"flex w-full min-w-0 items-center justify-between gap-2 rounded-[var(--aui-control-radius,var(--radius-md))] border border-[color:var(--aui-control-border-strong,var(--input))] bg-[color:var(--aui-control-surface,var(--background))] pr-3 pl-3 text-sm whitespace-nowrap text-foreground shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04))] transition-[background-color,border-color,box-shadow,color] outline-none select-none hover:border-[color:var(--aui-control-hover-border,var(--ring))] hover:bg-[color:var(--aui-control-surface-hover,var(--background))] hover:shadow-[var(--aui-control-shadow-hover,0_2px_6px_rgba(15,23,42,0.06))] focus-visible:border-[color:var(--ring)] focus-visible:ring-0 focus-visible:shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_4px_var(--aui-focus-ring-soft,transparent)] disabled:cursor-not-allowed disabled:border-[color:color-mix(in_oklch,var(--border),transparent_18%)] disabled:bg-[color:var(--aui-control-surface-disabled,var(--muted))] disabled:opacity-100 aria-invalid:border-destructive aria-invalid:shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-danger-ring,var(--destructive)),0_0_0_4px_var(--aui-danger-ring-soft,transparent)] data-placeholder:text-muted-foreground/74 data-[size=default]:h-
|
|
57
|
+
"flex w-full min-w-0 items-center justify-between gap-2 rounded-[var(--aui-control-radius,var(--radius-md))] border border-[color:var(--aui-control-border-strong,var(--input))] bg-[color:var(--aui-control-surface,var(--background))] pr-3 pl-3 text-sm whitespace-nowrap text-foreground shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04))] transition-[background-color,border-color,box-shadow,color] outline-none select-none hover:border-[color:var(--aui-control-hover-border,var(--ring))] hover:bg-[color:var(--aui-control-surface-hover,var(--background))] hover:shadow-[var(--aui-control-shadow-hover,0_2px_6px_rgba(15,23,42,0.06))] focus-visible:border-[color:var(--ring)] focus-visible:ring-0 focus-visible:shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-focus-ring,var(--ring)),0_0_0_4px_var(--aui-focus-ring-soft,transparent)] disabled:cursor-not-allowed disabled:border-[color:color-mix(in_oklch,var(--border),transparent_18%)] disabled:bg-[color:var(--aui-control-surface-disabled,var(--muted))] disabled:text-muted-foreground disabled:opacity-100 aria-invalid:border-destructive aria-invalid:shadow-[var(--aui-control-shadow,0_1px_2px_rgba(15,23,42,0.04)),0_0_0_1px_var(--aui-danger-ring,var(--destructive)),0_0_0_4px_var(--aui-danger-ring-soft,transparent)] data-placeholder:text-muted-foreground/74 data-[size=default]:h-11 data-[size=lg]:h-12 data-[size=sm]:h-9 data-[size=sm]:rounded-[var(--radius-sm)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:min-w-0 *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
58
58
|
className
|
|
59
59
|
)}
|
|
60
60
|
{...props}
|
|
@@ -166,7 +166,7 @@ function SelectScrollUpButton({
|
|
|
166
166
|
<SelectPrimitive.ScrollUpArrow
|
|
167
167
|
data-slot="select-scroll-up-button"
|
|
168
168
|
className={cn(
|
|
169
|
-
"top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1
|
|
169
|
+
"top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 text-muted-foreground [&_svg:not([class*='size-'])]:size-4",
|
|
170
170
|
className
|
|
171
171
|
)}
|
|
172
172
|
{...props}
|
|
@@ -184,7 +184,7 @@ function SelectScrollDownButton({
|
|
|
184
184
|
<SelectPrimitive.ScrollDownArrow
|
|
185
185
|
data-slot="select-scroll-down-button"
|
|
186
186
|
className={cn(
|
|
187
|
-
"bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1
|
|
187
|
+
"bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 text-muted-foreground [&_svg:not([class*='size-'])]:size-4",
|
|
188
188
|
className
|
|
189
189
|
)}
|
|
190
190
|
{...props}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const PACKAGE_LATEST_VERSION = "2.0.
|
|
2
|
-
export const PACKAGE_LATEST_RELEASE_DATE = "July
|
|
1
|
+
export const PACKAGE_LATEST_VERSION = "2.0.3"
|
|
2
|
+
export const PACKAGE_LATEST_RELEASE_DATE = "July 8, 2026"
|
|
3
3
|
export const PACKAGE_DEPENDENCY_RANGE = `^${PACKAGE_LATEST_VERSION}`
|
|
4
4
|
|
|
@@ -69,9 +69,13 @@ export function AppShellShowcase({ mode }: ComponentDemoProps) {
|
|
|
69
69
|
|
|
70
70
|
<div className="grid min-h-[420px] lg:grid-cols-[250px_minmax(0,1fr)_260px]">
|
|
71
71
|
<AppSidebar
|
|
72
|
-
|
|
72
|
+
responsive
|
|
73
|
+
mobileTitle="Workspace navigation"
|
|
74
|
+
mobileDescription="Open the shell menu first, then move through app routes without squeezing the main content."
|
|
73
75
|
header={<div className="px-3 py-2 text-sm font-semibold">AZA Studio</div>}
|
|
74
76
|
footer={<div className="aui-text-muted px-3 py-2 text-xs">Shell footer</div>}
|
|
77
|
+
className={collapsed ? "lg:w-[92px]" : ""}
|
|
78
|
+
collapsed={collapsed}
|
|
75
79
|
>
|
|
76
80
|
<SidebarNav items={navItems} />
|
|
77
81
|
</AppSidebar>
|
|
@@ -2,6 +2,7 @@ import * as React from "react"
|
|
|
2
2
|
import { BarChart3Icon, CreditCardIcon, FolderIcon, HomeIcon, SettingsIcon } from "lucide-react"
|
|
3
3
|
|
|
4
4
|
import { AppSidebar, Badge, Button } from "@/index"
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
5
6
|
|
|
6
7
|
import type { ComponentDemoProps } from "../types"
|
|
7
8
|
|
|
@@ -18,6 +19,7 @@ const panelClass = "rounded-[22px] border border-[color:var(--aui-divider)] bg-[
|
|
|
18
19
|
export function AppSidebarShowcase({ mode }: ComponentDemoProps) {
|
|
19
20
|
const [activeKey, setActiveKey] = React.useState("overview")
|
|
20
21
|
const [collapsed, setCollapsed] = React.useState(mode === "playground")
|
|
22
|
+
const [previewSurface, setPreviewSurface] = React.useState<"desktop" | "mobile">("desktop")
|
|
21
23
|
|
|
22
24
|
const items = React.useMemo(
|
|
23
25
|
() =>
|
|
@@ -30,6 +32,7 @@ export function AppSidebarShowcase({ mode }: ComponentDemoProps) {
|
|
|
30
32
|
)
|
|
31
33
|
|
|
32
34
|
const activeItem = navItems.find((item) => item.key === activeKey)
|
|
35
|
+
const mobilePreview = previewSurface === "mobile"
|
|
33
36
|
|
|
34
37
|
return (
|
|
35
38
|
<div className="space-y-5">
|
|
@@ -45,7 +48,7 @@ export function AppSidebarShowcase({ mode }: ComponentDemoProps) {
|
|
|
45
48
|
<div className="flex flex-wrap gap-2">
|
|
46
49
|
<Badge variant="outline" className="rounded-full">Header slot</Badge>
|
|
47
50
|
<Badge variant="outline" className="rounded-full">Badges</Badge>
|
|
48
|
-
<Badge variant="outline" className="rounded-full">
|
|
51
|
+
<Badge variant="outline" className="rounded-full">Mobile drawer</Badge>
|
|
49
52
|
</div>
|
|
50
53
|
</div>
|
|
51
54
|
</section>
|
|
@@ -58,14 +61,25 @@ export function AppSidebarShowcase({ mode }: ComponentDemoProps) {
|
|
|
58
61
|
<Button size="sm" variant="outline" onClick={() => setActiveKey("reports")}>
|
|
59
62
|
Jump to reports
|
|
60
63
|
</Button>
|
|
64
|
+
<Button size="sm" variant={mobilePreview ? "default" : "outline"} onClick={() => setPreviewSurface("mobile")}>
|
|
65
|
+
Mobile drawer
|
|
66
|
+
</Button>
|
|
67
|
+
<Button size="sm" variant={!mobilePreview ? "default" : "outline"} onClick={() => setPreviewSurface("desktop")}>
|
|
68
|
+
Desktop rail
|
|
69
|
+
</Button>
|
|
61
70
|
</div>
|
|
62
71
|
) : null}
|
|
63
72
|
|
|
64
73
|
<div className="grid gap-4 xl:grid-cols-[320px_minmax(0,1fr)]">
|
|
65
|
-
<section className={panelClass}>
|
|
74
|
+
<section className={cn(panelClass, mobilePreview && "mx-auto w-full max-w-[420px]")}>
|
|
66
75
|
<AppSidebar
|
|
67
76
|
collapsed={collapsed}
|
|
68
77
|
items={items}
|
|
78
|
+
responsive
|
|
79
|
+
mobileBreakpoint={mobilePreview ? 10000 : 0}
|
|
80
|
+
mobileTitle="Workspace navigation"
|
|
81
|
+
mobileDescription="Open routes, check badges, and move between sections from one compact drawer."
|
|
82
|
+
mobileToggleLabel="Open workspace menu"
|
|
69
83
|
header={<div className="px-3 py-2 text-sm font-semibold">Azamat Workspace</div>}
|
|
70
84
|
footer={<div className="aui-text-muted px-3 py-2 text-xs">Starter plan • 3 editors</div>}
|
|
71
85
|
className="min-h-[440px] rounded-[22px] border border-[color:var(--aui-surface-border)] bg-[color:var(--aui-surface)]"
|
|
@@ -81,8 +95,8 @@ export function AppSidebarShowcase({ mode }: ComponentDemoProps) {
|
|
|
81
95
|
|
|
82
96
|
<div className="mt-6 grid gap-3 sm:grid-cols-3">
|
|
83
97
|
<div className="rounded-[20px] border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg-alt)] px-4 py-3">
|
|
84
|
-
<p className="text-[11px] font-semibold uppercase tracking-[0.24em] aui-text-muted">
|
|
85
|
-
<p className="mt-2 text-lg font-semibold aui-text-strong">{collapsed ? "Collapsed" : "Expanded"}</p>
|
|
98
|
+
<p className="text-[11px] font-semibold uppercase tracking-[0.24em] aui-text-muted">Shell</p>
|
|
99
|
+
<p className="mt-2 text-lg font-semibold aui-text-strong">{mobilePreview ? "Mobile drawer" : (collapsed ? "Collapsed" : "Expanded")}</p>
|
|
86
100
|
</div>
|
|
87
101
|
<div className="rounded-[20px] border border-[color:var(--aui-divider)] bg-[color:var(--aui-page-bg-alt)] px-4 py-3">
|
|
88
102
|
<p className="text-[11px] font-semibold uppercase tracking-[0.24em] aui-text-muted">Visible items</p>
|