给门户(core/kb_web.py 渲染的所有页面)定的一套规矩。目标是:改一次配色/间距,全站一起变,
新人照着模板加页面也不会跑偏。所有令牌的唯一定义处是 core/theme.py。
页面只引用 CSS 变量,不写十六进制。需要新颜色时先加进 theme.py 的 THEMES,再在页面里引用。
测试 tests/test_kb.py 有两条断言盯着这条(样式块以外出现 #rrggbb 就失败)。
| 变量 | 语义 | 用在哪 |
|---|---|---|
--bg / --card |
页面底色 / 卡片底 | body、卡片、表格容器 |
--ink / --dim |
正文 / 次要文字 | 正文、说明小字、表头副信息 |
--line / --line2 |
分隔线 / 输入框描边 | 表格行线、卡片边框、表单控件 |
--brand / --brand_d / --brand_b |
主色 / hover / 浅底 | 每个区块唯一的主按钮、选中态、提示条 |
--accent / --accent_b |
强调色 | 链接、悬停高亮、当前页、焦点圈、? 气泡 |
--ok / --warn / --danger(各带 _b 浅底) |
成功 / 待处理 / 危险 | 状态胶囊、提示条、危险按钮 |
三套内置主题(kb theme <窗口> <名字> 切换,默认 teal):
| 主题 | 气质 | 主色 | 强调色 |
|---|---|---|---|
indigo 墨蓝 |
公文封皮,正式耐看,长表格不刺眼 | #1f4e8c |
#6c5ce7 |
teal 松石绿 |
温和,偏产品化 —— 默认 | #0f6b5f |
#0b7285 |
paper 暖纸质 |
米白 + 赭石,像阅读器 | #8a4b1f |
#8a6d1f |
正文与次要文字在卡片底上对比度 ≥ 4.5:1;状态不只靠颜色区分(胶囊里都有字,另有圆点 + 文字)。
| 类别 | 令牌 | 值 | 什么时候用 |
|---|---|---|---|
| 间距 | --s1…--s6 |
4 / 8 / 12 / 16 / 24 / 32 | 组件内部用 s1–s3,区块之间用 s4–s6 |
| 圆角 | --r1…--r4 |
7 / 10 / 14 / 999 | 控件 r1、条与提示 r2、卡片 r3、胶囊 r4 |
| 字号 | --f1…--f5 |
12 / 13 / 15 / 17 / 22 | 胶囊 f1、小字 f2、正文 f3、小节标题 f4、页标题 f5 |
| 阴影 | --sh1 / --sh2 |
极淡 | 卡片一层即可,别叠阴影 |
| 组件 | 类名 | 说明 |
|---|---|---|
| 卡片 | .card / form |
一个区块一张卡:标题 + 说明 + 操作。卡片之间有 --s4 间距 |
| 主按钮 | button(默认) |
一个区块只留一个,用于该区块的主要动作(上传、生成邀请码、发放地址、批准) |
| 次要按钮 | button.ghost |
其它平级动作(筛选、保存等级、停用、扫描、复制…) |
| 危险按钮 | button.danger |
删除/移除类,永远不要用主色 |
| 最轻按钮 | button.quiet |
表格里的文字型动作 |
| 小号 | button.tiny |
行内动作(可与上面组合:tiny ghost、tiny danger) |
| 按钮组 | .actsrow |
一排按钮/链接的容器,统一 --s2 间距。<td> 上不要直接设 flex,会破坏表格布局 |
| 条 | .bar |
一排控件 + 说明的横条(批量操作、提示条);里面的 select 不会拉满整行 |
| 分组线 | .bar .sep |
在条里把「普通动作」和「危险动作」隔开 |
| 状态胶囊 | .chip + .c-l1/.c-l2/.c-l3/.c-pending/.c-approved/.c-rejected |
等级与状态,永远带文字 |
| 圆点状态 | .dot.on / .dot.off |
同事启用/停用这类二值状态 |
| 空状态 | .empty |
虚线框 + 一句说明(写清「怎么才会有内容」),别只留一行灰字 |
| 悬停提示 | _q("说明") |
长解释一律收进 ? 气泡,页面上只留一句短话 |
| 折叠卡 | details.ucard |
长表单默认收起,点「编辑 ▾」展开 |
| 分页 | _pager(...) |
列表都要分页;翻页链接必须带管理令与筛选条件 |
| 完整链接 | _copybtn(标签, 完整地址) / _Portal._abs() |
给用户看/复制的链接一律带域名,只给路径会复制出半截 |
body = f"""
<h2>区块标题(数量)</h2>
<div class="card">
<div class="grid2">…字段…</div>
<div class="bar">
<label>选项</label><select>…</select>
<span class="sep"></span>
<button>该区块唯一的主操作</button>
<button class="ghost">次要操作</button>
<button class="danger" style="margin-left:auto">危险操作(推到最右)</button>
</div>
</div>
"""
return _page("页面标题", body, base, admin=admin, wide=True, who=who)写新页面的清单:
- 颜色只引用变量;间距用
--s*;不要新写#hex或魔法数字。 - 一个区块一个主按钮;危险动作用
danger且推到右侧。 - 长说明进
_q();列表分页;长内容用details折叠。 - 空状态用
.empty并说明原因;时间一律2026-09-24 14:05这种人类可读格式。 - 给用户看的链接一律完整地址。
- 跑
bash lighthouse.sh test(受控资料库那套里就有设计令牌断言)。
- 焦点可见:
:focus有强调色描边(--focus),别去掉 outline。 - 触屏友好:按钮高度 ≥ 32px(
tiny是 30px,只在行内用);表格外层.wrap横向滚动。 - 管理页在手机上要能批申请(这是需求,不是附加项):卡片与条都
flex-wrap,不要固定宽度。 - 不靠颜色单独传信息:状态胶囊带文字,等级用文字(
L1-商务)而非纯色块。
这些是"能用"和"看着能用"的分界线,改门户时逐条对。
- 总数可达:界面上声明「共 N 条」,就必须能抵达这 N 条(分页 / 展开 / 查看全部)。总数取真实口径,不是当前页长度;列表一律用
_pager(...)分页,不做无限滚动或"加载更多"。 - 可逆二态要闭环:同事启用/停用、篇目公开/下架、写开关这类控件要能看出「未激活 → 进行中 → 已激活 → 取消中 → 失败 → 无权限」。文案成对(
停用↔启用),请求中禁止重复点击,失败必须回到服务端确认的真实状态并说明原因。 - 单次命令不做成开关:生成邀请码、扫描、批准、打包是一次性动作,给执行中与成功/失败反馈,不套"再点一次撤销"。
- 空、错、部分结果要分开:空状态用
.empty写清"怎么才会有内容";失败不能伪装成空结果,要保留已确认内容并给重试;部分结果写「已显示 X / 共 N」。 - 危险动作永远用
danger并推到右侧,不与主操作并排争抢。 - 颜色不是唯一信息源:
.dot.on/.off这类状态点必须配文字,等级用文字而不是纯色块。 - 桌面与约 390px 都要看:表格外层
.wrap横向滚动、卡片与条flex-wrap,底部操作不被遮挡。
改完按 rules/delivery.md 的三、四节做两类复查并如实交代未验证范围。
管理页原来是「上传 + 文件夹 + 资料清单 + 待批申请 + 同事表 + 邀请码 + 用量入口」一屏到底, 一屏 4.3 屏高、几十个按钮,用户反馈「所有功能都挤在一页上」。现在按一件事一页拆:
| 页签 | 路径 | 只放什么 |
|---|---|---|
| 资料 | /admin |
上传、文件夹、资料清单(台账操作) |
| 人员 | /admin/people |
待批申请、已授权同事、直接发地址 |
| 邀请码 | /admin/invites |
生成/停用/删除邀请码 |
| 用量 | /admin/usage |
按人/按天/按资料/按工具的用量 |
规矩:
- 每页只留一个主按钮(资料页=「上传,先进待批」,人员页=「批准/发放地址」,邀请码页=「生成邀请码」);
其余动作降级为
ghost,一次性的、危险的塞进「更多设置 / 更多操作 / ⋯」折叠。 - POST 完回到自己那一页(
_SECTION_OF_SUB决定回哪个页签),别跳走。 - 拆页不改变鉴权:三个页签同一套管理员会话,管理令照旧可进。
用户明确要求:「取消一些小字的设计,变成鼠标移动上去再提醒」。口径:
- 解释性文字一律不进正文:写成
_q("…")/title="…"挂在对应控件、页签或标题上。 - 只留三类可见文字:① 数据(篇数、字数、等级、时间);② 状态回执(已上传 / 还没选文件 / 已选 0 篇); ③ 空状态里「怎么才会有内容」的一句。
- 分类、等级这类重复出现的值只在下拉里显示一次,别在旁边再写一遍「当前:X」。
- 调试味信息(doc_id、sha256、磁盘路径)不进列表,需要时进
title。
- 层级即设计:先保证「最重要的东西第一眼看到」,再谈装饰;一屏里不要什么都同等醒目。
- 间距/字号用刻度:间距
--s1..--s6= 4/8/12/16/24/32(相邻差 ≥25%);字号--f1..--f5= 12/14/16/18/24。 - 少用边框:分组优先用底色(
--code-bg)与留白,边框只留给表格行与必要控件;空状态、折叠区不再套虚线框。 - 表单别铺满:
.grid2上限 760px,宽屏下不拉成一条长龙。 - 表格数字右对齐(
td.num,等宽数字),文本左对齐。 - 危险操作降级:红色文字 + 灰底(
tiny ghost+color: var(--danger)),不整排顶着红框。