@raingor/pi-web-switch 0.4.3 → 0.5.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,106 +7,110 @@ import {
7
7
  Plug,
8
8
  Users,
9
9
  Globe,
10
+ ChevronDown,
11
+ X,
12
+ Orbit,
13
+ Gauge,
10
14
  } from "lucide-react";
11
15
  import { cn } from "@/lib/utils";
12
16
  import { useTranslation, LANGUAGES } from "@/lib/i18n";
13
17
  import { useState } from "react";
14
18
 
15
19
  const navItems = [
16
- { to: "/", icon: LayoutDashboard, key: "nav.dashboard" },
17
- { to: "/sessions", icon: History, key: "nav.sessions" },
18
- { to: "/memory", icon: Brain, key: "nav.memory" },
19
- { to: "/providers", icon: Plug, key: "nav.providers_models" },
20
- { to: "/subagents", icon: Users, key: "nav.subagents" },
21
- { to: "/settings", icon: Settings, key: "nav.settings" },
20
+ { to: "/", icon: LayoutDashboard, key: "nav.dashboard", code: "01" },
21
+ { to: "/sessions", icon: History, key: "nav.sessions", code: "02" },
22
+ { to: "/memory", icon: Brain, key: "nav.memory", code: "03" },
23
+ { to: "/providers", icon: Plug, key: "nav.providers_models", code: "04" },
24
+ { to: "/subagents", icon: Users, key: "nav.subagents", code: "05" },
25
+ { to: "/settings", icon: Settings, key: "nav.settings", code: "06" },
26
+ { to: "/speed-test", icon: Gauge, key: "nav.speed_test", code: "07" },
22
27
  ];
23
28
 
