Skip to content

Commit 8fc8719

Browse files
committed
refactor(ui): 迁入 Surface 受控槽与只出边框档的落点
1 parent 9755d47 commit 8fc8719

24 files changed

Lines changed: 241 additions & 194 deletions

‎app/src/components/AiProviderSettings.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import { useEffect, useState } from "react";
1414
import { invoke } from "@tauri-apps/api/core";
1515
import type { AiProviderInput, AiProviderView } from "../types";
16-
import { ConfirmDialog, Button, EmptyState, StatusLine } from "../ui/primitives";
16+
import { ConfirmDialog, Button, EmptyState, StatusLine, Surface } from "../ui/primitives";
1717

1818
const btn: React.CSSProperties = {
1919
padding: "5px 10px",
@@ -160,7 +160,7 @@ export default function AiProviderSettings() {
160160
)}
161161

162162
{providers.map((p) => (
163-
<div key={p.id} style={{ border: "1px solid #e5e7eb", borderRadius: 6, padding: 8, marginBottom: 8 }}>
163+
<Surface key={p.id} level="none" radius="panel" style={{ padding: 8, marginBottom: 8 }}>
164164
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
165165
<span style={{ fontWeight: 600 }}>{p.name}</span>
166166
{p.isDefault && <span style={{ color: "#0d9488", fontWeight: 600 }}>● 默认</span>}
@@ -218,7 +218,7 @@ export default function AiProviderSettings() {
218218
</Button>
219219
</div>
220220
)}
221-
</div>
221+
</Surface>
222222
))}
223223

