mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 04:11:58 +00:00
e10c4f23fc
来自 2026-09 的 UI/UX 审查(142 条)。本提交是前两波,第三波(记录页接入时间轴、跨页互链、check-ui 更新、全站扫尾)另行提交。 地基 - 设计令牌:全局规则和 .btn/.field/.chip 放进 CSS 层,Tailwind 工具类重新生效,选中态、开启态不再被吞掉;字号阶梯; 辅助文字在所有底色上 >= 4.5:1;状态色专用,节点类型色与之拉开色相;「跟随系统」真的跟随,首帧不闪深色;新字标与 favicon - 基础组件:confirmDialog / promptDialog 取代原生对话框;toast 出错不自动消失、可复制、读屏可播报;离线横幅与断线恢复; 九种剪影的状态徽标;唯一一份状态文案(lib/status)、格式化(lib/format)、术语(lib/terms)、报错人话(lib/errors) - 运行态内核:事件折成航迹(run/trace.ts),可投影到任意时刻;取消 / 失败 / 服务重启后统一收尾,不再永远转圈; run.status 随事件回写;token 事件不再堆进 events - 后端:协作成员逐个完成即发事件,调度者决策有事件;时长分执行 / 墙钟 / 等人;API 时间带时区; 中断的运行也发 stream.end;运行列表可筛选翻页;删除运行 / 工作流有保护;运行默认值接通;可测未保存的配置; 报错说清发生了什么、为什么、怎么办 功能 - 画布:状态四重编码、固定高度遥测槽、按缩放三档、运行胶囊与 HUD、航迹时间轴与回放、执行轨迹边、 等待闸门、跟随执行、正式运行只读、一次性时刻(开场点亮、回扫、阻断级联、出具印章) - 编辑:撤销重做、版本历史、问题面板可定位、三栏可收起、模板与表达式字段区分、变量血缘、快捷键、带搜索的选择器 - 回答流 / 问数据:贴底才跟随滚动、工件下钻、出具横幅列出缺口、答案可复制导出、按会话的忙闲、 答案不再在 2000 字处截断、重启后这一轮会收尾 - 记录页:待审批 / 运行中 / 失败页签、筛选翻页、实时接流、排错路径指到节点、封存凭证常驻 - 管理页:新的「数据」页、写操作失败都有反馈、弹窗里先测连接、统一持久的连接状态 - 外壳:导航改版、⌘K 命令面板、? 快捷键帮助、404、页面标题与 favicon 状态点、后台提醒 验证(沙箱):tsc 干净,pytest 579 passed,14 个检查脚本中 13 个全绿;check-ui 剩 1 项旧断言(按旧日期格式找运行行),第三波更新。
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
/**
|
||
* 主题偏好。
|
||
*
|
||
* 真源是后端 settings 的 ui.theme;localStorage 只是它的首帧缓存。index.html
|
||
* 里那段内联脚本要在 React 起来之前就决定画深色还是浅色——等 /api/settings
|
||
* 回来再切,浅色用户每次打开都会先看到一整帧深色。所以每次应用主题都顺手写回
|
||
* 缓存,键名和取值必须和 index.html 那段脚本一致。
|
||
*
|
||
* 「跟随系统」就是不写 data-theme:index.css 的 prefers-color-scheme 分支接管,
|
||
* 系统切换时页面跟着变,不需要这边监听 matchMedia。
|
||
*/
|
||
|
||
export type ThemePref = 'system' | 'light' | 'dark'
|
||
|
||
export const THEME_STORAGE_KEY = 'agentlab.theme'
|
||
|
||
/** 后端和缓存里的值都可能是旧的或手改坏的,认不出来的一律当「跟随系统」 */
|
||
export function normalizeTheme(value: unknown): ThemePref {
|
||
return value === 'light' || value === 'dark' ? value : 'system'
|
||
}
|
||
|
||
export function readThemePref(): ThemePref {
|
||
try {
|
||
return normalizeTheme(localStorage.getItem(THEME_STORAGE_KEY))
|
||
} catch {
|
||
return 'system'
|
||
}
|
||
}
|
||
|
||
export function applyTheme(pref: ThemePref): void {
|
||
const root = document.documentElement
|
||
// 切换这一帧关掉过渡:带 transition 的按钮、输入框会各自花 120ms 慢慢变色,
|
||
// 整页看着像在闪。先让新配色在无过渡的状态下落定(读一次样式逼它重算),
|
||
// 下一帧再把过渡还回去
|
||
root.classList.add('theme-switching')
|
||
if (pref === 'system') root.removeAttribute('data-theme')
|
||
else root.setAttribute('data-theme', pref)
|
||
void getComputedStyle(root).backgroundColor
|
||
requestAnimationFrame(() => root.classList.remove('theme-switching'))
|
||
try {
|
||
localStorage.setItem(THEME_STORAGE_KEY, pref)
|
||
} catch {
|
||
// 隐私模式下写不进去:只是下次首帧跟随系统,等设置接口回来再纠正
|
||
}
|
||
}
|
||
|
||
/** 眼下实际画的是哪一套。「跟随系统」时要问系统,给主题切换按钮挑图标用 */
|
||
export function resolvedTheme(): 'light' | 'dark' {
|
||
const attr = document.documentElement.getAttribute('data-theme')
|
||
if (attr === 'light' || attr === 'dark') return attr
|
||
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'
|
||
}
|