@tangle-network/sandbox-ui 0.52.0 → 0.54.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.
@@ -7,7 +7,8 @@ import {
7
7
  } from "./chunk-EI44GEQ5.js";
8
8
 
9
9
  // src/dashboard/app-sidebar.tsx
10
- import * as React2 from "react";
10
+ import * as React3 from "react";
11
+ import { createPortal as createPortal2 } from "react-dom";
11
12
  import { Avatar, AvatarFallback, AvatarImage } from "@tangle-network/ui/primitives";
12
13
  import {
13
14
  DropdownMenu,
@@ -15,9 +16,13 @@ import {
15
16
  DropdownMenuItem,
16
17
  DropdownMenuLabel,
17
18
  DropdownMenuSeparator,
19
+ DropdownMenuSub,
20
+ DropdownMenuSubContent,
21
+ DropdownMenuSubTrigger,
18
22
  DropdownMenuTrigger
19
23
  } from "@tangle-network/ui/primitives";
20
24
  import { Skeleton, useTheme } from "@tangle-network/ui/primitives";
25
+ import { Check, Monitor, PanelLeft } from "lucide-react";
21
26
 
22
27
  // src/dashboard/sidebar-context.tsx
23
28
  import * as React from "react";
@@ -135,27 +140,61 @@ function useSidebar() {
135
140
  }
136
141
 
137
142
  // src/dashboard/rail-tooltip.tsx
143
+ import * as React2 from "react";
144
+ import { createPortal } from "react-dom";
138
145
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
146
+ var RAIL_FLOATING_SURFACE = "rounded-md border border-[var(--md3-outline-variant)] bg-surface-container-highest shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]";
139
147
  function RailTooltip({ label, children, disabled, className }) {
148
+ const ref = React2.useRef(null);
149
+ const timer = React2.useRef(null);
150
+ const [coords, setCoords] = React2.useState(null);
151
+ React2.useEffect(() => () => {
152
+ if (timer.current) clearTimeout(timer.current);
153
+ }, []);
140
154
  if (disabled) return /* @__PURE__ */ jsx2(Fragment, { children });
141
- return /* @__PURE__ */ jsxs("span", { className: cn("group/tip relative flex", className), children: [
142
- children,
143
- /* @__PURE__ */ jsx2(
144
- "span",
145
- {
146
- role: "tooltip",
147
- "aria-hidden": "true",
148
- className: cn(
149
- "pointer-events-none absolute left-full top-1/2 z-50 ml-2 -translate-y-1/2 translate-x-1 whitespace-nowrap",
150
- "rounded-md border border-[var(--md3-outline-variant)] bg-surface-container-highest px-2 py-1 text-xs font-medium text-popover-foreground",
151
- "opacity-0 shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14] transition-[opacity,transform] duration-150 ease-out",
152
- "group-hover/tip:translate-x-0 group-hover/tip:opacity-100 group-hover/tip:delay-300",
153
- "group-focus-within/tip:translate-x-0 group-focus-within/tip:opacity-100"
154
- ),
155
- children: label
156
- }
157
- )
158
- ] });
155
+ const open = () => {
156
+ if (timer.current) clearTimeout(timer.current);
157
+ timer.current = setTimeout(() => {
158
+ const el = ref.current;
159
+ if (!el) return;
160
+ const r = el.getBoundingClientRect();
161
+ setCoords({ top: r.top + r.height / 2, left: r.right + 8 });
162
+ }, 250);
163
+ };
164
+ const close = () => {
165
+ if (timer.current) clearTimeout(timer.current);
166
+ setCoords(null);
167
+ };
168
+ return /* @__PURE__ */ jsxs(
169
+ "span",
170
+ {
171
+ ref,
172
+ className: cn("relative flex", className),
173
+ onMouseEnter: open,
174
+ onMouseLeave: close,
175
+ onFocusCapture: open,
176
+ onBlurCapture: close,
177
+ children: [
178
+ children,
179
+ coords !== null && typeof document !== "undefined" && createPortal(
180
+ /* @__PURE__ */ jsx2(
181
+ "span",
182
+ {
183
+ role: "tooltip",
184
+ "aria-hidden": "true",
185
+ style: { position: "fixed", top: coords.top, left: coords.left, transform: "translateY(-50%)" },
186
+ className: cn(
187
+ "pointer-events-none z-[70] whitespace-nowrap px-2 py-1 text-xs font-medium text-popover-foreground",
188
+ RAIL_FLOATING_SURFACE
189
+ ),
190
+ children: label
191
+ }
192
+ ),
193
+ document.body
194
+ )
195
+ ]
196
+ }
197
+ );
159
198
  }
160
199
 
161
200
  // src/dashboard/app-sidebar.tsx
@@ -204,8 +243,8 @@ function MoonIcon({ className }) {
204
243
  }
205
244
  function RailThemeToggle({ className }) {
206
245
  const { theme, setTheme } = useTheme();
207
- const [mounted, setMounted] = React2.useState(false);
208
- React2.useEffect(() => setMounted(true), []);
246
+ const [mounted, setMounted] = React3.useState(false);
247
+ React3.useEffect(() => setMounted(true), []);
209
248
  const isDark = mounted && (theme === "dark" || theme === "system" && typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches);
210
249
  return /* @__PURE__ */ jsx3(
211
250
  "button",
@@ -260,6 +299,67 @@ function RailCollapseToggle({ collapsed, showLabel, onToggle, className }) {
260
299
  }
261
300
  ) });
262
301
  }
