feat(V0.2): 打卡与日历合并为单视图, 打卡内容按 每天/每周/每月 分组
实现设计文档 §11.5「日历与打卡合并」待确认项 (界面设计.html 2.12 ②). 结构: - CheckinPage 由 3 个 tab 收敛为 2 个: 打卡(含日历) / 清单 - 新增 MergedView.jsx: 上为月历, 下为当日打卡项 (原 CalendarView + HabitView 的展示/交互合并到一个组件) 按规格落地: - 月历: 月份切换 + 回到今天; 去掉「昨天/今天/明天」分段; 日期格 38→31px - 分组: 每天 → 每周 → 每月, 组标题左侧 3px 主色竖条 + 右侧项数; 去掉「每年」分组 (若存在历史 year 项则归入"其它周期"分组, 避免数据凭空消失) - 卡片紧凑化: 内边距 12→8px, 环形 58→42px (环宽 6→5), 间距 10→7px - 操作: 撤销 / 编辑 / 归档 由卡片底部三个文字链接收进「⋯」底部面板 - 联动: 点日期即切换当日数据; 未来日期只读, 按钮灰显「计划」 - 组内仍按「未完成在前、已完成在后」排序 (F-CK-16) 样式: globals.css 新增 .mv-* 段 (月历/分组/紧凑卡片/操作面板), 数值与设计稿一致. 服务端无需改动: habits 接口已返回 period/periodLabel/expectedPerDay/canCheck 等字段.
This commit is contained in:
@@ -814,3 +814,72 @@ body.me-safe-top .app-safe-top { height: 0; }
|
||||
border: 2px solid transparent; transition: transform 0.15s ease;
|
||||
}
|
||||
.color-dot.active { border-color: rgba(0,0,0,.25); transform: scale(1.12); }
|
||||
|
||||
/* ================== 打卡 · 日历与打卡合并视图 (V0.2.1, 设计文档 §11.5) ================== */
|
||||
/* 上: 月历; 下: 当日打卡项, 按 每天/每周/每月 分组. 卡片紧凑化. */
|
||||
.mv-view { display: flex; flex-direction: column; min-height: 0; }
|
||||
|
||||
/* ---- 月历 ---- */
|
||||
.mv-cal { background: #fff; border-radius: 10px; margin: 8px 12px 0; padding: 6px 6px 8px; box-shadow: 0 1px 2px rgba(0,0,0,.04); }
|
||||
.mv-month { display: flex; align-items: center; gap: 8px; padding: 2px 4px 6px; }
|
||||
.mv-month b { font-size: 14px; }
|
||||
.mv-month .arrow { font-size: 17px; color: var(--color-muted); line-height: 1; padding: 0 3px; cursor: pointer; }
|
||||
.mv-month .today { margin-left: auto; font-size: 11px; color: var(--color-primary); cursor: pointer; }
|
||||
.mv-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
|
||||
.mv-wd span { text-align: center; font-size: 10px; color: var(--color-muted); padding: 1px 0 3px; display: block; }
|
||||
.mv-day {
|
||||
height: 31px; margin: 1px 0; display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; border-radius: 6px;
|
||||
font-size: 12px; line-height: 1.15; color: var(--color-text); cursor: pointer;
|
||||
}
|
||||
.mv-day.out { color: #c8c8c8; }
|
||||
.mv-day.future { color: #b0b0b0; }
|
||||
.mv-day.today { color: var(--color-primary); font-weight: 700; }
|
||||
.mv-day.sel { background: var(--color-primary); color: #fff; font-weight: 600; }
|
||||
.mv-day i { width: 4px; height: 4px; border-radius: 50%; margin-top: 2px; }
|
||||
.mv-day i.partial { background: #ff8f1f; }
|
||||
.mv-day i.full { background: #00b578; }
|
||||
.mv-day i.over { background: #ff6b6b; }
|
||||
.mv-day.sel i { background: #fff; }
|
||||
.mv-rate { display: flex; justify-content: space-between; align-items: center; font-size: 11px; color: var(--color-muted); padding: 7px 6px 0; }
|
||||
.mv-rate b { color: var(--color-primary); }
|
||||
|
||||
/* ---- 当日栏 ---- */
|
||||
.mv-daybar { display: flex; align-items: center; gap: 8px; padding: 10px 14px 2px; font-size: 13px; font-weight: 600; }
|
||||
.mv-daybar .badge { font-weight: 400; color: var(--color-muted); font-size: 11px; }
|
||||
.mv-daybar .sum { margin-left: auto; font-size: 11px; color: var(--color-muted); font-weight: 400; }
|
||||
|
||||
/* ---- 分组 ---- */
|
||||
.mv-groups { padding-bottom: 4px; }
|
||||
.mv-ghead { display: flex; align-items: center; gap: 6px; padding: 9px 14px 5px; font-size: 11px; font-weight: 600; color: var(--color-muted); }
|
||||
.mv-ghead::before { content: ""; width: 3px; height: 11px; border-radius: 2px; background: var(--color-primary); }
|
||||
.mv-ghead .cnt { margin-left: auto; font-weight: 400; color: #b8bcc4; }
|
||||
|
||||
/* ---- 紧凑卡片 ---- */
|
||||
.mv-card {
|
||||
position: relative; display: flex; align-items: center; gap: 9px; background: #fff;
|
||||
border-radius: 9px; padding: 8px 10px; margin: 0 12px 7px; box-shadow: 0 1px 2px rgba(0,0,0,.04);
|
||||
}
|
||||
.mv-card.done { background: #f7fbf8; }
|
||||
.mv-main { flex: 1; min-width: 0; }
|
||||
.mv-name { font-size: 14px; font-weight: 600; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.mv-meta { font-size: 10px; color: var(--color-muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.mv-meta .st { color: #ff8f1f; background: rgba(255,143,31,.12); border-radius: 3px; padding: 0 4px; margin-left: 5px; }
|
||||
.mv-btn {
|
||||
font-size: 11px; border-radius: 999px; padding: 4px 12px; background: var(--color-primary);
|
||||
color: #fff; flex-shrink: 0; white-space: nowrap; cursor: pointer;
|
||||
}
|
||||
.mv-btn.grey { background: #f2f3f5; color: var(--color-muted); }
|
||||
.mv-more { color: #c0c4cc; font-size: 15px; line-height: 1; padding: 4px 2px 4px 6px; flex-shrink: 0; cursor: pointer; }
|
||||
.mv-add-wrap { margin-top: 2px; }
|
||||
|
||||
/* ---- 「⋯」操作面板 ---- */
|
||||
.mv-sheet { padding: 16px 16px 4px; }
|
||||
.mv-sheet .sheet-title { font-size: 15px; font-weight: 600; margin-bottom: 8px; }
|
||||
.mv-sheet-row {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 12px 4px; border-top: 1px solid var(--color-border); font-size: 14px; cursor: pointer;
|
||||
}
|
||||
.mv-sheet-row.danger { color: var(--color-danger); }
|
||||
.mv-sheet-row.disabled { opacity: .45; cursor: default; }
|
||||
.mv-sheet-row .k { font-size: 11px; color: #b8bcc4; }
|
||||
|
||||
Reference in New Issue
Block a user