@tangle-network/sandbox-ui 0.52.0 → 0.53.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,9 @@ 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";
1902
+ import * as React8 from "react";
1903
+ import { Plus as Plus2, Bell } from "lucide-react";
1520
1904
  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
- ] });
1527
- }
1528
1905
  function MenuIcon({ className }) {
1529
1906
  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
1907
  /* @__PURE__ */ jsx14("title", { children: "Menu icon" }),
@@ -1574,19 +1951,18 @@ function DashboardLayoutInner({
1574
1951
  topBarLeading,
1575
1952
  LinkComponent = DefaultLink2,
1576
1953
  logoHref = "/",
1577
- onLogoClick,
1578
- logoAriaLabel = "Toggle navigation",
1579
1954
  labeledRail = false,
1580
1955
  footer,
1581
1956
  railFooter,
1582
1957
  profileMenuItems,
1958
+ appearance,
1583
1959
  notifications: notifData
1584
1960
  }) {
1585
1961
  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(() => {
1962
+ const [mobileMenuOpen, setMobileMenuOpen] = React8.useState(false);
1963
+ const [notificationsOpen, setNotificationsOpen] = React8.useState(false);
1964
+ const notifRef = React8.useRef(null);
1965
+ React8.useEffect(() => {
1590
1966
  if (!notificationsOpen) return;
1591
1967
  const handler = (e) => {
1592
1968
  if (notifRef.current && !notifRef.current.contains(e.target)) {
@@ -1604,123 +1980,87 @@ function DashboardLayoutInner({
1604
1980
  };
1605
1981
  }, [notificationsOpen]);
1606
1982
  const { contentMargin, hidden, mode, hasPanels, panelOpen, toggleRail, railCollapsed } = useSidebar();
1607
- const modeSet = React7.useMemo(() => new Set(modeItems), [modeItems]);
1608
- const sidebarUser = React7.useMemo(
1983
+ const modeSet = React8.useMemo(() => new Set(modeItems), [modeItems]);
1984
+ const sidebarUser = React8.useMemo(
1609
1985
  () => user ? { email: user.email, name: user.name, tier: user.tier, avatarUrl: user.avatarUrl } : void 0,
1610
1986
  [user?.email, user?.name, user?.tier, user?.avatarUrl]
1611
1987
  );
1612
1988
  const activePanel = panels.find((p) => p.mode === mode);
1613
- const buildSidebarContent = React7.useCallback(
1989
+ const buildSidebarContent = React8.useCallback(
1614
1990
  (showLabels, allowCollapse) => /* @__PURE__ */ jsxs13(Fragment9, { children: [
1615
1991
  /* @__PURE__ */ jsxs13(SidebarRail, { wide: showLabels, children: [
1616
- /* @__PURE__ */ jsx14(SidebarRailHeader, { className: cn(showLabels && "justify-start px-3"), children: onLogoClick ? /* @__PURE__ */ jsx14(
1617
- "button",
1992
+ /* @__PURE__ */ jsx14(
1993
+ RailHeader,
1618
1994
  {
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 })
1995
+ brand: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true }),
1996
+ brandHref: logoHref,
1997
+ collapsed: !showLabels,
1998
+ onToggle: toggleRail,
1999
+ collapsible: allowCollapse,
2000
+ LinkComponent: Link
1624
2001
  }
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,
2002
+ ),
2003
+ /* @__PURE__ */ jsx14(
2004
+ SidebarRailNav,
1650
2005
  {
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 })
2006
+ className: cn(showLabels ? "px-2" : void 0, !showLabels && allowCollapse && "cursor-pointer"),
2007
+ onClick: !showLabels && allowCollapse ? (e) => {
2008
+ if (e.target === e.currentTarget) toggleRail();
2009
+ } : void 0,
2010
+ children: navItems.map((item, i) => {
2011
+ const isMode = modeSet.has(item.id);
2012
+ const prevIsMode = i > 0 && modeSet.has(navItems[i - 1].id);
2013
+ const showSep = i > 0 && isMode && !prevIsMode;
2014
+ return /* @__PURE__ */ jsxs13(React8.Fragment, { children: [
2015
+ showSep && /* @__PURE__ */ jsx14(
2016
+ RailSeparator,
2017
+ {
2018
+ className: showLabels ? "w-full" : void 0
2019
+ }
2020
+ ),
2021
+ isMode ? /* @__PURE__ */ jsx14(
2022
+ RailModeButton,
2023
+ {
2024
+ mode: item.id,
2025
+ icon: item.icon,
2026
+ label: item.label,
2027
+ badge: item.badge,
2028
+ showLabel: showLabels
2029
+ }
2030
+ ) : /* @__PURE__ */ jsx14(
2031
+ RailButton,
2032
+ {
2033
+ icon: item.icon,
2034
+ label: item.label,
2035
+ isActive: activeNavId === item.id,
2036
+ showLabel: showLabels,
2037
+ asChild: true,
2038
+ children: /* @__PURE__ */ jsx14(Link, { href: item.href, to: item.href })
2039
+ }
2040
+ )
2041
+ ] }, item.id);
2042
+ })
1655
2043
  }
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(
2044
+ ),
2045
+ /* @__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: [
2046
+ /* @__PURE__ */ jsx14("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx14(
2047
+ ProfileAvatar,
2048
+ {
2049
+ user: sidebarUser,
2050
+ isLoading,
2051
+ onLogout,
2052
+ onSettingsClick,
2053
+ settingsHref,
2054
+ showDetails: showLabels,
2055
+ appearance,
2056
+ LinkComponent,
2057
+ children: profileMenuItems
2058
+ }
2059
+ ) }),
2060
+ /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: railFooter })
2061
+ ] }) : /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center gap-1", children: [
2062
+ railFooter,
2063
+ /* @__PURE__ */ jsx14(
1724
2064
  ProfileAvatar,
1725
2065
  {
1726
2066
  user: sidebarUser,
@@ -1729,11 +2069,25 @@ function DashboardLayoutInner({
1729
2069
  onSettingsClick,
1730
2070
  settingsHref,
1731
2071
  showDetails: showLabels,
2072
+ appearance,
1732
2073
  LinkComponent,
1733
2074
  children: profileMenuItems
1734
2075
  }
1735
2076
  )
1736
- ] })
2077
+ ] }) : /* @__PURE__ */ jsx14(
2078
+ ProfileAvatar,
2079
+ {
2080
+ user: sidebarUser,
2081
+ isLoading,
2082
+ onLogout,
2083
+ onSettingsClick,
2084
+ settingsHref,
2085
+ showDetails: showLabels,
2086
+ appearance,
2087
+ LinkComponent,
2088
+ children: profileMenuItems
2089
+ }
2090
+ ) })
1737
2091
  ] }),