302
+ function PanelToggleButton({ collapsed, onToggle, className }) {
303
+ const label = collapsed ? "Expand sidebar" : "Collapse sidebar";
304
+ return /* @__PURE__ */ jsx3(
305
+ "button",
306
+ {
307
+ type: "button",
308
+ onClick: onToggle,
309
+ "aria-label": label,
310
+ "aria-pressed": collapsed,
311
+ title: label,
312
+ className: cn(
313
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
314
+ "hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
315
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
316
+ className
317
+ ),
318
+ children: /* @__PURE__ */ jsx3(PanelLeft, { className: "h-[18px] w-[18px] shrink-0" })
319
+ }
320
+ );
321
+ }
322
+ function RailHeader({ brand, brandHref, children, collapsed, onToggle, collapsible = true, LinkComponent, className }) {
323
+ const Link = LinkComponent ?? DefaultLink;
324
+ const brandNode = brandHref !== void 0 ? /* @__PURE__ */ jsx3(
325
+ Link,
326
+ {
327
+ href: brandHref,
328
+ to: brandHref,
329
+ "aria-label": "Home",
330
+ className: "flex items-center justify-center rounded-md p-1 transition-colors hover:bg-[var(--accent-surface-soft)]",
331
+ children: brand
332
+ }
333
+ ) : /* @__PURE__ */ jsx3("span", { className: "flex items-center justify-center p-1", children: brand });
334
+ return /* @__PURE__ */ jsx3(
335
+ "div",
336
+ {
337
+ className: cn(
338
+ "flex h-14 shrink-0 items-center border-b border-[var(--md3-outline-variant)]",
339
+ collapsed ? "justify-center px-2" : "gap-2 px-3",
340
+ className
341
+ ),
342
+ children: collapsed ? collapsible ? /* @__PURE__ */ jsx3(RailTooltip, { label: "Expand sidebar", children: /* @__PURE__ */ jsxs2(
343
+ "button",
344
+ {
345
+ type: "button",
346
+ onClick: onToggle,
347
+ "aria-label": "Expand sidebar",
348
+ "aria-pressed": true,
349
+ className: "group/brand relative flex h-9 w-9 items-center justify-center rounded-md transition-colors hover:bg-[var(--accent-surface-soft)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
350
+ children: [
351
+ /* @__PURE__ */ jsx3("span", { className: "flex items-center justify-center transition-opacity duration-150 group-hover/brand:opacity-0", children: brand }),
352
+ /* @__PURE__ */ jsx3("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-center text-foreground opacity-0 transition-opacity duration-150 group-hover/brand:opacity-100", children: /* @__PURE__ */ jsx3(PanelLeft, { className: "h-[18px] w-[18px]" }) })
353
+ ]
354
+ }
355
+ ) }) : brandNode : /* @__PURE__ */ jsxs2(Fragment2, { children: [
356
+ brand !== void 0 && brandNode,
357
+ /* @__PURE__ */ jsx3("div", { className: "min-w-0 flex-1", children }),
358
+ collapsible && /* @__PURE__ */ jsx3(PanelToggleButton, { collapsed, onToggle })
359
+ ] })
360
+ }
361
+ );
362
+ }
263
363
  function Sidebar({ children, className, style }) {
264
364
  const { panelOpen, hidden, hasPanels, railWidth } = useSidebar();
265
365
  return /* @__PURE__ */ jsx3(
@@ -294,8 +394,8 @@ function SidebarRail({ children, className, wide = false }) {
294
394
  function SidebarRailHeader({ children, className }) {
295
395
  return /* @__PURE__ */ jsx3("div", { className: cn("flex h-14 shrink-0 items-center justify-center border-b border-[var(--md3-outline-variant)]", className), children });
296
396
  }
297
- function SidebarRailNav({ children, className }) {
298
- return /* @__PURE__ */ jsx3("nav", { className: cn("flex flex-col items-center gap-1 py-3 flex-1 min-h-0 overflow-y-auto", className), children });
397
+ function SidebarRailNav({ children, className, onClick }) {
398
+ return /* @__PURE__ */ jsx3("nav", { onClick, className: cn("flex flex-col items-center gap-1 py-3 flex-1 min-h-0 overflow-y-auto", className), children });
299
399
  }
300
400
  function SidebarRailFooter({ children, className }) {
301
401
  return /* @__PURE__ */ jsx3("div", { className: cn("flex flex-col items-center gap-1 pb-3 shrink-0", className), children });
@@ -303,13 +403,16 @@ function SidebarRailFooter({ children, className }) {
303
403
  function RailSeparator({ className }) {
304
404
  return /* @__PURE__ */ jsx3("div", { className: cn("my-2 h-px w-10 bg-[var(--md3-outline-variant)]", className) });
305
405
  }
306
- function RailButton({ icon: Icon, label, isActive, badge, onClick, className, showLabel, asChild, children }) {
406
+ function RailButton({ icon: Icon, label, isActive, badge, onClick, className, showLabel, asChild, children, variant = "normal" }) {
307
407
  const classes = cn(
308
408
  "relative flex shrink-0 items-center justify-center rounded-md transition-colors duration-150",
309
409
  showLabel ? "w-full justify-start px-2.5 h-9 gap-2.5" : "w-9 h-9 justify-center",
310
410
  // Quiet press feedback via color only — no scale on the full-width row.
311
411
  "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
312
- isActive ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
412
+ // The active item (route matches) and any explicit primary share one
413
+ // emphasized look — a filled accent pill with an accent ring — so the
414
+ // current destination clearly stands out from the default rows.
415
+ variant === "primary" || isActive ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)] font-medium ring-1 ring-inset ring-[var(--border-accent)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
313
416
  className
314
417
  );
315
418
  const iconWithBadge = /* @__PURE__ */ jsxs2("span", { className: "relative flex shrink-0 items-center justify-center", children: [
@@ -320,9 +423,9 @@ function RailButton({ icon: Icon, label, isActive, badge, onClick, className, sh
320
423
  iconWithBadge,
321
424
  showLabel && /* @__PURE__ */ jsx3("span", { className: "text-[13.5px] font-medium", children: label })
322
425
  ] });
323
- if (asChild && React2.isValidElement(children)) {
426
+ if (asChild && React3.isValidElement(children)) {
324
427
  const child = children;
325
- const merged = React2.cloneElement(
428
+ const merged = React3.cloneElement(
326
429
  child,
327
430
  { className: cn(classes, child.props.className), "aria-label": child.props["aria-label"] ?? label },
328
431
  content
@@ -340,9 +443,9 @@ function RailFlyout({
340
443
  children,
341
444
  className
342
445
  }) {
343
- const [open, setOpen] = React2.useState(false);
344
- const ref = React2.useRef(null);
345
- React2.useEffect(() => {
446
+ const [open, setOpen] = React3.useState(false);
447
+ const ref = React3.useRef(null);
448
+ React3.useEffect(() => {
346
449
  if (!open) return;
347
450
  const onPointer = (e) => {
348
451
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -402,8 +505,8 @@ function RailFlyout({
402
505
  if (el.closest("a,button")) setOpen(false);
403
506
  },
404
507
  className: cn(
405
- "absolute top-0 z-50 min-w-[12rem] rounded-md border border-[var(--md3-outline-variant)] bg-surface-container-highest p-1.5 shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
406
- showLabel ? "left-full ml-2" : "left-full ml-2"
508
+ "absolute left-full top-0 z-50 ml-2 min-w-[12rem] p-1.5",
509
+ RAIL_FLOATING_SURFACE
407
510
  ),
408
511
  children: [
409
512
  /* @__PURE__ */ jsx3("p", { className: "px-2 pb-1 pt-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70 select-none", children: title ?? label }),
@@ -419,6 +522,233 @@ function ChevronRightIcon({ className }) {
419
522
  /* @__PURE__ */ jsx3("path", { d: "m9 18 6-6-6-6" })
420
523
  ] });
421
524
  }
525
+ function useExpandableItems(subItems, loadSubItems) {
526
+ const [items, setItems] = React3.useState(subItems ?? null);
527
+ const [loading, setLoading] = React3.useState(false);
528
+ const loadedRef = React3.useRef(subItems !== void 0);
529
+ React3.useEffect(() => {
530
+ if (subItems !== void 0) {
531
+ setItems(subItems);
532
+ loadedRef.current = true;
533
+ }
534
+ }, [subItems]);
535
+ const ensureLoaded = React3.useCallback(() => {
536
+ if (loadedRef.current || !loadSubItems) return;
537
+ loadedRef.current = true;
538
+ setLoading(true);
539
+ Promise.resolve(loadSubItems()).then(
540
+ (resolved) => {
541
+ setItems(resolved);
542
+ setLoading(false);
543
+ },
544
+ () => {
545
+ setItems([]);
546
+ setLoading(false);
547
+ loadedRef.current = false;
548
+ }
549
+ );
550
+ }, [loadSubItems]);
551
+ return { items, loading, ensureLoaded };
552
+ }
553
+ function SubItemsSkeleton() {
554
+ const widths = ["w-[88%]", "w-[76%]", "w-[82%]", "w-[64%]"];
555
+ return /* @__PURE__ */ jsx3("div", { className: "flex flex-col gap-1.5 px-2 py-1.5", children: widths.map((w, i) => /* @__PURE__ */ jsx3(Skeleton, { className: cn("h-4", w) }, i)) });
556
+ }
557
+ function RailExpandable({
558
+ icon: Icon,
559
+ label,
560
+ href,
561
+ isActive,
562
+ showLabel,
563
+ subItems,
564
+ loadSubItems,
565
+ activeSubIds,
566
+ emptyLabel = "Nothing here yet",
567
+ onNavigate,
568
+ LinkComponent,
569
+ className
570
+ }) {
571
+ const Link = LinkComponent ?? DefaultLink;
572
+ const [open, setOpen] = React3.useState(false);
573
+ const { items, loading, ensureLoaded } = useExpandableItems(subItems, loadSubItems);
574
+ const activeSet = React3.useMemo(() => new Set(activeSubIds ?? []), [activeSubIds]);
575
+ const triggerRef = React3.useRef(null);
576
+ const closeTimer = React3.useRef(null);
577
+ const [coords, setCoords] = React3.useState(null);
578
+ React3.useEffect(() => () => {
579
+ if (closeTimer.current) clearTimeout(closeTimer.current);
580
+ }, []);
581
+ const subLink = (item) => {
582
+ const FIcon = item.icon;
583
+ const active = activeSet.has(item.id);
584
+ return /* @__PURE__ */ jsxs2(
585
+ Link,
586
+ {
587
+ href: item.href,
588
+ to: item.href,
589
+ onClick: onNavigate,
590
+ ...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {},
591
+ className: cn(
592
+ "flex h-8 items-center gap-2 rounded-md px-2.5 text-[12px] transition-colors",
593
+ active ? "bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
594
+ ),
595
+ children: [
596
+ FIcon ? /* @__PURE__ */ jsx3(FIcon, { className: "h-4 w-4 shrink-0" }) : null,
597
+ /* @__PURE__ */ jsx3("span", { className: "truncate", children: item.label })
598
+ ]
599
+ },
600
+ item.id
601
+ );
602
+ };
603
+ const list = loading ? /* @__PURE__ */ jsx3(SubItemsSkeleton, {}) : items && items.length > 0 ? items.map(subLink) : /* @__PURE__ */ jsx3("p", { className: "px-2.5 py-1.5 text-xs text-muted-foreground", children: emptyLabel });
604
+ if (!showLabel) {
605
+ const triggerClasses = cn(
606
+ "relative flex h-9 w-9 items-center justify-center rounded-md transition-colors duration-150",
607
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
608
+ isActive || open ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)] font-medium ring-1 ring-inset ring-[var(--border-accent)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
609
+ );
610
+ const openFlyout = () => {
611
+ if (closeTimer.current) {
612
+ clearTimeout(closeTimer.current);
613
+ closeTimer.current = null;
614
+ }
615
+ ensureLoaded();
616
+ const el = triggerRef.current;
617
+ if (el) {
618
+ const r = el.getBoundingClientRect();
619
+ const m = 8;
620
+ const left = r.right + m;
621
+ const spaceBelow = window.innerHeight - r.top - m;
622
+ const spaceAbove = r.bottom - m;
623
+ setCoords(
624
+ spaceBelow >= spaceAbove ? { left, top: r.top, maxHeight: spaceBelow } : { left, bottom: window.innerHeight - r.bottom, maxHeight: spaceAbove }
625
+ );
626
+ }
627
+ setOpen(true);
628
+ };
629
+ const scheduleClose = () => {
630
+ if (closeTimer.current) clearTimeout(closeTimer.current);
631
+ closeTimer.current = setTimeout(() => setOpen(false), 140);
632
+ };
633
+ const cancelClose = () => {
634
+ if (closeTimer.current) {
635
+ clearTimeout(closeTimer.current);
636
+ closeTimer.current = null;
637
+ }
638
+ };
639
+ return /* @__PURE__ */ jsxs2(
640
+ "div",
641
+ {
642
+ ref: triggerRef,
643
+ className: cn("relative", className),
644
+ onMouseEnter: openFlyout,
645
+ onMouseLeave: scheduleClose,
646
+ onFocusCapture: openFlyout,
647
+ onBlurCapture: (e) => {
648
+ if (!e.currentTarget.contains(e.relatedTarget)) scheduleClose();
649
+ },
650
+ children: [
651
+ href ? /* @__PURE__ */ jsx3(Link, { href, to: href, onClick: onNavigate, "aria-label": label, className: triggerClasses, children: /* @__PURE__ */ jsx3(Icon, { className: "h-[17px] w-[17px] shrink-0" }) }) : /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": label, "aria-haspopup": "menu", "aria-expanded": open, className: triggerClasses, children: /* @__PURE__ */ jsx3(Icon, { className: "h-[17px] w-[17px] shrink-0" }) }),
652
+ open && coords !== null && typeof document !== "undefined" && createPortal2(
653
+ /* @__PURE__ */ jsxs2(
654
+ "div",
655
+ {
656
+ role: "menu",
657
+ style: {
658
+ position: "fixed",
659
+ left: coords.left,
660
+ top: coords.top,
661
+ bottom: coords.bottom,
662
+ maxHeight: coords.maxHeight
663
+ },
664
+ onMouseEnter: cancelClose,
665
+ onMouseLeave: scheduleClose,
666
+ onClickCapture: (e) => {
667
+ if (e.target.closest("a")) setOpen(false);
668
+ },
669
+ className: cn("z-[70] flex w-60 flex-col overflow-hidden p-1.5", RAIL_FLOATING_SURFACE),
670
+ children: [
671
+ /* @__PURE__ */ jsx3("p", { className: "shrink-0 px-2 pb-1 pt-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70 select-none", children: label }),
672
+ /* @__PURE__ */ jsx3("div", { className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto", children: list })
673
+ ]
674
+ }
675
+ ),
676
+ document.body
677
+ )
678
+ ]
679
+ }
680
+ );
681
+ }
682
+ const toggle = () => {
683
+ setOpen((v) => {
684
+ const next = !v;
685
+ if (next) ensureLoaded();
686
+ return next;
687
+ });
688
+ };
689
+ return /* @__PURE__ */ jsxs2("div", { className: cn("w-full", className), children: [
690
+ /* @__PURE__ */ jsxs2(
691
+ "div",
692
+ {
693
+ className: cn(
694
+ "group/exp relative flex h-9 w-full items-center rounded-md transition-colors duration-150",
695
+ isActive ? "bg-[var(--accent-surface-strong)] text-[var(--accent-text)] font-medium ring-1 ring-inset ring-[var(--border-accent)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
696
+ ),
697
+ children: [
698
+ /* @__PURE__ */ jsxs2(
699
+ "button",
700
+ {
701
+ type: "button",
702
+ onClick: toggle,
703
+ "aria-expanded": open,
704
+ "aria-label": open ? `Collapse ${label}` : `Expand ${label}`,
705
+ className: "relative flex h-9 w-9 shrink-0 items-center justify-center rounded-md focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
706
+ children: [
707
+ /* @__PURE__ */ jsx3(
708
+ Icon,
709
+ {
710
+ className: cn(
711
+ "h-[17px] w-[17px] shrink-0 transition-opacity duration-150",
712
+ open ? "opacity-0" : "opacity-100 group-hover/exp:opacity-0"
713
+ )
714
+ }
715
+ ),
716
+ /* @__PURE__ */ jsx3(
717
+ ChevronRightIcon,
718
+ {
719
+ className: cn(
720
+ "absolute h-4 w-4 transition-all duration-150",
721
+ open ? "rotate-90 opacity-100" : "opacity-0 group-hover/exp:opacity-100"
722
+ )
723
+ }
724
+ )
725
+ ]
726
+ }
727
+ ),
728
+ href ? /* @__PURE__ */ jsx3(
729
+ Link,
730
+ {
731
+ href,
732
+ to: href,
733
+ onClick: onNavigate,
734
+ className: "flex h-9 min-w-0 flex-1 items-center pr-2.5 text-[13.5px] font-medium",
735
+ children: /* @__PURE__ */ jsx3("span", { className: "truncate", children: label })
736
+ }
737
+ ) : /* @__PURE__ */ jsx3(
738
+ "button",
739
+ {
740
+ type: "button",
741
+ onClick: toggle,
742
+ className: "flex h-9 min-w-0 flex-1 items-center pr-2.5 text-left text-[13.5px] font-medium",
743
+ children: /* @__PURE__ */ jsx3("span", { className: "truncate", children: label })
744
+ }
745
+ )
746
+ ]
747
+ }
748
+ ),
749
+ open && /* @__PURE__ */ jsx3("div", { className: "mt-0.5 flex flex-col gap-0.5 pl-3", children: list })
750
+ ] });
751
+ }
422
752
  function RailModeButton({ mode, icon, label, badge, className, showLabel }) {
423
753
  const { panelOpen, mode: currentMode, switchMode } = useSidebar();
424
754
  return /* @__PURE__ */ jsx3(
@@ -468,6 +798,58 @@ function SidebarContent({ children, className }) {
468
798
  }
469
799
  );
470
800
  }
801
+ var APPEARANCE_META = {
802
+ light: { label: "Light", Icon: SunIcon },
803
+ dark: { label: "Dark", Icon: MoonIcon },
804
+ system: { label: "System", Icon: Monitor }
805
+ };
806
+ function AppearanceMenuSection({ appearance, divider = true }) {
807
+ const modes = appearance.modes ?? ["light", "dark", "system"];
808
+ const [systemDark, setSystemDark] = React3.useState(false);
809
+ React3.useEffect(() => {
810
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
811
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
812
+ setSystemDark(mq.matches);
813
+ const onChange = () => setSystemDark(mq.matches);
814
+ mq.addEventListener("change", onChange);
815
+ return () => mq.removeEventListener("change", onChange);
816
+ }, []);
817
+ const resolved = appearance.value === "system" ? systemDark ? "dark" : "light" : appearance.value;
818
+ const TriggerIcon = resolved === "dark" ? MoonIcon : SunIcon;
819
+ const caption = appearance.value === "system" ? `System (${resolved === "dark" ? "Dark" : "Light"})` : APPEARANCE_META[appearance.value].label;
820
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
821
+ divider && /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
822
+ /* @__PURE__ */ jsxs2(DropdownMenuSub, { children: [
823
+ /* @__PURE__ */ jsxs2(DropdownMenuSubTrigger, { children: [
824
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "mr-2 inline-flex shrink-0", children: /* @__PURE__ */ jsx3(TriggerIcon, { className: "h-4 w-4" }) }),
825
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-col leading-tight", children: [
826
+ /* @__PURE__ */ jsx3("span", { children: "Appearance" }),
827
+ /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", children: caption })
828
+ ] })
829
+ ] }),
830
+ /* @__PURE__ */ jsx3(DropdownMenuSubContent, { sideOffset: 6, className: "min-w-[12rem]", children: modes.map((m) => {
831
+ const { label, Icon } = APPEARANCE_META[m];
832
+ const active = appearance.value === m;
833
+ return /* @__PURE__ */ jsxs2(
834
+ DropdownMenuItem,
835
+ {
836
+ onSelect: (e) => {
837
+ e.preventDefault();
838
+ appearance.onChange(m);
839
+ },
840
+ className: "gap-3 py-2 text-[14px]",
841
+ children: [
842
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "inline-flex shrink-0", children: /* @__PURE__ */ jsx3(Icon, { className: "h-[18px] w-[18px]" }) }),
843
+ /* @__PURE__ */ jsx3("span", { className: "flex-1", children: label }),
844
+ active && /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "inline-flex shrink-0 text-[var(--accent-text)]", children: /* @__PURE__ */ jsx3(Check, { className: "h-[18px] w-[18px]" }) })
845
+ ]
846
+ },
847
+ m
848
+ );
849
+ }) })
850
+ ] })
851
+ ] });
852
+ }
471
853
  function ProfileAvatar({
472
854
  user,
473
855
  isLoading = false,
@@ -477,6 +859,7 @@ function ProfileAvatar({
477
859
  children,
478
860
  className,
479
861
  showDetails = false,
862
+ appearance,
480
863
  LinkComponent
481
864
  }) {
482
865
  const Link = LinkComponent ?? DefaultLink;
@@ -501,7 +884,7 @@ function ProfileAvatar({
501
884
  ]
502
885
  }
503
886
  ) }),
504
- /* @__PURE__ */ jsxs2(DropdownMenuContent, { side: "right", align: "end", sideOffset: 8, className: "w-72", children: [
887
+ /* @__PURE__ */ jsxs2(DropdownMenuContent, { side: "top", align: "start", sideOffset: 8, className: "w-72", children: [
505
888
  /* @__PURE__ */ jsx3(DropdownMenuLabel, { className: "p-0 font-normal", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 px-2 py-3", children: [
506
889
  /* @__PURE__ */ jsxs2(Avatar, { className: "h-12 w-12 shrink-0", children: [
507
890
  user?.avatarUrl && /* @__PURE__ */ jsx3(AvatarImage, { src: user.avatarUrl, alt: "" }),
@@ -521,6 +904,7 @@ function ProfileAvatar({
521
904
  ] }) }),
522
905
  /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
523
906
  children,
907
+ appearance && /* @__PURE__ */ jsx3(AppearanceMenuSection, { appearance, divider: Boolean(children) }),
524
908
  onSettingsClick ? /* @__PURE__ */ jsxs2(DropdownMenuItem, { onClick: onSettingsClick, children: [
525
909
  /* @__PURE__ */ jsx3(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
526
910
  "Settings"
@@ -540,7 +924,7 @@ function ProfileAvatar({
540
924
  }
541
925
 
542
926
  // src/dashboard/credit-balance.tsx
543
- import * as React3 from "react";
927
+ import * as React4 from "react";
544
928
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
545
929
  function CreditBalance({
546
930
  amount,
@@ -549,7 +933,7 @@ function CreditBalance({
549
933
  quickAmounts = [10, 25, 100],
550
934
  className
551
935
  }) {
552
- const [topUpValue, setTopUpValue] = React3.useState("50.00");
936
+ const [topUpValue, setTopUpValue] = React4.useState("50.00");
553
937
  return /* @__PURE__ */ jsxs3(
554
938
  "div",
555
939
  {
@@ -679,12 +1063,12 @@ function OutOfCreditsModal({
679
1063
  }
680
1064
 
681
1065
  // src/dashboard/cluster-status-bar.tsx
682
- import * as React4 from "react";
1066
+ import * as React5 from "react";
683
1067
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
684
1068
  function ClusterStatusBar({ items, latency, className }) {
685
1069
  if (!items?.length) return null;
686
1070
  return /* @__PURE__ */ jsx6("div", { className: cn("fixed bottom-6 left-1/2 -translate-x-1/2 z-40 w-max max-w-[90vw] animate-in slide-in-from-bottom flex justify-center", className), children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-4 overflow-x-auto rounded-full border border-[var(--md3-outline-variant)] bg-surface-container px-5 py-2.5 shadow-sm", children: [
687
- items.map((item, i) => /* @__PURE__ */ jsxs5(React4.Fragment, { children: [
1071
+ items.map((item, i) => /* @__PURE__ */ jsxs5(React5.Fragment, { children: [
688
1072
  i > 0 && /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "h-5 w-px shrink-0 bg-border" }),
689
1073
  /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-2", children: [
690
1074
  item.icon ? /* @__PURE__ */ jsx6("span", { className: "flex shrink-0 items-center text-[var(--md3-primary)] [&_svg]:h-[18px] [&_svg]:w-[18px]", children: item.icon }) : null,
@@ -776,7 +1160,7 @@ function ResourceSnapshot({
776
1160
  }
777
1161
 
778
1162
  // src/dashboard/activity-feed.tsx
779
- import * as React5 from "react";
1163
+ import * as React6 from "react";
780
1164
  import { Skeleton as Skeleton3 } from "@tangle-network/ui/primitives";
781
1165
  import { timeAgo } from "@tangle-network/ui/utils";
782
1166
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
@@ -789,7 +1173,7 @@ function ActivityFeed({
789
1173
  emptyLabel = "No recent activity",
790
1174
  className
791
1175
  }) {
792
- const sorted = React5.useMemo(
1176
+ const sorted = React6.useMemo(
793
1177
  () => [...items].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0)).slice(0, maxItems),
794
1178
  [items, maxItems]
795
1179
  );
@@ -1103,7 +1487,7 @@ function NewSandboxCard({ onClick, className }) {
1103
1487
  }
1104
1488
 
1105
1489
  // src/dashboard/sandbox-table.tsx
1106
- import * as React6 from "react";
1490
+ import * as React7 from "react";
1107
1491
  import {
1108
1492
  Activity as Activity2,
1109
1493
  BarChart2 as BarChart22,
@@ -1378,7 +1762,7 @@ function SandboxTable({
1378
1762
  children: /* @__PURE__ */ jsx11(MoreVertical2, { className: "h-4 w-4" })
1379
1763
  }
1380
1764
  ) }),
1381
- /* @__PURE__ */ jsx11(DropdownMenuContent3, { align: "end", className: "min-w-[180px]", children: overflowSections.map((section, sectionIdx) => /* @__PURE__ */ jsxs10(React6.Fragment, { children: [
1765
+ /* @__PURE__ */ jsx11(DropdownMenuContent3, { align: "end", className: "min-w-[180px]", children: overflowSections.map((section, sectionIdx) => /* @__PURE__ */ jsxs10(React7.Fragment, { children: [
1382
1766
  sectionIdx > 0 && /* @__PURE__ */ jsx11(DropdownMenuSeparator3, {}),
1383
1767
  section
1384
1768
  ] }, sectionIdx)) })
@@ -1466,7 +1850,7 @@ function InvoiceTable({ invoices, onExportAll, onLoadMore, onViewInvoice, hasMor
1466
1850
  }
1467
1851
 
1468
1852
  // src/dashboard/plan-cards.tsx
1469
- import { Check } from "lucide-react";
1853
+ import { Check as Check2 } from "lucide-react";
1470
1854
  import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1471
1855
  function PlanCards({ plans, className }) {
1472
1856
  return /* @__PURE__ */ jsxs12("section", { className, children: [
@@ -1492,7 +1876,7 @@ function PlanCards({ plans, className }) {
1492
1876
  ] })
1493
1877
  ] }),
1494
1878
  /* @__PURE__ */ jsx13("ul", { className: "space-y-2 mb-5 text-sm text-muted-foreground", children: plan.features.map((f, i) => /* @__PURE__ */ jsxs12("li", { className: "flex items-center gap-2", children: [
1495
- /* @__PURE__ */ jsx13(Check, { className: "h-3.5 w-3.5 text-primary shrink-0" }),
1879
+ /* @__PURE__ */ jsx13(Check2, { className: "h-3.5 w-3.5 text-primary shrink-0" }),
1496
1880
  f.text
1497
1881
  ] }, i)) }),
1498
1882
  /* @__PURE__ */ jsx13(
@@ -1515,16 +1899,30 @@ function PlanCards({ plans, className }) {
1515
1899
  }
1516
1900
 
1517
1901
  // src/dashboard/dashboard-layout.tsx
1518
- import * as React7 from "react";
1519
- import { Plus as Plus2, Bell, ChevronsLeft, ChevronsRight } from "lucide-react";
1520
- import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1521
- function SettingsIconSmall({ className }) {
1522
- return /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1523
- /* @__PURE__ */ jsx14("title", { children: "Settings" }),
1524
- /* @__PURE__ */ jsx14("path", { d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" }),
1525
- /* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "3" })
1526
- ] });
1902
+ import * as React9 from "react";
1903
+ import { Plus as Plus2, Bell } from "lucide-react";
1904
+
1905
+ // src/dashboard/use-brand-theme-sync.ts
1906
+ import * as React8 from "react";
1907
+ function useBrandThemeSync() {
1908
+ React8.useEffect(() => {
1909
+ if (typeof document === "undefined") return;
1910
+ const el = document.documentElement;
1911
+ const sync = () => {
1912
+ const dark = el.classList.contains("dark");
1913
+ el.classList.toggle("light", !dark);
1914
+ const next = dark ? "dark" : "light";
1915
+ if (el.getAttribute("data-theme") !== next) el.setAttribute("data-theme", next);
1916
+ };
1917
+ sync();
1918
+ const observer = new MutationObserver(sync);
1919
+ observer.observe(el, { attributes: true, attributeFilter: ["class"] });
1920
+ return () => observer.disconnect();
1921
+ }, []);
1527
1922
  }
1923
+
1924
+ // src/dashboard/dashboard-layout.tsx
1925
+ import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1528
1926
  function MenuIcon({ className }) {
1529
1927
  return /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1530
1928
  /* @__PURE__ */ jsx14("title", { children: "Menu icon" }),
@@ -1574,19 +1972,19 @@ function DashboardLayoutInner({
1574
1972
  topBarLeading,
1575
1973
  LinkComponent = DefaultLink2,
1576
1974
  logoHref = "/",
1577
- onLogoClick,
1578
- logoAriaLabel = "Toggle navigation",
1579
1975
  labeledRail = false,
1580
1976
  footer,
1581
1977
  railFooter,
1582
1978
  profileMenuItems,
1979
+ appearance,
1583
1980
  notifications: notifData
1584
1981
  }) {
1982
+ useBrandThemeSync();
1585
1983
  const Link = LinkComponent;
1586
- const [mobileMenuOpen, setMobileMenuOpen] = React7.useState(false);
1587
- const [notificationsOpen, setNotificationsOpen] = React7.useState(false);
1588
- const notifRef = React7.useRef(null);
1589
- React7.useEffect(() => {
1984
+ const [mobileMenuOpen, setMobileMenuOpen] = React9.useState(false);
1985
+ const [notificationsOpen, setNotificationsOpen] = React9.useState(false);
1986
+ const notifRef = React9.useRef(null);
1987
+ React9.useEffect(() => {
1590
1988
  if (!notificationsOpen) return;
1591
1989
  const handler = (e) => {
1592
1990
  if (notifRef.current && !notifRef.current.contains(e.target)) {
@@ -1604,123 +2002,87 @@ function DashboardLayoutInner({
1604
2002
  };
1605
2003
  }, [notificationsOpen]);
1606
2004
  const { contentMargin, hidden, mode, hasPanels, panelOpen, toggleRail, railCollapsed } = useSidebar();
1607
- const modeSet = React7.useMemo(() => new Set(modeItems), [modeItems]);
1608
- const sidebarUser = React7.useMemo(
2005
+ const modeSet = React9.useMemo(() => new Set(modeItems), [modeItems]);
2006
+ const sidebarUser = React9.useMemo(
1609
2007
  () => user ? { email: user.email, name: user.name, tier: user.tier, avatarUrl: user.avatarUrl } : void 0,
1610
2008
  [user?.email, user?.name, user?.tier, user?.avatarUrl]
1611
2009
  );
1612
2010
  const activePanel = panels.find((p) => p.mode === mode);
1613
- const buildSidebarContent = React7.useCallback(
2011
+ const buildSidebarContent = React9.useCallback(
1614
2012
  (showLabels, allowCollapse) => /* @__PURE__ */ jsxs13(Fragment9, { children: [
1615
2013
  /* @__PURE__ */ jsxs13(SidebarRail, { wide: showLabels, children: [
1616
- /* @__PURE__ */ jsx14(SidebarRailHeader, { className: cn(showLabels && "justify-start px-3"), children: onLogoClick ? /* @__PURE__ */ jsx14(
1617
- "button",
2014
+ /* @__PURE__ */ jsx14(
2015
+ RailHeader,
1618
2016
  {
1619
- type: "button",
1620
- onClick: onLogoClick,
1621
- "aria-label": logoAriaLabel,
1622
- className: "p-1 rounded-md transition-colors hover:bg-surface-container-high",
1623
- children: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true })
2017
+ brand: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true }),
2018
+ brandHref: logoHref,
2019
+ collapsed: !showLabels,
2020
+ onToggle: toggleRail,
2021
+ collapsible: allowCollapse,
2022
+ LinkComponent: Link
1624
2023
  }
1625
- ) : allowCollapse ? (
1626
- // The logo IS the collapse/expand control on the desktop rail
1627
- // (allowCollapse). The mobile drawer never collapses, so it falls
1628
- // through to the plain logo link. Expanded: full logotype with a
1629
- // collapse chevron that fades in on hover. Collapsed: the mark,
1630
- // with an expand chevron overlay on hover.
1631
- /* @__PURE__ */ jsxs13(
1632
- "button",
1633
- {
1634
- type: "button",
1635
- onClick: toggleRail,
1636
- "aria-label": railCollapsed ? "Expand navigation" : "Collapse navigation",
1637
- "aria-expanded": !railCollapsed,
1638
- className: cn(
1639
- "group/logo relative flex items-center gap-2 rounded-md p-1 transition-colors hover:bg-surface-container-high",
1640
- showLabels && "w-full"
1641
- ),
1642
- children: [
1643
- /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: !showLabels }),
1644
- showLabels ? /* @__PURE__ */ jsx14(ChevronsLeft, { className: "ml-auto h-4 w-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover/logo:opacity-100" }) : /* @__PURE__ */ jsx14("span", { className: "absolute inset-0 flex items-center justify-center rounded-md bg-surface-container-high opacity-0 transition-opacity group-hover/logo:opacity-100", children: /* @__PURE__ */ jsx14(ChevronsRight, { className: "h-4 w-4 text-foreground" }) })
1645
- ]
1646
- }
1647
- )
1648
- ) : /* @__PURE__ */ jsx14(
1649
- Link,
2024
+ ),
2025
+ /* @__PURE__ */ jsx14(
2026
+ SidebarRailNav,
1650
2027
  {
1651
- href: logoHref,
1652
- to: logoHref,
1653
- className: "p-1 rounded-md transition-colors hover:bg-surface-container-high",
1654
- children: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true })
2028
+ className: cn(showLabels ? "px-2" : void 0, !showLabels && allowCollapse && "cursor-pointer"),
2029
+ onClick: !showLabels && allowCollapse ? (e) => {
2030
+ if (e.target === e.currentTarget) toggleRail();
2031
+ } : void 0,
2032
+ children: navItems.map((item, i) => {
2033
+ const isMode = modeSet.has(item.id);
2034
+ const prevIsMode = i > 0 && modeSet.has(navItems[i - 1].id);
2035
+ const showSep = i > 0 && isMode && !prevIsMode;
2036
+ return /* @__PURE__ */ jsxs13(React9.Fragment, { children: [
2037
+ showSep && /* @__PURE__ */ jsx14(
2038
+ RailSeparator,
2039
+ {
2040
+ className: showLabels ? "w-full" : void 0
2041
+ }
2042
+ ),
2043
+ isMode ? /* @__PURE__ */ jsx14(
2044
+ RailModeButton,
2045
+ {
2046
+ mode: item.id,
2047
+ icon: item.icon,
2048
+ label: item.label,
2049
+ badge: item.badge,
2050
+ showLabel: showLabels
2051
+ }
2052
+ ) : /* @__PURE__ */ jsx14(
2053
+ RailButton,
2054
+ {
2055
+ icon: item.icon,
2056
+ label: item.label,
2057
+ isActive: activeNavId === item.id,
2058
+ showLabel: showLabels,
2059
+ asChild: true,
2060
+ children: /* @__PURE__ */ jsx14(Link, { href: item.href, to: item.href })
2061
+ }
2062
+ )
2063
+ ] }, item.id);
2064
+ })
1655
2065
  }
1656
- ) }),
1657
- /* @__PURE__ */ jsx14(SidebarRailNav, { className: showLabels ? "px-2" : void 0, children: navItems.map((item, i) => {
1658
- const isMode = modeSet.has(item.id);
1659
- const prevIsMode = i > 0 && modeSet.has(navItems[i - 1].id);
1660
- const showSep = i > 0 && isMode && !prevIsMode;
1661
- return /* @__PURE__ */ jsxs13(React7.Fragment, { children: [
1662
- showSep && /* @__PURE__ */ jsx14(
1663
- RailSeparator,
1664
- {
1665
- className: showLabels ? "w-full" : void 0
1666
- }
1667
- ),
1668
- isMode ? /* @__PURE__ */ jsx14(
1669
- RailModeButton,
1670
- {
1671
- mode: item.id,
1672
- icon: item.icon,
1673
- label: item.label,
1674
- badge: item.badge,
1675
- showLabel: showLabels
1676
- }
1677
- ) : /* @__PURE__ */ jsx14(
1678
- RailButton,
1679
- {
1680
- icon: item.icon,
1681
- label: item.label,
1682
- isActive: activeNavId === item.id,
1683
- showLabel: showLabels,
1684
- asChild: true,
1685
- children: /* @__PURE__ */ jsx14(Link, { href: item.href, to: item.href })
1686
- }
1687
- )
1688
- ] }, item.id);
1689
- }) }),
1690
- /* @__PURE__ */ jsxs13(SidebarRailFooter, { className: cn(showLabels && "items-stretch px-2"), children: [
1691
- onSettingsClick ? /* @__PURE__ */ jsx14(RailButton, { icon: SettingsIconSmall, label: "Settings", onClick: onSettingsClick, showLabel: showLabels }) : /* @__PURE__ */ jsx14(RailButton, { icon: SettingsIconSmall, label: "Settings", showLabel: showLabels, asChild: true, children: /* @__PURE__ */ jsx14(Link, { href: settingsHref, to: settingsHref }) }),
1692
- /* @__PURE__ */ jsx14(RailSeparator, { className: showLabels ? "w-full" : void 0 }),
1693
- railFooter !== void 0 ? showLabels ? /* @__PURE__ */ jsxs13("div", { className: "flex w-full items-center gap-1", children: [
1694
- /* @__PURE__ */ jsx14("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx14(
1695
- ProfileAvatar,
1696
- {
1697
- user: sidebarUser,
1698
- isLoading,
1699
- onLogout,
1700
- onSettingsClick,
1701
- settingsHref,
1702
- showDetails: showLabels,
1703
- LinkComponent,
1704
- children: profileMenuItems
1705
- }
1706
- ) }),
1707
- /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: railFooter })
1708
- ] }) : /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center gap-1", children: [
1709
- railFooter,
1710
- /* @__PURE__ */ jsx14(
1711
- ProfileAvatar,
1712
- {
1713
- user: sidebarUser,
1714
- isLoading,
1715
- onLogout,
1716
- onSettingsClick,
1717
- settingsHref,
1718
- showDetails: showLabels,
1719
- LinkComponent,
1720
- children: profileMenuItems
1721
- }
1722
- )
1723
- ] }) : /* @__PURE__ */ jsx14(
2066
+ ),
2067
+ /* @__PURE__ */ jsx14(SidebarRailFooter, { className: cn("border-t border-[var(--md3-outline-variant)] pt-2", showLabels && "items-stretch px-2"), children: railFooter !== void 0 ? showLabels ? /* @__PURE__ */ jsxs13("div", { className: "flex w-full items-center gap-1", children: [
2068
+ /* @__PURE__ */ jsx14("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx14(
2069
+ ProfileAvatar,
2070
+ {
2071
+ user: sidebarUser,
2072
+ isLoading,
2073
+ onLogout,
2074
+ onSettingsClick,
2075
+ settingsHref,
2076
+ showDetails: showLabels,
2077
+ appearance,
2078
+ LinkComponent,
2079
+ children: profileMenuItems
2080
+ }
2081
+ ) }),
2082
+ /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: railFooter })
2083
+ ] }) : /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center gap-1", children: [
2084
+ railFooter,
2085
+ /* @__PURE__ */ jsx14(
1724
2086
  ProfileAvatar,
1725
2087
  {
1726
2088
  user: sidebarUser,
@@ -1729,11 +2091,25 @@ function DashboardLayoutInner({
1729
2091
  onSettingsClick,
1730
2092
  settingsHref,
1731
2093
  showDetails: showLabels,
2094
+ appearance,
1732
2095
  LinkComponent,
1733
2096
  children: profileMenuItems
1734
2097
  }
1735
2098
  )
1736
- ] })
2099
+ ] }) : /* @__PURE__ */ jsx14(
2100
+ ProfileAvatar,
2101
+ {
2102
+ user: sidebarUser,
2103
+ isLoading,
2104
+ onLogout,
2105
+ onSettingsClick,
2106
+ settingsHref,
2107
+ showDetails: showLabels,
2108
+ appearance,
2109
+ LinkComponent,
2110
+ children: profileMenuItems
2111
+ }
2112
+ ) })
1737
2113
  ] }),
1738
2114
  panels.length > 0 && /* @__PURE__ */ jsxs13(SidebarPanel, { children: [
1739
2115
  /* @__PURE__ */ jsx14(SidebarPanelHeader, { title: activePanel?.title ?? mode }),
@@ -1744,8 +2120,6 @@ function DashboardLayoutInner({
1744
2120
  [
1745
2121
  Link,
1746
2122
  variant,
1747
- onLogoClick,
1748
- logoAriaLabel,
1749
2123
  logoHref,
1750
2124
  labeledRail,
1751
2125
  toggleRail,
@@ -1761,16 +2135,17 @@ function DashboardLayoutInner({
1761
2135
  onLogout,
1762
2136
  LinkComponent,
1763
2137
  profileMenuItems,
2138
+ appearance,
1764
2139
  panels,
1765
2140
  activePanel,
1766
2141
  mode
1767
2142
  ]
1768
2143
  );
1769
- const sidebarContent = React7.useMemo(
2144
+ const sidebarContent = React9.useMemo(
1770
2145
  () => buildSidebarContent(labeledRail && !railCollapsed, labeledRail),
1771
2146
  [buildSidebarContent, labeledRail, railCollapsed]
1772
2147
  );
1773
- const mobileSidebarContent = React7.useMemo(() => buildSidebarContent(true, false), [buildSidebarContent]);
2148
+ const mobileSidebarContent = React9.useMemo(() => buildSidebarContent(true, false), [buildSidebarContent]);
1774
2149
  return /* @__PURE__ */ jsxs13("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
1775
2150
  /* @__PURE__ */ jsxs13(
1776
2151
  "nav",
@@ -1933,9 +2308,8 @@ function SidebarLayoutInner({
1933
2308
  onSettingsClick,
1934
2309
  settingsHref,
1935
2310
  profileMenuItems,
1936
- showThemeToggle = false,
2311
+ appearance,
1937
2312
  railFooter,
1938
- railCollapseToggle = "footer",
1939
2313
  LinkComponent,
1940
2314
  hideBelow,
1941
2315
  railLabels = false,
@@ -1944,29 +2318,50 @@ function SidebarLayoutInner({
1944
2318
  sidebarClassName,
1945
2319
  contentClassName
1946
2320
  }) {
2321
+ useBrandThemeSync();
1947
2322
  const Link = LinkComponent ?? DefaultLink3;
1948
2323
  const { panelOpen, togglePanel, setPanelOpen, railCollapsed, toggleRail } = useSidebar();
1949
2324
  const handleNavClick = closePanelOnNavigate && panelOpen ? () => setPanelOpen(false) : void 0;
2325
+ const expandOnEmptyClick = railLabels && railCollapsed ? (e) => {
2326
+ if (e.target === e.currentTarget) toggleRail();
2327
+ } : void 0;
1950
2328
  const hasProfile = user !== void 0 || onLogout !== void 0 || onSettingsClick !== void 0;
1951
2329
  const showLabels = railLabels && !railCollapsed;
1952
2330
  return /* @__PURE__ */ jsxs14("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
1953
2331
  /* @__PURE__ */ jsx15("div", { className: cn(hideBelow && HIDE_BELOW_CLASS[hideBelow]), children: /* @__PURE__ */ jsxs14(Sidebar, { className: sidebarClassName, children: [
1954
2332
  /* @__PURE__ */ jsxs14(SidebarRail, { children: [
1955
- (railHeaderContent !== void 0 || logo !== void 0 || railLabels && railCollapseToggle === "header") && /* @__PURE__ */ jsxs14(SidebarRailHeader, { className: cn(showLabels && (railHeaderContent !== void 0 ? "px-2" : "justify-start px-4")), children: [
1956
- railHeaderContent !== void 0 ? railHeaderContent : logo !== void 0 ? /* @__PURE__ */ jsx15(
1957
- Link,
1958
- {
1959
- href: logoHref,
1960
- to: logoHref,
1961
- className: "flex items-center justify-center rounded-lg p-1 transition-colors hover:bg-surface-container-high",
1962
- children: logo
1963
- }
1964
- ) : null,
1965
- railLabels && railCollapseToggle === "header" && // Icon-only in the header row (the labeled, full-width variant is
1966
- // for the vertical footer stack); sits beside the logo/content.
1967
- /* @__PURE__ */ jsx15(RailCollapseToggle, { collapsed: railCollapsed, showLabel: false, onToggle: toggleRail, className: "shrink-0" })
1968
- ] }),
1969
- /* @__PURE__ */ jsx15(SidebarRailNav, { className: showLabels ? "px-2" : void 0, children: navItems.map((item) => {
2333
+ (logo !== void 0 || railHeaderContent !== void 0 || railLabels) && /* @__PURE__ */ jsx15(
2334
+ RailHeader,
2335
+ {
2336
+ brand: logo,
2337
+ brandHref: logoHref,
2338
+ collapsed: !showLabels,
2339
+ onToggle: toggleRail,
2340
+ collapsible: railLabels,
2341
+ LinkComponent,
2342
+ children: railHeaderContent
2343
+ }
2344
+ ),
2345
+ /* @__PURE__ */ jsx15(SidebarRailNav, { className: cn(showLabels ? "px-2" : void 0, expandOnEmptyClick && "cursor-pointer"), onClick: expandOnEmptyClick, children: navItems.map((item) => {
2346
+ if (item.expandable) {
2347
+ return /* @__PURE__ */ jsx15(
2348
+ RailExpandable,
2349
+ {
2350
+ icon: item.icon,
2351
+ label: item.label,
2352
+ href: item.href,
2353
+ isActive: activeId === item.id,
2354
+ showLabel: showLabels,
2355
+ subItems: item.subItems,
2356
+ loadSubItems: item.loadSubItems,
2357
+ activeSubIds: item.subActiveIds,
2358
+ emptyLabel: item.emptyLabel,
2359
+ onNavigate: handleNavClick,
2360
+ LinkComponent
2361
+ },
2362
+ item.id
2363
+ );
2364
+ }
1970
2365
  if (item.flyoutItems && item.flyoutItems.length > 0) {
1971
2366
  const activeSet = new Set(item.flyoutActiveIds ?? []);
1972
2367
  return /* @__PURE__ */ jsx15(
@@ -2014,7 +2409,7 @@ function SidebarLayoutInner({
2014
2409
  showLabel: showLabels
2015
2410
  },
2016
2411
  item.id
2017
- ) : /* @__PURE__ */ jsx15(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: showLabels, asChild: true, children: /* @__PURE__ */ jsx15(
2412
+ ) : /* @__PURE__ */ jsx15(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: showLabels, variant: item.variant, asChild: true, children: /* @__PURE__ */ jsx15(
2018
2413
  Link,
2019
2414
  {
2020
2415
  href: item.href,
@@ -2024,32 +2419,22 @@ function SidebarLayoutInner({
2024
2419
  }
2025
2420
  ) }, item.id);
2026
2421
  }) }),
2027
- (railLabels || railFooter !== void 0 || hasProfile) && /* @__PURE__ */ jsxs14(SidebarRailFooter, { className: cn("border-t border-[var(--md3-outline-variant)] pt-2", showLabels && "items-stretch px-2"), children: [
2028
- railLabels && railCollapseToggle === "footer" && /* @__PURE__ */ jsx15(RailCollapseToggle, { collapsed: railCollapsed, showLabel: showLabels, onToggle: toggleRail }),
2422
+ (railFooter !== void 0 || hasProfile) && /* @__PURE__ */ jsxs14(SidebarRailFooter, { className: cn("border-t border-[var(--md3-outline-variant)] pt-2", showLabels && "items-stretch px-2"), children: [
2029
2423
  railFooter,
2030
- hasProfile && (() => {
2031
- const profile = /* @__PURE__ */ jsx15(
2032
- ProfileAvatar,
2033
- {
2034
- user: user ?? void 0,
2035
- isLoading,
2036
- onLogout,
2037
- onSettingsClick,
2038
- settingsHref,
2039
- showDetails: showLabels,
2040
- LinkComponent: Link,
2041
- children: profileMenuItems
2042
- }
2043
- );
2044
- if (!showThemeToggle) return profile;
2045
- return showLabels ? /* @__PURE__ */ jsxs14("div", { className: "flex w-full items-center gap-1", children: [
2046
- /* @__PURE__ */ jsx15("div", { className: "min-w-0 flex-1", children: profile }),
2047
- /* @__PURE__ */ jsx15(RailThemeToggle, {})
2048
- ] }) : /* @__PURE__ */ jsxs14("div", { className: "flex flex-col items-center gap-1", children: [
2049
- /* @__PURE__ */ jsx15(RailThemeToggle, {}),
2050
- profile
2051
- ] });
2052
- })()
2424
+ hasProfile && /* @__PURE__ */ jsx15(
2425
+ ProfileAvatar,
2426
+ {
2427
+ user: user ?? void 0,
2428
+ isLoading,
2429
+ onLogout,
2430
+ onSettingsClick,
2431
+ settingsHref,
2432
+ showDetails: showLabels,
2433
+ appearance,
2434
+ LinkComponent: Link,
2435
+ children: profileMenuItems
2436
+ }
2437
+ )
2053
2438
  ] })
2054
2439
  ] }),
2055
2440
  panel != null && /* @__PURE__ */ jsx15(SidebarPanel, { children: panel })
@@ -2083,7 +2468,7 @@ function SidebarLayout({
2083
2468
  }
2084
2469
 
2085
2470
  // src/dashboard/profile-selector.tsx
2086
- import { Check as Check2, ChevronDown, Plus as Plus3, Settings } from "lucide-react";
2471
+ import { Check as Check3, ChevronDown, Plus as Plus3, Settings } from "lucide-react";
2087
2472
  import { Button as Button2 } from "@tangle-network/ui/primitives";
2088
2473
  import { Badge } from "@tangle-network/ui/primitives";
2089
2474
  import {
@@ -2124,7 +2509,7 @@ function ProfileSelector({
2124
2509
  className: "flex items-center justify-between",
2125
2510
  children: [
2126
2511
  /* @__PURE__ */ jsx16("span", { children: placeholder }),
2127
- !selectedId && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2512
+ !selectedId && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2128
2513
  ]
2129
2514
  }
2130
2515
  ),
@@ -2145,7 +2530,7 @@ function ProfileSelector({
2145
2530
  profile.extends
2146
2531
  ] })
2147
2532
  ] }),
2148
- selectedId === profile.id && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2533
+ selectedId === profile.id && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2149
2534
  ] }),
2150
2535
  profile.description && /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description })
2151
2536
  ]
@@ -2167,7 +2552,7 @@ function ProfileSelector({
2167
2552
  /* @__PURE__ */ jsx16("span", { className: "font-medium", children: profile.name }),
2168
2553
  profile.model && /* @__PURE__ */ jsx16(Badge, { variant: "secondary", className: "border-0 text-xs", children: profile.model.split("/").pop() })
2169
2554
  ] }),
2170
- selectedId === profile.id && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2555
+ selectedId === profile.id && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2171
2556
  ] }),
2172
2557
  profile.description && /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description }),
2173
2558
  showMetrics && profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs15("div", { className: "flex gap-3 text-muted-foreground text-xs", children: [
@@ -2285,7 +2670,7 @@ function ProfileComparison({
2285
2670
  }
2286
2671
 
2287
2672
  // src/dashboard/metric-area-chart.tsx
2288
- import * as React8 from "react";
2673
+ import * as React10 from "react";
2289
2674
  import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2290
2675
  var TONE_VARS = {
2291
2676
  primary: "var(--brand-primary, hsl(var(--primary)))",
@@ -2332,7 +2717,7 @@ function MetricAreaChart({
2332
2717
  emptyState,
2333
2718
  className
2334
2719
  }) {
2335
- const gradientId = React8.useId();
2720
+ const gradientId = React10.useId();
2336
2721
  const width = 400;
2337
2722
  const values = points.map((p) => p.value).filter((v) => v !== null);
2338
2723
  const latest = values.length > 0 ? values[values.length - 1] : null;
@@ -2392,7 +2777,7 @@ function MetricAreaChart({
2392
2777
  /* @__PURE__ */ jsx17("stop", { offset: "0%", stopColor: color, stopOpacity: 0.28 }),
2393
2778
  /* @__PURE__ */ jsx17("stop", { offset: "100%", stopColor: color, stopOpacity: 0.02 })
2394
2779
  ] }) }),
2395
- segments.map((segment) => /* @__PURE__ */ jsxs16(React8.Fragment, { children: [
2780
+ segments.map((segment) => /* @__PURE__ */ jsxs16(React10.Fragment, { children: [
2396
2781
  /* @__PURE__ */ jsx17("path", { d: segment.area, fill: `url(#${gradientId})` }),
2397
2782
  /* @__PURE__ */ jsx17(
2398
2783
  "path",
@@ -2421,7 +2806,7 @@ function MetricAreaChart({
2421
2806
 
2422
2807
  // src/dashboard/variant-list.tsx
2423
2808
  import {
2424
- Check as Check3,
2809
+ Check as Check4,
2425
2810
  CheckCircle2,
2426
2811
  Clock as Clock3,
2427
2812
  ExternalLink as ExternalLink2,
@@ -2568,7 +2953,7 @@ function VariantList({
2568
2953
  },
2569
2954
  disabled: isActioning === variant.id,
2570
2955
  children: [
2571
- /* @__PURE__ */ jsx18(Check3, { className: "mr-1 h-3 w-3" }),
2956
+ /* @__PURE__ */ jsx18(Check4, { className: "mr-1 h-3 w-3" }),
2572
2957
  "Accept"
2573
2958
  ]
2574
2959
  }
@@ -2617,14 +3002,14 @@ function VariantList({
2617
3002
 
2618
3003
  // src/dashboard/system-logs.tsx
2619
3004
  import { Terminal as Terminal2 } from "lucide-react";
2620
- import { useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
3005
+ import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
2621
3006
  import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2622
3007
  function SystemLogsViewer({ apiUrl, token, className }) {
2623
- const [logs, setLogs] = useState5([]);
2624
- const [error, setError] = useState5(null);
2625
- const [isFollowing, setIsFollowing] = useState5(true);
2626
- const scrollRef = useRef3(null);
2627
- useEffect3(() => {
3008
+ const [logs, setLogs] = useState6([]);
3009
+ const [error, setError] = useState6(null);
3010
+ const [isFollowing, setIsFollowing] = useState6(true);
3011
+ const scrollRef = useRef4(null);
3012
+ useEffect5(() => {
2628
3013
  let timeoutId;
2629
3014
  let backoff = 2e3;
2630
3015
  const controller = new AbortController();
@@ -2660,7 +3045,7 @@ function SystemLogsViewer({ apiUrl, token, className }) {
2660
3045
  clearTimeout(timeoutId);
2661
3046
  };
2662
3047
  }, [apiUrl, token]);
2663
- useEffect3(() => {
3048
+ useEffect5(() => {
2664
3049
  if (isFollowing && scrollRef.current) {
2665
3050
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
2666
3051
  }
@@ -2867,14 +3252,14 @@ function GitPanel({ status, log, loading = false, onRefresh, className }) {
2867
3252
  }
2868
3253
 
2869
3254
  // src/dashboard/ports-list.tsx
2870
- import * as React10 from "react";
2871
- import { Copy as Copy3, Check as Check4, Globe, Plus as Plus4, Trash2 as Trash23 } from "lucide-react";
3255
+ import * as React12 from "react";
3256
+ import { Copy as Copy3, Check as Check5, Globe, Plus as Plus4, Trash2 as Trash23 } from "lucide-react";
2872
3257
  import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2873
3258
  function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, className }) {
2874
- const [newPort, setNewPort] = React10.useState("");
2875
- const [copiedPort, setCopiedPort] = React10.useState(null);
2876
- const copyTimerRef = React10.useRef(null);
2877
- React10.useEffect(() => {
3259
+ const [newPort, setNewPort] = React12.useState("");
3260
+ const [copiedPort, setCopiedPort] = React12.useState(null);
3261
+ const copyTimerRef = React12.useRef(null);
3262
+ React12.useEffect(() => {
2878
3263
  return () => {
2879
3264
  if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
2880
3265
  };
@@ -2914,7 +3299,7 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
2914
3299
  className: "flex items-center gap-2 font-mono text-xs text-primary hover:underline cursor-pointer group",
2915
3300
  children: [
2916
3301
  /* @__PURE__ */ jsx22("span", { className: "truncate max-w-[300px]", children: p.url }),
2917
- copiedPort === p.port ? /* @__PURE__ */ jsx22(Check4, { className: "h-3 w-3 text-[var(--surface-success-text)] shrink-0" }) : /* @__PURE__ */ jsx22(Copy3, { className: "h-3 w-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0" })
3302
+ copiedPort === p.port ? /* @__PURE__ */ jsx22(Check5, { className: "h-3 w-3 text-[var(--surface-success-text)] shrink-0" }) : /* @__PURE__ */ jsx22(Copy3, { className: "h-3 w-3 opacity-0 group-hover:opacity-100 transition-opacity shrink-0" })
2918
3303
  ]
2919
3304
  }
2920
3305
  ) }),
@@ -2968,7 +3353,7 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
2968
3353
  }
2969
3354
 
2970
3355
  // src/dashboard/process-list.tsx
2971
- import * as React11 from "react";
3356
+ import * as React13 from "react";
2972
3357
  import { Activity as Activity3, Plus as Plus5, Skull, Terminal as Terminal3 } from "lucide-react";
2973
3358
  import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2974
3359
  function formatUptime(startedAt) {
@@ -2980,7 +3365,7 @@ function formatUptime(startedAt) {
2980
3365
  return `${Math.floor(ms / 36e5)}h ${Math.floor(ms % 36e5 / 6e4)}m`;
2981
3366
  }
2982
3367
  function ProcessList({ processes, onSpawn, onKill, loading = false, className }) {
2983
- const [newCommand, setNewCommand] = React11.useState("");
3368
+ const [newCommand, setNewCommand] = React13.useState("");
2984
3369
  const handleSpawn = () => {
2985
3370
  const cmd = newCommand.trim();
2986
3371
  if (cmd) {
@@ -3053,11 +3438,11 @@ function ProcessList({ processes, onSpawn, onKill, loading = false, className })
3053
3438
  }
3054
3439
 
3055
3440
  // src/dashboard/network-config.tsx
3056
- import * as React12 from "react";
3441
+ import * as React14 from "react";
3057
3442
  import { Network as Network2, Plus as Plus6, Trash2 as Trash24, ShieldAlert } from "lucide-react";
3058
3443
  import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
3059
3444
  function NetworkConfig({ config, onUpdate, loading = false, className }) {
3060
- const [newCidr, setNewCidr] = React12.useState("");
3445
+ const [newCidr, setNewCidr] = React14.useState("");
3061
3446
  const isValidCidr = (value) => {
3062
3447
  const match = value.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/);
3063
3448
  if (!match) return false;
@@ -3161,7 +3546,7 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
3161
3546
  }
3162
3547
 
3163
3548
  // src/dashboard/backend-config.tsx
3164
- import * as React13 from "react";
3549
+ import * as React15 from "react";
3165
3550
  import { Bot, Plus as Plus7, RefreshCw as RefreshCw2, Trash2 as Trash25, Server, Wrench } from "lucide-react";
3166
3551
  import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3167
3552
  function BackendConfig({
@@ -3173,10 +3558,10 @@ function BackendConfig({
3173
3558
  loading = false,
3174
3559
  className
3175
3560
  }) {
3176
- const [showAddMcp, setShowAddMcp] = React13.useState(false);
3177
- const [mcpName, setMcpName] = React13.useState("");
3178
- const [mcpCommand, setMcpCommand] = React13.useState("");
3179
- const [mcpArgs, setMcpArgs] = React13.useState("");
3561
+ const [showAddMcp, setShowAddMcp] = React15.useState(false);
3562
+ const [mcpName, setMcpName] = React15.useState("");
3563
+ const [mcpCommand, setMcpCommand] = React15.useState("");
3564
+ const [mcpArgs, setMcpArgs] = React15.useState("");
3180
3565
  const handleAddMcp = () => {
3181
3566
  const name = mcpName.trim();
3182
3567
  const command = mcpCommand.trim();
@@ -3334,7 +3719,7 @@ function BackendConfig({
3334
3719
  }
3335
3720
 
3336
3721
  // src/dashboard/snapshot-list.tsx
3337
- import * as React14 from "react";
3722
+ import * as React16 from "react";
3338
3723
  import { Camera, Clock as Clock5, HardDrive as HardDrive2, Plus as Plus8, RotateCcw } from "lucide-react";
3339
3724
  import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
3340
3725
  function formatBytes(bytes) {
@@ -3351,8 +3736,8 @@ function formatDate(dateStr) {
3351
3736
  return d.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
3352
3737
  }
3353
3738
  function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loading = false, className }) {
3354
- const [showCreate, setShowCreate] = React14.useState(false);
3355
- const [tags, setTags] = React14.useState("");
3739
+ const [showCreate, setShowCreate] = React16.useState(false);
3740
+ const [tags, setTags] = React16.useState("");
3356
3741
  const handleCreate = () => {
3357
3742
  const tagList = tags.trim() ? tags.trim().split(",").map((t) => t.trim()).filter(Boolean) : void 0;
3358
3743
  onCreate(tagList);
@@ -3513,6 +3898,7 @@ export {
3513
3898
  RailTooltip,
3514
3899
  RailThemeToggle,
3515
3900
  RailCollapseToggle,
3901
+ RailHeader,
3516
3902
  Sidebar,
3517
3903
  SidebarRail,
3518
3904
  SidebarRailHeader,
@@ -3521,6 +3907,7 @@ export {
3521
3907
  RailSeparator,
3522
3908
  RailButton,
3523
3909
  RailFlyout,
3910
+ RailExpandable,
3524
3911
  RailModeButton,
3525
3912
  SidebarPanel,
3526
3913
  SidebarPanelHeader,