From 406bfb1dad5575698d984a2828c93c25d84328a5 Mon Sep 17 00:00:00 2001 From: Color2333 <1552429809@qq.com> Date: Sat, 10 Oct 2026 12:40:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E5=85=A8=E7=AB=99=E8=A7=86?= =?UTF-8?q?=E8=A7=89=E7=BB=9F=E4=B8=80=E2=80=94=E2=80=94Agent=20=E7=A9=BA?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=B4=A7=E5=87=91=E5=8C=96=20+=20Login/Devic?= =?UTF-8?q?e=20=E6=9A=96=E9=BB=91=E5=8C=96=20+=20gray/slate=20=E7=A1=AC?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=85=A8=E9=87=8F=E6=8D=A2=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E4=BB=A4=E7=89=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agent 空状态:窄栏内大 hero 收紧(图标 10x10/标题 lg/文案合并) - 登录/设备授权页:冷蓝 slate 渐变 → 暖黑渐变(与暗色令牌一致) - JobMonitor/ResearchState/Statistics:gray/slate 硬编码 64 处 → ink/border/bg 令牌 - 全站 tailwind 灰阶硬编码清零 --- frontend/src/pages/Agent.tsx | 17 +++++------- frontend/src/pages/DeviceAuthorize.tsx | 24 ++++++++--------- frontend/src/pages/JobMonitor.tsx | 36 +++++++++++++------------- frontend/src/pages/Login.tsx | 14 +++++----- frontend/src/pages/ResearchState.tsx | 28 ++++++++++---------- frontend/src/pages/Statistics.tsx | 20 +++++++------- 6 files changed, 68 insertions(+), 71 deletions(-) diff --git a/frontend/src/pages/Agent.tsx b/frontend/src/pages/Agent.tsx index e5fe96d..cae5d72 100644 --- a/frontend/src/pages/Agent.tsx +++ b/frontend/src/pages/Agent.tsx @@ -532,18 +532,15 @@ const EmptyState = memo(function EmptyState({ onSelect }: { onSelect: (p: string }, []); return ( -
-
- +
+
+
-

PaperMind Agent

-

+

PaperMind Agent

+

{engine === "python" ? "由 Python 引擎驱动(pm 未部署)。" - : "由 Pi agent core 驱动——与终端 pm 同一循环、同一工具集。"} -

-

- 告诉我你的研究需求,我会自动规划执行步骤:搜索论文、下载、分析、生成综述。 + : "由 Pi agent core 驱动,与终端 pm 同一循环、同一工具集。描述研究需求,我会自动规划:搜索 → 下载 → 分析 → 综述。"}

{/* 今日研究速览 */} @@ -552,7 +549,7 @@ const EmptyState = memo(function EmptyState({ onSelect }: { onSelect: (p: string {/* 统计卡片 */}
-
{today.total_papers}
+
{today.total_papers}
论文总量
diff --git a/frontend/src/pages/DeviceAuthorize.tsx b/frontend/src/pages/DeviceAuthorize.tsx index 8d1b0b0..d3c2a4b 100644 --- a/frontend/src/pages/DeviceAuthorize.tsx +++ b/frontend/src/pages/DeviceAuthorize.tsx @@ -77,7 +77,7 @@ export default function DeviceAuthorize() { // 未认证:内嵌登录页(登录成功后回到本页授权流程) if (!checked) { return ( -
+
); @@ -90,17 +90,17 @@ export default function DeviceAuthorize() { const finalized = decision !== null || info?.status === "denied" || expired; return ( -
+

设备登录授权

-

确认下面设备码与你终端 pm login 显示的一致

+

确认下面设备码与你终端 pm login 显示的一致

-
+
{/* 设备码输入(URL 未带或需要更正时) */} {!info && !loadError && (
@@ -108,7 +108,7 @@ export default function DeviceAuthorize() { value={userCode} onChange={(e) => setUserCode(e.target.value.toUpperCase())} placeholder="输入设备码,如 ABKQ-WERT" - className="w-full rounded-xl border border-slate-600 bg-slate-900/50 px-4 py-3 text-center font-mono text-lg tracking-widest text-white placeholder-slate-500 outline-none focus:border-primary" + className="w-full rounded-xl border border-[#2E2A25] bg-[#131110]/60 px-4 py-3 text-center font-mono text-lg tracking-widest text-white placeholder-[#575047] outline-none focus:border-primary" maxLength={9} /> @@ -142,14 +142,14 @@ export default function DeviceAuthorize() { {info && !finalized && (
-
+
{info.user_code}
-

+

设备 {info.client_name} 请求登录 PaperMind

-

+

{Math.floor(info.expires_in / 60)} 分{" "} {String(info.expires_in % 60).padStart(2, "0")} 秒后过期 @@ -206,14 +206,14 @@ export default function DeviceAuthorize() { )} {expired && ( } + icon={} title="已过期" desc="授权请求超时,请在终端重新执行 pm login" /> )}

-

+

PaperMind · 设备码授权(类似 GitHub CLI 登录流程)

@@ -226,7 +226,7 @@ function ResultPanel({ icon, title, desc }: { icon: React.ReactNode; title: stri
{icon}

{title}

-

{desc}

+

{desc}

); } diff --git a/frontend/src/pages/JobMonitor.tsx b/frontend/src/pages/JobMonitor.tsx index 71c4790..3c0eb3a 100644 --- a/frontend/src/pages/JobMonitor.tsx +++ b/frontend/src/pages/JobMonitor.tsx @@ -2,12 +2,12 @@ import { useEffect, useState, useCallback } from "react"; import { jobApi, type DurableJobItem, type DurableJobGraph } from "@/services/api"; const STATUS_COLORS: Record = { - queued: "bg-gray-100 text-gray-600", + queued: "bg-hover text-ink-secondary", running: "bg-blue-100 text-blue-700", succeeded: "bg-green-100 text-green-800", partially_succeeded: "bg-yellow-100 text-yellow-800", failed: "bg-red-100 text-red-700", - cancelled: "bg-gray-100 text-gray-400", + cancelled: "bg-hover text-ink-tertiary", dead_letter: "bg-red-200 text-red-900", manual_recovery: "bg-purple-100 text-purple-800", }; @@ -102,7 +102,7 @@ export default function JobMonitor() { {/* Jobs 列表 */} {loading && !jobs.length ? ( -

Loading...

+

Loading...

) : (
{jobs.map((j) => ( @@ -116,7 +116,7 @@ export default function JobMonitor() {
{j.status} @@ -133,13 +133,13 @@ export default function JobMonitor() { {(j as any).authority === "go_core" ? "Go" : "存档"} )} - {j.id} + {j.id}
{j.progress?.message && ( -

{j.progress.message}

+

{j.progress.message}

)}
-
+
- + {j.progress?.current ?? 0}/{j.progress?.total ?? 0}
@@ -176,7 +176,7 @@ export default function JobMonitor() {
))} - {!jobs.length &&

No jobs found.

} + {!jobs.length &&

No jobs found.

}
)} @@ -202,7 +202,7 @@ export default function JobMonitor() { )} @@ -99,7 +99,7 @@ export default function LoginPage({ onLoginSuccess }: LoginPageProps) {
diff --git a/frontend/src/pages/ResearchState.tsx b/frontend/src/pages/ResearchState.tsx index 69632e6..4a52df1 100644 --- a/frontend/src/pages/ResearchState.tsx +++ b/frontend/src/pages/ResearchState.tsx @@ -13,7 +13,7 @@ interface QuestionInfo { const STATUS_COLORS: Record = { confirmed: "bg-green-100 text-green-800", pending_verification: "bg-yellow-100 text-yellow-800", - draft: "bg-gray-100 text-gray-600", + draft: "bg-hover text-ink-secondary", superseded: "bg-orange-100 text-orange-700", invalidated: "bg-red-100 text-red-700", }; @@ -143,13 +143,13 @@ export default function ResearchState() { {/* 问题概览 */}

{question.title}

-

{question.question}

+

{question.question}

{Object.entries(question.claim_counts.by_status).map(([s, n]) => ( {s}: {n} @@ -187,20 +187,20 @@ export default function ResearchState() {
{c.status} - {c.certainty} - origin: {c.origin} - + {c.certainty} + origin: {c.origin} + 证据: {c.evidence_count}

{c.statement}

{c.statement_zh && ( -

{c.statement_zh}

+

{c.statement_zh}

)}
))} @@ -223,17 +223,17 @@ export default function ResearchState() { ? "bg-green-100 text-green-700" : ev.stance === "contradicts" ? "bg-red-100 text-red-700" - : "bg-gray-100" + : "bg-hover" }`} > {ev.stance} - + {ev.source_version.paper.title} v{ev.source_version.version_label}
- {ev.quote &&

"{ev.quote}"

} -

+ {ev.quote &&

"{ev.quote}"

} +

{JSON.stringify(ev.locator)}

@@ -260,8 +260,8 @@ export default function ResearchState() { > {DIFF_LABELS[d.diff_kind] ?? d.diff_kind} - {d.event} - + {d.event} + {d.occurred_at?.slice(0, 19)}
diff --git a/frontend/src/pages/Statistics.tsx b/frontend/src/pages/Statistics.tsx index 4a27823..c773f43 100644 --- a/frontend/src/pages/Statistics.tsx +++ b/frontend/src/pages/Statistics.tsx @@ -21,7 +21,7 @@ import { } from "lucide-react"; const STATUS_COLORS: Record = { - unread: "bg-slate-400", + unread: "bg-ink-tertiary", skimmed: "bg-yellow-500", deep_read: "bg-primary", }; @@ -30,7 +30,7 @@ const SOURCE_COLORS: Record = { arxiv: "bg-red-500", semantic_scholar: "bg-blue-500", reference_import: "bg-green-500", - unknown: "bg-gray-500", + unknown: "bg-page0", initial_import: "bg-purple-500", manual_collect: "bg-orange-500", auto_collect: "bg-cyan-500", @@ -153,7 +153,7 @@ const TopicCard = memo(function TopicCard({ stat }: { stat: TopicStats }) { style={{ width: `${(stat.status_dist.skimmed / total) * 100}%` }} />
@@ -169,7 +169,7 @@ const TopicCard = memo(function TopicCard({ stat }: { stat: TopicStats }) { 粗读 {stat.status_dist.skimmed} - + 未读 {stat.status_dist.unread}
@@ -401,7 +401,7 @@ function VenueDistribution({ data }: { data: PaperDistributionResponse }) { const venues = data.by_venue; const maxCount = Math.max(...venues.map((v) => v.count), 1); - const medals = ["text-amber-500", "text-slate-400", "text-orange-400"]; + const medals = ["text-amber-500", "text-ink-tertiary", "text-orange-400"]; return ( }> @@ -447,12 +447,12 @@ function ActionSourceStats({ data }: { data: PaperDistributionResponse }) { return (
{a.source}
@@ -480,7 +480,7 @@ function ReadStatusOverview({ data }: { data: PaperDistributionResponse }) { {statuses.map((s) => (
0 ? (s.count / total) * 100 : 0}%` }} /> ))} @@ -494,11 +494,11 @@ function ReadStatusOverview({ data }: { data: PaperDistributionResponse }) { ? "bg-primary/10" : s.raw_status === "skimmed" ? "bg-yellow-500/10" - : "bg-slate-100 dark:bg-slate-800" + : "bg-hover dark:bg-hover" }`} >
{s.status}