diff --git a/MEMORY.md b/MEMORY.md index 86ca19f..cc79c8e 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -41,3 +41,16 @@ - 部署 compose 中 DB 镜像应通过 `POSTGRES_IMAGE` 可配置,默认使用镜像站的 pgvector 镜像(`docker.m.daocloud.io/pgvector/pgvector:pg16`)。 - 宿主机 DB 暴露端口统一走 `POSTGRES_PORT`(默认 `5433`),用于规避与宿主机已有 PostgreSQL(常见 `5432`)冲突;容器内连接仍保持 `db:5432`。 - GitHub Actions 使用 `appleboy/ssh-action` 部署时,慢网环境需显式设置 `command_timeout`(建议 `45m`)并为 `docker compose pull` 增加重试,避免出现 `Run Command Timeout` 直接中断发布。 + +## 前端视觉口径(2026-04-12) + +- 后台视觉基线采用 `Slate + Cyan`(浅色)风格,优先使用 `web/src/app/globals.css` 中统一样式类: + - `surface-card` / `surface-card-muted` + - `notice` + `notice-error` / `notice-success` + - `btn-primary` / `btn-secondary` / `btn-danger` + - `control` + - `table-modern` / `table-head` / `table-body` +- 字体基线: + - 标题:`Space Grotesk` + - 正文:`Manrope` + - 等宽:`JetBrains Mono` diff --git a/memory/2026-04-12.md b/memory/2026-04-12.md index 5254030..46b819c 100644 --- a/memory/2026-04-12.md +++ b/memory/2026-04-12.md @@ -124,6 +124,28 @@ - 推送触发 `main` 发布,观察部署日志不再在固定时长点报 `Run Command Timeout`。 - 远端 `docker compose ps` 应显示 `db/api/web` 均为 `Up`(或 `healthy`)。 +## 追加改造(后台视觉风格方案 A) + +- 目标: + - 将后台从默认黑白风格升级为更现代的 `Slate + Cyan` 视觉基线,保持业务逻辑不变。 +- 处理: + - `web/src/app/layout.tsx`: + - 字体切换为 `Space Grotesk`(标题)+ `Manrope`(正文)+ `JetBrains Mono`(等宽)。 + - `web/src/app/globals.css`: + - 新增统一设计 token(背景/边框/强调色/文本层级)。 + - 新增通用样式类:`surface-card`、`surface-card-muted`、`notice`、`btn-*`、`control`、`table-*`。 + - 增加浅色渐变背景与柔和光斑,提升整体层次。 + - `web/src/app/admin/layout.tsx`: + - 后台侧栏、顶部标题区改为半透明磨砂卡片风格,激活态采用青色高亮。 + - `web/src/app/admin/**` 与 `web/src/app/page.tsx`: + - 统一替换卡片/按钮/表单/表格样式到新通用类,保持页面结构与交互逻辑不变。 +- 验证: + - `npm run lint:web` 通过。 + - `npm run build:web` 失败(环境问题,非本次样式改动引入): + - Turbopack 报 `Can't resolve '@tanstack/react-query'` / `Can't resolve 'react'`,但 `npm --workspace web ls react @tanstack/react-query --depth=0` 可见依赖存在。 +- 风险: + - 本次改动覆盖前端多个后台页面,主要风险是视觉回归与局部间距细节,需要联调页面人工验收。 + ## 追加修复(DB 端口冲突 + pgvector 基线) - 触发问题: diff --git a/web/src/app/admin/files/page.tsx b/web/src/app/admin/files/page.tsx index 86e03f0..df38620 100644 --- a/web/src/app/admin/files/page.tsx +++ b/web/src/app/admin/files/page.tsx @@ -379,14 +379,14 @@ export default function AdminFilesPage() { uploadMutation.isPending; if (initializing || filesQuery.isLoading) { - return

Loading files...

; + return

Loading files...

; } if (!user) { return (
-

请先登录后再访问文件管理页面。

- 返回首页 +

请先登录后再访问文件管理页面。

+ 返回首页
); } @@ -394,8 +394,8 @@ export default function AdminFilesPage() { if (!canRead) { return (
-

你没有访问该页面的权限(需要 `file.read`)。

- 返回首页 +

你没有访问该页面的权限(需要 `file.read`)。

+ 返回首页
); } @@ -403,20 +403,20 @@ export default function AdminFilesPage() { return (
{(listError || errorMessage) && ( -
+        
           {listError || errorMessage}
         
)} {feedbackMessage && ( -
+        
           {feedbackMessage}
         
)}
-
+

挂载点

-

一期按挂载点浏览目录树,支持 VFS/S3。

+

一期按挂载点浏览目录树,支持 VFS/S3。

{mounts.map((mount) => { const selected = mount.code === (listData?.current_mount.code ?? mountCode); @@ -427,35 +427,35 @@ export default function AdminFilesPage() { onClick={() => handleSelectMount(mount)} className={`w-full rounded-lg border px-3 py-2 text-left text-sm transition ${ selected - ? "border-black bg-black text-white dark:border-white dark:bg-white dark:text-black" - : "border-black/15 hover:bg-black/5 dark:border-white/20 dark:hover:bg-white/10" + ? "border-cyan-400 bg-gradient-to-r from-cyan-500 to-cyan-600 text-white shadow-[0_10px_22px_rgba(8,145,178,0.28)]" + : "border-[var(--border)] bg-white/70 text-slate-700 hover:border-cyan-200 hover:bg-cyan-50/70" }`} >

{mount.name}

-

+

{mount.backend.driver_type} · {mount.code}

); })} {mounts.length === 0 && ( -

暂无可用挂载点。

+

暂无可用挂载点。

)}
-
+

文件列表

-

+

存储后端:{listData?.current_mount.backend.name ?? "-"}({listData?.current_mount.backend.driver_type ?? "-"})

-
+
{(listData?.breadcrumbs ?? [{ name: "根目录", path: "/" }]).map((crumb, index, all) => (
- {index < all.length - 1 && /} + {index < all.length - 1 && /}
))}
@@ -506,11 +506,11 @@ export default function AdminFilesPage() { value={newDirectoryName} onChange={(event) => setNewDirectoryName(event.target.value)} placeholder="新建目录名" - className="w-full max-w-xs rounded-md border border-black/15 bg-transparent px-3 py-2 text-sm outline-none focus:border-black/40 dark:border-white/20 dark:focus:border-white/40" + className="w-full max-w-xs control" />