From fa56e960a312daefbf79f945c0df3ac86b37aea6 Mon Sep 17 00:00:00 2001 From: AlkaidSTART <2595006848@qq.com> Date: Thu, 6 Aug 2026 10:45:46 +0800 Subject: [PATCH 1/8] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20CI/Pages=20?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E4=B8=AD=20pnpm=20=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E3=80=81Node=20=E7=89=88=E6=9C=AC=E5=BC=83?= =?UTF-8?q?=E7=94=A8=E5=8F=8A=20Pages=20=E5=90=AF=E7=94=A8=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- .github/workflows/pages.yml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e81ba9..6d5840f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '22' + node-version: '24' cache: 'pnpm' - name: Install dependencies diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 594693a..db4b103 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -32,7 +32,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '22' + node-version: '24' cache: 'pnpm' - name: Install dependencies @@ -43,6 +43,8 @@ jobs: - name: Configure Pages uses: actions/configure-pages@v5 + with: + enablement: true - name: Upload Packages Client uses: actions/upload-pages-artifact@v3 From a18fd3fe9838a8536813213abf8ec9c1d9077764 Mon Sep 17 00:00:00 2001 From: AlkaidSTART <2595006848@qq.com> Date: Thu, 6 Aug 2026 10:50:33 +0800 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=E6=8E=A8=E9=80=81=20dev=20?= =?UTF-8?q?=E5=88=86=E6=94=AF=E6=97=B6=E8=87=AA=E5=8A=A8=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E5=88=B0=20gh-pages=20=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy-gh-pages.yml | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/deploy-gh-pages.yml diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml new file mode 100644 index 0000000..cf93ff8 --- /dev/null +++ b/.github/workflows/deploy-gh-pages.yml @@ -0,0 +1,40 @@ +name: Deploy to gh-pages + +on: + push: + branches: [dev] + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '24' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build client + run: pnpm build:client + + - name: Deploy to gh-pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: packages/client/dist + publish_branch: gh-pages + force_orphan: true From b13a4e746f200051e60361476e5ae4d050c79390 Mon Sep 17 00:00:00 2001 From: AlkaidSTART <2595006848@qq.com> Date: Thu, 6 Aug 2026 11:26:54 +0800 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20client=20U?= =?UTF-8?q?I=20=E2=80=94=20=E5=A4=9A=E5=B7=B4=E8=83=BA=E9=85=8D=E8=89=B2?= =?UTF-8?q?=20+=20=E5=A2=9E=E5=BC=BA=E6=AF=9B=E7=8E=BB=E7=92=83=E6=95=88?= =?UTF-8?q?=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - global.css: 三色光晕背景(薰衣草紫/珊瑚粉/薄荷绿)、角色专属 CSS 变量、 渐变品牌色、消息气泡样式、搜索框聚焦动画 - App.tsx: 统一使用 app-shell/app-grid 布局,移除硬编码背景色 - Sidebar.tsx: Logo 渐变化、选中态用渐变竖条指示、hover 反馈 - MainPanel.tsx: 统一用 CSS 变量控制颜色,msg-bubble 替代内联 style - MessageItem.tsx: 角色色彩多巴胺化(紫/粉/琥珀)、带发光点指示器、 彩色左边框气泡 --- packages/client/src/App.tsx | 16 +- packages/client/src/components/MainPanel.tsx | 178 ++++++----- .../client/src/components/MessageItem.tsx | 54 ++-- packages/client/src/components/Sidebar.tsx | 204 ++++++++----- packages/client/src/global.css | 289 +++++++++++++++++- 5 files changed, 535 insertions(+), 206 deletions(-) diff --git a/packages/client/src/App.tsx b/packages/client/src/App.tsx index 0f7f962..11d7bd3 100644 --- a/packages/client/src/App.tsx +++ b/packages/client/src/App.tsx @@ -64,23 +64,27 @@ export default function App() { if (loadState === 'loading') { return ( -
- 正在读取会话 +
+
+ 正在读取会话 +
); } if (loadState === 'error' || !data) { return ( -
- 无法读取会话数据 +
+
+ 无法读取会话数据 +
); } return ( -
-
+
+
= [ { value: 'tool', label: '工具' }, ]; -const glassPanel = - 'flex min-h-0 flex-col overflow-hidden rounded-lg border border-black/10 bg-white/70 shadow-[0_18px_50px_rgba(15,23,42,0.12)] backdrop-blur-2xl lg:h-[calc(100vh-2rem)] dark:border-white/10 dark:bg-[#0d1116]/75 dark:shadow-[0_18px_60px_rgba(0,0,0,0.42)]'; +function StatRow({ session }: { session: WebSession }) { + const items = [ + ['消息', `${session.entries.length}`], + ['tokens', session.stats?.totalTokens?.toLocaleString() ?? '0'], + ['成本', `$${(session.stats?.costTotal ?? 0).toFixed(3)}`], + ['目录', session.cwd], + ] as const; + + return ( +
+ {items.map(([label, value]) => ( + + {label} + {value} + + ))} +
+ ); +} function FactGrid({ facts }: { facts: WebFact[] }) { if (facts.length === 0) { @@ -24,19 +41,29 @@ function FactGrid({ facts }: { facts: WebFact[] }) { } return ( -
- {facts.slice(0, 12).map((fact, index) => ( -
-
{fact.kind}
-
- {fact.value || fact.key || String(fact.seq)} +
+
+ 事实 +
+
+ {facts.slice(0, 12).map((fact, index) => ( +
+
+ {fact.kind} +
+
+ {fact.value || fact.key || String(fact.seq)} +
-
- ))} -
+ ))} +
+ ); } @@ -45,44 +72,44 @@ const payloadText = (payload: unknown): string => { return payload; } if (payload && typeof payload === 'object') { - return JSON.stringify(payload); + return JSON.stringify(payload, null, 2); } return String(payload ?? ''); }; -function RecordGrid({ records }: { records: WebRecord[] }) { +function RecordList({ records }: { records: WebRecord[] }) { if (records.length === 0) { return null; } return ( -
-
- 运行记录 ({records.length}) +
+
+ 运行记录 · 最近 {Math.min(20, records.length)} 条
-
+
{records .slice(-20) .reverse() .map((record) => ( -
-
- +
+
+ {record.type} {record.opKind ? ` / ${record.opKind}` : ''} - {formatTime(record.timestamp)} + {formatTime(record.timestamp)}
-
+
{payloadText(record.payload)}
))}
-
+
); } @@ -90,48 +117,28 @@ export function MainPanel({ session, filter, onFilterChange }: MainPanelProps) { const entries = session ? filterEntries(session.entries, filter) : []; return ( -
-
-
-

- {session ? getSessionTitle(session) : 'Call Code'} -

-
- {session ? ( - <> - - {getSessionMode(session).toUpperCase()} - - - {session.entries.length} 条消息 - - - tokens {session.stats?.totalTokens ?? 0} - - - 成本 {session.stats?.costTotal ?? 0} - - - {session.cwd} - - - ) : null} -
-
-
+
+ {/* 标题栏 */} +
+

+ {session ? getSessionTitle(session) : 'Call Code'} +

+ {session ? : null} +
-
-
+ {/* 过滤器 */} +
+
{filters.map((item) => ( @@ -139,24 +146,27 @@ export function MainPanel({ session, filter, onFilterChange }: MainPanelProps) {
-
- {!session ? ( -
- 暂无会话数据 -
- ) : entries.length === 0 ? ( -
- 没有匹配的消息 -
- ) : ( -
- {entries.map((entry) => ( - - ))} - {session.facts ? : null} - {session.records ? : null} -
- )} + {/* 消息列表 */} +
+
+ {!session ? ( +
+ 暂无会话数据 +
+ ) : entries.length === 0 ? ( +
+ 没有匹配的消息 +
+ ) : ( +
+ {entries.map((entry) => ( + + ))} + {session.facts ? : null} + {session.records ? : null} +
+ )} +
); diff --git a/packages/client/src/components/MessageItem.tsx b/packages/client/src/components/MessageItem.tsx index 79c65f1..576914e 100644 --- a/packages/client/src/components/MessageItem.tsx +++ b/packages/client/src/components/MessageItem.tsx @@ -1,16 +1,17 @@ import type { WebEntry } from '../types'; import { entryRole, entryText, formatTime } from '../utils'; +import type { EntryRole } from '../types'; interface MessageItemProps { entry: WebEntry; } -const roleMeta = { - user: { avatar: 'U', label: '用户', className: 'bg-teal-600 text-white dark:bg-cyan-400 dark:text-cyan-950' }, - assistant: { avatar: 'A', label: '助手', className: 'bg-amber-600 text-white dark:bg-amber-400 dark:text-amber-950' }, - tool: { avatar: 'T', label: '工具', className: 'bg-slate-200 text-slate-600 dark:bg-white/10 dark:text-slate-300' }, - system: { avatar: 'S', label: '系统', className: 'bg-slate-200 text-slate-600 dark:bg-white/10 dark:text-slate-300' }, -} as const; +const roleMeta: Record = { + user: { label: '用户', dotClass: 'role-dot role-dot--user', bubbleClass: 'msg-bubble--user' }, + assistant: { label: '助手', dotClass: 'role-dot role-dot--assistant', bubbleClass: 'msg-bubble--assistant' }, + tool: { label: '工具', dotClass: 'role-dot role-dot--tool', bubbleClass: 'msg-bubble--tool' }, + system: { label: '系统', dotClass: 'role-dot role-dot--system', bubbleClass: '' }, +}; export function MessageItem({ entry }: MessageItemProps) { const role = entryRole(entry); @@ -19,34 +20,35 @@ export function MessageItem({ entry }: MessageItemProps) { const isCode = role === 'tool' || text.length > 320; return ( -
-
- {meta.avatar} +
+ {/* 角色指示点 — 带多巴胺发光 */} +
+
-
-
-
- {meta.label} - {entry.tool ? ( - - {entry.tool} - - ) : null} -
-
- {formatTime(entry.timestamp)} -
+
+ {/* 元信息行 */} +
+ {meta.label} + {entry.tool ? ( + {entry.tool} + ) : null} + {formatTime(entry.timestamp)}
+ {/* 内容 */} {isCode ? ( -
+          
             {text}
           
) : ( -
+
{text}
)} diff --git a/packages/client/src/components/Sidebar.tsx b/packages/client/src/components/Sidebar.tsx index 7f7a1b0..7f1f0e6 100644 --- a/packages/client/src/components/Sidebar.tsx +++ b/packages/client/src/components/Sidebar.tsx @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import type { Theme, WebSession } from '../types'; -import { entryRole, formatTime, getSessionMode, getSessionTitle } from '../utils'; +import { entryRole, formatTime, getSessionTitle } from '../utils'; interface SidebarProps { sessions: WebSession[]; @@ -12,9 +12,6 @@ interface SidebarProps { onThemeChange: (theme: Theme) => void; } -const glassPanel = - 'flex max-h-[46vh] min-h-0 flex-col overflow-hidden rounded-lg border border-black/10 bg-white/70 shadow-[0_18px_50px_rgba(15,23,42,0.12)] backdrop-blur-2xl lg:sticky lg:top-4 lg:h-[calc(100vh-2rem)] lg:max-h-none dark:border-white/10 dark:bg-[#0d1116]/75 dark:shadow-[0_18px_60px_rgba(0,0,0,0.42)]'; - export function Sidebar({ sessions, activeId, @@ -24,112 +21,161 @@ export function Sidebar({ onQueryChange, onThemeChange, }: SidebarProps) { - const stats = useMemo(() => { - const messages = sessions.reduce((sum, session) => sum + session.entries.length, 0); - const tools = sessions.reduce( - (sum, session) => - sum + session.entries.filter((entry) => entryRole(entry) === 'tool').length, - 0, - ); - return { sessions: sessions.length, messages, tools }; - }, [sessions]); - - const statDefs = [ - ['会话', stats.sessions], - ['消息', stats.messages], - ['工具', stats.tools], - ] as const; + const count = useMemo( + () => + sessions.reduce( + (acc, session) => { + acc.messages += session.entries.length; + acc.tools += session.entries.filter((e) => entryRole(e) === 'tool').length; + return acc; + }, + { messages: 0, tools: 0 }, + ), + [sessions], + ); return ( -