1738
2092
  panels.length > 0 && /* @__PURE__ */ jsxs13(SidebarPanel, { children: [
1739
2093
  /* @__PURE__ */ jsx14(SidebarPanelHeader, { title: activePanel?.title ?? mode }),
@@ -1744,8 +2098,6 @@ function DashboardLayoutInner({
1744
2098
  [
1745
2099
  Link,
1746
2100
  variant,
1747
- onLogoClick,
1748
- logoAriaLabel,
1749
2101
  logoHref,
1750
2102
  labeledRail,
1751
2103
  toggleRail,
@@ -1761,16 +2113,17 @@ function DashboardLayoutInner({
1761
2113
  onLogout,
1762
2114
  LinkComponent,
1763
2115
  profileMenuItems,
2116
+ appearance,
1764
2117
  panels,
1765
2118
  activePanel,
1766
2119
  mode
1767
2120
  ]
1768
2121
  );
1769
- const sidebarContent = React7.useMemo(
2122
+ const sidebarContent = React8.useMemo(
1770
2123
  () => buildSidebarContent(labeledRail && !railCollapsed, labeledRail),
1771
2124
  [buildSidebarContent, labeledRail, railCollapsed]
1772
2125
  );
1773
- const mobileSidebarContent = React7.useMemo(() => buildSidebarContent(true, false), [buildSidebarContent]);
2126
+ const mobileSidebarContent = React8.useMemo(() => buildSidebarContent(true, false), [buildSidebarContent]);
1774
2127
  return /* @__PURE__ */ jsxs13("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
1775
2128
  /* @__PURE__ */ jsxs13(
1776
2129
  "nav",
@@ -1933,9 +2286,8 @@ function SidebarLayoutInner({
1933
2286
  onSettingsClick,
1934
2287
  settingsHref,
1935
2288
  profileMenuItems,
1936
- showThemeToggle = false,
2289
+ appearance,
1937
2290
  railFooter,
1938
- railCollapseToggle = "footer",
1939
2291
  LinkComponent,
1940
2292
  hideBelow,
1941
2293
  railLabels = false,
@@ -1947,26 +2299,46 @@ function SidebarLayoutInner({
1947
2299
  const Link = LinkComponent ?? DefaultLink3;
1948
2300
  const { panelOpen, togglePanel, setPanelOpen, railCollapsed, toggleRail } = useSidebar();
1949
2301
  const handleNavClick = closePanelOnNavigate && panelOpen ? () => setPanelOpen(false) : void 0;
2302
+ const expandOnEmptyClick = railLabels && railCollapsed ? (e) => {
2303
+ if (e.target === e.currentTarget) toggleRail();
2304
+ } : void 0;
1950
2305
  const hasProfile = user !== void 0 || onLogout !== void 0 || onSettingsClick !== void 0;
1951
2306
  const showLabels = railLabels && !railCollapsed;
1952
2307
  return /* @__PURE__ */ jsxs14("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
1953
2308
  /* @__PURE__ */ jsx15("div", { className: cn(hideBelow && HIDE_BELOW_CLASS[hideBelow]), children: /* @__PURE__ */ jsxs14(Sidebar, { className: sidebarClassName, children: [
1954
2309
  /* @__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) => {
2310
+ (logo !== void 0 || railHeaderContent !== void 0 || railLabels) && /* @__PURE__ */ jsx15(
2311
+ RailHeader,
2312
+ {
2313
+ brand: logo,
2314
+ brandHref: logoHref,
2315
+ collapsed: !showLabels,
2316
+ onToggle: toggleRail,
2317
+ collapsible: railLabels,
2318
+ LinkComponent,
2319
+ children: railHeaderContent
2320
+ }
2321
+ ),
2322
+ /* @__PURE__ */ jsx15(SidebarRailNav, { className: cn(showLabels ? "px-2" : void 0, expandOnEmptyClick && "cursor-pointer"), onClick: expandOnEmptyClick, children: navItems.map((item) => {
2323
+ if (item.expandable) {
2324
+ return /* @__PURE__ */ jsx15(
2325
+ RailExpandable,
2326
+ {
2327
+ icon: item.icon,
2328
+ label: item.label,
2329
+ href: item.href,
2330
+ isActive: activeId === item.id,
2331
+ showLabel: showLabels,
2332
+ subItems: item.subItems,
2333
+ loadSubItems: item.loadSubItems,
2334
+ activeSubIds: item.subActiveIds,
2335
+ emptyLabel: item.emptyLabel,
2336
+ onNavigate: handleNavClick,
2337
+ LinkComponent
2338
+ },
2339
+ item.id
2340
+ );
2341
+ }
1970
2342
  if (item.flyoutItems && item.flyoutItems.length > 0) {
1971
2343
  const activeSet = new Set(item.flyoutActiveIds ?? []);
1972
2344
  return /* @__PURE__ */ jsx15(
@@ -2014,7 +2386,7 @@ function SidebarLayoutInner({
2014
2386
  showLabel: showLabels
2015
2387
  },
2016
2388
  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(
2389
+ ) : /* @__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
2390
  Link,
2019
2391
  {
2020
2392
  href: item.href,
@@ -2024,32 +2396,22 @@ function SidebarLayoutInner({
2024
2396
  }
2025
2397
  ) }, item.id);
2026
2398
  }) }),
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 }),
2399
+ (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
2400
  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
- })()
2401
+ hasProfile && /* @__PURE__ */ jsx15(
2402
+ ProfileAvatar,
2403
+ {
2404
+ user: user ?? void 0,
2405
+ isLoading,
2406
+ onLogout,
2407
+ onSettingsClick,
2408
+ settingsHref,
2409
+ showDetails: showLabels,
2410
+ appearance,
2411
+ LinkComponent: Link,
2412
+ children: profileMenuItems
2413
+ }
2414
+ )
2053
2415
  ] })
2054
2416
  ] }),
2055
2417
  panel != null && /* @__PURE__ */ jsx15(SidebarPanel, { children: panel })
@@ -2083,7 +2445,7 @@ function SidebarLayout({
2083
2445
  }
2084
2446
 
2085
2447
  // src/dashboard/profile-selector.tsx
2086
- import { Check as Check2, ChevronDown, Plus as Plus3, Settings } from "lucide-react";
2448
+ import { Check as Check3, ChevronDown, Plus as Plus3, Settings } from "lucide-react";
2087
2449
  import { Button as Button2 } from "@tangle-network/ui/primitives";
2088
2450
  import { Badge } from "@tangle-network/ui/primitives";
2089
2451
  import {
@@ -2124,7 +2486,7 @@ function ProfileSelector({
2124
2486
  className: "flex items-center justify-between",
2125
2487
  children: [
2126
2488
  /* @__PURE__ */ jsx16("span", { children: placeholder }),
2127
- !selectedId && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2489
+ !selectedId && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2128
2490
  ]
2129
2491
  }
2130
2492
  ),
@@ -2145,7 +2507,7 @@ function ProfileSelector({
2145
2507
  profile.extends
2146
2508
  ] })
2147
2509
  ] }),
2148
- selectedId === profile.id && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2510
+ selectedId === profile.id && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2149
2511
  ] }),
2150
2512
  profile.description && /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description })
2151
2513
  ]
@@ -2167,7 +2529,7 @@ function ProfileSelector({
2167
2529
  /* @__PURE__ */ jsx16("span", { className: "font-medium", children: profile.name }),
2168
2530
  profile.model && /* @__PURE__ */ jsx16(Badge, { variant: "secondary", className: "border-0 text-xs", children: profile.model.split("/").pop() })
2169
2531
  ] }),
2170
- selectedId === profile.id && /* @__PURE__ */ jsx16(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2532
+ selectedId === profile.id && /* @__PURE__ */ jsx16(Check3, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
2171
2533
  ] }),
2172
2534
  profile.description && /* @__PURE__ */ jsx16("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description }),
2173
2535
  showMetrics && profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs15("div", { className: "flex gap-3 text-muted-foreground text-xs", children: [
@@ -2285,7 +2647,7 @@ function ProfileComparison({
2285
2647
  }
2286
2648
 
2287
2649
  // src/dashboard/metric-area-chart.tsx
2288
- import * as React8 from "react";
2650
+ import * as React9 from "react";
2289
2651
  import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2290
2652
  var TONE_VARS = {
2291
2653
  primary: "var(--brand-primary, hsl(var(--primary)))",
@@ -2332,7 +2694,7 @@ function MetricAreaChart({
2332
2694
  emptyState,
2333
2695
  className
2334
2696
  }) {
2335
- const gradientId = React8.useId();
2697
+ const gradientId = React9.useId();
2336
2698
  const width = 400;
2337
2699
  const values = points.map((p) => p.value).filter((v) => v !== null);
2338
2700
  const latest = values.length > 0 ? values[values.length - 1] : null;
@@ -2392,7 +2754,7 @@ function MetricAreaChart({
2392
2754
  /* @__PURE__ */ jsx17("stop", { offset: "0%", stopColor: color, stopOpacity: 0.28 }),
2393
2755
  /* @__PURE__ */ jsx17("stop", { offset: "100%", stopColor: color, stopOpacity: 0.02 })
2394
2756
  ] }) }),
2395
- segments.map((segment) => /* @__PURE__ */ jsxs16(React8.Fragment, { children: [
2757
+ segments.map((segment) => /* @__PURE__ */ jsxs16(React9.Fragment, { children: [
2396
2758
  /* @__PURE__ */ jsx17("path", { d: segment.area, fill: `url(#${gradientId})` }),
2397
2759
  /* @__PURE__ */ jsx17(
2398
2760
  "path",
@@ -2421,7 +2783,7 @@ function MetricAreaChart({
2421
2783
 
2422
2784
  // src/dashboard/variant-list.tsx
2423
2785
  import {
2424
- Check as Check3,
2786
+ Check as Check4,
2425
2787
  CheckCircle2,
2426
2788
  Clock as Clock3,
2427
2789
  ExternalLink as ExternalLink2,
@@ -2568,7 +2930,7 @@ function VariantList({
2568
2930
  },
2569
2931
  disabled: isActioning === variant.id,
2570
2932
  children: [
2571
- /* @__PURE__ */ jsx18(Check3, { className: "mr-1 h-3 w-3" }),
2933
+ /* @__PURE__ */ jsx18(Check4, { className: "mr-1 h-3 w-3" }),
2572
2934
  "Accept"
2573
2935
  ]
2574
2936
  }
@@ -2617,14 +2979,14 @@ function VariantList({
2617
2979
 
2618
2980
  // src/dashboard/system-logs.tsx
2619
2981
  import { Terminal as Terminal2 } from "lucide-react";
2620
- import { useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
2982
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState6 } from "react";
2621
2983
  import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
2622
2984
  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(() => {
2985
+ const [logs, setLogs] = useState6([]);
2986
+ const [error, setError] = useState6(null);
2987
+ const [isFollowing, setIsFollowing] = useState6(true);
2988
+ const scrollRef = useRef4(null);
2989
+ useEffect4(() => {
2628
2990
  let timeoutId;
2629
2991
  let backoff = 2e3;
2630
2992
  const controller = new AbortController();
@@ -2660,7 +3022,7 @@ function SystemLogsViewer({ apiUrl, token, className }) {
2660
3022
  clearTimeout(timeoutId);
2661
3023
  };
2662
3024
  }, [apiUrl, token]);
2663
- useEffect3(() => {
3025
+ useEffect4(() => {
2664
3026
  if (isFollowing && scrollRef.current) {
2665
3027
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
2666
3028
  }
@@ -2867,14 +3229,14 @@ function GitPanel({ status, log, loading = false, onRefresh, className }) {
2867
3229
  }
2868
3230
 
2869
3231
  // 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";
3232
+ import * as React11 from "react";
3233
+ import { Copy as Copy3, Check as Check5, Globe, Plus as Plus4, Trash2 as Trash23 } from "lucide-react";
2872
3234
  import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
2873
3235
  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(() => {
3236
+ const [newPort, setNewPort] = React11.useState("");
3237
+ const [copiedPort, setCopiedPort] = React11.useState(null);
3238
+ const copyTimerRef = React11.useRef(null);
3239
+ React11.useEffect(() => {
2878
3240
  return () => {
2879
3241
  if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
2880
3242
  };
@@ -2914,7 +3276,7 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
2914
3276
  className: "flex items-center gap-2 font-mono text-xs text-primary hover:underline cursor-pointer group",
2915
3277
  children: [
2916
3278
  /* @__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" })
3279
+ 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
3280
  ]
2919
3281
  }
2920
3282
  ) }),
@@ -2968,7 +3330,7 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
2968
3330
  }
2969
3331
 
2970
3332
  // src/dashboard/process-list.tsx
2971
- import * as React11 from "react";
3333
+ import * as React12 from "react";
2972
3334
  import { Activity as Activity3, Plus as Plus5, Skull, Terminal as Terminal3 } from "lucide-react";
2973
3335
  import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
2974
3336
  function formatUptime(startedAt) {
@@ -2980,7 +3342,7 @@ function formatUptime(startedAt) {
2980
3342
  return `${Math.floor(ms / 36e5)}h ${Math.floor(ms % 36e5 / 6e4)}m`;
2981
3343
  }
2982
3344
  function ProcessList({ processes, onSpawn, onKill, loading = false, className }) {
2983
- const [newCommand, setNewCommand] = React11.useState("");
3345
+ const [newCommand, setNewCommand] = React12.useState("");
2984
3346
  const handleSpawn = () => {
2985
3347
  const cmd = newCommand.trim();
2986
3348
  if (cmd) {
@@ -3053,11 +3415,11 @@ function ProcessList({ processes, onSpawn, onKill, loading = false, className })
3053
3415
  }
3054
3416
 
3055
3417
  // src/dashboard/network-config.tsx
3056
- import * as React12 from "react";
3418
+ import * as React13 from "react";
3057
3419
  import { Network as Network2, Plus as Plus6, Trash2 as Trash24, ShieldAlert } from "lucide-react";
3058
3420
  import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
3059
3421
  function NetworkConfig({ config, onUpdate, loading = false, className }) {
3060
- const [newCidr, setNewCidr] = React12.useState("");
3422
+ const [newCidr, setNewCidr] = React13.useState("");
3061
3423
  const isValidCidr = (value) => {
3062
3424
  const match = value.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/);
3063
3425
  if (!match) return false;
@@ -3161,7 +3523,7 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
3161
3523
  }
3162
3524
 
3163
3525
  // src/dashboard/backend-config.tsx
3164
- import * as React13 from "react";
3526
+ import * as React14 from "react";
3165
3527
  import { Bot, Plus as Plus7, RefreshCw as RefreshCw2, Trash2 as Trash25, Server, Wrench } from "lucide-react";
3166
3528
  import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3167
3529
  function BackendConfig({
@@ -3173,10 +3535,10 @@ function BackendConfig({
3173
3535
  loading = false,
3174
3536
  className
3175
3537
  }) {
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("");
3538
+ const [showAddMcp, setShowAddMcp] = React14.useState(false);
3539
+ const [mcpName, setMcpName] = React14.useState("");
3540
+ const [mcpCommand, setMcpCommand] = React14.useState("");
3541
+ const [mcpArgs, setMcpArgs] = React14.useState("");
3180
3542
  const handleAddMcp = () => {
3181
3543
  const name = mcpName.trim();
3182
3544
  const command = mcpCommand.trim();
@@ -3334,7 +3696,7 @@ function BackendConfig({
3334
3696
  }
3335
3697
 
3336
3698
  // src/dashboard/snapshot-list.tsx
3337
- import * as React14 from "react";
3699
+ import * as React15 from "react";
3338
3700
  import { Camera, Clock as Clock5, HardDrive as HardDrive2, Plus as Plus8, RotateCcw } from "lucide-react";
3339
3701
  import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
3340
3702
  function formatBytes(bytes) {
@@ -3351,8 +3713,8 @@ function formatDate(dateStr) {
3351
3713
  return d.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
3352
3714
  }
3353
3715
  function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loading = false, className }) {
3354
- const [showCreate, setShowCreate] = React14.useState(false);
3355
- const [tags, setTags] = React14.useState("");
3716
+ const [showCreate, setShowCreate] = React15.useState(false);
3717
+ const [tags, setTags] = React15.useState("");
3356
3718
  const handleCreate = () => {
3357
3719
  const tagList = tags.trim() ? tags.trim().split(",").map((t) => t.trim()).filter(Boolean) : void 0;
3358
3720
  onCreate(tagList);
@@ -3513,6 +3875,7 @@ export {
3513
3875
  RailTooltip,
3514
3876
  RailThemeToggle,
3515
3877
  RailCollapseToggle,
3878
+ RailHeader,
3516
3879
  Sidebar,
3517
3880
  SidebarRail,
3518
3881
  SidebarRailHeader,
@@ -3521,6 +3884,7 @@ export {
3521
3884
  RailSeparator,
3522
3885
  RailButton,
3523
3886
  RailFlyout,
3887
+ RailExpandable,
3524
3888
  RailModeButton,
3525
3889
  SidebarPanel,
3526
3890
  SidebarPanelHeader,