@arqel-dev/ui 0.11.0 → 0.13.0

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 (111) hide show
  1. package/SKILL.md +5 -2
  2. package/dist/AreaChart-NMQ2RQGA.js +33 -0
  3. package/dist/AreaChart-NMQ2RQGA.js.map +1 -0
  4. package/dist/ArqelCreatePage-P3G6TKIK.js +8 -0
  5. package/dist/ArqelCreatePage-P3G6TKIK.js.map +1 -0
  6. package/dist/ArqelDashboardPage-PX3Y75AA.js +6 -0
  7. package/dist/ArqelDashboardPage-PX3Y75AA.js.map +1 -0
  8. package/dist/ArqelEditPage-HKQSE6E5.js +8 -0
  9. package/dist/ArqelEditPage-HKQSE6E5.js.map +1 -0
  10. package/dist/ArqelIndexPage-MRH3572Z.js +12 -0
  11. package/dist/ArqelIndexPage-MRH3572Z.js.map +1 -0
  12. package/dist/ArqelShowPage-4FS5MTUN.js +6 -0
  13. package/dist/ArqelShowPage-4FS5MTUN.js.map +1 -0
  14. package/dist/BarChart-KLHKTLO2.js +19 -0
  15. package/dist/BarChart-KLHKTLO2.js.map +1 -0
  16. package/dist/DonutChart-L56R4QF2.js +11 -0
  17. package/dist/DonutChart-L56R4QF2.js.map +1 -0
  18. package/dist/LineChart-GHMPHFZZ.js +30 -0
  19. package/dist/LineChart-GHMPHFZZ.js.map +1 -0
  20. package/dist/PieChart-T2VQOFPP.js +4 -0
  21. package/dist/PieChart-T2VQOFPP.js.map +1 -0
  22. package/dist/RadarChart-CSWR5AO7.js +32 -0
  23. package/dist/RadarChart-CSWR5AO7.js.map +1 -0
  24. package/dist/Topbar-DffcNdcJ.d.ts +50 -0
  25. package/dist/action.d.ts +12 -2
  26. package/dist/action.js +6 -1090
  27. package/dist/action.js.map +1 -1
  28. package/dist/auth.js +1 -10
  29. package/dist/auth.js.map +1 -1
  30. package/dist/chunk-2LTZJ4R7.js +110 -0
  31. package/dist/chunk-2LTZJ4R7.js.map +1 -0
  32. package/dist/chunk-3JJOHYD7.js +57 -0
  33. package/dist/chunk-3JJOHYD7.js.map +1 -0
  34. package/dist/chunk-47HD7ALI.js +370 -0
  35. package/dist/chunk-47HD7ALI.js.map +1 -0
  36. package/dist/chunk-6UJQP7KU.js +737 -0
  37. package/dist/chunk-6UJQP7KU.js.map +1 -0
  38. package/dist/chunk-7LSZADUC.js +50 -0
  39. package/dist/chunk-7LSZADUC.js.map +1 -0
  40. package/dist/chunk-B7ULUJVO.js +11 -0
  41. package/dist/chunk-B7ULUJVO.js.map +1 -0
  42. package/dist/chunk-C5H44NSP.js +37 -0
  43. package/dist/chunk-C5H44NSP.js.map +1 -0
  44. package/dist/chunk-DSULVRB6.js +101 -0
  45. package/dist/chunk-DSULVRB6.js.map +1 -0
  46. package/dist/chunk-ERT7LL6C.js +199 -0
  47. package/dist/chunk-ERT7LL6C.js.map +1 -0
  48. package/dist/chunk-EYAUPJ6J.js +64 -0
  49. package/dist/chunk-EYAUPJ6J.js.map +1 -0
  50. package/dist/chunk-FHRQ7PWE.js +58 -0
  51. package/dist/chunk-FHRQ7PWE.js.map +1 -0
  52. package/dist/chunk-FV7RESKL.js +285 -0
  53. package/dist/chunk-FV7RESKL.js.map +1 -0
  54. package/dist/chunk-K7QY56XN.js +610 -0
  55. package/dist/chunk-K7QY56XN.js.map +1 -0
  56. package/dist/chunk-L3JBBN4H.js +27 -0
  57. package/dist/chunk-L3JBBN4H.js.map +1 -0
  58. package/dist/chunk-MSRTGCTJ.js +597 -0
  59. package/dist/chunk-MSRTGCTJ.js.map +1 -0
  60. package/dist/chunk-MTNFFSVA.js +92 -0
  61. package/dist/chunk-MTNFFSVA.js.map +1 -0
  62. package/dist/chunk-MTZJDFQ6.js +32 -0
  63. package/dist/chunk-MTZJDFQ6.js.map +1 -0
  64. package/dist/chunk-MXUXMHOK.js +16 -0
  65. package/dist/chunk-MXUXMHOK.js.map +1 -0
  66. package/dist/chunk-PXON56HL.js +35 -0
  67. package/dist/chunk-PXON56HL.js.map +1 -0
  68. package/dist/chunk-PZEVKMZX.js +598 -0
  69. package/dist/chunk-PZEVKMZX.js.map +1 -0
  70. package/dist/chunk-R4BOUU6Y.js +55 -0
  71. package/dist/chunk-R4BOUU6Y.js.map +1 -0
  72. package/dist/chunk-RMPOR2YZ.js +12 -0
  73. package/dist/chunk-RMPOR2YZ.js.map +1 -0
  74. package/dist/chunk-RNAMHQM6.js +12 -0
  75. package/dist/chunk-RNAMHQM6.js.map +1 -0
  76. package/dist/chunk-TNJEHYRF.js +387 -0
  77. package/dist/chunk-TNJEHYRF.js.map +1 -0
  78. package/dist/chunk-VSTRVXXZ.js +49 -0
  79. package/dist/chunk-VSTRVXXZ.js.map +1 -0
  80. package/dist/chunk-WKWV36PG.js +140 -0
  81. package/dist/chunk-WKWV36PG.js.map +1 -0
  82. package/dist/cn-By8XWiSA.d.ts +12 -0
  83. package/dist/flash.js +2 -104
  84. package/dist/flash.js.map +1 -1
  85. package/dist/form.js +4 -673
  86. package/dist/form.js.map +1 -1
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.js +18 -3706
  89. package/dist/index.js.map +1 -1
  90. package/dist/pages.js +23 -3025
  91. package/dist/pages.js.map +1 -1
  92. package/dist/palette.js +1 -283
  93. package/dist/palette.js.map +1 -1
  94. package/dist/primitives.js +3 -658
  95. package/dist/primitives.js.map +1 -1
  96. package/dist/resource.js +5 -720
  97. package/dist/resource.js.map +1 -1
  98. package/dist/shell.d.ts +26 -46
  99. package/dist/shell.js +46 -1039
  100. package/dist/shell.js.map +1 -1
  101. package/dist/table.js +4 -618
  102. package/dist/table.js.map +1 -1
  103. package/dist/utility.js +3 -104
  104. package/dist/utility.js.map +1 -1
  105. package/dist/utils.d.ts +12 -6
  106. package/dist/utils.js +2 -9
  107. package/dist/utils.js.map +1 -1
  108. package/dist/widgets.d.ts +7 -2
  109. package/dist/widgets.js +3 -675
  110. package/dist/widgets.js.map +1 -1
  111. package/package.json +15 -14
