v24 第 11 批:7 大条 20 子项(首页/名册/观影/裁剪/日程/财务)

用户 2026-10-04 第 11 批,7 大条:
- #1 首页:未来七天过滤掉「农历」(每日一条会淹掉真日程);右侧日历本标签
  从灰字(.dash-tag)改成**实心色块**(底色=日历色、白字、text-shadow 兜底浅色)。
- #2 名册:分组改**居中模态框**(用户要"像选观影人一样")。修掉"点第二次失效"
  ——根因是旧实现用**捕获阶段**监听 document click 做"点外面就关",与触发按钮
  的 click 打架;模态把关闭收敛到遮罩/✕/取消。卡片「编辑」后加「删除」
  (→ people/destroy);详情页底部删除改成 btn-danger + btn-block-lg 大红按钮 + 两步确认。
- #3 名册详情页重排:.detail(260px+1fr) → .pcard(头像左上 + 右侧姓名/标签)
  + .detail-stack 全宽往下。旧布局头像卡比右栏矮,头像下留一大片空白。
- #4 观影:影院下拉换**自定义组件**(原生 <option> 画不了色块)——按钮+列表、
  每行色点,值仍写隐藏 input[name=cinema_id];「管理影院」→「新建影院」弹框
  (带 back=movies/new,存完回本页并 ?cinema=<id> 自动选中)。
  修「开始/结束时间标签跑到控件下面」:upgradeRange 原来 insertBefore(host, group.firstChild)
  把控件插到了 label 之上 —— 改成插在第一个原生控件之前。
- #5 裁剪改 **Cropper.js**(assets/vendor/cropper/,按需加载走 fb-cropper meta):
  弹框 overflow:hidden + 固定画布(**无滚动条**)、**去掉缩放条**改滚轮 wheelZoomRatio、
  viewMode:1 + autoCropArea 保证框小于画布、8 个触点全露。
  结果仍写 *_crop = 归一化 x,y,w,h(提交契约不变)。
- #6 日程:内置节假日原来每天只标**一天**(国庆只出一条)→ FIXED 改成
  [名字, 放假天数] 按区间铺;月视图从周日改**周一**起(表头同步);
  跳转日期从"长条+原生框"改成**单个 btn-icon**,点开弹 Semi 日期选择器。
