@@ -38,7 +45,7 @@ export function Sidebar(): React.ReactNode {
active={connected}
icon="channel"
label={connected ? "实时连接" : "未连接"}
- onClick={() => {}}
+ onClick={onNavigate}
hint={wsStatus}
/>
@@ -52,12 +59,18 @@ export function Sidebar(): React.ReactNode {
{ window.location.hash = "#/admin/system"; }}
+ onClick={() => {
+ window.location.hash = "#/admin/system";
+ onNavigate();
+ }}
/>
{ window.location.hash = "#/admin"; }}
+ onClick={() => {
+ window.location.hash = "#/admin";
+ onNavigate();
+ }}
/>
{!hasToken ? 未登录 : null}
+ >
+ );
+}
+
+/** Desktop left rail. */
+export function Sidebar(): React.ReactNode {
+ return (
+
);
}
+/** Mobile drawer — overlay + scrim + spring slide-in panel. */
+export function MobileNav({ open, onClose }: { open: boolean; onClose: () => void }): React.ReactNode {
+ if (!open) return null;
+ return (
+
+ {/* scrim */}
+
+ {/* panel */}
+
+
+ );
+}
+
function NavItem({
icon,
label,
diff --git a/frontend/web/src/components/TopBar.tsx b/frontend/web/src/components/TopBar.tsx
index b3109c6..606a169 100644
--- a/frontend/web/src/components/TopBar.tsx
+++ b/frontend/web/src/components/TopBar.tsx
@@ -25,7 +25,7 @@ const wsMeta: Record
void }): React.ReactNode {
const wsStatus = useAppStore((s) => s.wsStatus);
const mood = useAppStore((s) => s.mood);
const currentPersona = useAppStore((s) => s.currentPersona);
@@ -41,12 +41,21 @@ export function TopBar(): React.ReactNode {
const meta = wsMeta[wsStatus];
return (
-
-
-
})
-
-
Cyrene · 昔涟
-
+
+
+
+
+
})
+
+
Cyrene · {currentPersona?.name ?? "昔涟"}
+
{MODE_LABEL[mode]}
@@ -57,11 +66,11 @@ export function TopBar(): React.ReactNode {
- {mood ? 心情 · {mood} : null}
+ {mood ? 心情 · {mood} : null}
-
+
{meta.label}
@@ -70,14 +79,14 @@ export function TopBar(): React.ReactNode {
onClick={() => { window.location.hash = "#/admin"; }}
aria-label="管理面板"
title="管理面板 /admin"
- className="inline-flex h-8 w-8 items-center justify-center rounded-[var(--mu-radius)] bg-[var(--mu-surface-4)] text-sm transition-all duration-200 ease-[var(--mu-spring)] hover:bg-[var(--mu-surface-5)] active:scale-95"
+ className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--mu-radius)] bg-[var(--mu-surface-4)] text-sm transition-all duration-200 ease-[var(--mu-spring)] hover:bg-[var(--mu-surface-5)] active:scale-95"
>
diff --git a/frontend/web/src/styles/index.css b/frontend/web/src/styles/index.css
index 9157ccf..ed8761b 100644
--- a/frontend/web/src/styles/index.css
+++ b/frontend/web/src/styles/index.css
@@ -153,3 +153,13 @@ textarea {
.mu-awaken {
animation: mu-awaken 1.2s var(--mu-spring) ease-in-out;
}
+
+/* 移动端抽屉(MobileNav)滑入:从左侧收起,弹簧过冲,仅一次性入场 */
+@keyframes mu-drawer-in {
+ from {
+ transform: translateX(-100%);
+ }
+ to {
+ transform: translateX(0);
+ }
+}