Skip to content

Commit 37c068a

Browse files
committed
refactor(ui): migrate empty state call sites
1 parent cbc1583 commit 37c068a

27 files changed

Lines changed: 455 additions & 100 deletions

‎app/src/components/AiConversationDock.tsx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
import { useCallback, useEffect, useRef, useState } from "react";
1818
import { zIndex } from "../ui/zIndex";
19+
import { EmptyState } from "../ui/primitives";
1920
import { invoke } from "@tauri-apps/api/core";
2021
import { listen } from "@tauri-apps/api/event";
2122
import type { AiTaskRecord, AiTaskState, AiTurn, ChatMessage, ChatSession } from "../types";
@@ -156,7 +157,7 @@ export default function AiConversationDock({
156157
const renderList = () => {
157158
if (tab === "task") {
158159
return tasks.length === 0 ? (
159-
<div style={{ padding: 12, fontSize: 12, color: "#9ca3af" }}>暂无精修/补充任务</div>
160+
<EmptyState title="暂无精修/补充任务" compact />
160161
) : (
161162
tasks.map((t) => {
162163
const done = t.state === "succeeded" || t.state === "failed";
@@ -184,7 +185,7 @@ export default function AiConversationDock({
184185
);
185186
}
186187
return chatSessions.length === 0 ? (
187-
<div style={{ padding: 12, fontSize: 12, color: "#9ca3af" }}>暂无对话会话——到「💬 AI 对话」页新建</div>
188+
<EmptyState title="暂无对话会话——" description="到「💬 AI 对话」页新建" compact />
188189
) : (
189190
chatSessions.map((s) => (
190191
<button
@@ -206,7 +207,7 @@ export default function AiConversationDock({
206207
/** 会话详情 v1 只读消息(同源——继续对话请到 AI 对话页) */
207208
const renderChatDetail = () => {
208209
if (messages.length === 0) {
209-
return <div style={{ padding: 14, fontSize: 12, color: "#9ca3af" }}>该会话暂无消息</div>;
210+
return <EmptyState title="该会话暂无消息" compact />;
210211
}
211212
return messages.map((m) => (
212213
<div key={m.id} style={{ marginBottom: 8 }}>

‎app/src/components/AiProviderSettings.tsx‎

Lines changed: 6 additions & 4 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 } from "../ui/primitives";
16+
import { ConfirmDialog, Button, EmptyState } from "../ui/primitives";
1717

1818
const btn: React.CSSProperties = {
1919
padding: "5px 10px",
@@ -152,9 +152,11 @@ export default function AiProviderSettings() {
152152
</div>
153153

154154
{providers.length === 0 && (
155-
<div style={{ color: "#9ca3af", marginBottom: 8 }}>
156-
尚未配置 Provider——添加后即可启用 AI 功能(支持 SiliconFlow/DeepSeek/OpenRouter/Ollama 本地等)。
157-
</div>
155+
<EmptyState
156+
title="尚未配置 Provider——"
157+
description="添加后即可启用 AI 功能(支持 SiliconFlow/DeepSeek/OpenRouter/Ollama 本地等)。"
158+
action={{ label: "+ 添加 Provider", onClick: () => setShowAdd(true) }}
159+
/>
158160
)}
159161

160162
{providers.map((p) => (

‎app/src/components/AiServicePanel.tsx‎

Lines changed: 2 additions & 2 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 } from "../ui/primitives";
16+
import { Button, EmptyState } from "../ui/primitives";
1717

1818
/** 通用小按钮样式(与各设置面板一致) */
1919
const btn: React.CSSProperties = {
@@ -257,7 +257,7 @@ export default function AiServicePanel() {
257257
</button>
258258
</div>
259259
{audit.length === 0 ? (
260-
<div style={{ color: "#9ca3af" }}>暂无调用记录</div>
260+
<EmptyState title="暂无调用记录" compact />
261261
) : (
262262
<div style={{ maxHeight: 140, overflowY: "auto", border: "1px solid #e5e7eb", borderRadius: 6 }}>
263263
{audit.map((a, i) => (

‎app/src/components/AiTaskPanel.tsx‎

Lines changed: 2 additions & 2 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 } from "../ui/primitives";
18+
import { Button, EmptyState } 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

@@ -152,7 +152,7 @@ export default function AiTaskPanel() {
152152
</div>
153153

154154
{tasks.length === 0 ? (
155-
<div style={{ fontSize: 11, color: "#9ca3af", marginBottom: 6 }}>暂无任务记录(精修/补充完成后自动记录)</div>
155+
<EmptyState title="暂无任务记录" description="精修/补充完成后自动记录" compact />
156156
) : (
157157
<div style={{ maxHeight: 200, overflowY: "auto", border: "1px solid #e5e7eb", borderRadius: 6 }}>
158158
{tasks.map((t) => {

‎app/src/components/AsrConfusionPanel.tsx‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99
import { useCallback, useEffect, useState } from "react";
1010
import { invoke } from "@tauri-apps/api/core";
11-
import { Button } from "../ui/primitives";
11+
import { Button, EmptyState, Loading } from "../ui/primitives";
1212

1313
interface AsrPairView {
1414
wrong: string;
@@ -110,9 +110,11 @@ export function AsrConfusionPanel() {
110110
)}
111111
</div>
112112
{candidates.length === 0 ? (
113-
<div style={{ fontSize: 12, color: "#9ca3af" }}>
114-
{view === null ? "加载中…" : "暂无新候选——采纳离线精修草稿后自动积累画像(≥2 次出现才提名)"}
115-
</div>
113+
view === null ? (
114+
<Loading label="加载中…" />
115+
) : (
116+
<EmptyState title="暂无新候选——" description="采纳离线精修草稿后自动积累画像(≥2 次出现才提名)" compact />
117+
)
116118
) : (
117119
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
118120
{candidates.map((c) => (

‎app/src/components/ChatSidebar.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { AiTaskRecord, ChatSession } from "../types";
1414
// 2026-09-09 批 1:任务标题统一按类别解析(taskRefLabel——会话级/笔记级
1515
// 精修 ref_id 语义不同;enrich 恒笔记级),侧栏与对话页/dock 同口径
1616
import { taskRefLabel } from "../utils/entityLabel";
17+
import { EmptyState } from "../ui/primitives";
1718
// 批 3(规格 §6.2「AI 对话侧栏:接入列基础设施」):列宽不再写死——
1819
// 规格住在 shell/columnRegistry,运行时由页面里的 useColumnLayout 执行
1920
import { columnSpec } from "../shell/columnRegistry";
@@ -114,7 +115,7 @@ export default function ChatSidebar(props: ChatSidebarProps) {
114115
</div>
115116
<div style={{ overflowY: "auto", flex: 1, minHeight: 0, padding: "0 8px 8px" }}>
116117
{sessions.length === 0 && (
117-
<div style={{ fontSize: 12, color: "#9ca3af", padding: "4px 8px" }}>还没有对话——点 + 开始</div>
118+
<EmptyState title="还没有对话——" description="点 + 开始" compact align="start" />
118119
)}
119120
{sessions.map((s) => (
120121
<div
@@ -150,7 +151,7 @@ export default function ChatSidebar(props: ChatSidebarProps) {
150151
style={{ fontSize: 12, fontWeight: 600, color: "#6b7280", padding: "14px 8px 4px" }}
151152
title="AI 精修/补充任务的轨迹条目(来源=会话或笔记),不是上方 💬 聊天会话——点选查看轨迹与采纳入口"
152153
>🤖 AI 任务</div>
153-
{tasks.length === 0 && <div style={{ fontSize: 12, color: "#9ca3af", padding: "4px 8px" }}>暂无精修/补充任务</div>}
154+
{tasks.length === 0 && <EmptyState title="暂无精修/补充任务" compact align="start" />}
154155
{/* 2026-09-09 批 1 语义说明:本段是精修/补充任务(来源会话/笔记)的
155156
只读轨迹视图,不是 💬 聊天会话——点选打开任务对话、结果可采纳 */}
156157
{tasks.length > 0 && (

‎app/src/components/DiscoverySuggestSection.tsx‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
1111
import { invoke } from "@tauri-apps/api/core";
1212
import type { KbDiscoveryResult, KbHit } from "../types";
1313
import { hitLabel } from "../utils/kbHits";
14+
import { EmptyState } from "../ui/primitives";
1415

1516
interface Props {
1617
systemId: number;
@@ -131,9 +132,7 @@ export default function DiscoverySuggestSection({ systemId, conceptId, onChanged
131132
{result && (
132133
<>
133134
{result.evidence.length === 0 && (
134-
<p style={{ fontSize: 11, color: "#9ca3af", margin: "4px 0 0" }}>
135-
暂无未挂接的候选素材——可先沉淀相关笔记/碎片再试
136-
</p>
135+
<EmptyState title="暂无未挂接的候选素材——" description="可先沉淀相关笔记/碎片再试" compact align="start" />
137136
)}
138137
{result.evidence.map((h) => (
139138
<label

‎app/src/components/GoalDetail.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import InterviewDialog from "./InterviewDialog";
1414
import GraduateDialog from "./GraduateDialog";
1515
import RetroTimeline from "./RetroTimeline";
1616
import GoalPlanApprovalDialog from "./GoalPlanApprovalDialog";
17-
import { ConfirmDialog } from "../ui/primitives";
17+
import { ConfirmDialog, EmptyState } from "../ui/primitives";
1818

1919
interface Props {
2020
goalId: number;
@@ -254,7 +254,7 @@ export default function GoalDetail({ goalId, onChanged, onDeleted }: Props) {
254254
<button onClick={() => void removeGroup(g.id)} style={smallDanger}>×</button>
255255
</span>
256256
))}
257-
{detail.groups.length === 0 && <span style={{ fontSize: 11, color: "#9ca3af" }}>暂无绑定——绑定后结算/复习/弱项才计入进度</span>}
257+
{detail.groups.length === 0 && <EmptyState title="暂无绑定——" description="绑定后结算/复习/弱项才计入进度" compact align="start" />}
258258
</div>
259259
{bindable.length > 0 && (
260260
<div style={{ display: "flex", gap: 6, marginBottom: 14 }}>
@@ -278,7 +278,7 @@ export default function GoalDetail({ goalId, onChanged, onDeleted }: Props) {
278278
</div>
279279
))
280280
) : (
281-
<p style={{ fontSize: 11, color: "#9ca3af", margin: "0 0 10px" }}>暂无弱项信号(绑定组无卡)</p>
281+
<EmptyState title="暂无弱项信号" description="绑定组无卡" compact align="start" />
282282
)}
283283

284284
{/* v0.18.2:最弱概念(90 天无引用/未应用——规则信号,M3 真实化) */}

‎app/src/components/GroupSidebar.tsx‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import GroupCreateDialog from "./GroupCreateDialog";
3939
// REQ-287:多选拖拽载荷读取(text/note-ids JSON + 单 id 兜底)
4040
import { crateDndReadIds } from "./NoteTreeSection";
4141
import { blobToBase64 } from "../utils/blobToBase64";
42+
import { EmptyState } from "../ui/primitives";
4243

4344
interface Props {
4445
/** 列宽(v0.15 全站自适应——父层 useColumnLayout 驱动;缺省 240=历史值) */
@@ -460,9 +461,7 @@ export default function GroupSidebar({
460461
)}
461462

462463
{groups.length === 0 && (
463-
<p style={{ fontSize: 12, color: "#9ca3af", padding: "12px 8px" }}>
464-
暂无笔记组——会话转笔记时自动归组
465-
</p>
464+
<EmptyState title="暂无笔记组——" description="会话转笔记时自动归组" compact align="start" />
466465
)}
467466
</div>
468467

‎app/src/components/ImageGallery.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { convertFileSrc } from "@tauri-apps/api/core";
1313
import { listen } from "@tauri-apps/api/event";
1414
import ImagePreviewOverlay from "./ImagePreviewOverlay";
1515
import StructureImageSection from "./StructureImageSection";
16-
import { Button } from "../ui/primitives";
16+
import { Button, EmptyState } from "../ui/primitives";
1717

1818
export default function ImageGallery({ sessionId }: { sessionId: number }) {
1919
const [images, setImages] = useState<string[]>([]);
@@ -75,9 +75,7 @@ export default function ImageGallery({ sessionId }: { sessionId: number }) {
7575
{error && <span style={{ fontSize: 11, color: "#dc2626" }}>{error}</span>}
7676
</div>
7777
{images.length === 0 && !loading && (
78-
<div style={{ fontSize: 11, color: "#9ca3af" }}>
79-
暂无图片(实时捕获中画面变化会自动归档;Ctrl+Shift+S 手动截图置顶)
80-
</div>
78+
<EmptyState title="暂无图片(实时捕获中画面变化会自动归档;Ctrl+Shift+S 手动截图置顶)" compact align="start" />
8179
)}
8280
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))", gap: 8 }}>
8381
{images.map((rel) => (

0 commit comments

Comments
 (0)