24
- export function Sidebar() {
29
+ interface SidebarProps {
30
+ mobileOpen?: boolean;
31
+ onClose?: () => void;
32
+ }
33
+
34
+ export function Sidebar({ mobileOpen = false, onClose }: SidebarProps) {
25
35
  const { t, lang, setLang } = useTranslation();
26
36
  const [langOpen, setLangOpen] = useState(false);
27
37
 
28
38
  return (
29
- <aside
30
- className="flex h-screen w-64 flex-col border-r"
31
- style={{
32
- backgroundColor: "var(--sidebar-bg)",
33
- borderColor: "var(--sidebar-border)",
34
- }}
35
- >
36
- {/* Logo */}
37
- <div
38
- className="flex items-center gap-3 border-b px-6 py-5"
39
- style={{ borderColor: "var(--sidebar-border)" }}
40
- >
41
- <img src="/pi.svg" alt="pi-switch" className="h-9 w-9 rounded-lg" />
42
- <div>
43
- <h1 className="text-base font-semibold" style={{ color: "var(--page-text)" }}>pi-switch</h1>
44
- <p className="text-xs" style={{ color: "var(--subtle-text)" }}>{t("app.subtitle")}</p>
39
+ <aside className={cn("command-sidebar", mobileOpen && "is-open")}>
40
+ <div className="sidebar-edge" aria-hidden="true" />
41
+
42
+ <div className="brand-block">
43
+ <div className="brand-mark">
44
+ <img src="/pi.svg" alt="pi-switch" />
45
+ <span className="brand-orbit" aria-hidden="true" />
46
+ </div>
47
+ <div className="min-w-0">
48
+ <div className="brand-name">pi-switch</div>
49
+ <div className="brand-subtitle">{t("app.subtitle")}</div>
45
50
  </div>
51
+ <button className="sidebar-close" aria-label="Close navigation" onClick={onClose}>
52
+ <X className="h-4 w-4" />
53
+ </button>
54
+ </div>
55
+
56
+ <div className="sidebar-system-label">
57
+ <span>CONTROL MATRIX</span>
58
+ <span className="sidebar-label-line" />
46
59
  </div>
47
60
 
48
- {/* Navigation */}
49
- <nav className="flex-1 space-y-1 px-3 py-4">
50
- {navItems.map(({ to, icon: Icon, key }) => (
61
+ <nav className="command-nav">
62
+ {navItems.map(({ to, icon: Icon, key, code }) => (
51
63
  <NavLink
52
64
  key={to}
53
65
  to={to}
54
66
  end={to === "/"}
55
- className={({ isActive }) =>
56
- cn(
57
- "flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
58
- )
59
- }
60
- style={({ isActive }) => ({
61
- backgroundColor: isActive ? "var(--sidebar-active-bg)" : "transparent",
62
- color: isActive ? "var(--sidebar-active-text)" : "var(--sidebar-text)",
63
- })}
67
+ onClick={onClose}
68
+ className={({ isActive }) => cn("command-nav-item", isActive && "is-active")}
64
69
  >
65
- <Icon className="h-4 w-4" />
66
- {t(key)}
70
+ <span className="nav-code">{code}</span>
71
+ <span className="nav-icon"><Icon className="h-4 w-4" /></span>
72
+ <span className="nav-label">{t(key)}</span>
73
+ <span className="nav-signal" aria-hidden="true" />
67
74
  </NavLink>
68
75
  ))}
69
76
  </nav>
70
77
 
71
- {/* Language Switcher */}
72
- <div className="border-t px-3 py-3" style={{ borderColor: "var(--sidebar-border)" }}>
73
- <button
74
- onClick={() => setLangOpen(!langOpen)}
75
- className="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors"
76
- style={{ color: "var(--sidebar-text)" }}
77
- >
78
- <Globe className="h-4 w-4" />
79
- <span className="flex-1 text-left">{LANGUAGES.find((l) => l.code === lang)?.nativeLabel || "English"}</span>
80
- </button>
81
- {langOpen && (
82
- <div className="mt-1 space-y-0.5 px-1">
83
- {LANGUAGES.map((l) => (
84
- <button
85
- key={l.code}
86
- onClick={() => { setLang(l.code); setLangOpen(false); }}
87
- className={cn(
88
- "flex w-full items-center gap-3 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors",
89
- lang === l.code ? "bg-blue-600/10 text-blue-400" : ""
90
- )}
91
- style={{
92
- color: lang === l.code ? "var(--sidebar-active-text)" : "var(--sidebar-text)",
93
- backgroundColor: lang === l.code ? "var(--sidebar-active-bg)" : "transparent",
94
- }}
95
- >
96
- {l.nativeLabel}
97
- </button>
98
- ))}
78
+ <div className="sidebar-footer">
79
+ <div className="node-status">
80
+ <div className="node-status-icon"><Orbit className="h-4 w-4" /></div>
81
+ <div>
82
+ <span className="node-status-label">LOCAL NODE</span>
83
+ <span className="node-status-value"><i /> SYSTEM ONLINE</span>
99
84
  </div>
100
- )}
101
- </div>
85
+ </div>
102
86
 
103
- {/* Version */}
104
- <div
105
- className="border-t px-6 py-3"
106
- style={{ borderColor: "var(--sidebar-border)" }}
107
- >
108
- <p className="text-xs" style={{ color: "var(--subtle-text)" }}>{t("app.version")}</p>
87
+ <div className="language-panel">
88
+ <button onClick={() => setLangOpen(!langOpen)} className="language-trigger">
89
+ <Globe className="h-4 w-4" />
90
+ <span>{LANGUAGES.find((l) => l.code === lang)?.nativeLabel || "English"}</span>
91
+ <ChevronDown className={cn("ml-auto h-3.5 w-3.5 transition-transform", langOpen && "rotate-180")} />
92
+ </button>
93
+ {langOpen && (
94
+ <div className="language-menu">
95
+ {LANGUAGES.map((l) => (
96
+ <button
97
+ key={l.code}
98
+ onClick={() => { setLang(l.code); setLangOpen(false); }}
99
+ className={cn("language-option", lang === l.code && "is-selected")}
100
+ >
101
+ <span>{l.nativeLabel}</span>
102
+ {lang === l.code && <i />}
103
+ </button>
104
+ ))}
105
+ </div>
106
+ )}
107
+ </div>
108
+
109
+ <div className="version-strip">
110
+ <span>{t("app.version")}</span>
111
+ <span>BUILD // STABLE</span>
112
+ </div>
109
113
  </div>
110
114
  </aside>
111
115
  );
112
- }
116
+ }