package/dist/shell.js CHANGED
@@ -1,1048 +1,55 @@
1
- import * as React5 from 'react';
2
- import { useMemo, useRef, useState, useId, useEffect, useCallback } from 'react';
1
+ export { AppShell, Footer, MainContent, Sidebar, Topbar } from './chunk-6UJQP7KU.js';
2
+ import './chunk-FV7RESKL.js';
3
+ import './chunk-R4BOUU6Y.js';
4
+ import './chunk-RMPOR2YZ.js';
5
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-EYAUPJ6J.js';
6
+ import { Button } from './chunk-FHRQ7PWE.js';
7
+ import './chunk-B7ULUJVO.js';
8
+ import { router } from '@inertiajs/react';
3
9
  import { jsxs, jsx } from 'react/jsx-runtime';
4
- import { cva } from 'class-variance-authority';
5
- import { PanelLeftIcon, XIcon } from 'lucide-react';
6
- import { Slot, Tooltip as Tooltip$1, Dialog } from 'radix-ui';
7
- import { clsx } from 'clsx';
8
- import { twMerge } from 'tailwind-merge';
9
- import { useNavigation } from '@arqel-dev/hooks';
10
- import { useTheme } from '@arqel-dev/react/providers';
11
10
 
12
- // src/palette/CommandPalette.tsx
13
- var RECENT_KEY = "arqel:cmdpal:recent";
14
- var RECENT_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
15
- var RECENT_LIMIT = 5;
16
- var DEBOUNCE_MS = 150;
17
- function readRecents() {
18
- try {
19
- const raw = globalThis.localStorage?.getItem(RECENT_KEY);
20
- if (!raw) return [];
21
- const parsed = JSON.parse(raw);
22
- if (!Array.isArray(parsed)) return [];
23
- const now = Date.now();
24
- return parsed.filter(
25
- (e) => typeof e === "object" && e !== null && typeof e.id === "string" && typeof e.count === "number" && typeof e.lastUsed === "number" && now - e.lastUsed <= RECENT_WINDOW_MS && typeof e.command === "object"
26
- );
27
- } catch {
28
- return [];
29
- }
30
- }
31
- function writeRecents(entries) {
32
- try {
33
- globalThis.localStorage?.setItem(RECENT_KEY, JSON.stringify(entries));
34
- } catch {
35
- }
36
- }
37
- function recordUsage(command) {
38
- const entries = readRecents();
39
- const now = Date.now();
40
- const idx = entries.findIndex((e) => e.id === command.id);
41
- if (idx >= 0) {
42
- const existing = entries[idx];
43
- if (existing) {
44
- entries[idx] = {
45
- ...existing,
46
- count: existing.count + 1,
47
- lastUsed: now,
48
- command
49
- };
50
- }
51
- } else {
52
- entries.push({ id: command.id, count: 1, lastUsed: now, command });
53
- }
54
- const fresh = entries.filter((e) => now - e.lastUsed <= RECENT_WINDOW_MS);
55
- writeRecents(fresh);
56
- }
57
- function topRecents() {
58
- return readRecents().slice().sort((a, b) => b.count === a.count ? b.lastUsed - a.lastUsed : b.count - a.count).slice(0, RECENT_LIMIT).map((e) => e.command);
59
- }
60
- function groupByCategory(commands) {
61
- const order = [];
62
- const buckets = /* @__PURE__ */ new Map();
63
- for (const cmd of commands) {
64
- const key = cmd.category ?? "General";
65
- if (!buckets.has(key)) {
66
- buckets.set(key, []);
67
- order.push(key);
68
- }
69
- buckets.get(key)?.push(cmd);
70
- }
71
- return order.map((category) => ({ category, commands: buckets.get(category) ?? [] }));
72
- }
73
- function flattenGroups(groups) {
74
- return groups.flatMap((g) => g.commands);
75
- }
76
- var dialogStyle = {
77
- border: "none",
78
- borderRadius: "0.75rem",
79
- padding: 0,
80
- width: "min(640px, 92vw)",
81
- maxHeight: "70vh",
82
- background: "var(--background, #fff)",
83
- color: "var(--foreground, #111)"
84
- };
85
- function CommandPalette({ endpoint = "/admin/commands" }) {
86
- const dialogRef = useRef(null);
87
- const inputRef = useRef(null);
88
- const debounceTimer = useRef(null);
89
- const [open, setOpen] = useState(false);
90
- const [query, setQuery] = useState("");
91
- const [results, setResults] = useState([]);
92
- const [recents, setRecents] = useState([]);
93
- const [highlight, setHighlight] = useState(0);
94
- const titleId = useId();
95
- const hintId = useId();
96
- const listId = useId();
97
- const optBaseId = useId();
98
- const visibleCommands = query.trim().length === 0 ? recents : results;
99
- const groups = query.trim().length === 0 && recents.length > 0 ? [{ category: "Recent", commands: recents }] : groupByCategory(visibleCommands);
100
- const flat = flattenGroups(groups);
101
- useEffect(() => {
102
- function onKey(event) {
103
- const isToggle = (event.key === "k" || event.key === "K") && (event.metaKey || event.ctrlKey);
104
- if (!isToggle) return;
105
- event.preventDefault();
106
- setOpen((prev) => !prev);
107
- }
108
- window.addEventListener("keydown", onKey);
109
- return () => window.removeEventListener("keydown", onKey);
110
- }, []);
111
- useEffect(() => {
112
- const dialog = dialogRef.current;
113
- if (!dialog) return;
114
- if (open && !dialog.open) {
115
- try {
116
- dialog.showModal();
117
- } catch {
118
- }
119
- setRecents(topRecents());
120
- setQuery("");
121
- setResults([]);
122
- setHighlight(0);
123
- queueMicrotask(() => inputRef.current?.focus());
124
- } else if (!open && dialog.open) {
125
- dialog.close();
126
- }
127
- }, [open]);
128
- useEffect(() => {
129
- if (!open) return;
130
- if (query.trim().length === 0) {
131
- setResults([]);
132
- return;
133
- }
134
- if (debounceTimer.current) clearTimeout(debounceTimer.current);
135
- debounceTimer.current = setTimeout(() => {
136
- const url = `${endpoint}?q=${encodeURIComponent(query)}`;
137
- fetch(url, { headers: { Accept: "application/json" } }).then((res) => res.ok ? res.json() : { commands: [] }).then((data) => {
138
- setResults(Array.isArray(data?.commands) ? data.commands : []);
139
- setHighlight(0);
140
- }).catch(() => {
141
- setResults([]);
142
- });
143
- }, DEBOUNCE_MS);
144
- return () => {
145
- if (debounceTimer.current) clearTimeout(debounceTimer.current);
146
- };
147
- }, [query, open, endpoint]);
148
- const close = useCallback(() => setOpen(false), []);
149
- const execute = useCallback((command) => {
150
- recordUsage(command);
151
- setOpen(false);
152
- window.location.assign(command.url);
153
- }, []);
154
- const onKeyDown = useCallback(
155
- (event) => {
156
- if (event.key === "Escape") {
157
- event.preventDefault();
158
- close();
159
- return;
160
- }
161
- if (flat.length === 0) return;
162
- if (event.key === "ArrowDown") {
163
- event.preventDefault();
164
- setHighlight((h) => (h + 1) % flat.length);
165
- } else if (event.key === "ArrowUp") {
166
- event.preventDefault();
167
- setHighlight((h) => (h - 1 + flat.length) % flat.length);
168
- } else if (event.key === "Enter") {
169
- event.preventDefault();
170
- const target = flat[highlight];
171
- if (target) execute(target);
172
- }
173
- },
174
- [flat, highlight, close, execute]
175
- );
176
- const onDialogClick = useCallback(
177
- (event) => {
178
- if (event.target === dialogRef.current) close();
179
- },
180
- [close]
181
- );
182
- const optionId = (idx) => `${optBaseId}-opt-${idx}`;
183
- const activeOptionId = flat.length > 0 ? optionId(highlight) : void 0;
184
- return (
185
- // biome-ignore lint/a11y/useKeyWithClickEvents: dialog backdrop click closes; Escape (onCancel) handles keyboard close
186
- /* @__PURE__ */ jsx(
187
- "dialog",
188
- {
189
- ref: dialogRef,
190
- "aria-labelledby": titleId,
191
- "aria-describedby": hintId,
192
- onClick: onDialogClick,
193
- onClose: () => setOpen(false),
194
- onCancel: (event) => {
195
- event.preventDefault();
196
- close();
197
- },
198
- style: dialogStyle,
199
- className: "backdrop:bg-black/40",
200
- "data-arqel-cmdpal": "",
201
- children: /* @__PURE__ */ jsxs("div", { onKeyDown, className: "flex flex-col", children: [
202
- /* @__PURE__ */ jsx("h2", { id: titleId, className: "sr-only", children: "Command palette" }),
203
- /* @__PURE__ */ jsx(
204
- "input",
205
- {
206
- ref: inputRef,
207
- type: "text",
208
- role: "combobox",
209
- "aria-expanded": open,
210
- "aria-controls": listId,
211
- "aria-autocomplete": "list",
212
- ...activeOptionId ? { "aria-activedescendant": activeOptionId } : {},
213
- placeholder: "Type a command\u2026",
214
- value: query,
215
- onChange: (e) => setQuery(e.target.value),
216
- className: "w-full border-b border-[var(--border,#e5e7eb)] bg-transparent px-4 py-3 text-base outline-none"
217
- }
218
- ),
219
- /* @__PURE__ */ jsxs("div", { role: "status", "aria-live": "polite", className: "sr-only", children: [
220
- flat.length,
221
- " commands"
222
- ] }),
223
- /* @__PURE__ */ jsxs(
224
- "ul",
225
- {
226
- id: listId,
227
- role: "listbox",
228
- "aria-label": "Commands",
229
- className: "max-h-[50vh] overflow-y-auto py-2",
230
- children: [
231
- groups.length === 0 && /* @__PURE__ */ jsx("li", { role: "presentation", className: "px-4 py-3 text-sm opacity-60", children: "No commands found" }),
232
- groups.map((group) => {
233
- const startIdx = flat.indexOf(group.commands[0] ?? {});
234
- return /* @__PURE__ */ jsxs("li", { role: "presentation", children: [
235
- /* @__PURE__ */ jsx(
236
- "div",
237
- {
238
- role: "presentation",
239
- className: "px-4 pt-2 pb-1 text-xs font-semibold uppercase tracking-wide opacity-60",
240
- children: group.category
241
- }
242
- ),
243
- /* @__PURE__ */ jsx("ul", { role: "presentation", className: "m-0 list-none p-0", children: group.commands.map((cmd, j) => {
244
- const idx = startIdx + j;
245
- const isActive = idx === highlight;
246
- return (
247
- // biome-ignore lint/a11y/useFocusableInteractive: focus stays on combobox; selection via aria-activedescendant
248
- // biome-ignore lint/a11y/useKeyWithClickEvents: keyboard nav handled by combobox input ArrowUp/Down/Enter handler
249
- /* @__PURE__ */ jsxs(
250
- "li",
251
- {
252
- id: optionId(idx),
253
- role: "option",
254
- "aria-selected": isActive,
255
- "data-active": isActive ? "" : void 0,
256
- onMouseEnter: () => setHighlight(idx),
257
- onClick: () => execute(cmd),
258
- className: "flex cursor-pointer items-center gap-3 px-4 py-2 text-sm " + (isActive ? "bg-[var(--accent,#f1f5f9)]" : ""),
259
- children: [
260
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: cmd.label }),
261
- cmd.description ? /* @__PURE__ */ jsx("span", { className: "text-xs opacity-60", children: cmd.description }) : null
262
- ]
263
- },
264
- cmd.id
265
- )
266
- );
267
- }) })
268
- ] }, group.category);
269
- })
270
- ]
271
- }
272
- ),
273
- /* @__PURE__ */ jsxs(
274
- "footer",
275
- {
276
- id: hintId,
277
- className: "flex items-center gap-3 border-t border-[var(--border,#e5e7eb)] px-4 py-2 text-xs opacity-70",
278
- children: [
279
- /* @__PURE__ */ jsx("span", { children: "\u2191\u2193 navigate" }),
280
- /* @__PURE__ */ jsx("span", { children: "\u21B5 select" }),
281
- /* @__PURE__ */ jsx("span", { children: "esc close" })
282
- ]
283
- }
284
- )
285
- ] })
286
- }
287
- )
288
- );
289
- }
290
- var MOBILE_BREAKPOINT = 768;
291
- function useIsMobile() {
292
- const [isMobile, setIsMobile] = React5.useState(void 0);
293
- React5.useEffect(() => {
294
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
295
- const onChange = () => {
296
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
297
- };
298
- mql.addEventListener("change", onChange);
299
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
300
- return () => mql.removeEventListener("change", onChange);
301
- }, []);
302
- return !!isMobile;
303
- }
304
- function cn(...inputs) {
305
- return twMerge(clsx(inputs));
306
- }
307
- var buttonVariants = cva(
308
- "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
309
- {
310
- variants: {
311
- variant: {
312
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
313
- destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
314
- outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
315
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
316
- ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
317
- link: "text-primary underline-offset-4 hover:underline"
318
- },
319
- size: {
320
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
321
- xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
322
- sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
323
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
324
- icon: "size-9",
325
- "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
326
- "icon-sm": "size-8",
327
- "icon-lg": "size-10"
328
- }
329
- },
330
- defaultVariants: {
331
- variant: "default",
332
- size: "default"
333
- }
334
- }
335
- );
336
- function Button({
337
- className,
338
- variant = "default",
339
- size = "default",
340
- asChild = false,
341
- ...props
342
- }) {
343
- const Comp = asChild ? Slot.Root : "button";
344
- return /* @__PURE__ */ jsx(
345
- Comp,
346
- {
347
- "data-slot": "button",
348
- "data-variant": variant,
349
- "data-size": size,
350
- className: cn(buttonVariants({ variant, size, className })),
351
- ...props
352
- }
353
- );
354
- }
355
- function Sheet({ ...props }) {
356
- return /* @__PURE__ */ jsx(Dialog.Root, { "data-slot": "sheet", ...props });
357
- }
358
- function SheetPortal({
359
- ...props
360
- }) {
361
- return /* @__PURE__ */ jsx(Dialog.Portal, { "data-slot": "sheet-portal", ...props });
362
- }
363
- function SheetOverlay({
364
- className,
365
- ...props
366
- }) {
367
- return /* @__PURE__ */ jsx(
368
- Dialog.Overlay,
369
- {
370
- "data-slot": "sheet-overlay",
371
- className: cn(
372
- "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
373
- className
374
- ),
375
- ...props
376
- }
377
- );
378
- }
379
- function SheetContent({
380
- className,
381
- children,
382
- side = "right",
383
- showCloseButton = true,
384
- ...props
385
- }) {
386
- return /* @__PURE__ */ jsxs(SheetPortal, { children: [
387
- /* @__PURE__ */ jsx(SheetOverlay, {}),
388
- /* @__PURE__ */ jsxs(
389
- Dialog.Content,
390
- {
391
- "data-slot": "sheet-content",
392
- className: cn(
393
- "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
394
- side === "right" && "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
395
- side === "left" && "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
396
- side === "top" && "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
397
- side === "bottom" && "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
398
- className
399
- ),
400
- ...props,
401
- children: [
402
- children,
403
- showCloseButton && /* @__PURE__ */ jsxs(Dialog.Close, { className: "absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
404
- /* @__PURE__ */ jsx(XIcon, { className: "size-4" }),
405
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
406
- ] })
407
- ]
408
- }
409
- )
410
- ] });
411
- }
412
- function SheetHeader({ className, ...props }) {
413
- return /* @__PURE__ */ jsx(
414
- "div",
415
- {
416
- "data-slot": "sheet-header",
417
- className: cn("flex flex-col gap-1.5 p-4", className),
418
- ...props
419
- }
420
- );
421
- }
422
- function SheetTitle({
423
- className,
424
- ...props
425
- }) {
426
- return /* @__PURE__ */ jsx(
427
- Dialog.Title,
428
- {
429
- "data-slot": "sheet-title",
430
- className: cn("font-semibold text-foreground", className),
431
- ...props
432
- }
433
- );
434
- }
435
- function SheetDescription({
436
- className,
437
- ...props
438
- }) {
439
- return /* @__PURE__ */ jsx(
440
- Dialog.Description,
441
- {
442
- "data-slot": "sheet-description",
443
- className: cn("text-sm text-muted-foreground", className),
444
- ...props
445
- }
446
- );
447
- }
448
- function TooltipProvider({
449
- delayDuration = 0,
450
- ...props
451
- }) {
452
- return /* @__PURE__ */ jsx(
453
- Tooltip$1.Provider,
454
- {
455
- "data-slot": "tooltip-provider",
456
- delayDuration,
457
- ...props
458
- }
459
- );
460
- }
461
- function Tooltip({
462
- ...props
463
- }) {
464
- return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
465
- }
466
- function TooltipTrigger({
467
- ...props
468
- }) {
469
- return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
470
- }
471
- function TooltipContent({
472
- className,
473
- sideOffset = 0,
474
- children,
475
- ...props
476
- }) {
477
- return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsxs(
478
- Tooltip$1.Content,
479
- {
480
- "data-slot": "tooltip-content",
481
- sideOffset,
482
- className: cn(
483
- "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
484
- className
485
- ),
486
- ...props,
487
- children: [
488
- children,
489
- /* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" })
490
- ]
491
- }
492
- ) });
493
- }
494
- var SIDEBAR_COOKIE_NAME = "sidebar_state";
495
- var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
496
- var SIDEBAR_WIDTH = "16rem";
497
- var SIDEBAR_WIDTH_MOBILE = "18rem";
498
- var SIDEBAR_WIDTH_ICON = "3rem";
499
- var SIDEBAR_KEYBOARD_SHORTCUT = "b";
500
- var SidebarContext = React5.createContext(null);
501
- function useSidebar() {
502
- const context = React5.useContext(SidebarContext);
503
- if (!context) {
504
- throw new Error("useSidebar must be used within a SidebarProvider.");
505
- }
506
- return context;
507
- }
508
- function SidebarProvider({
509
- defaultOpen = true,
510
- open: openProp,
511
- onOpenChange: setOpenProp,
512
- className,
513
- style,
514
- children,
515
- ...props
516
- }) {
517
- const isMobile = useIsMobile();
518
- const [openMobile, setOpenMobile] = React5.useState(false);
519
- const [_open, _setOpen] = React5.useState(defaultOpen);
520
- const open = openProp ?? _open;
521
- const setOpen = React5.useCallback(
522
- (value) => {
523
- const openState = typeof value === "function" ? value(open) : value;
524
- if (setOpenProp) {
525
- setOpenProp(openState);
526
- } else {
527
- _setOpen(openState);
528
- }
529
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
530
- },
531
- [setOpenProp, open]
532
- );
533
- const toggleSidebar = React5.useCallback(() => {
534
- return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
535
- }, [isMobile, setOpen, setOpenMobile]);
536
- React5.useEffect(() => {
537
- const handleKeyDown = (event) => {
538
- if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
539
- event.preventDefault();
540
- toggleSidebar();
541
- }
542
- };
543
- window.addEventListener("keydown", handleKeyDown);
544
- return () => window.removeEventListener("keydown", handleKeyDown);
545
- }, [toggleSidebar]);
546
- const state = open ? "expanded" : "collapsed";
547
- const contextValue = React5.useMemo(
548
- () => ({
549
- state,
550
- open,
551
- setOpen,
552
- isMobile,
553
- openMobile,
554
- setOpenMobile,
555
- toggleSidebar
556
- }),
557
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
558
- );
559
- return /* @__PURE__ */ jsx(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx(
560
- "div",
561
- {
562
- "data-slot": "sidebar-wrapper",
563
- style: {
564
- "--sidebar-width": SIDEBAR_WIDTH,
565
- "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
566
- ...style
567
- },
568
- className: cn(
569
- "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar",
570
- className
571
- ),
572
- ...props,
573
- children
574
- }
575
- ) }) });
576
- }
577
- function Sidebar({
578
- side = "left",
579
- variant = "sidebar",
580
- collapsible = "offcanvas",
581
- className,
582
- children,
583
- ...props
584
- }) {
585
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
586
- if (collapsible === "none") {
587
- return /* @__PURE__ */ jsx(
588
- "div",
11
+ var DEFAULT_SWITCH_URL = (id) => `/admin/tenants/${id}/switch`;
12
+ function TenantSwitcher({
13
+ current,
14
+ available,
15
+ switchUrl
16
+ }) {
17
+ if (!current || available.length <= 1) return null;
18
+ const buildUrl = switchUrl ?? DEFAULT_SWITCH_URL;
19
+ const labelFor = (tenant) => tenant.name?.trim() ? tenant.name : `Tenant ${tenant.id}`;
20
+ const currentLabel = labelFor(current);
21
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
22
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
23
+ Button,
589
24
  {
590
- "data-slot": "sidebar",
591
- className: cn(
592
- "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
593
- className
594
- ),
595
- ...props,
596
- children
597
- }
598
- );
599
- }
600
- if (isMobile) {
601
- return /* @__PURE__ */ jsx(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ jsxs(
602
- SheetContent,
603
- {
604
- "data-sidebar": "sidebar",
605
- "data-slot": "sidebar",
606
- "data-mobile": "true",
607
- className: "w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
608
- style: {
609
- "--sidebar-width": SIDEBAR_WIDTH_MOBILE
25
+ variant: "ghost",
26
+ size: "sm",
27
+ "data-testid": "tenant-switcher-trigger",
28
+ "aria-label": `Switch tenant (current: ${currentLabel})`,
29
+ children: currentLabel
30
+ }
31
+ ) }),
32
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: available.map((tenant) => {
33
+ const isCurrent = tenant.id === current.id;
34
+ return /* @__PURE__ */ jsxs(
35
+ DropdownMenuItem,
36
+ {
37
+ "data-testid": `tenant-switcher-option-${String(tenant.id)}`,
38
+ disabled: isCurrent,
39
+ onSelect: () => {
40
+ router.post(buildUrl(tenant.id), {}, { preserveScroll: true });
41
+ },
42
+ children: [
43
+ labelFor(tenant),
44
+ isCurrent ? " \u2713" : ""
45
+ ]
610
46
  },
611
- side,
612
- children: [
613
- /* @__PURE__ */ jsxs(SheetHeader, { className: "sr-only", children: [
614
- /* @__PURE__ */ jsx(SheetTitle, { children: "Sidebar" }),
615
- /* @__PURE__ */ jsx(SheetDescription, { children: "Displays the mobile sidebar." })
616
- ] }),
617
- /* @__PURE__ */ jsx("div", { className: "flex h-full w-full flex-col", children })
618
- ]
619
- }
620
- ) });
621
- }
622
- return /* @__PURE__ */ jsxs(
623
- "div",
624
- {
625
- className: "group peer hidden text-sidebar-foreground md:block",
626
- "data-state": state,
627
- "data-collapsible": state === "collapsed" ? collapsible : "",
628
- "data-variant": variant,
629
- "data-side": side,
630
- "data-slot": "sidebar",
631
- children: [
632
- /* @__PURE__ */ jsx(
633
- "div",
634
- {
635
- "data-slot": "sidebar-gap",
636
- className: cn(
637
- "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
638
- "group-data-[collapsible=offcanvas]:w-0",
639
- "group-data-[side=right]:rotate-180",
640
- variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
641
- )
642
- }
643
- ),
644
- /* @__PURE__ */ jsx(
645
- "div",
646
- {
647
- "data-slot": "sidebar-container",
648
- className: cn(
649
- "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
650
- side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
651
- // Adjust the padding for floating and inset variants.
652
- variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
653
- className
654
- ),
655
- ...props,
656
- children: /* @__PURE__ */ jsx(
657
- "div",
658
- {
659
- "data-sidebar": "sidebar",
660
- "data-slot": "sidebar-inner",
661
- className: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm",
662
- children
663
- }
664
- )
665
- }
666
- )
667
- ]
668
- }
669
- );
670
- }
671
- function SidebarTrigger({
672
- className,
673
- onClick,
674
- ...props
675
- }) {
676
- const { toggleSidebar } = useSidebar();
677
- return /* @__PURE__ */ jsxs(
678
- Button,
679
- {
680
- "data-sidebar": "trigger",
681
- "data-slot": "sidebar-trigger",
682
- variant: "ghost",
683
- size: "icon",
684
- className: cn("size-7", className),
685
- onClick: (event) => {
686
- onClick?.(event);
687
- toggleSidebar();
688
- },
689
- ...props,
690
- children: [
691
- /* @__PURE__ */ jsx(PanelLeftIcon, {}),
692
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Toggle Sidebar" })
693
- ]
694
- }
695
- );
696
- }
697
- function SidebarInset({ className, ...props }) {
698
- return /* @__PURE__ */ jsx(
699
- "main",
700
- {
701
- "data-slot": "sidebar-inset",
702
- className: cn(
703
- "relative flex w-full flex-1 flex-col bg-background",
704
- "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
705
- className
706
- ),
707
- ...props
708
- }
709
- );
710
- }
711
- function SidebarHeader({ className, ...props }) {
712
- return /* @__PURE__ */ jsx(
713
- "div",
714
- {
715
- "data-slot": "sidebar-header",
716
- "data-sidebar": "header",
717
- className: cn("flex flex-col gap-2 p-2", className),
718
- ...props
719
- }
720
- );
721
- }
722
- function SidebarFooter({ className, ...props }) {
723
- return /* @__PURE__ */ jsx(
724
- "div",
725
- {
726
- "data-slot": "sidebar-footer",
727
- "data-sidebar": "footer",
728
- className: cn("flex flex-col gap-2 p-2", className),
729
- ...props
730
- }
731
- );
732
- }
733
- function SidebarContent({ className, ...props }) {
734
- return /* @__PURE__ */ jsx(
735
- "div",
736
- {
737
- "data-slot": "sidebar-content",
738
- "data-sidebar": "content",
739
- className: cn(
740
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
741
- className
742
- ),
743
- ...props
744
- }
745
- );
746
- }
747
- function SidebarGroup({ className, ...props }) {
748
- return /* @__PURE__ */ jsx(
749
- "div",
750
- {
751
- "data-slot": "sidebar-group",
752
- "data-sidebar": "group",
753
- className: cn("relative flex w-full min-w-0 flex-col p-2", className),
754
- ...props
755
- }
756
- );
757
- }
758
- function SidebarGroupLabel({
759
- className,
760
- asChild = false,
761
- ...props
762
- }) {
763
- const Comp = asChild ? Slot.Root : "div";
764
- return /* @__PURE__ */ jsx(
765
- Comp,
766
- {
767
- "data-slot": "sidebar-group-label",
768
- "data-sidebar": "group-label",
769
- className: cn(
770
- "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
771
- "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
772
- className
773
- ),
774
- ...props
775
- }
776
- );
777
- }
778
- function SidebarGroupContent({
779
- className,
780
- ...props
781
- }) {
782
- return /* @__PURE__ */ jsx(
783
- "div",
784
- {
785
- "data-slot": "sidebar-group-content",
786
- "data-sidebar": "group-content",
787
- className: cn("w-full text-sm", className),
788
- ...props
789
- }
790
- );
791
- }
792
- function SidebarMenu({ className, ...props }) {
793
- return /* @__PURE__ */ jsx(
794
- "ul",
795
- {
796
- "data-slot": "sidebar-menu",
797
- "data-sidebar": "menu",
798
- className: cn("flex w-full min-w-0 flex-col gap-1", className),
799
- ...props
800
- }
801
- );
802
- }
803
- function SidebarMenuItem({ className, ...props }) {
804
- return /* @__PURE__ */ jsx(
805
- "li",
806
- {
807
- "data-slot": "sidebar-menu-item",
808
- "data-sidebar": "menu-item",
809
- className: cn("group/menu-item relative", className),
810
- ...props
811
- }
812
- );
813
- }
814
- var sidebarMenuButtonVariants = cva(
815
- "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
816
- {
817
- variants: {
818
- variant: {
819
- default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
820
- outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
821
- },
822
- size: {
823
- default: "h-8 text-sm",
824
- sm: "h-7 text-xs",
825
- lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
826
- }
827
- },
828
- defaultVariants: {
829
- variant: "default",
830
- size: "default"
831
- }
832
- }
833
- );
834
- function SidebarMenuButton({
835
- asChild = false,
836
- isActive = false,
837
- variant = "default",
838
- size = "default",
839
- tooltip,
840
- className,
841
- ...props
842
- }) {
843
- const Comp = asChild ? Slot.Root : "button";
844
- const { isMobile, state } = useSidebar();
845
- const button = /* @__PURE__ */ jsx(
846
- Comp,
847
- {
848
- "data-slot": "sidebar-menu-button",
849
- "data-sidebar": "menu-button",
850
- "data-size": size,
851
- "data-active": isActive,
852
- className: cn(sidebarMenuButtonVariants({ variant, size }), className),
853
- ...props
854
- }
855
- );
856
- if (!tooltip) {
857
- return button;
858
- }
859
- if (typeof tooltip === "string") {
860
- tooltip = {
861
- children: tooltip
862
- };
863
- }
864
- return /* @__PURE__ */ jsxs(Tooltip, { children: [
865
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: button }),
866
- /* @__PURE__ */ jsx(
867
- TooltipContent,
868
- {
869
- side: "right",
870
- align: "center",
871
- hidden: state !== "collapsed" || isMobile,
872
- ...tooltip
873
- }
874
- )
875
- ] });
876
- }
877
- function AppShell({
878
- variant = "sidebar-left",
879
- sidebar,
880
- topbar,
881
- footer,
882
- children,
883
- className
884
- }) {
885
- if (variant === "full-width") {
886
- return /* @__PURE__ */ jsxs(
887
- "div",
888
- {
889
- "data-arqel-shell": "full-width",
890
- className: cn("min-h-screen bg-background text-foreground", className),
891
- children: [
892
- /* @__PURE__ */ jsx(CommandPalette, {}),
893
- children
894
- ]
895
- }
896
- );
897
- }
898
- if (variant === "topbar-only") {
899
- return /* @__PURE__ */ jsxs(
900
- "div",
901
- {
902
- "data-arqel-shell": "topbar-only",
903
- className: cn("flex min-h-screen flex-col bg-background text-foreground", className),
904
- children: [
905
- /* @__PURE__ */ jsx(CommandPalette, {}),
906
- topbar,
907
- /* @__PURE__ */ jsx("main", { className: "flex-1", children }),
908
- footer
909
- ]
910
- }
911
- );
912
- }
913
- const sidebarSide = variant === "sidebar-right" ? "right" : "left";
914
- return /* @__PURE__ */ jsx(SidebarProvider, { children: /* @__PURE__ */ jsxs(
915
- "div",
916
- {
917
- "data-arqel-shell": variant,
918
- "data-sidebar-side": sidebarSide,
919
- className: cn(
920
- "flex min-h-svh w-full bg-background text-foreground",
921
- sidebarSide === "right" && "flex-row-reverse",
922
- className
923
- ),
924
- children: [
925
- /* @__PURE__ */ jsx(CommandPalette, {}),
926
- sidebar,
927
- /* @__PURE__ */ jsxs(SidebarInset, { children: [
928
- topbar,
929
- /* @__PURE__ */ jsx("main", { className: "flex-1", children }),
930
- footer
931
- ] })
932
- ]
933
- }
934
- ) });
935
- }
936
- function Footer({ children, className }) {
937
- return /* @__PURE__ */ jsx(
938
- "footer",
939
- {
940
- "data-arqel-footer": "",
941
- className: cn(
942
- "shrink-0 border-t border-border bg-background px-4 py-3 text-sm text-muted-foreground",
943
- className
944
- ),
945
- children
946
- }
947
- );
948
- }
949
- var MAX_WIDTH_CLASSES = {
950
- none: "",
951
- md: "max-w-md",
952
- lg: "max-w-lg",
953
- xl: "max-w-xl",
954
- "2xl": "max-w-2xl",
955
- "4xl": "max-w-4xl",
956
- "6xl": "max-w-6xl",
957
- "7xl": "max-w-7xl"
958
- };
959
- function MainContent({
960
- breadcrumbs,
961
- header,
962
- children,
963
- maxWidth = "7xl",
964
- className
965
- }) {
966
- return /* @__PURE__ */ jsxs(
967
- "div",
968
- {
969
- "data-arqel-main": "",
970
- className: cn(
971
- "mx-auto w-full px-4 py-6 sm:px-6 lg:px-8",
972
- MAX_WIDTH_CLASSES[maxWidth],
973
- className
974
- ),
975
- children: [
976
- breadcrumbs && /* @__PURE__ */ jsx("div", { className: "mb-3", children: breadcrumbs }),
977
- header && /* @__PURE__ */ jsx("div", { className: "mb-6", children: header }),
978
- children
979
- ]
980
- }
981
- );
982
- }
983
- function Sidebar2({ items: itemsProp, brand, footer, className }) {
984
- const { items: sharedItems } = useNavigation();
985
- const items = itemsProp ?? sharedItems;
986
- const grouped = useMemo(() => groupItems(items), [items]);
987
- return /* @__PURE__ */ jsxs(Sidebar, { collapsible: "icon", className, children: [
988
- brand ? /* @__PURE__ */ jsx(SidebarHeader, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 px-2 py-1.5 text-sm font-semibold", children: brand }) }) : null,
989
- /* @__PURE__ */ jsx(SidebarContent, { children: grouped.map(([group, list]) => /* @__PURE__ */ jsxs(SidebarGroup, { children: [
990
- group ? /* @__PURE__ */ jsx(SidebarGroupLabel, { children: group }) : null,
991
- /* @__PURE__ */ jsx(SidebarGroupContent, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: list.map((item) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(SidebarMenuButton, { asChild: Boolean(item.url), isActive: Boolean(item.active), children: item.url ? /* @__PURE__ */ jsx("a", { href: item.url, children: /* @__PURE__ */ jsx("span", { children: item.label }) }) : /* @__PURE__ */ jsx("span", { children: item.label }) }) }, item.url ?? item.label)) }) })
992
- ] }, group ?? "__ungrouped__")) }),
993
- footer ? /* @__PURE__ */ jsx(SidebarFooter, { children: footer }) : null
47
+ String(tenant.id)
48
+ );
49
+ }) })
994
50
  ] });