- #7 财务:单条曲线无盘点时只回一个点(图看着像全 0)→ 改成"从创建日(0)画到今天";
  图下条目从"每账目一张小图卡"改成**一张 chart_multi 多线图 + 颜色图例**
  (Ledger::LEGEND_COLORS 按 id 取模,保证颜色稳定);账目页卡顿同源治理
  (行上只留按钮、表单全页一份 #ledPanels);修改按钮改弹框并回填归属人。

## 顺带修的真 bug(本批最要紧的三条)
1. **观影表单提交静默失效**:「新建影院」弹框被误嵌在观影主表单 <form> 内。
   HTML 不允许 form 嵌套 → 浏览器拆开内层,弹框里 required 的"影院名称"变成
   主表单必填项、又因 hidden 无法聚焦 → 点「记下这场电影」什么都不发生
   (Chrome: invalid form control with name='name' is not focusable)。
   → 弹框移到主表单之后。部署脚本加防线:按顺序配平 form 开闭判断是否嵌套。
2. **裁剪取消没清空文件框**(换 Cropper 时丢)→ close(cancelled),4 个取消入口
   传 true 清空;否则"点了取消"仍会把没裁的原图传上去。
3. **裁剪预览退化成原图**(同批丢)→ 用 canvas 按 Cropper 的原图像素矩形重画,
   toDataURL 写回预览,恢复"所见即所得"。

## 连带修复:选人组件懒渲染(线上实测的必要性)
线上真实数据下账目页 6939 KB / 16788 个 input、观影表单 1194 个 input ——
根因是 _person_picker.php 首屏就把**全部候选人**渲成 <label>+<input>。
改成:首屏只留「不选」+ data-pp-people(JSON),**打开弹框时**才 buildList();
无 JS 兜底走 <noscript>(HTML5 规定启用脚本时其内容按纯文本解析,不产生节点)。
新增 window.ppSetSelected / decorateItems(动态项要补算首字母)。
实测账目页 6939 KB → 544 KB。新增 _fb_picker_lazy_check.py(11/0 + 反向 2 红)。

验证:e2e 786/0、交互 90/0、半集成 27/0、batch_e 91/0、batch10 46/0、batch9 38/0、
crop 17/0(+反向)、picker_unify 28/0、picker_lazy 11/0(+反向)、formbloat 9/0、
upgrade 126/0、mobile 688/0、drag 5/0、geom 5/5。
线上自检 19/19;线上真实账号验收 7/0(含"主表单无隐藏必填""线上 Cropper 接管+取消清空")。
This commit is contained in:
2026-10-04 17:42:21 +08:00
parent b2ca4f336e
commit 5d80b9480b
17 changed files with 1592 additions and 637 deletions
+286 -60
View File
@@ -460,6 +460,38 @@ textarea.input { min-height: 76px; resize: vertical; }
.detail-photo .name { font-size: 18px; font-weight: 600; margin: 14px 0 4px; }
.detail-photo .sub { color: var(--muted); font-size: 13px; }
/* ---- v24 第 11 批 #3:详情页改「名片卡 + 全宽堆叠」----
⚠️ 旧的 .detail 是 260px + 1fr 两栏,头像卡比右栏矮得多 → 头像下面留一大片空白。
现在头像与基本信息并排成一张名片,其余内容全宽往下排。 */
.pcard {
display: flex; align-items: flex-start; gap: 18px;
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--radius); box-shadow: var(--shadow);
padding: 18px 20px; margin-bottom: 18px;
}
.pcard-avatar { flex: 0 0 auto; }
.pcard-avatar img {
width: 108px; height: 108px; object-fit: cover;
border-radius: 12px; display: block; background: var(--line-2);
}
.pcard-main { flex: 1 1 auto; min-width: 0; padding-top: 2px; }
.pcard-name {
display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
font-size: 21px; font-weight: 600; margin-bottom: 8px;
}
.pcard-real { font-size: 13px; font-weight: 400; color: var(--muted); }
.pcard-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pcard-chip {
display: inline-block; padding: 3px 10px; border-radius: 999px;
background: var(--line-2); color: var(--ink); font-size: 12.5px;
}
.detail-stack { display: flex; flex-direction: column; gap: 18px; }
.detail-stack > div { min-width: 0; }
@media (max-width: 640px) {
.pcard { flex-direction: column; align-items: center; text-align: center; }
.pcard-name, .pcard-meta { justify-content: center; }
}
.kv { display: flex; flex-direction: column; }
.kv-row {
display: grid; grid-template-columns: 96px 1fr; gap: 12px;
@@ -1013,16 +1045,58 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
「分组」「移出名册」两份表单全页只渲染一份(原来每卡各一份,1184 人 =
2369 个 form / 27234 个 input,密码管理器逐个扫描把页面拖死)。
这里给共享浮层一个定位容器,面板由 JS 贴合触发按钮摆放。 */
.roster-menus { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.roster-menus .rm-panel {
position: fixed; pointer-events: auto;
/* ---- v24 第 11 批 #2:名册卡片的动作**居中模态框** ----
(第 10 批是"贴按钮的浮层",用户反馈分组"点第二次失效"且要求"像选观影人一样弹框",
于是改成遮罩 + 居中面板,与 _person_picker 同一形态。) */
.rm-modal { position: fixed; inset: 0; z-index: 60; display: flex;
align-items: center; justify-content: center; }
.rm-modal[hidden] { display: none; }
.rm-mask { position: absolute; inset: 0; background: rgba(47, 36, 30, .34); }
.rm-panel {
position: relative; z-index: 1;
background: var(--surface); border: 1px solid var(--line);
border-radius: 10px; box-shadow: var(--shadow-l);
padding: 8px 0; min-width: 200px;
border-radius: 14px; box-shadow: var(--shadow-l);
width: min(360px, 92vw); max-height: min(78vh, 620px);
display: flex; flex-direction: column;
}
.roster-menus .rm-panel .person-move { padding: 0 10px; }
.roster-menus .rm-panel .person-move.is-self { padding: 0 12px; }
.roster-menus[hidden] { display: none; }
.rm-panel[hidden] { display: none; }
.rm-head {
display: flex; align-items: center; gap: 10px;
padding: 12px 14px 10px; border-bottom: 1px solid var(--line-2);
}
.rm-head b { font-size: 14.5px; font-weight: 600; }
.rm-x {
margin-left: auto; border: 0; background: transparent; cursor: pointer;
font-size: 15px; line-height: 1; color: var(--muted); padding: 4px 6px; border-radius: 6px;
}
.rm-x:hover { background: var(--line-2); color: var(--ink); }
.rm-body { padding: 8px 6px; overflow-y: auto; }
.rm-foot {
display: flex; gap: 8px; justify-content: flex-end;
padding: 10px 14px; border-top: 1px solid var(--line-2);
}
.rm-warn {
margin: 0; padding: 10px 12px; font-size: 13px; line-height: 1.7;
background: #FDF2F0; border: 1px solid #F0D6D1; border-radius: 8px; color: #7A2A20;
}
.rm-modal .pg-menu { display: contents; }
.rm-modal .pd-form { display: contents; }
.rm-modal .person-move { display: block; padding: 6px 14px 10px; }
.rm-modal .person-move.is-kin { padding: 6px 14px 10px; }
/* ---- v24 第 11 批 #2:详情页底部「删除」= 大按钮(与「开通账号」同规格,红色底)---- */
.del-big { display: flex; flex-direction: column; gap: 12px; max-width: 420px; }
.del-big-tip { margin: 0; font-size: 13px; line-height: 1.75; color: var(--muted); }
.btn-block-lg {
display: flex; align-items: center; justify-content: center;
width: 100%; padding: 12px 16px; font-size: 14.5px;
}
.del-big-confirm {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 10px 12px; background: #FDF2F0;
border: 1px solid #F0D6D1; border-radius: 8px; font-size: 13px; color: #7A2A20;
}
.del-big-confirm[hidden] { display: none; }
.person-move { display: flex; gap: 6px; padding: 8px 12px; flex-wrap: wrap; }
.person-move .select { flex: 1 1 auto; min-width: 0; padding: 6px 8px; font-size: 13px; }
.person-move .btn { flex: 0 0 auto; }
@@ -1244,6 +1318,13 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
/* ---------------- 图片裁剪浮层 ---------------- */
/* 覆盖层默认不占空间;打开时铺满整屏,把底下的页面锁住(裁剪时不该能点到别处) */
/* ---- 图片裁剪(v24 第 11 批 #5:改用 Cropper.js)----
用户的四条硬要求(原话见 assets/js/app.js 那段注释)在这里逐条落地:
① 弹框**不要有任何滚动条** → 面板 overflow:hidden;画布尺寸固定,由 Cropper 缩放图片去适应。
② 图片无论多大都要缩放到框内 → 交给 Cropper 的 viewMode:1(container 自适应)。
③ **不要缩放条** → 原来那根 .crop-zoom-row 整块删掉了,改滚轮缩放。
④ 裁剪框要比弹框小、**所有触点都露出来** → 画布四周留出 22px 内边距,
Cropper 的四个角手柄画成实心白点,永远落在面板可见区内。 */
.crop-overlay { display: none; }
.crop-overlay.is-open {
display: flex; position: fixed; inset: 0; z-index: 100;
@@ -1251,49 +1332,52 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
padding: 20px; background: rgba(44, 35, 29, .55);
}
.crop-panel {
background: var(--surface); border-radius: var(--radius);
background: var(--surface); border-radius: 14px;
box-shadow: var(--shadow-l); padding: 16px;
max-width: calc(100vw - 24px); max-height: calc(100vh - 24px); overflow: auto;
max-width: calc(100vw - 24px); max-height: calc(100vh - 24px);
/* ① 不许出滚动条:面板自己 overflow:hidden,画布尺寸按视口算死在下面 */
overflow: hidden;
display: flex; flex-direction: column;
}
.crop-head {
display: flex; align-items: baseline; gap: 8px;
font-size: 15px; font-weight: 600; margin-bottom: 12px;
font-size: 15px; font-weight: 600; margin-bottom: 12px; flex: 0 0 auto;
}
.crop-head .crop-shape { font-size: 12px; font-weight: 400; color: var(--muted); }
.crop-stage {
position: relative; margin: 0 auto; overflow: auto;
background: #F1E7D6; border-radius: var(--radius-s);
touch-action: none; /* 手机上拖框时别把页面一起滚走 */
user-select: none;
.crop-x {
margin-left: auto; align-self: center; border: 0; background: transparent;
font-size: 15px; line-height: 1; color: var(--muted);
cursor: pointer; padding: 4px 6px; border-radius: 6px;
}
/* 图片的宽高由 JS 按倍率写死(放大后比舞台大,靠舞台自身滚动看别处)——
所以这里**不能**写 width/height:100%,否则缩放就永远没效果。 */
.crop-img { display: block; max-width: none; }
/* 缩放条 —— 用户明确要求"裁剪的时候要能缩放" */
.crop-zoom-row {
display: flex; align-items: center; gap: 10px;
margin-top: 12px; font-size: 13px; color: var(--muted);
.crop-x:hover { background: var(--line-2); color: var(--ink); }
/* 画布:**固定尺寸**(不是 max-height),这样 Cropper 一定会把图片缩进来,
而不会让容器去滚动。宽高都换算成"视口内还能放下的最大方块"。
⚠️ 留 22px 内边距是给裁剪框四个角的手柄留位(要求④)。 */
.crop-canvas {
flex: 0 0 auto; position: relative;
width: min(560px, calc(100vw - 88px));
height: min(66vh, 460px);
border-radius: var(--radius-s); overflow: hidden;
background: #2C231D;
}
.crop-zoom { flex: 1; min-width: 120px; accent-color: var(--brand); }
.crop-zoom-val { font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }
/* 框外的部分压暗 —— 这是"你只留下框里这块"最直观的表达 */
.crop-box {
position: absolute; cursor: move;
border: 2px solid #fff;
box-shadow: 0 0 0 9999px rgba(44, 35, 29, .5);
.crop-canvas img { display: block; max-width: 100%; }
.crop-tip { color: var(--muted); font-size: 12px; margin: 12px 0 0; flex: 0 0 auto; }
.crop-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px; flex: 0 0 auto; }
/* ④ 触点全露出:Cropper 默认的手柄太细、颜色偏灰,在深色画布上不好抓。
这里加粗、改成白底品牌边,并**保证它们不被画布裁掉**(Cropper 自己会留 margin)。 */
.cropper-view-box,
.cropper-face { border-radius: 2px; }
.cropper-line { background-color: rgba(255, 255, 255, .9); }
.cropper-point {
width: 12px; height: 12px; opacity: 1;
background-color: #fff; border: 2px solid var(--brand);
border-radius: 50%;
}
.crop-box::before {
content: ''; position: absolute; inset: 0;
border: 1px dashed rgba(255, 255, 255, .75); pointer-events: none;
}
.crop-handle {
position: absolute; right: -8px; bottom: -8px;
width: 20px; height: 20px; border-radius: 50%;
background: #fff; border: 2px solid var(--brand);
cursor: nwse-resize;
}
.crop-tip { color: var(--muted); font-size: 12px; margin: 12px 0 0; }
.crop-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 14px; }
.cropper-point.point-se { width: 14px; height: 14px; }
.cropper-bg { background-image: none; background-color: #2C231D; }
.cropper-modal { background-color: rgba(20, 14, 10, .55); }
@media (max-width: 720px) {
.order-move .btn { padding: 4px 10px; }
@@ -1595,6 +1679,62 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
.ck-head b { font-size: 14px; }
.ck-svg { display: block; margin-top: 2px; }
/* ---- v24 第 11 批 #7:账目行的两个弹框(全页各一份)----
原来每行内联一套(form + 选人组件),账目一多就是几千个 form
—— 用户报的"账目页也卡、还是 Bitwarden 冲突"就是这个。
现在行上只有按钮,表单集中到 #ledPanels。 */
.led-modal {
position: fixed; inset: 0; z-index: 75;
display: flex; align-items: center; justify-content: center;
}
.led-modal[hidden] { display: none; }
.led-mask { position: absolute; inset: 0; background: rgba(47, 36, 30, .34); }
.led-panel-lg {
position: relative; z-index: 1;
background: var(--surface); border: 1px solid var(--line);
border-radius: 14px; box-shadow: var(--shadow-l);
width: min(460px, 92vw); max-height: min(86vh, 660px);
display: flex; flex-direction: column;
}
.led-panel-lg[hidden] { display: none; }
.led-ph {
display: flex; align-items: center; gap: 10px;
padding: 12px 14px 10px; border-bottom: 1px solid var(--line-2);
}
.led-ph b { font-size: 14.5px; }
.led-x {
margin-left: auto; border: 0; background: transparent; cursor: pointer;
font-size: 15px; color: var(--muted); padding: 4px 6px; border-radius: 6px;
}
.led-x:hover { background: var(--line-2); color: var(--ink); }
.led-pb { padding: 12px 14px; overflow-y: auto; }
.led-pb .field { margin-bottom: 12px; }
.led-pb .field > label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px; }
.led-pf {
display: flex; gap: 8px; justify-content: flex-end;
padding: 10px 14px; border-top: 1px solid var(--line-2);
}
/* 弹框里的选人组件别撑破面板 */
.led-pb .pp { max-width: none; }
.led-panel-lg .led-hist { margin-top: 4px; }
/* ---- v24 第 11 批 #7:图例(只显示"哪个颜色代表哪个账目")----
用户原话:「图下面的条目不用显示详情,只需要显示每个账目的颜色,
就是说哪个颜色代表哪个账目,就可以了。」
所以从"每账目一张小卡"改成一行色块图例。 */
.ck-legend {
display: flex; flex-wrap: wrap; gap: 6px 16px;
margin: 10px 2px 0; font-size: 13px; color: var(--ink);
}
.ck-lg-item { display: inline-flex; align-items: center; gap: 6px; }
.ck-lg-item[hidden] { display: none; }
.ck-lg-dot {
width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
/* 多线图:比单条小图高一点,才看得出差异 */
.ck-multi { margin-top: 4px; }
/* ---- v24 第 10 批 #3:总金额图在最前(跨整行),下面才是逐条账目 ---- */
.ck-total { margin-bottom: 14px; }
.ck-total .ck-head b { font-size: 15px; }
@@ -2428,6 +2568,92 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
.dash-when { flex: 0 0 96px; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.dash-what { flex: 1 1 auto; min-width: 0; font-size: 14px; }
.dash-tag { flex: 0 0 auto; font-size: 11px; color: var(--faint); }
/* ---- v24 第 11 批 #4:影院下拉(带色点)+ 新建影院弹框 ----
原生 <option> 画不了色块,所以自己做一个"按钮 + 弹出列表":
值仍写进隐藏的 input[name=cinema_id],服务端与既有测试都不用改。 */
.cinema-select-row { display: flex; align-items: flex-start; gap: 8px; }
.cs { position: relative; flex: 1 1 auto; min-width: 0; }
.cs-btn {
display: flex; align-items: center; gap: 8px; width: 100%;
padding: 10px 12px; font: inherit; font-size: 14px; color: var(--ink);
background: #fff; border: 1px solid var(--line); border-radius: var(--radius-s);
cursor: pointer; text-align: left;
}
.cs-btn:hover { border-color: var(--brand-2); }
.cs-btn:focus { outline: none; border-color: var(--brand); }
.cs-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-caret { flex: 0 0 auto; color: var(--muted); font-size: 11px; }
.cs-dot {
flex: 0 0 auto; width: 12px; height: 12px; border-radius: 3px;
background: var(--line-2); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.cs-dot.is-none { background: transparent; box-shadow: inset 0 0 0 1px var(--line); }
.cs-menu {
position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 40;
background: var(--surface); border: 1px solid var(--line);
border-radius: 10px; box-shadow: var(--shadow-l);
padding: 4px; max-height: 280px; overflow-y: auto;
}
.cs-menu[hidden] { display: none; }
.cs-item {
display: flex; align-items: center; gap: 8px; width: 100%;
padding: 8px 10px; border: 0; border-radius: 7px; background: transparent;
font: inherit; font-size: 13.5px; color: var(--ink); cursor: pointer; text-align: left;
}
.cs-item:hover, .cs-item:focus { background: var(--line-2); outline: none; }
/* 新建影院:居中弹框(与名册的动作弹框同一形态,只是更宽) */
.cn-modal {
position: fixed; inset: 0; z-index: 70;
display: flex; align-items: center; justify-content: center;
}
.cn-modal[hidden] { display: none; }
.cn-mask { position: absolute; inset: 0; background: rgba(47, 36, 30, .34); }
.cn-panel {
position: relative; z-index: 1;
background: var(--surface); border: 1px solid var(--line);
border-radius: 14px; box-shadow: var(--shadow-l);
width: min(420px, 92vw); max-height: min(84vh, 620px);
display: flex; flex-direction: column;
}
.cn-head {
display: flex; align-items: center; gap: 10px;
padding: 12px 14px 10px; border-bottom: 1px solid var(--line-2);
}
.cn-head b { font-size: 14.5px; }
.cn-x {
margin-left: auto; border: 0; background: transparent; cursor: pointer;
font-size: 15px; color: var(--muted); padding: 4px 6px; border-radius: 6px;
}
.cn-x:hover { background: var(--line-2); color: var(--ink); }
.cn-body { padding: 12px 14px; overflow-y: auto; }
.cn-body .field { margin-bottom: 12px; }
.cn-body .field > label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 5px; }
.cn-foot {
display: flex; gap: 8px; justify-content: flex-end;
padding: 10px 14px; border-top: 1px solid var(--line-2);
}
.cn-presets { display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.cn-preset {
width: 20px; height: 20px; border-radius: 5px; border: 1px solid rgba(0, 0, 0, .12);
cursor: pointer; padding: 0;
}
.cn-preset:hover { transform: scale(1.08); }
/* ---- v24 第 11 批 #1:日历本改「实心色块」----
原来 .dash-tag 是 --faint 的 11px 灰字,压在宣纸底上几乎看不见(用户原话"看不清")。
现在:底色 = 该日历本的颜色(由模板内联),文字白色 —— 与左侧那个小圆点同一个颜色,
扫一眼就知道"这条是哪本日历的"。
⚠️ 颜色是用户自选的,浅色(如 #97A630)上白字会发虚 → 加一点文字阴影保底,
比"强制加深颜色"好:本子的颜色是用户定的,不该被我们改。 */
.dash-cal {
flex: 0 0 auto; align-self: center;
padding: 2px 9px; border-radius: 999px;
color: #fff; font-size: 11.5px; font-weight: 500; line-height: 1.7;
white-space: nowrap; max-width: 40%;
overflow: hidden; text-overflow: ellipsis;
text-shadow: 0 1px 1px rgba(0, 0, 0, .22);
}
@media (max-width: 620px) {
.dash-when { flex: 0 0 auto; }
}
@@ -2458,28 +2684,28 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb,
background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600;
}
/* ---- v24 第 10 批 #6:日程页头的「跳到某一天」按钮 ----
外观与 .btn 一致(它是 <label> 包着一个原生 date 输入,所以自己画外壳)。
原生日历指示器收掉:整个按钮都是可点的,多一个小图标反而抢视线。 */
/* ---- 日程页头的「跳到某一天」(v24 第 11 批 #6 重做)----
用户要求:「跳转日期那个地方,不要那么长,只需要和设置一样,一个按钮即可」,
且日期选择要用 Semi(与全站统一)。
所以现在是**一个方图标按钮**(与 ☰ 的 .btn-icon 同规格):
点开弹一个只含 Semi 日期选择器的轻浮层,选中即跳。 */
.cal-jump { display: inline-flex; margin: 0; }
.cal-jump-btn {
display: inline-flex; align-items: center; gap: 6px;
cursor: pointer; white-space: nowrap;
.cal-jump-btn { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.cal-jump-host { position: fixed; inset: 0; z-index: 80; display: flex;
align-items: center; justify-content: center; }
.cal-jump-pop {
background: var(--surface); border: 1px solid var(--line);
border-radius: 14px; box-shadow: var(--shadow-l); padding: 10px 12px 12px;
}
.cal-jump-btn:hover { border-color: var(--brand-2); }
.cal-jump-txt { font-size: 13px; }
.cal-jump-date {
border: 0; background: transparent; font: inherit; font-size: 13px;
color: var(--ink); cursor: pointer; padding: 0; min-width: 118px;
font-variant-numeric: tabular-nums;
.cal-jump-pop-head {
display: flex; align-items: center; gap: 10px;
font-size: 13.5px; font-weight: 600; margin-bottom: 8px;
}
.cal-jump-date::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .55; }
.cal-jump-date:focus { outline: none; }
@media (max-width: 640px) {
/* 窄屏:只留图标 + 日期,把「跳到」两个字收掉(不然页头一排按钮换行) */
.cal-jump-txt { display: none; }
.cal-jump-date { min-width: 104px; }
.cal-jump-x {
margin-left: auto; border: 0; background: transparent; cursor: pointer;
font-size: 14px; color: var(--muted); padding: 3px 6px; border-radius: 6px;
}
.cal-jump-x:hover { background: var(--line-2); color: var(--ink); }
/* ==================== 周 / 天:按小时铺的时间网格 ==================== */
/* 结构:左边一条"小时刻度"沟槽(tg-gutter),右边 N 个日期列(tg-col)。