feat(ui): 工作台精修 + 拆分(P3-3..7)
- Workbench.tsx 937→467 行,抽出 AiToolbar/WorkbenchToolbar/MobileContextBar - P3-3 AI 工具条分组留白 + 眉题 + 主 CTA 凸显 - P3-4 专注写作模式(useFocusMode hook+vitest,隐藏侧栏加宽正文)+ 左双栏面色区分 - P3-5 右栏本章参考小标题去衬线(font-sans) + 空态引导(无标题保 h2→h3 大纲) - P3-6 底栏信息/操作/状态三区 + TOC 当前章高亮;TOC 状态点因无每章状态数据跳过 - P3-7 展示层流式跟随滚动(不触碰 SSE 逻辑,尊重 reduced-motion) - AppShell 加可选 hideNav(加法式,默认 false)
This commit is contained in:
46
apps/web/lib/workbench/useFocusMode.ts
Normal file
46
apps/web/lib/workbench/useFocusMode.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
// 「专注写作」偏好的持久化键(对齐既有 `ww.` 前缀约定)。
|
||||
export const FOCUS_MODE_KEY = "ww.workbench_focus_mode";
|
||||
|
||||
export interface FocusMode {
|
||||
// true=专注模式:隐藏左侧图标导航 + 目录 TOC,让宽给正文;false=常规四栏。
|
||||
focus: boolean;
|
||||
toggle: () => void;
|
||||
}
|
||||
|
||||
function persist(focus: boolean): void {
|
||||
if (typeof window === "undefined") return;
|
||||
try {
|
||||
window.localStorage.setItem(FOCUS_MODE_KEY, focus ? "1" : "0");
|
||||
} catch {
|
||||
// 隐私模式/配额异常忽略:专注模式是纯 UI 偏好,写盘失败不影响写作功能。
|
||||
}
|
||||
}
|
||||
|
||||
// 记住「专注写作」开关(P3-4):SSR 首帧恒关(避免 hydration 不一致),
|
||||
// 挂载后再从 localStorage 恢复;toggle 即时写回。仅桌面(≥xl)改变栅格,窄屏本就单列不受影响。
|
||||
export function useFocusMode(): FocusMode {
|
||||
const [focus, setFocus] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
try {
|
||||
setFocus(window.localStorage.getItem(FOCUS_MODE_KEY) === "1");
|
||||
} catch {
|
||||
// 读盘失败则维持默认关闭。
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setFocus((prev) => {
|
||||
const next = !prev;
|
||||
persist(next);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return { focus, toggle };
|
||||
}
|
||||
Reference in New Issue
Block a user