224224
{showAdd && (

‎app/src/components/AiServicePanel.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { invoke } from "@tauri-apps/api/core";
1313
import type { AiAuditEntry, AiSettingsView, RefineStrategyMeta } from "../types";
1414
import RefineStrategyPicker from "./RefineStrategyPicker";
1515
import { draftFromPrefs, prefsFromDraft, type StrategyDraft } from "../utils/refineStrategy";
16-
import { Button, EmptyState, StatusLine, Text } from "../ui/primitives";
16+
import { Button, EmptyState, StatusLine, Surface, Text } from "../ui/primitives";
1717

1818
/** 通用小按钮样式(与各设置面板一致) */
1919
const btn: React.CSSProperties = {
@@ -259,7 +259,7 @@ export default function AiServicePanel() {
259259
{audit.length === 0 ? (
260260
<EmptyState title="暂无调用记录" compact />
261261
) : (
262-
<div style={{ maxHeight: 140, overflowY: "auto", border: "1px solid #e5e7eb", borderRadius: 6 }}>
262+
<Surface level="none" radius="panel" style={{ maxHeight: 140, overflowY: "auto" }}>
263263
{audit.map((a, i) => (
264264
<div key={i} style={{ display: "flex", gap: 8, padding: "4px 8px", borderBottom: "1px solid #f3f4f6" }}>
265265
<span style={{ color: "#6b7280", width: 64, flexShrink: 0 }}>{fmtTime(a.at_unix)}</span>
@@ -269,7 +269,7 @@ export default function AiServicePanel() {
269269
<StatusLine kind={a.result === "ok" ? "ok" : "error"}>{a.result}</StatusLine>
270270
</div>
271271
))}
272-
</div>
272+
</Surface>
273273
)}
274274
</div>
275275

‎app/src/components/AiTaskPanel.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { invoke } from "@tauri-apps/api/core";
1515
import type { AiEnrichResult, AiRefineResult, AiTaskRecord } from "../types";
1616
// 低5(审查):类别词经 entityLabel.kindWord 单一来源(不带 id 的语义词)
1717
import { kindWord } from "../utils/entityLabel";
18-
import { Button, EmptyState, StatusLine, Text } from "../ui/primitives";
18+
import { Button, EmptyState, StatusLine, Surface, Text } from "../ui/primitives";
1919

2020
const btn: React.CSSProperties = { padding: "3px 8px", fontSize: 11, borderRadius: 5, border: "1px solid #d1d5db", background: "#fff", cursor: "pointer" };
2121

@@ -154,7 +154,7 @@ export default function AiTaskPanel() {
154154
{tasks.length === 0 ? (
155155
<EmptyState title="暂无任务记录" description="精修/补充完成后自动记录" compact />
156156
) : (
157-
<div style={{ maxHeight: 200, overflowY: "auto", border: "1px solid #e5e7eb", borderRadius: 6 }}>
157+
<Surface level="none" radius="panel" style={{ maxHeight: 200, overflowY: "auto" }}>
158158
{tasks.map((t) => {
159159
const badge = stateBadge(t.state);
160160
return (
@@ -188,7 +188,7 @@ export default function AiTaskPanel() {
188188
</div>
189189
);
190190
})}
191-
</div>
191+
</Surface>
192192
)}
193193

194194
{/* 结果摘要 + 采纳(防重复采纳:采纳后任务标记 adopted,历史中不再可恢复) */}

‎app/src/components/ClassroomCapturePanel.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ import { AUTO_RESUME_HINTS } from "../hooks/liveCaptureState";
2121
import type { CaptureActionKind } from "../hooks/useLiveCaptureControl";
2222
import type { PrepareState } from "../hooks/useClassroomHints";
2323
import type { FloatSnapshot } from "../hooks/useFloatWindow";
24+
import { Surface } from "../ui/primitives";
2425
import type { DownloadProgress, PauseSource, StreamingModelStatus } from "../types";
2526

2627
const btn: React.CSSProperties = { padding: "6px 12px", cursor: "pointer", fontSize: 13 };
27-
const panel: React.CSSProperties = { border: "1px solid #e5e7eb", borderRadius: 8, padding: 12 };
2828

2929
/** 采集卡暂停状态行文案(按 reason 三态;沿用原横幅语义——媒体暂停含"自动继续"
3030
* 说明,前台切走含"回窗即继续"说明;徽标/右栏/浮窗用短文案 pauseReasonLabel) */
@@ -106,7 +106,7 @@ export default function ClassroomCapturePanel({
106106
pausedReason === "media" || pausedReason === "foreground" ? AUTO_RESUME_HINTS[pausedReason] : undefined;
107107

108108
return (
109-
<div style={panel}>
109+
<Surface level="none" radius="panel" padded>
110110
<div style={{ fontSize: 12, color: "#6b7280", marginBottom: 6 }}>
111111
实时捕获{active && <span style={{ color: "#dc2626" }}> ● 录制中</span>}
112112
</div>
@@ -292,6 +292,6 @@ export default function ClassroomCapturePanel({
292292
{sessionId && !starting && (
293293
<p style={{ fontSize: 11, color: "#6b7280", margin: "6px 0 0" }}>实时捕获中(可到「会话」页查看)</p>
294294
)}
295-
</div>
295+
</Surface>
296296
);
297297
}

‎app/src/components/ClassroomRightPane.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
*/
1414
import LiveActivityPanel from "./LiveActivityPanel";
1515
import ProfileDetector from "./ProfileDetector";
16+
import { Surface } from "../ui/primitives";
1617
import { columnSpec } from "../shell/columnRegistry";
1718
import type { Note, ProfileKind, WindowInfo } from "../types";
1819

1920
const btn: React.CSSProperties = { padding: "6px 12px", cursor: "pointer", fontSize: 13 };
20-
const panel: React.CSSProperties = { border: "1px solid #e5e7eb", borderRadius: 8, padding: 12 };
2121

2222
/**
2323
* 非采集态内容区的**唯一**宽度上限(规格 §6.2:右面板是 flex 列,「统一 wrapper」)。
@@ -135,14 +135,14 @@ export default function ClassroomRightPane({
135135
<li><strong>添加学习素材</strong>:音频文件(WAV,本地 SenseVoice 转写)与图片(本地 PP-OCRv6 识别)</li>
136136
<li><strong>一键提取</strong>:转写 + OCR → 本地拼接为 Markdown 笔记 → 自动保存</li>
137137
</ol>
138-
<div style={{ ...panel, marginTop: 16, fontSize: 12, color: "#6b7280", lineHeight: 1.9 }}>
138+
<Surface level="none" radius="panel" padded style={{ marginTop: 16, fontSize: 12, color: "#6b7280", lineHeight: 1.9 }}>
139139
<div><strong>当前配置</strong></div>
140140
<div>目标窗口:{selectedWindow ? `${selectedWindow.title}(${selectedWindow.processName || "未知进程"})` : "未选择(实时捕获将抓全屏)"}</div>
141141
<div>流式转写:sherpa-onnx Zipformer(实时字幕,需模型就绪)</div>
142142
<div>转写引擎:sherpa-onnx SenseVoice(本地,已就绪)</div>
143143
<div>OCR 引擎:oar-ocr PP-OCRv6(本地,首次使用自动下载模型)</div>
144144
<div>数据主权:全部本地处理,内容不出本机</div>
145-
</div>
145+
</Surface>
146146
</div>
147147
)}
148148
</div>

‎app/src/components/LiveImageStrip.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ export default function LiveImageStrip({ sessionId }: { sessionId: number | null
107107
{/* 点击放大的大图预览(full 原图) */}
108108
{expanded && baseUrl && (
109109
<div style={{ marginBottom: 6, position: "relative", border: "1px solid #e5e7eb", borderRadius: 6, overflow: "hidden" }}>
110+
{/* ⚠️ 批 7 T7:本处是「透明边框容器」的候选,但本文件是 `SURFACE_TAG_REGISTRY` 的 **legacy 行**
111+
(`≤` 上限只许降)⇒ 迁它会顶红牙 1;抬高 legacy 面属 §C9.5 禁止 ⇒ 留在原地并登记
112+
(见 `surfaceResidual.ts` 的 `legacy-registry-frozen`)。 */}
110113
<img
111114
src={convertFileSrc(`${baseUrl}/${expanded}`)}
112115
alt="关键帧原图"

‎app/src/components/MaterialInputPanel.tsx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ import { open } from "@tauri-apps/plugin-dialog";
1313
import type { Note } from "../types";
1414
// Low 清扫:标题截断长度单一定义源(与 ClassroomPage 共享)
1515
import { NOTE_TITLE_MAX_LEN } from "../utils/constants";
16-
import { Button, Text } from "../ui/primitives";
16+
import { Button, Surface, Text } from "../ui/primitives";
1717

1818
const btn: React.CSSProperties = { padding: "6px 12px", cursor: "pointer", fontSize: 13 };
19-
const panel: React.CSSProperties = { border: "1px solid #e5e7eb", borderRadius: 8, padding: 12 };
2019

2120
interface Props {
2221
/** 标题来源:选定窗口标题(无窗口 → 默认名) */
@@ -63,15 +62,15 @@ export default function MaterialInputPanel({ windowTitle, onNote, onStatus }: Pr
6362
return (
6463
<>
6564
{/* 素材输入(v0.1.0:文件流水线) */}
66-
<div style={panel}>
65+
<Surface level="none" radius="panel" padded>
6766
<div style={{ fontSize: 12, color: "#6b7280", marginBottom: 6 }}>学习素材(文件)</div>
6867
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
6968
<Button variant="secondary" size="lg" busy={processing} onClick={pickAudio}>选音频 WAV</Button>
7069
<Button variant="secondary" size="lg" busy={processing} onClick={pickImages}>选图片(多选)</Button>
7170
</div>
7271
{audioPath && <p style={{ fontSize: 11, color: "#374151", marginTop: 6, wordBreak: "break-all" }}>🎵 {audioPath}</p>}
7372
{imagePaths.length > 0 && <p style={{ fontSize: 11, color: "#374151", marginTop: 4 }}>🖼 已选 {imagePaths.length} 张图片</p>}
74-
</div>
73+
</Surface>
7574

7675
{/* 底部启动按钮(参考原项目"开始回声定位"位置) */}
7776
<div style={{ padding: 12, borderTop: "1px solid #e5e7eb" }}>

‎app/src/components/NotePreviewView.tsx‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { invoke, convertFileSrc } from "@tauri-apps/api/core";
1515
import type { Note, NoteFilterResult, TextFilterDecision, TextFilterReview, TextFilterStatus } from "../types";
1616
import { escapeHtml, renderTimestampAnchors } from "../utils/html";
1717
import AiRefineCard from "./AiRefineCard";
18-
import { ConfirmDialog, Loading, Text } from "../ui/primitives";
18+
import { ConfirmDialog, Loading, Surface, Text } from "../ui/primitives";
1919

2020
const btn: React.CSSProperties = { padding: "5px 10px", cursor: "pointer", fontSize: 12 };
2121

@@ -290,15 +290,21 @@ export default function NotePreviewView({
290290
回到规则版预览
291291
</button>
292292
</div>
293-
<div
294-
style={{ fontSize: 13, lineHeight: 1.6, background: "#fff", border: "1px solid #d1fae5", borderRadius: 6, padding: 12 }}
295-
dangerouslySetInnerHTML={{ __html: renderMarkdown(adopted.content, baseUrl, dataDir) }}
293+
<Surface
294+
level="surface"
295+
radius="panel"
296+
padded
297+
html={renderMarkdown(adopted.content, baseUrl, dataDir)}
298+
style={{ fontSize: 13, lineHeight: 1.6 }}
296299
/>
297300
</div>
298301
) : (
299-
<div
300-
style={{ fontSize: 13, lineHeight: 1.6, background: "#fff", border: "1px solid #e5e7eb", borderRadius: 8, padding: 12 }}
301-
dangerouslySetInnerHTML={{ __html: renderMarkdown(preview.markdown, baseUrl, dataDir) }}
302+
<Surface
303+
level="surface"
304+
radius="panel"
305+
padded
306+
html={renderMarkdown(preview.markdown, baseUrl, dataDir)}
307+
style={{ fontSize: 13, lineHeight: 1.6 }}
302308
/>
303309
)}
304310

‎app/src/components/PhotoCapturePanel.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import { useCallback, useEffect, useState } from "react";
1212
import { invoke } from "@tauri-apps/api/core";
1313
import { convertFileSrc } from "@tauri-apps/api/core";
1414
import { listen } from "@tauri-apps/api/event";
15+
import { Surface } from "../ui/primitives";
1516
import ScreenSelectOverlay from "./ScreenSelectOverlay";
1617

1718
const btn: React.CSSProperties = { padding: "6px 12px", cursor: "pointer", fontSize: 13 };
18-
const panel: React.CSSProperties = { border: "1px solid #e5e7eb", borderRadius: 8, padding: 12 };
1919

2020
interface Props {
2121
onOpenSessions?: (sessionId: number) => void;
@@ -151,7 +151,7 @@ export default function PhotoCapturePanel({ onOpenSessions, onStatus }: Props) {
151151

152152
return (
153153
<>
154-
<div style={panel}>
154+
<Surface level="none" radius="panel" padded>
155155
<div style={{ fontSize: 12, color: "#6b7280", marginBottom: 6 }}>图文采集(截屏导入图文内容)</div>
156156
{phase === "idle" && (
157157
<button
@@ -212,7 +212,7 @@ export default function PhotoCapturePanel({ onOpenSessions, onStatus }: Props) {
212212
</button>
213213
</>
214214
)}
215-
</div>
215+
</Surface>
216216
{snapshot && (
217217
<ScreenSelectOverlay
218218
src={snapshot.src}

‎app/src/components/PracticeQuestionsOverlays.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* (`ActionCenterPanel` 的条件挂载)⇒ `open` 恒为 `true`,160ms 退场相位不触发。
1212
*/
1313
import { useCallback, useEffect, useState } from "react";
14-
import { Button, EmptyState, Modal, Text } from "../ui/primitives";
14+
import { Button, EmptyState, Modal, Surface, Text } from "../ui/primitives";
1515
import { invoke } from "@tauri-apps/api/core";
1616

1717
/** 响应结构(PracticeItem/QuestionItem 均 serde camelCase——字段须 camel 读取) */
@@ -112,15 +112,15 @@ export function PracticeOverlay({ onClose }: { onClose: () => void }) {
112112
) : (
113113
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
114114
{items.map((it) => (
115-
<div key={it.id} style={{ border: "1px solid #e5e7eb", borderRadius: 8, padding: "6px 10px", display: "flex", gap: 6, alignItems: "center" }}>
115+
<Surface key={it.id} level="none" radius="panel" style={{ padding: "6px 10px", display: "flex", gap: 6, alignItems: "center" }}>
116116
<span style={{ fontSize: 12.5, flex: 1 }}>{it.text}</span>
117117
<Text tone="ink-3" style={{ fontSize: 10.5 }}>
118118
{it.frequency === "daily" ? "每日" : "手动"}
119119
{it.mastery != null ? ` · 熟练 ${it.mastery}/5` : ""}
120120
{it.nextDue != null ? ` · 下次 ${new Date(it.nextDue * 1000).toLocaleDateString()}` : ""}
121121
</Text>
122122
<Button variant="primary" size="md" onClick={() => void tick(it)}>🎯 打点</Button>
123-
</div>
123+
</Surface>
124124
))}
125125
</div>
126126
)}
@@ -196,7 +196,7 @@ export function QuestionsOverlay({ onClose }: { onClose: () => void }) {
196196
</div>
197197
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
198198
{open.map((q) => (
199-
<div key={q.id} style={{ border: "1px solid #e5e7eb", borderRadius: 8, padding: "6px 10px" }}>
199+
<Surface key={q.id} level="none" radius="panel" style={{ padding: "6px 10px" }}>
200200
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
201201
<span style={{ fontSize: 12.5, flex: 1 }}>❓ {q.text}</span>
202202
<Button variant="secondary" size="md" onClick={() => setAnswerFor(answerFor === q.id ? null : q.id)}>已答</Button>
@@ -208,7 +208,7 @@ export function QuestionsOverlay({ onClose }: { onClose: () => void }) {
208208
<Button variant="primary" size="md" onClick={() => void answer(q)}>确认</Button>
209209
</div>
210210
)}
211-
</div>
211+
</Surface>
212212
))}
213213
{open.length === 0 && answered.length === 0 && (
214214
<EmptyState title="暂无问题——" description="学习中的疑问随手记下,答沉淀后归档(可转复习卡出口规划中)" />

0 commit comments

Comments
 (0)