--- /** * 热力图动效方案预览(Phase 5j):一页并陈 5 个方案,供用户点选。 * * 为什么单开预览路由:热力图的"动"是纯审美 + 体感决策,改错要回滚一轮; * 一页五案 + 页顶锚点,用户在任何设备上点开就能比。选定后我把选中方案 * 落进 Heatmap.astro,然后删掉本路由。 * * 设计红线(五个方案都守):灰阶骨架、只允许 accent 做强调、prefers-reduced-motion * 下一律退化为静态、零第三方依赖、不引入持续 rAF 循环(省电)。 */ import BaseLayout from '../layouts/BaseLayout.astro'; import HeatGrid from '../components/geek/HeatGrid.astro'; import { loadHeatmap, levelOf, type HeatDay } from '../lib/heatmap'; const { weeks, total } = await loadHeatmap(); const days: HeatDay[] = weeks.flat(); const buildTime = new Date().toISOString().slice(0, 10); /* ── 连续贡献(本地计算,替代此前构建期抓取的 streak.svg 快照)── */ const countOf = new Map(days.map((d) => [d.date, d.count])); const today = new Date(); const isoOf = (d: Date) => d.toISOString().slice(0, 10); // 「当前连续」按最后一个有贡献的日子往回数:今天尚未贡献不该让连续归零(GitHub 同口径), // 若严格按"今天必须是活跃日"计算,早上访问本站会看到 0,与直觉冲突。 let current = 0; const lastActive = [...days].reverse().find((d) => d.count > 0)?.date ?? ''; if (lastActive) { const start = new Date(`${lastActive}T00:00:00Z`); for (let i = 0; ; i++) { const d = new Date(start); d.setUTCDate(start.getUTCDate() - i); const c = countOf.get(isoOf(d)) ?? 0; if (c > 0) current++; else break; } } let longest = 0; let run = 0; for (const d of days) { run = d.count > 0 ? run + 1 : 0; if (run > longest) longest = run; } const bestDay = days.reduce((a, b) => (b.count > a.count ? b : a), days[0]); const activeDays = days.filter((d) => d.count > 0).length; const stats = { total, current, longest, best: bestDay?.count ?? 0, bestDate: bestDay?.date ?? '', activeDays }; ---

热力图:五个动效方案

同一份真实数据(近一年 {total} 次贡献 · 活跃 {stats.activeDays} 天 · 当前连续 {stats.current} 天 · 最长 {stats.longest} 天),数据更新于 {buildTime}(构建期快照)。
看完告诉我选哪个(回「A」「B」「C」「D」「E」,也可以说「C 但速度慢一点」)。 五个方案都守灰阶红线、都尊重「减少动态效果」系统设置。

A

入场波纹

滚动到热力图时,格子像水面一样按「周 + 星期」斜向漫过、逐个亮起(约 0.9s)。 优点有生命感、不打扰、只播一次;代价纯装饰,不提供额外信息。

B

光标光晕

鼠标在网格上移动时,一小片光晕跟着走,被照到的格子更亮,右下角浮出「日期 · 贡献数」。 优点能精确读数、零轮播;代价触屏设备没有指针,需退化为点按读数。

把指针移到格子上 →

C

年度回放

拖动滑块从头"重放"这一年,累计贡献数跟着涨;也可点播放自动扫过。 优点最有叙事感、能直观感受节奏;代价多一层交互,需要一点耐心。

累计 {total} 次 · 第 {weeks.length} 周
D

连续电流

当前连续的那几天会有一条光带从最早一格流到最新一格,像电流经过;旁边显示连续天数。 优点把"坚持"这件事讲成故事;代价只覆盖最近一小段,全年的信息仍靠静态格子。

{stats.current} 连续天数{lastActive ? `(截至 ${lastActive})` : ''} 最长 {stats.longest} 天 · 单日最高 {stats.best} 次
E

悬停周详情

指针落在任一格上,整列(那一周)轻轻抬起,右侧给出「这一周合计 / 最好的一天」。 优点信息密度最高、动效克制;代价仍是鼠标优先,触屏靠点按。

数据口径:GitHub GraphQL 贡献日历,构建期快照({buildTime})。切到"减少动态效果"时五个方案全部退化为静态网格。