995
51
  }
996
- function groupItems(items) {
997
- const groups = /* @__PURE__ */ new Map();
998
- for (const item of items) {
999
- const key = item.group ?? void 0;
1000
- const list = groups.get(key) ?? [];
1001
- list.push(item);
1002
- groups.set(key, list);
1003
- }
1004
- return Array.from(groups.entries());
1005
- }
1006
- function Topbar({
1007
- brand,
1008
- search,
1009
- userMenu,
1010
- tenantSwitcher,
1011
- onMobileMenuClick,
1012
- className
1013
- }) {
1014
- const { resolved, toggle } = useTheme();
1015
- return /* @__PURE__ */ jsxs(
1016
- "header",
1017
- {
1018
- "data-arqel-topbar": "",
1019
- className: cn(
1020
- "flex h-14 shrink-0 items-center gap-2 border-b border-border bg-background px-4",
1021
- className
1022
- ),
1023
- children: [
1024
- /* @__PURE__ */ jsx(SidebarTrigger, { className: "-ml-1" }),
1025
- brand && /* @__PURE__ */ jsx("div", { className: "flex items-center", children: brand }),
1026
- /* @__PURE__ */ jsx("div", { className: "hidden flex-1 md:block", children: search }),
1027
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 md:ml-0", children: [
1028
- tenantSwitcher,
1029
- /* @__PURE__ */ jsx(
1030
- Button,
1031
- {
1032
- variant: "ghost",
1033
- size: "icon",
1034
- "aria-label": `Switch to ${resolved === "dark" ? "light" : "dark"} theme`,
1035
- onClick: toggle,
1036
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: resolved === "dark" ? "\u2600" : "\u263E" })
1037
- }
1038
- ),
1039
- userMenu
1040
- ] })
1041
- ]
1042
- }
1043
- );
1044
- }
1045
52
 
1046
- export { AppShell, Footer, MainContent, Sidebar2 as Sidebar, Topbar };
53
+ export { TenantSwitcher };
1047
54
  //# sourceMappingURL=shell.js.map
1048
55
  //# sourceMappingURL=shell.js.map