Files
kanboard/UI_GUIDE_FOR_GEMINI.md
T
2026-06-02 14:26:59 +00:00

153 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端 UI 开发规范(给 Gemini)
> 你(Gemini)**只负责前端 UI**。这份文档是你动手前的唯一须知,请**先完整读一遍再改任何代码**。
> 本项目是 **Kanboard 1.2.52**(开源 PHP 看板)的二次开发,分支 `fix-newUI`。
> 代码根目录:`W:\kanban\kanboard-1.2.52\`(下文所有相对路径都以此为基准)。
> 文档里说的"屎山"指:同一样式散落多处互相打架、死代码、内联样式乱塞、写死颜色/宽度。**本规范的全部目的就是不让它再变成屎山。**
---
## 0. 三条铁律(违反任何一条 = 制造屎山)
1. **所有 CSS 只写在 `assets/css/custom_dashboard.css`,并放进正确的编号区块。** 严禁在 `.php` 模板里内联 `<style>`,严禁新建别的 css 文件。
2. **同一个东西只允许有一处样式来源。** 改样式先去对应区块找现成的改,别另起一段重复定义(重复 = 下次没人知道哪段生效)。
3. **改颜色一律用变量,不准写死色值。** 主题色变量在 `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 加载的,不是随页面一起来的。** 所以看弹窗的改动要:
1.**F5 刷新整个页面**(让 `<head>` 里的新 CSS 重新加载)
2. **再重新打开那个弹窗**(光 F5 不重开弹窗,看到的还是旧弹窗 DOM)
### 「改了看不见」自查清单(按顺序排查,别瞎猜缓存)
1. 改的是不是 `custom_dashboard.css` 的**正确区块**?(不是某个模板里的内联样式 / 不是 `.min.css`
2. 有没有 **F5 + 重新打开弹窗**
3. 服务器还在跑吗?(浏览器 `ERR_CONNECTION_REFUSED` = 8000 端口的服务进程被关了,重开 `start-kanban.bat`**这跟你的代码无关**
4. 是不是被**核心写死的样式用更高特异性盖住了**?见第 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. 顶栏 Headerlogo / 标题 / 项目切换器)
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. 标准改动流程(每次都这样做)
1. **定位**:先按第 3 节速查表找到该改的区块/文件,去看现有规则,**在原处改**。
2. **不破坏现状**:尽量不动其它区块;删任何东西前,先确认它没被别的模板/页面引用(两套表单类名见 4 节)。
3. **用变量**:颜色用 `:root` 变量,不写死。
4. **验证**:F5 + 重新打开弹窗,亲眼确认效果;顺手看一眼别的页面/弹窗没被你连累。
5. **保持整洁**:新增区块要在 TOC 登记;写一句注释说明"这段管什么"。
6. **括号配平**:CSS 大括号要成对,别留半截规则。
---
## 7. 当前已知待办(都是 JS 行为,CSS 改不动它们)
这些在新建任务弹窗里,属于 `custom_dashboard.js` / 核心 JS 的行为问题,**别试图用 CSS 硬怼**:
- 游离的"我"(指派给我链接)定位错乱 → `custom_dashboard.js` 第 5879 行
- 标题下红色 `*` 没被隐藏 → `custom_dashboard.js` 第 4647 行
- 部分字段 label→占位符转换不干净 → `custom_dashboard.js` 第 644 行
- 颜色选择器弹层定位 → 核心 `app.min.js`(最难,建议最后碰)
---
## 8. 一句话总结
**CSS 全进 `custom_dashboard.css` 的对应编号区块;颜色用变量;别碰 `.min.js`/`.min.css`;新建和编辑是两套类名别混;核心写死的宽度要在表单里覆盖成 100%;改完 F5+重开弹窗验证。** 守住这些,就不会再变屎山,也不会再出"改了看不见"的怪事。