fix(token/flatpickr): dark mode calendar + friendlier date display

- Add !important to all Flatpickr CSS overrides to beat CDN specificity
- Change dateFormat from ISO 'Y-m-d\TH:i' to 'Y-m-d  H:i' (double space)
- Update tokGetFiltered to use .replace(/\s+/,'T') for Safari compat
This commit is contained in:
wjl2023 committed 2026-05-27 16:36:41 +08:00
1 parent 65b1dab225
commit a4adb63e45
3 files changed
+75 -19

No files matched your search

+55
View File
@@ -225,3 +225,58 @@ CSS: `.task-elapsed { color: var(--accent); font-size: 12px; font-weight: 600; }
2. `restoreElapsedBadges(sess, box)` 从 `renderAllMessages` 移到 `pollSession` finally 块 — 确保消息已加载
3. `startTaskTimer(sess)` 从最后一条 user 消息的 ts 恢复 taskStartedAt — 运行中任务继续计时
- 验证结果:刷新后 badge 正确显示"已运行 17s"/"已运行 14s",已完成任务静态显示,运行中任务实时计时
---
## 9. Feature: Flatpickr 日期选择器 (Token 统计页)
**状态**:✅ 完成
**分支**:`feat/flatpickr-datepicker`
**Commit**:5e20cc7
### 9.1 改动摘要
| # | 文件 | 改动 | 行数 |
|---|------|------|------|
| 1 | index.html | +Flatpickr CDN (CSS + JS + zh locale);input type="text" + class="tok-date" + readonly | +6/-2 |
| 2 | styles.css | .tok-date 样式 + Flatpickr 主题覆盖(全用 CSS 变量,含暗色模式) | +30/-3 |
| 3 | app.js | 替换原生 change 事件为 Flatpickr 初始化 + reset 用 fp.clear() | +6/-4 |
**总计**:3 files, +44/-8
### 9.2 关键决策
- **dateFormat: `'Y-m-d\\TH:i'`** — 输出 ISO 格式(如 `2026-05-27T14:30`),Safari 兼容
- **locale 判断**:`document.documentElement.lang==='en' ? 'default' : 'zh'`
- **readonly**:禁止手动输入,只能通过日历选择
- **Flatpickr 主题覆盖**:所有颜色走 CSS 变量(--bg, --txt, --blue, --hover-2 等),暗色用 `html[data-appearance="dark"]` 选择器
### 9.3 关联代码图
```
index.html:199-201 → <input .tok-date>
styles.css:729-760 → .tok-date + .flatpickr-calendar 主题覆盖
app.js:2265-2266 → tokSince / tokUntil 声明(未改)
app.js:2353-2360 → tokGetFiltered() 用 new Date(input.value) 解析(未改)
app.js:2408-2413 → Flatpickr 初始化 + reset 逻辑(新)
```
### 9.4 验证结果
- ✅ Flatpickr 正常初始化(input 获得 `flatpickr-input` class)
- ✅ 点击弹出日历
- ✅ 用户手动测试选择日期成功
- ✅ dateFormat ISO 兼容 tokGetFiltered 的 `new Date()` 解析
- ✅ 无硬编码颜色/文本
### 9.5 Code Review 自检
| 检查项 | 通过 |
|--------|------|
| 无硬编码颜色 | ✅ 全走 CSS 变量 |
| 无硬编码文本 | ✅ placeholder 走 data-i18n-ph |
| 暗色模式兼容 | ✅ html[data-appearance="dark"] 覆盖 |
| Safari 兼容 | ✅ ISO dateFormat |
| 原有逻辑不变 | ✅ tokGetFiltered 未修改 |
| 单分支隔离 | ✅ feat/flatpickr-datepicker |
+4 -3
View File
@@ -2352,8 +2352,9 @@ async function tokPollBridge() {
function tokGetFiltered() {
let records = tokLoadHistory();
const since = tokSince?.value ? new Date(tokSince.value).getTime()/1000 : 0;
const until = tokUntil?.value ? new Date(tokUntil.value).getTime()/1000 : 0;
const parseD = v => v ? new Date(v.replace(/\s+/,'T')).getTime()/1000 : 0;
const since = parseD(tokSince?.value);
const until = parseD(tokUntil?.value);
if (since) records = records.filter(r=>r.ts>=since);
if (until) records = records.filter(r=>r.ts<=until);
return records;
@@ -2406,7 +2407,7 @@ function tokRenderTable(records) {
async function loadTokenPage(){await tokPollBridge();const f=tokGetFiltered();const all=tokLoadHistory();tokRenderStats(f,all);tokRenderTable(f);}
/* Flatpickr 初始化 */
const _fpOpts = { enableTime:true, time_24hr:true, dateFormat:'Y-m-d\\TH:i', locale:window.flatpickr?.l10ns?.[document.documentElement.lang==='en'?'default':'zh']||'default', allowInput:false, onChange(){ _tokPage=0; loadTokenPage(); } };
const _fpOpts = { enableTime:true, time_24hr:true, dateFormat:'Y-m-d H:i', locale:window.flatpickr?.l10ns?.[document.documentElement.lang==='en'?'default':'zh']||'default', allowInput:false, onChange(){ _tokPage=0; loadTokenPage(); } };
const fpSince = tokSince ? flatpickr(tokSince, _fpOpts) : null;
const fpUntil = tokUntil ? flatpickr(tokUntil, _fpOpts) : null;
const tokResetBtn=document.getElementById('tok-reset');
+16 -16
View File
@@ -736,32 +736,32 @@ html[data-boot-has-sessions] .chat-start{ display:none !important; }
.tok-date:focus{ border-color:var(--blue); outline:none; }
/* Flatpickr 主题覆盖 — 全部使用项目 CSS 变量 */
.flatpickr-calendar{
background:var(--card); border:1px solid var(--line); border-radius:var(--radius);
box-shadow:var(--shadow-pop); font-size:13px;
background:var(--card) !important; border:1px solid var(--line) !important; border-radius:var(--radius) !important;
box-shadow:var(--shadow-pop) !important; font-size:13px;
}
.flatpickr-months .flatpickr-month,
.flatpickr-current-month{ color:var(--txt); fill:var(--txt); }
.flatpickr-current-month{ color:var(--txt) !important; fill:var(--txt) !important; }
.flatpickr-current-month .flatpickr-monthDropdown-months,
.flatpickr-current-month input.cur-year{ color:var(--txt); background:var(--field-bg); }
.flatpickr-weekdays{ background:var(--field-bg); }
span.flatpickr-weekday{ color:var(--muted); font-size:11px; }
.flatpickr-current-month input.cur-year{ color:var(--txt) !important; background:var(--field-bg) !important; }
.flatpickr-weekdays{ background:var(--field-bg) !important; }
span.flatpickr-weekday{ color:var(--muted) !important; font-size:11px; }
.flatpickr-day{
color:var(--txt); border-radius:6px;
color:var(--txt) !important; border-radius:6px;
}
.flatpickr-day:hover{ background:var(--hover-2); border-color:transparent; }
.flatpickr-day.today{ border-color:var(--blue); }
.flatpickr-day.selected{ background:var(--blue); color:var(--on-accent); border-color:var(--blue); }
.flatpickr-day:hover{ background:var(--hover-2) !important; border-color:transparent !important; }
.flatpickr-day.today{ border-color:var(--blue) !important; }
.flatpickr-day.selected{ background:var(--blue) !important; color:var(--on-accent) !important; border-color:var(--blue) !important; }
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay{ color:var(--muted2); }
.flatpickr-day.nextMonthDay{ color:var(--muted2) !important; }
.flatpickr-time input,
.flatpickr-time .flatpickr-am-pm{ color:var(--txt); background:var(--field-bg); }
.flatpickr-time .flatpickr-am-pm{ color:var(--txt) !important; background:var(--field-bg) !important; }
.flatpickr-time input:hover,
.flatpickr-time input:focus{ background:var(--hover-2); }
.numInputWrapper:hover{ background:var(--hover-2); }
.flatpickr-time input:focus{ background:var(--hover-2) !important; }
.numInputWrapper:hover{ background:var(--hover-2) !important; }
.flatpickr-months .flatpickr-prev-month,
.flatpickr-months .flatpickr-next-month{ fill:var(--txt-2); }
.flatpickr-months .flatpickr-next-month{ fill:var(--txt-2) !important; }
.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg{ fill:var(--txt); }
.flatpickr-months .flatpickr-next-month:hover svg{ fill:var(--txt) !important; }
.tok-reset{
border:1px solid var(--line); border-radius:6px; padding:5px 10px;
font-size:12px; background:var(--field-bg); color:var(--muted); cursor:pointer;