From 8f9d72c05f9dbd812aba3a0d48699589ee235118 Mon Sep 17 00:00:00 2001 From: Aisland Date: Tue, 1 Sep 2026 02:03:46 +0800 Subject: [PATCH] feat(console): card shape selector (square/circle) + circle-mode layout/fonts + done-glow re-light fix --- 01_content/src/client/index.tsx | 16 ++++++++++++++++ 01_content/src/client/locales.ts | 6 ++++++ 01_content/src/client/split.tsx | 15 ++++++++++++++- 01_content/src/client/styles.ts | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/01_content/src/client/index.tsx b/01_content/src/client/index.tsx index 1833676..df9c63b 100644 --- a/01_content/src/client/index.tsx +++ b/01_content/src/client/index.tsx @@ -69,6 +69,8 @@ type ViewState = { consoleTheme?: 'dark' | 'light' | 'system' /** 控制室每行显示项目数(1-5,默认 3)*/ consoleCols?: number + /** 控制室卡片形状:square/circle(默认 square)*/ + consoleShape?: 'square' | 'circle' } /** 卡片上报的项目元信息(协议 v2)。 */ @@ -295,6 +297,7 @@ function loadView(): ViewState { floatTop: typeof p.floatTop === 'number' ? p.floatTop : null, consoleTheme: p.consoleTheme === 'dark' || p.consoleTheme === 'light' || p.consoleTheme === 'system' ? p.consoleTheme : 'system', consoleCols: typeof p.consoleCols === 'number' && p.consoleCols >= 1 && p.consoleCols <= 5 ? Math.round(p.consoleCols) : 3, + consoleShape: p.consoleShape === 'circle' ? 'circle' : 'square', } } catch { return { ...DEFAULT_VIEW } @@ -921,6 +924,8 @@ function buildMountContent(folder: string, d: any): any { /** 每会话最近一次观察到的「需要判断」布尔值:状态转移时清除旧 ack(新一轮待决重新点亮) */ const notifyStateSeenRef: { current: Record } = { current: {} } +/** 每会话最近观察到的「已完成」布尔值:新一次完成时清除旧 done ack(控制室绿光重新点亮) */ +const doneSeenRef: { current: Record } = { current: {} } /** 清除某会话的 ack 记录(状态转移时调用,保证新问题不会被旧确认压住) */ function clearNotifyAck(sid: string) { try { @@ -1196,6 +1201,11 @@ function WorktableSection(props: any) { if (Array.isArray(face?.pending) && face.pending.length > 0) return 'need' } catch {} if (e.completed === true) return 'done' + // 会话面兜底:宿主快照可能滞后或缺少完成字段 + try { + const face = sessionBridge?.sessions?.binding?.(sid)?.session?.getSnapshot?.() + if (face && face.completed === true) return 'done' + } catch {} if (e.running === true) return 'busy' return 'idle' } @@ -1328,6 +1338,8 @@ function WorktableSection(props: any) { setTheme: (th: 'dark' | 'light' | 'system') => persistView({ consoleTheme: th }), getCols: () => viewRef.current.consoleCols ?? 3, setCols: (n: number) => persistView({ consoleCols: n }), + getShape: () => viewRef.current.consoleShape ?? 'square', + setShape: (s: 'square' | 'circle') => persistView({ consoleShape: s }), onAck: (id) => { ackRef.current?.(id); setNotifyTick((t) => t + 1); notifyConsole() }, refreshPreviews: () => { if (previewTimer != null) { window.clearTimeout(previewTimer); previewTimer = null } @@ -1837,11 +1849,15 @@ function buildCustomLayoutPrompt(req: string): string { const e = byId[sid] if (!e) continue if (e.completed === true) { + // 新一次完成 → 清除旧 done ack,控制室绿光重新点亮(即使旧完成已被确认过) + if (doneSeenRef.current[sid] !== true) clearNotifyAck(sid) + doneSeenRef.current[sid] = true if (!mountConsumedRef.current.has(sid)) { mountConsumedRef.current.add(sid) tryAutoMount(pid, sid) } } else { + doneSeenRef.current[sid] = false mountConsumedRef.current.delete(sid) } } diff --git a/01_content/src/client/locales.ts b/01_content/src/client/locales.ts index bb9470e..a77edbb 100644 --- a/01_content/src/client/locales.ts +++ b/01_content/src/client/locales.ts @@ -118,6 +118,9 @@ export const zh = { 'console.themeLabel': '面板主题', 'console.cols': '每行', 'console.colsLabel': '每行显示项目数', + 'console.shapeLabel': '卡片形状', + 'console.shapeSquare': '方形', + 'console.shapeCircle': '圆形', 'console.themeDark': '深色', 'console.themeLight': '白色', 'console.themeSystem': '跟随系统', @@ -298,6 +301,9 @@ export const en = { 'console.themeLabel': 'Panel theme', 'console.cols': 'Per row', 'console.colsLabel': 'Projects per row', + 'console.shapeLabel': 'Card shape', + 'console.shapeSquare': 'Square', + 'console.shapeCircle': 'Circle', 'console.themeDark': 'Dark', 'console.themeLight': 'Light', 'console.themeSystem': 'System', diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index d34dfd2..3321da4 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -1017,6 +1017,7 @@ function ConsolePane() { const [, setTick] = useState(0) const [now, setNow] = useState(() => Date.now()) const [cols, setColsState] = useState(() => splitEnv?.console?.getCols?.() ?? 3) + const [shape, setShapeState] = useState<'square' | 'circle'>(() => splitEnv?.console?.getShape?.() ?? 'square') const gridRef = useRef(null) const firstRectsRef = useRef | null>(null) const onCols = (n: number) => { @@ -1033,6 +1034,10 @@ function ConsolePane() { setColsState(n) splitEnv?.console?.setCols?.(n) } + const onShape = (s: 'square' | 'circle') => { + setShapeState(s) + splitEnv?.console?.setShape?.(s) + } useLayoutEffect(() => { const first = firstRectsRef.current if (!first) return @@ -1108,8 +1113,16 @@ function ConsolePane() { { mode: 'system', icon: '🖥️', key: 'console.themeSystem' }, ] return ( -
+
+
+ + +
{themeOpts.map((o) => (