9.8 KiB
前端 UI 开发规范(给 Gemini)
你(Gemini)只负责前端 UI。这份文档是你动手前的唯一须知,请先完整读一遍再改任何代码。 本项目是 Kanboard 1.2.52(开源 PHP 看板)的二次开发,分支
fix-newUI。 代码根目录:W:\kanban\kanboard-1.2.52\(下文所有相对路径都以此为基准)。 文档里说的"屎山"指:同一样式散落多处互相打架、死代码、内联样式乱塞、写死颜色/宽度。本规范的全部目的就是不让它再变成屎山。
0. 三条铁律(违反任何一条 = 制造屎山)
- 所有 CSS 只写在
assets/css/custom_dashboard.css,并放进正确的编号区块。 严禁在.php模板里内联<style>,严禁新建别的 css 文件。 - 同一个东西只允许有一处样式来源。 改样式先去对应区块找现成的改,别另起一段重复定义(重复 = 下次没人知道哪段生效)。
- 改颜色一律用变量,不准写死色值。 主题色变量在
assets/css/custom_login.css的:root里(如--login-bg、--login-card-bg、--color-primary)。
1. 怎么运行 / 怎么看到你的改动
- 应用跑在
http://127.0.0.1:8000,由本地 PHP 实时读磁盘文件提供服务(双击W:\kanban\start-kanban.bat启动;那个黑窗口要一直开着)。 - 改完文件不需要清缓存:框架会给 css/js 的 URL 自动加
?文件修改时间戳,存盘即换新。 - ⚠️ 弹窗(modal)内容是 AJAX 加载的,不是随页面一起来的。 所以看弹窗的改动要:
- 先 F5 刷新整个页面(让
<head>里的新 CSS 重新加载) - 再重新打开那个弹窗(光 F5 不重开弹窗,看到的还是旧弹窗 DOM)
- 先 F5 刷新整个页面(让
「改了看不见」自查清单(按顺序排查,别瞎猜缓存)
- 改的是不是
custom_dashboard.css的正确区块?(不是某个模板里的内联样式 / 不是.min.css) - 有没有 F5 + 重新打开弹窗?
- 服务器还在跑吗?(浏览器
ERR_CONNECTION_REFUSED= 8000 端口的服务进程被关了,重开start-kanban.bat,这跟你的代码无关) - 是不是被核心写死的样式用更高特异性盖住了?见第 5 节。
2. 你能碰 / 绝对不能碰的文件
✅ 允许修改(前端 UI 全在这几处)
| 文件 | 作用 |
|---|---|
assets/css/custom_dashboard.css |
全站自定义样式总入口(登录页除外)。你 95% 的工作在这里 |
assets/css/custom_login.css |
登录页样式 + 全站主题色变量 :root |
assets/js/custom_dashboard.js |
UI 行为脚本(label 转 placeholder、定位"指派给我"等) |
app/Template/ 下的自定义模板(见第 4 节) |
弹窗/页面的 HTML 结构 |
⛔ 绝对不要改(改了要么白改,要么炸)
assets/js/app.min.js、assets/js/vendor.min.js—— 压缩文件,没有源码,无法维护。Kanboard 弹窗的结构和行为就藏在app.min.js里,别手改它;要调 UI 行为就写在custom_dashboard.js。assets/css/*.min.css(vendor/light/dark/auto/print)—— 核心主题,只读。vendor/、app/Model/、app/Controller/、app/Core/、data/db.sqlite—— 后端/数据,不归你管。
3. custom_dashboard.css 的结构(必须维护好目录)
文件顶部有一个编号目录(TOC),正文按编号分区块。新增样式时:放进对应编号区块;如果开了新主题,更新顶部 TOC。
1. 全局背景
2. 顶栏 Header(logo / 标题 / 项目切换器)
3. 侧边栏 Sidebar
4. 页面头部标签 Page header
5. 列表 / 卡片 / 提示 / 搜索框
6. 顶栏注入组件(视图切换 / 过滤)
7. 项目概览仪表盘(KPI + 标签页)
8. 看板 Kanban board
9. 任务【编辑】弹窗表单布局 (.task-form-*)
10. 任务【新建】弹窗表单布局 (.custom-task-form-*)
11. 弹窗通用外观(所有 #modal-box)
「改什么 → 改哪里」速查
| 你想改 | 去这里 |
|---|---|
| 任意弹窗的外壳(宽度/圆角/遮罩/关闭按钮/通用按钮) | custom_dashboard.css §11 |
| 新建任务弹窗的表单布局 | custom_dashboard.css §10 |
| 编辑任务弹窗的表单布局 | custom_dashboard.css §9 |
| 主题色 | custom_login.css 的 :root(亮色)和 @media (prefers-color-scheme: dark)(暗色) |
| 弹窗内字段的行为(隐藏 label、占位符等) | custom_dashboard.js |
| 弹窗的 HTML 结构(加/删字段、换列) | 对应模板(第 4 节),样式仍写回 css |
4. 关键模板 & 一个必须知道的"两套表单"陷阱
| 模板 | 是什么 |
|---|---|
app/Template/layout.php |
全站骨架,负责加载 css/js(一般别动) |
app/Template/header/title.php |
顶栏标题区 |
app/Template/header/custom_board_selector.php |
项目切换下拉 |
app/Template/project_overview/show.php |
项目概览(KPI 卡 + 纯 CSS 标签页) |
app/Template/task_creation/show.php |
新建任务弹窗(已去内联样式,只剩 HTML) |
app/Template/task_modification/show.php |
编辑任务弹窗 |
⚠️ 陷阱:新建 和 编辑 是两套不同的类名,别搞混!
- 新建任务(
task_creation/show.php)用.custom-task-form-container/.custom-task-form-main/.custom-task-form-secondary/.custom-task-form-tertiary,样式在 §10。 - 编辑任务(
task_modification/show.php)用.task-form-container/.task-form-main-column/.task-form-secondary-column/.task-form-bottom,样式在 §9。 - 改其中一个弹窗,只动它对应那套类名;想两个一起改,两节都要改。别把
.task-form-*的规则套到新建弹窗上(反之亦然),那是无效的死代码。
5. Kanboard 核心避坑大全(不知道这些 = 改半天找不到原因)
5.1 核心给很多控件写死了像素宽度 —— 放进网格/弹窗会撑爆或太窄
在三列网格里,这些写死宽度会把整张表撑出横向滚动条。已知清单:
| 选择器 | 核心写死的宽度 | 出现在 |
|---|---|---|
.text-editor textarea / .text-editor .text-editor-preview-area |
700px | 描述(markdown 编辑器) |
input[type="text"]:not(.input-addon-field) |
300px | 普通文本框 |
.form-date / .form-datetime |
150px | 到期/开始时间 |
.form-input-small |
150px | 参考 |
.form-input-large / .tag-autocomplete |
400px | 标签等 |
.color-picker |
220px | 颜色下拉 |
.task-form-main-column input[type="text"] |
700px | 编辑弹窗标题 |
处理原则:在表单容器里把它们强制改成 width:100% !important; max-width:100% !important,让它随所在列自适应。 §10 已经对编辑器和这些字段做了覆盖,照着那个写法加即可,不要去改核心 .min.css。
5.2 弹窗的"滚动层"是 #modal-box,不是 #modal-content
核心:#modal-box { overflow:auto }。所以想处理弹窗的横向溢出,要针对 #modal-box,针对 #modal-content 没用(这是上次踩了很久的坑)。
- 已有一条精准收口:
#modal-box:has(.custom-task-form-container)(用:has()只作用于任务表单弹窗,不影响其它可能需要横向滚动的弹窗)。收溢出前要先确认右侧没有真内容被藏起来,否则就是"裁掉内容糊弄",不允许。
5.3 CSS 特异性:你的规则可能被核心更高特异性的规则盖住
例:核心 input[type="text"]:not(.input-addon-field).form-date{width:150px} 的特异性是 (0,3,1),会压过你写的 .custom-task-form-container input[type="text"]{...}(0,2,1)。
- 现象就是"我明明写了 width 却不生效"。
- 解决:把选择器写得更具体(带上具体类名,如
.custom-task-form-container input.form-date)或在该属性上加!important。!important只在确实被核心盖住时用,不要全文乱撒。
5.4 样式加载顺序(layout.php)
vendor/theme.min.css → custom_login.css → custom_dashboard.css → DB 自定义 CSS(目前为空)。
你的 custom_dashboard.css 在主题之后加载,同特异性下能赢核心。变量来自 custom_login.css(在它之前加载,所以变量可用)。
6. 标准改动流程(每次都这样做)
- 定位:先按第 3 节速查表找到该改的区块/文件,去看现有规则,在原处改。
- 不破坏现状:尽量不动其它区块;删任何东西前,先确认它没被别的模板/页面引用(两套表单类名见 4 节)。
- 用变量:颜色用
:root变量,不写死。 - 验证:F5 + 重新打开弹窗,亲眼确认效果;顺手看一眼别的页面/弹窗没被你连累。
- 保持整洁:新增区块要在 TOC 登记;写一句注释说明"这段管什么"。
- 括号配平:CSS 大括号要成对,别留半截规则。
7. 当前已知待办(都是 JS 行为,CSS 改不动它们)
这些在新建任务弹窗里,属于 custom_dashboard.js / 核心 JS 的行为问题,别试图用 CSS 硬怼:
- 游离的"我"(指派给我链接)定位错乱 →
custom_dashboard.js第 58–79 行 - 标题下红色
*没被隐藏 →custom_dashboard.js第 46–47 行 - 部分字段 label→占位符转换不干净 →
custom_dashboard.js第 6–44 行 - 颜色选择器弹层定位 → 核心
app.min.js(最难,建议最后碰)
8. 一句话总结
CSS 全进 custom_dashboard.css 的对应编号区块;颜色用变量;别碰 .min.js/.min.css;新建和编辑是两套类名别混;核心写死的宽度要在表单里覆盖成 100%;改完 F5+重开弹窗验证。 守住这些,就不会再变屎山,也不会再出"改了看不见"的怪事。