skill-forge-hub 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.en.md +9 -0
- package/CHANGELOG.md +9 -0
- package/README.en.md +18 -7
- package/README.md +18 -7
- package/annual-report/SKILL.md +10 -0
- package/annual-report/resources/disk-and-html.md +1 -0
- package/annual-report/resources/reference.html +1 -1
- package/annual-report/resources/skillforge-guide.html +408 -0
- package/annual-report/resources/skillforge-guide.txt +131 -0
- package/article-to-html/SKILL.md +12 -0
- package/article-to-html/resources/skillforge-guide.html +408 -0
- package/article-to-html/resources/skillforge-guide.txt +131 -0
- package/cli.js +6 -5
- package/commit-heatmap/SKILL.md +70 -0
- package/commit-heatmap/resources/collect.md +22 -0
- package/commit-heatmap/resources/generate.md +15 -0
- package/commit-heatmap/resources/html-rules.md +21 -0
- package/commit-heatmap/resources/reference.html +228 -0
- package/commit-heatmap/resources/skillforge-guide.html +408 -0
- package/commit-heatmap/resources/skillforge-guide.txt +131 -0
- package/commit-heatmap/resources/usage-guide.md +23 -0
- package/commit-heatmap/user-config.md +12 -0
- package/daily-report/SKILL.md +10 -0
- package/daily-report/resources/disk-and-html.md +1 -1
- package/daily-report/resources/reference.html +1 -1
- package/daily-report/resources/skillforge-guide.html +408 -0
- package/daily-report/resources/skillforge-guide.txt +131 -0
- package/data-prepper/SKILL.md +54 -0
- package/data-prepper/resources/clean-rules.md +18 -0
- package/data-prepper/resources/overview.md +17 -0
- package/data-prepper/resources/read-data.md +13 -0
- package/data-prepper/resources/skillforge-guide.html +408 -0
- package/data-prepper/resources/skillforge-guide.txt +131 -0
- package/data-prepper/resources/usage-guide.md +24 -0
- package/data-prepper/user-config.md +11 -0
- package/decision-log/SKILL.md +53 -0
- package/decision-log/resources/index.md +21 -0
- package/decision-log/resources/record.md +19 -0
- package/decision-log/resources/skillforge-guide.html +408 -0
- package/decision-log/resources/skillforge-guide.txt +131 -0
- package/decision-log/resources/usage-guide.md +23 -0
- package/decision-log/user-config.md +9 -0
- package/deck-stage/SKILL.md +11 -1
- package/deck-stage/resources/cover-template.html +1 -1
- package/deck-stage/resources/skillforge-guide.html +408 -0
- package/deck-stage/resources/skillforge-guide.txt +131 -0
- package/docs/architecture.en.md +2 -1
- package/docs/architecture.md +2 -1
- package/docs/install.en.md +56 -0
- package/docs/install.md +56 -0
- package/docs/usage-examples.en.md +50 -0
- package/docs/usage-examples.md +50 -0
- package/magic-deck/SKILL.md +11 -1
- package/magic-deck/resources/deck-spec.md +1 -1
- package/magic-deck/resources/reference.html +1 -1
- package/magic-deck/resources/skillforge-guide.html +408 -0
- package/magic-deck/resources/skillforge-guide.txt +131 -0
- package/meeting-minutes/SKILL.md +10 -0
- package/meeting-minutes/resources/disk-and-html.md +1 -0
- package/meeting-minutes/resources/reference.html +1 -1
- package/meeting-minutes/resources/skillforge-guide.html +408 -0
- package/meeting-minutes/resources/skillforge-guide.txt +131 -0
- package/meta-forge/SKILL.md +11 -1
- package/meta-forge/resources/forge-rules.md +4 -1
- package/meta-forge/resources/skillforge-guide.html +408 -0
- package/meta-forge/resources/skillforge-guide.txt +131 -0
- package/monthly-report/SKILL.md +10 -0
- package/monthly-report/resources/disk-and-html.md +1 -0
- package/monthly-report/resources/reference.html +1 -1
- package/monthly-report/resources/skillforge-guide.html +408 -0
- package/monthly-report/resources/skillforge-guide.txt +131 -0
- package/one-pager/SKILL.md +71 -0
- package/one-pager/resources/content.md +18 -0
- package/one-pager/resources/generate.md +16 -0
- package/one-pager/resources/html-rules.md +21 -0
- package/one-pager/resources/reference.html +209 -0
- package/one-pager/resources/skillforge-guide.html +408 -0
- package/one-pager/resources/skillforge-guide.txt +131 -0
- package/one-pager/resources/usage-guide.md +23 -0
- package/one-pager/user-config.md +11 -0
- package/package.json +10 -1
- package/prompt-pouch/SKILL.md +12 -1
- package/prompt-pouch/resources/reference.html +1 -1
- package/prompt-pouch/resources/skillforge-guide.html +408 -0
- package/prompt-pouch/resources/skillforge-guide.txt +131 -0
- package/quarterly-report/SKILL.md +10 -0
- package/quarterly-report/resources/disk-and-html.md +1 -0
- package/quarterly-report/resources/reference.html +1 -1
- package/quarterly-report/resources/skillforge-guide.html +408 -0
- package/quarterly-report/resources/skillforge-guide.txt +131 -0
- package/release-notes/SKILL.md +54 -0
- package/release-notes/resources/collect.md +17 -0
- package/release-notes/resources/publish-checklist.md +11 -0
- package/release-notes/resources/skillforge-guide.html +408 -0
- package/release-notes/resources/skillforge-guide.txt +131 -0
- package/release-notes/resources/usage-guide.md +25 -0
- package/release-notes/resources/write.md +27 -0
- package/release-notes/user-config.md +15 -0
- package/skill-doctor/SKILL.md +53 -0
- package/skill-doctor/resources/checks.md +27 -0
- package/skill-doctor/resources/report.md +26 -0
- package/skill-doctor/resources/skillforge-guide.html +408 -0
- package/skill-doctor/resources/skillforge-guide.txt +131 -0
- package/skill-doctor/resources/usage-guide.md +22 -0
- package/skill-doctor/user-config.md +9 -0
- package/spec-doc2spec/SKILL.md +10 -0
- package/spec-doc2spec/resources/skillforge-guide.html +408 -0
- package/spec-doc2spec/resources/skillforge-guide.txt +131 -0
- package/spec-spec2doc/SKILL.md +10 -0
- package/spec-spec2doc/resources/skillforge-guide.html +408 -0
- package/spec-spec2doc/resources/skillforge-guide.txt +131 -0
- package/team-report-collector/SKILL.md +70 -0
- package/team-report-collector/resources/collect.md +23 -0
- package/team-report-collector/resources/generate.md +14 -0
- package/team-report-collector/resources/html-rules.md +22 -0
- package/team-report-collector/resources/reference.html +384 -0
- package/team-report-collector/resources/skillforge-guide.html +408 -0
- package/team-report-collector/resources/skillforge-guide.txt +131 -0
- package/team-report-collector/resources/usage-guide.md +25 -0
- package/team-report-collector/user-config.md +12 -0
- package/twin-docs/SKILL.md +53 -0
- package/twin-docs/resources/glossary.md +12 -0
- package/twin-docs/resources/skillforge-guide.html +408 -0
- package/twin-docs/resources/skillforge-guide.txt +131 -0
- package/twin-docs/resources/sync-check.md +15 -0
- package/twin-docs/resources/translate.md +20 -0
- package/twin-docs/resources/usage-guide.md +24 -0
- package/twin-docs/user-config.md +11 -0
- package/weekly-report/SKILL.md +10 -0
- package/weekly-report/resources/disk-and-html.md +1 -1
- package/weekly-report/resources/reference.html +1 -1
- package/weekly-report/resources/skillforge-guide.html +408 -0
- package/weekly-report/resources/skillforge-guide.txt +131 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-heatmap
|
|
3
|
+
description: 把 git 仓库近一年提交聚合为 GitHub 风格提交热力图 HTML 页面(53 周×7 天格子、颜色深浅按提交数分档、悬停显示日期与次数、总提交数/最长连续提交天数统计),离线零依赖、主题可切换。当用户请求提交热力图、commit heatmap、代码活跃度、提交日历、年度代码贡献图时使用。
|
|
4
|
+
allowed-tools: Bash, Read, Write
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 提交热力图(commit-heatmap)
|
|
9
|
+
|
|
10
|
+
把冷冰冰的 git log 变成一张可视的代码活跃度图:聚合近一年提交 → 按日计数 → 热力图 HTML(GitHub 风格格子 + 统计卡)落盘。
|
|
11
|
+
|
|
12
|
+
## 生成流程
|
|
13
|
+
|
|
14
|
+
0. **读用户配置**(REPO/DAYS/DIR/OPEN_HTML/THEME/EXCLUDE)→ 先 Read 同目录 `user-config.md`
|
|
15
|
+
1. **收集数据**(git log 聚合按日计数)→ 读 `resources/collect.md`
|
|
16
|
+
2. **生成 HTML**(先 Read reference.html 骨架替换数据)→ 读 `resources/generate.md` 与 `resources/html-rules.md` 两份
|
|
17
|
+
2.5 **交付前自检**(硬门禁不可跳过):HTML 文件写好后——
|
|
18
|
+
- 挂 pageerror 监听用 Chrome headless 访问页面(零容忍报错)→ 截全页 PNG Read 自查:标题卡、统计卡、热力图格子全渲染、无溢出、无豆腐块缺字
|
|
19
|
+
- 任何报错或视觉问题:修 HTML → 重检;全绿才进第 3 步
|
|
20
|
+
3. **使用咨询**(用户只问「热力图怎么用」等用法、未要求生成)→ 读 `resources/usage-guide.md`,将其内容原样输出(首行标题改为「提交热力图使用指南」),不收集提交、不落盘、不开浏览器
|
|
21
|
+
|
|
22
|
+
## ⚙️ 配置与自定义
|
|
23
|
+
|
|
24
|
+
**执行本 skill 前必须先 Read 同目录 `user-config.md`**:默认配置(REPO/DAYS/DIR/OPEN_HTML/THEME/EXCLUDE)都在该文件中,以它为准。升级技能时 user-config.md 不会被覆盖,你的修改永久保留;官方更新配置时另存 `user-config.md.upstream` 对照文件,可按需手动合并新配置点。
|
|
25
|
+
|
|
26
|
+
- **THEME**:页面主题,github 经典绿(默认)/ dark 深夜绿 / amber 琥珀金;生成时写 `<html data-theme="THEME值">` 定默认,页面右下角换肤坞随点随换(localStorage 记忆,键按页内嵌唯一 ID 隔离、多份产物互不串台、改名/移动目录记忆不丢;生成时头部写 `<meta name="heat-id" content="<UUID>">`,每次 crypto.randomUUID() 生成标准 UUID v4(8-4-4-4-12 十六进制,禁止手写变体、禁止沿用占位与旧值);落盘写文件前顺扫落盘目录下本技能命名的 html,读各文件 id meta 查重,撞号重掷至不重复)
|
|
27
|
+
|
|
28
|
+
## 配置版本机制(升级保护)
|
|
29
|
+
|
|
30
|
+
本 skill 当前配置版本为 `1`(对应 user-config.md 中的 `CONFIG_VERSION`)。执行时若发现 user-config.md 的 CONFIG_VERSION 与本节声明不一致:
|
|
31
|
+
|
|
32
|
+
1. 先将旧 user-config.md 备份为 `user-config.md.bak-<时间戳>`(同目录,绝不删除旧值)
|
|
33
|
+
2. 按本节「配置升级规则」迁移字段:新增字段补默认值、改名字段按映射改写、删除字段的值保留在备份中并在对话提示用户手动确认
|
|
34
|
+
3. 更新 CONFIG_VERSION 为当前版本
|
|
35
|
+
4. 对话中明确告知用户「检测到配置版本从 X 升级到 Y,旧配置已备份至 <路径>」
|
|
36
|
+
|
|
37
|
+
升级本 skill 时,配置结构如有变化必须同步更新本节的当前版本号与迁移说明;禁止在未声明版本变更的情况下静默修改配置语义。
|
|
38
|
+
## 文档同步自检纪律(维护者必读)
|
|
39
|
+
|
|
40
|
+
修改本 skill 任一文件(SKILL.md / user-config.md / resources/*)后,必须 grep 全文核对相关关键词在各文件间一致(字段名 / 流程节点 / 模板名改名时新旧词全仓核对,旧词零残留才算完成)。
|
|
41
|
+
## 🔧 报修处理流程(用户报页面问题时)
|
|
42
|
+
|
|
43
|
+
用户说「这个页面效果不对 / 布局乱了 / 有 UI 问题 / 样式错了 / 交互坏了」(常附截图或指出具体现象)→ 按以下流程处理,不以「重新生成一份」敷衍:
|
|
44
|
+
|
|
45
|
+
1. **立标准**:先 Read 本 skill 目录 `resources/reference.html`——它就是设计标准答案(布局/配色/交互全在代码里)
|
|
46
|
+
2. **找问题**:Read 用户那份问题 html 文件,与 reference 逐处比对(结构顺序 / CSS 变量 / 关键类名 / 交互 JS),定位跑偏处;用户给了截图则按截图现象反查
|
|
47
|
+
3. **修复**:以 reference 为准修复那份 html(只修跑偏处,不动正确内容;reference 与 html 不一致时以 reference 为准)
|
|
48
|
+
4. **自证**:Chrome headless 访问修复后页面截全页 PNG,Read 自查修复点恢复标准效果
|
|
49
|
+
5. **汇报**:一句话说清问题根因 + 修复了什么 + 附截图;若根因在 reference.html 自身,顺修 reference.html 对应处并在汇报中说明「参考模板已同步修正」
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## 产物升级(回炉)
|
|
53
|
+
|
|
54
|
+
生成 HTML 时头部写版本戳 `<meta name="sf-template" content="commit-heatmap@1">`(模板升级时递增 @N 并同步 reference.html 与本文档)。用户说「升级旧热力图/回炉」时:扫落盘目录读版本戳筛旧版(无版本戳或缺少 `<meta name="heat-id">` 稳定 ID 的产物视为 v0 最旧版,一并进清单)→ 列清单(文件/旧版本)→ AskUserQuestion 选全部或部分 → 逐份升级:浅升级(仅 CSS/JS 变化)对旧页替换 `<style>` 块与交互脚本、正文原样保留;深升级(DOM 结构变化)重新跑 git 收集按当前 reference.html 重建,先备份旧版 `.bak-时间戳`,重建必须沿用原页 heat-id meta 值(换 ID = 主题记忆失联)→ 报告三段式:✅ 已升级清单 / ⚠️ 手改保留说明 / 🟡 失败项原因。模板改动分级:业务改动、数据格式改动、页面改动任一发生即模板升级,版本戳 +1 并同步 reference.html 与本文档;纯措辞润色不 bump。每次生成 HTML 时顺扫落盘目录读版本戳:发现旧版产物主动告知用户「说『把我旧热力图都升级成新样式』即可一键升级」。
|
|
55
|
+
|
|
56
|
+
## 规则速览
|
|
57
|
+
|
|
58
|
+
- 计数口径:单仓库按提交者邮箱(默认)或姓名聚合;合并提交按 --no-merges 排除(需含时用户说明);时区按仓库本地 git 配置
|
|
59
|
+
- 数据零编造:热力图格子只画 git 统计出的真实数字;EXCLUDE 名单(邮箱/路径)过滤的提交如实排除并备注
|
|
60
|
+
- 离线零依赖:页面禁止 CDN/@import/外链资源,纯 HTML/CSS/JS 渲染格子,双击可开
|
|
61
|
+
- 落盘完成后对话必须报告落盘位置:完整路径,并注明 html 是否已在浏览器打开
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🔍 SkillForge 使用指引(整体咨询时触发)
|
|
66
|
+
|
|
67
|
+
当用户询问 **SkillForge 本身**(不是单个技能用法)——「skillforge 怎么用 / 使用说明 / 使用指引 / 是什么」「技能怎么安装 / 怎么升级 / 装了哪些技能 / 技能清单」「skill-forge ls / init / update 等命令怎么用」「技能安装器 / 技能锻造坊」等(中英文、近似说法均可,关键词可自由扩展):
|
|
68
|
+
1. Read 同目录 `resources/skillforge-guide.txt` 全文,按其内容整理回答(命令与参数以 txt 为准,勿自行编造)
|
|
69
|
+
2. 用系统命令打开同目录 `resources/skillforge-guide.html`(macOS `open`,Windows `start`),让用户在浏览器看排版版
|
|
70
|
+
3. 用户只问单个技能怎么用时(如「日报怎么用」)不触发本指引,走本技能的使用说明
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 收集数据(阶段 1)
|
|
2
|
+
|
|
3
|
+
## 聚合命令
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git -C <REPO> log --since="<DAYS> days ago" --until="today 23:59:59" --no-merges --pretty=format:'%ad|%ae' --date=format:'%Y-%m-%d'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
- 按行解析「日期|邮箱」,按日累加计数 → `{"YYYY-MM-DD": N}` 映射
|
|
10
|
+
- EXCLUDE 非空时:对每条提交用 `git log --pretty=format:'%ae|%an' -- <path>` 核对或直接按邮箱/路径关键词过滤,排除的提交计数减去
|
|
11
|
+
- 多作者仓库可按 `%ae` 分作者出多份(用户指定「按作者分」时)
|
|
12
|
+
|
|
13
|
+
## 统计派生
|
|
14
|
+
|
|
15
|
+
1. **总提交数**:所有日期计数之和
|
|
16
|
+
2. **最长连续提交天数**:日期集合按天扫描连续段,取最长段天数(当前未断的连续段标注「进行中」)
|
|
17
|
+
3. **活跃日占比**:有提交的天数 / DAYS
|
|
18
|
+
4. **最活跃日**:计数最高的日期 Top 1(并列取最近)
|
|
19
|
+
|
|
20
|
+
## 输出
|
|
21
|
+
|
|
22
|
+
`{"2026-11-12": 3, ...}` 映射 + 四项统计数字,交给阶段 2。日期零计数的日子自然缺失,渲染层补零。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 生成 HTML(阶段 2)
|
|
2
|
+
|
|
3
|
+
先 Read `resources/reference.html` 全文,以其为骨架模板逐处替换数据:
|
|
4
|
+
|
|
5
|
+
1. **meta**:`sf-template` 版本戳保持当前模板版本;`heat-id` 换成新 UUID(crypto.randomUUID() 标准 v4,落盘前顺扫落盘目录下本技能命名的 html 读 id meta 查重,撞号重掷)
|
|
6
|
+
2. **`window.HEAT_DATA`**:替换为 `{"2026-11-12": 3, ...}` 计数映射(JSON 序列化)
|
|
7
|
+
3. **`window.HEAT_STATS`**:替换为四项统计 `{total, streak, active, topDay, topCount}`
|
|
8
|
+
4. **标题与日期区间**:`<title>`、头部标题、区间徽章(YYYY-MM-DD 至 YYYY-MM-DD)替换
|
|
9
|
+
5. 其余(CSS/JS/结构)一律不许动;样式参数解释与禁止项见 `resources/html-rules.md`
|
|
10
|
+
|
|
11
|
+
## 落盘
|
|
12
|
+
|
|
13
|
+
- 文件名 `commit-heatmap.html`(DIR: auto 时落 REPO 根 reports/ 子目录,不存在则创建;目录已存在直接复用)
|
|
14
|
+
- OPEN_HTML: true 且落盘了 html 时自动打开浏览器(macOS:open <html文件>;Windows PowerShell:Start-Process <html文件>)
|
|
15
|
+
- **落盘完成后对话报告落盘位置**:完整路径,并注明 html 是否已在浏览器打开;对话中同时输出四项统计数字
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
> ⛔ **Reference 铁律(最高优先)**:本目录 `reference.html` 是定稿样式源码。生成 HTML 时必须先 Read `resources/reference.html` 与本文件两份,以 reference.html 为骨架模板逐处替换数据(HEAT_DATA/HEAT_STATS/标题/日期区间/heat-id UUID),本文件的描述是参数解释、变体规则与禁止项;两者冲突时**以 reference.html 为准**。修改本 skill 的 HTML 效果时,必须同步更新 `resources/reference.html` 与本文档的对应描述,禁止只改一处。
|
|
2
|
+
|
|
3
|
+
# 热力图 HTML 版式(GitHub 风格三主题)
|
|
4
|
+
|
|
5
|
+
## 版式总览
|
|
6
|
+
|
|
7
|
+
- GitHub 风格热力图:53 周列 × 7 天行格子矩阵(周起周日),格子 11px 圆角 2px、间距 3px;颜色按提交数五档深浅(0 档底色 var(--cell-0) 极浅,1 档 / 2 档 / 3 档 / 4+ 档逐级加深,档位变量 --cell-1 ~ --cell-4);格子 hover 放大 + tooltip「MM-DD · N 次提交」
|
|
8
|
+
- 三主题:github 经典绿(默认,浅底 #ffffff 系 + 绿色格)/ dark 深夜绿(深底 #0d1117 + 亮绿格)/ amber 琥珀金(暖底 + 金橙格);`html[data-theme]` 运行时切换;右下角换肤坞三点随点随换、localStorage 记忆(键 `heat:<ID>-theme`,ID = 页内嵌 heat-id meta,多份产物互不串台、改名/移动目录记忆不丢)
|
|
9
|
+
- 字体全用系统本地字体栈(system-ui + ui-monospace/'SF Mono'/Menlo/Consolas,品牌字体 PingFang/YaHei/apple-system 零出现),禁止 CDN、@import、外链 CSS/JS/图片/网络字体——页面离线双击可开
|
|
10
|
+
- 多文件隔离(必植):头部写 `<meta name="heat-id" content="<UUID>">`(crypto.randomUUID() 标准 UUID v4);localStorage 键一律 `heat:<ID>-xxx`,禁止裸通用键名;页面 JS 启动时校验 id meta——非法或缺失(占位残留/手写变体/误沿用旧值)时按路径键(`'sf-heal:' + location.pathname`)自愈为 crypto.randomUUID() 标准 v4 并回写 meta,console.warn 显性报警;路径键持久化保证同文件跨打开稳定复用;合法 UUID 原样放行
|
|
11
|
+
- 版本戳:`<meta name="sf-template" content="commit-heatmap@1">`(模板升级递增 @N)
|
|
12
|
+
- 布局:头部标题卡(标题 + 日期区间徽章)+ 统计卡四张横排(总提交数/最长连续天数/活跃日占比/最活跃日)+ 热力图容器(左侧月份纵标 + 顶部星期横标 + 格子矩阵)+ 图例(少 → 多 五色块);宽度超出容器横向滚动(.grid-scroll overflow-x:auto)
|
|
13
|
+
- 入场动画:标题卡与统计卡错峰上浮淡入;fill-mode 必须用 backwards 严禁 both;滚动入场用 IntersectionObserver + 2s 兜底 setTimeout 强制全显(headless 截图 / 打印预览环境格子不得永久隐藏)
|
|
14
|
+
- 页脚 10px muted 文字,署名固定 GENERATED BY AI TEAM(禁止真实团队名/项目名)
|
|
15
|
+
|
|
16
|
+
## 渲染规则
|
|
17
|
+
|
|
18
|
+
- `window.HEAT_DATA`:日期 → 次数映射;渲染从统计区间起点所在周的周日对齐补全至今天所在周,缺失日期补 0 档
|
|
19
|
+
- `window.HEAT_STATS`:{total, streak, active, topDay, topCount} 五项统计(active 为百分比数字)
|
|
20
|
+
- 格子 title 属性即 tooltip 兜底(原生 title,不引第三方库);今天所在格子加描边高亮
|
|
21
|
+
- ?shot 截图模式:页面 JS 检测 location.search 含 shot 时给 html 挂 data-shot 属性(CSS 关闭入场动画直接终态,headless 虚拟时间下动画帧不推进会停在初始帧导致截图空白)、强制全部卡片 opacity 1、隐藏标题卡/换肤坞/图例外的装饰,body 四周 padding 统一 40px
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN" data-theme="github">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<meta name="sf-template" content="commit-heatmap@1">
|
|
7
|
+
<meta name="heat-id" content="REF-HEAT-0000">
|
|
8
|
+
<title>提交热力图 · 示例项目</title>
|
|
9
|
+
<style>
|
|
10
|
+
:root, [data-theme="github"]{
|
|
11
|
+
--bg:#f6f8fa; --panel:#ffffff;
|
|
12
|
+
--text:#1f2328; --muted:#656d76;
|
|
13
|
+
--border:#d0d7de;
|
|
14
|
+
--cell-0:#ebedf0; --cell-1:#9be9a8; --cell-2:#40c463; --cell-3:#30a14e; --cell-4:#216e39;
|
|
15
|
+
--accent:#1f883d;
|
|
16
|
+
--today-ring:#0969da;
|
|
17
|
+
}
|
|
18
|
+
[data-theme="dark"]{
|
|
19
|
+
--bg:#0d1117; --panel:#161b22;
|
|
20
|
+
--text:#e6edf3; --muted:#8b949e;
|
|
21
|
+
--border:#30363d;
|
|
22
|
+
--cell-0:#161b22; --cell-1:#0e4429; --cell-2:#006d32; --cell-3:#26a641; --cell-4:#39d353;
|
|
23
|
+
--accent:#3fb950;
|
|
24
|
+
--today-ring:#58a6ff;
|
|
25
|
+
}
|
|
26
|
+
[data-theme="amber"]{
|
|
27
|
+
--bg:#1c1208; --panel:#281a0c;
|
|
28
|
+
--text:#f5e9d6; --muted:#b39b7c;
|
|
29
|
+
--border:#4a3620;
|
|
30
|
+
--cell-0:#241708; --cell-1:#6b3d14; --cell-2:#9c5a1a; --cell-3:#d08028; --cell-4:#f0a648;
|
|
31
|
+
--accent:#f0a648;
|
|
32
|
+
--today-ring:#ffd28a;
|
|
33
|
+
}
|
|
34
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
35
|
+
body{background:var(--bg);color:var(--text);font-family:system-ui,'Segoe UI',Roboto,sans-serif;min-height:100vh;padding:40px 20px}
|
|
36
|
+
.mono{font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,monospace}
|
|
37
|
+
.wrap{width:clamp(320px,92%,1100px);margin:0 auto}
|
|
38
|
+
.card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:24px;margin-bottom:20px;box-shadow:0 4px 16px rgba(0,0,0,.08);animation:riseIn .5s ease backwards}
|
|
39
|
+
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
|
|
40
|
+
.header-card{animation-delay:0s}
|
|
41
|
+
.stats-card{animation-delay:.13s}
|
|
42
|
+
.heat-card{animation-delay:.26s}
|
|
43
|
+
.header-card{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:10px}
|
|
44
|
+
.header-card h1{font-size:22px;color:var(--text)}
|
|
45
|
+
.range{font-size:12px;color:var(--muted)}
|
|
46
|
+
.stats-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;padding:0}
|
|
47
|
+
.stat{text-align:left}
|
|
48
|
+
.stat .num{font-size:26px;font-weight:700;color:var(--accent)}
|
|
49
|
+
.stat .lbl{font-size:12px;color:var(--muted);margin-top:4px}
|
|
50
|
+
.heat-card{overflow:hidden}
|
|
51
|
+
.legend{display:flex;align-items:center;gap:6px;justify-content:flex-end;margin-bottom:12px;font-size:11px;color:var(--muted)}
|
|
52
|
+
.legend .sw{width:11px;height:11px;border-radius:2px;display:inline-block}
|
|
53
|
+
.grid-scroll{overflow-x:auto;padding-bottom:8px}
|
|
54
|
+
.grid-wrap{display:inline-block;position:relative}
|
|
55
|
+
.months{display:flex;gap:3px;margin-left:28px;margin-bottom:4px;font-size:10px;color:var(--muted)}
|
|
56
|
+
.months span{width:48px;flex:none}
|
|
57
|
+
.rows{display:flex;gap:3px}
|
|
58
|
+
.weekdays{display:flex;flex-direction:column;gap:3px;margin-right:5px}
|
|
59
|
+
.weekdays span{width:18px;height:11px;font-size:9px;color:var(--muted);line-height:11px;text-align:right}
|
|
60
|
+
.grid{display:grid;grid-auto-flow:column;grid-template-rows:repeat(7,11px);gap:3px}
|
|
61
|
+
.cell{width:11px;height:11px;border-radius:2px;background:var(--cell-0);transition:transform .12s ease}
|
|
62
|
+
.cell:hover{transform:scale(1.35);outline:1px solid var(--border)}
|
|
63
|
+
.cell.l1{background:var(--cell-1)}
|
|
64
|
+
.cell.l2{background:var(--cell-2)}
|
|
65
|
+
.cell.l3{background:var(--cell-3)}
|
|
66
|
+
.cell.l4{background:var(--cell-4)}
|
|
67
|
+
.cell.today{outline:1.5px solid var(--today-ring);outline-offset:0}
|
|
68
|
+
.theme-dock{position:fixed;right:14px;bottom:14px;display:flex;gap:8px;background:var(--panel);border:1px solid var(--border);border-radius:20px;padding:7px 10px;z-index:9}
|
|
69
|
+
.th-dot{width:16px;height:16px;border-radius:50%;cursor:pointer;border:1.5px solid transparent;transition:transform .15s ease}
|
|
70
|
+
.th-dot:hover{transform:scale(1.2)}
|
|
71
|
+
.th-dot[data-t="github"]{background:#40c463}
|
|
72
|
+
.th-dot[data-t="dark"]{background:#39d353}
|
|
73
|
+
.th-dot[data-t="amber"]{background:#f0a648}
|
|
74
|
+
.th-dot.on{border-color:var(--today-ring)}
|
|
75
|
+
footer{text-align:center;color:var(--muted);font-size:10px;margin-top:26px}
|
|
76
|
+
html[data-shot] .card{animation:none!important}
|
|
77
|
+
</style>
|
|
78
|
+
</head>
|
|
79
|
+
<body>
|
|
80
|
+
<div class="wrap">
|
|
81
|
+
<div class="card header-card">
|
|
82
|
+
<h1>提交热力图 · 示例项目</h1>
|
|
83
|
+
<span class="range mono">2025-11-13 至 2026-11-12</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="card stats-card" style="padding:0;border:none;background:transparent;box-shadow:none">
|
|
86
|
+
<div class="stats-row">
|
|
87
|
+
<div class="card stat"><div class="num mono" id="st-total">486</div><div class="lbl">总提交数</div></div>
|
|
88
|
+
<div class="card stat"><div class="num mono" id="st-streak">12 天</div><div class="lbl">最长连续提交</div></div>
|
|
89
|
+
<div class="card stat"><div class="num mono" id="st-active">62%</div><div class="lbl">活跃日占比</div></div>
|
|
90
|
+
<div class="card stat"><div class="num mono" id="st-top">-</div><div class="lbl">最活跃日</div></div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="card heat-card">
|
|
94
|
+
<div class="legend">
|
|
95
|
+
<span>少</span>
|
|
96
|
+
<span class="sw" style="background:var(--cell-0)"></span>
|
|
97
|
+
<span class="sw" style="background:var(--cell-1)"></span>
|
|
98
|
+
<span class="sw" style="background:var(--cell-2)"></span>
|
|
99
|
+
<span class="sw" style="background:var(--cell-3)"></span>
|
|
100
|
+
<span class="sw" style="background:var(--cell-4)"></span>
|
|
101
|
+
<span>多</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="grid-scroll">
|
|
104
|
+
<div class="grid-wrap">
|
|
105
|
+
<div class="months" id="months"></div>
|
|
106
|
+
<div class="rows">
|
|
107
|
+
<div class="weekdays"><span></span><span>一</span><span></span><span>三</span><span></span><span>五</span><span></span></div>
|
|
108
|
+
<div class="grid" id="grid"></div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
<footer>GENERATED BY AI TEAM · 2026-11</footer>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="theme-dock" id="dock">
|
|
116
|
+
<span class="th-dot on" data-t="github" title="经典绿"></span>
|
|
117
|
+
<span class="th-dot" data-t="dark" title="深夜绿"></span>
|
|
118
|
+
<span class="th-dot" data-t="amber" title="琥珀金"></span>
|
|
119
|
+
</div>
|
|
120
|
+
<script>
|
|
121
|
+
window.HEAT_DATA = {"2026-11-05":9,"2026-11-06":4,"2026-11-07":2,"2026-11-08":7,"2026-11-09":1,"2026-11-10":5,"2026-11-11":3,"2026-11-12":2};
|
|
122
|
+
window.HEAT_STATS = {total:486, streak:12, active:"62%", topDay:"2026-11-05", topCount:9};
|
|
123
|
+
(function(){
|
|
124
|
+
var KEY = 'sf-heal:' + location.pathname;
|
|
125
|
+
var m = document.querySelector('meta[name="heat-id"]');
|
|
126
|
+
var ok = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(m ? m.content : '');
|
|
127
|
+
var ID;
|
|
128
|
+
if (ok) { ID = m.content; }
|
|
129
|
+
else {
|
|
130
|
+
var v = localStorage.getItem(KEY);
|
|
131
|
+
if (!v) { v = crypto.randomUUID(); localStorage.setItem(KEY, v); }
|
|
132
|
+
ID = v;
|
|
133
|
+
m.setAttribute('content', v);
|
|
134
|
+
console.warn('[heat] 非法 id meta 已自愈为 ' + v);
|
|
135
|
+
}
|
|
136
|
+
var THEME_KEY = 'heat:' + ID + '-theme';
|
|
137
|
+
var savedTheme = localStorage.getItem(THEME_KEY);
|
|
138
|
+
if (savedTheme) document.documentElement.setAttribute('data-theme', savedTheme);
|
|
139
|
+
var cur = document.documentElement.getAttribute('data-theme');
|
|
140
|
+
document.querySelectorAll('.th-dot').forEach(function(d){ d.classList.toggle('on', d.getAttribute('data-t') === cur); });
|
|
141
|
+
document.querySelectorAll('.th-dot').forEach(function(d){
|
|
142
|
+
d.addEventListener('click', function(){
|
|
143
|
+
var t = d.getAttribute('data-t');
|
|
144
|
+
document.documentElement.setAttribute('data-theme', t);
|
|
145
|
+
localStorage.setItem(THEME_KEY, t);
|
|
146
|
+
document.querySelectorAll('.th-dot').forEach(function(x){ x.classList.toggle('on', x === d); });
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
var DATA = window.HEAT_DATA || {};
|
|
151
|
+
var STATS = window.HEAT_STATS || {total:0,streak:0,active:'0%',topDay:'-',topCount:0};
|
|
152
|
+
var rangeEl = document.querySelector('.range');
|
|
153
|
+
var start = null, end = null;
|
|
154
|
+
Object.keys(DATA).forEach(function(d){
|
|
155
|
+
if (!start || d < start) start = d;
|
|
156
|
+
if (!end || d > end) end = d;
|
|
157
|
+
});
|
|
158
|
+
var todayStr = (function(){
|
|
159
|
+
var d = new Date(); var p = function(n){ return n < 10 ? '0' + n : n; };
|
|
160
|
+
return d.getFullYear() + '-' + p(d.getMonth()+1) + '-' + p(d.getDate());
|
|
161
|
+
})();
|
|
162
|
+
if (!end) end = todayStr;
|
|
163
|
+
function addDays(s, n){
|
|
164
|
+
var d = new Date(s + 'T00:00:00'); d.setDate(d.getDate() + n);
|
|
165
|
+
var p = function(x){ return x < 10 ? '0' + x : x; };
|
|
166
|
+
return d.getFullYear() + '-' + p(d.getMonth()+1) + '-' + p(d.getDate());
|
|
167
|
+
}
|
|
168
|
+
function dayOfWeek(s){ return new Date(s + 'T00:00:00').getDay(); }
|
|
169
|
+
var first = start || addDays(todayStr, -364);
|
|
170
|
+
var dow = dayOfWeek(first);
|
|
171
|
+
var gridStart = addDays(first, -dow);
|
|
172
|
+
var cells = [];
|
|
173
|
+
var d = gridStart, months = {};
|
|
174
|
+
var idx = 0;
|
|
175
|
+
while (d <= todayStr) {
|
|
176
|
+
cells.push(d);
|
|
177
|
+
var mon = d.slice(0, 7);
|
|
178
|
+
if (!(mon in months)) months[mon] = idx;
|
|
179
|
+
d = addDays(d, 1); idx++;
|
|
180
|
+
}
|
|
181
|
+
var cols = Math.ceil(cells.length / 7);
|
|
182
|
+
var gridEl = document.getElementById('grid');
|
|
183
|
+
gridEl.style.gridTemplateColumns = 'repeat(' + cols + ',11px)';
|
|
184
|
+
var cellMap = {};
|
|
185
|
+
cells.forEach(function(c){
|
|
186
|
+
var n = DATA[c] || 0;
|
|
187
|
+
var cls = 'cell';
|
|
188
|
+
if (n > 0) cls += n >= 4 ? ' l4' : n === 3 ? ' l3' : n === 2 ? ' l2' : ' l1';
|
|
189
|
+
if (c === todayStr) cls += ' today';
|
|
190
|
+
var el = document.createElement('div');
|
|
191
|
+
el.className = cls;
|
|
192
|
+
el.title = c + ' · ' + n + ' 次提交';
|
|
193
|
+
gridEl.appendChild(el);
|
|
194
|
+
});
|
|
195
|
+
var mEl = document.getElementById('months');
|
|
196
|
+
Object.keys(months).sort().forEach(function(mon, i, arr){
|
|
197
|
+
var startIdx = months[mon];
|
|
198
|
+
var endIdx = (i + 1 < arr.length) ? months[arr[i+1]] : cells.length;
|
|
199
|
+
var span = endIdx - startIdx;
|
|
200
|
+
var el = document.createElement('span');
|
|
201
|
+
el.style.width = (span * 14 - 3) + 'px';
|
|
202
|
+
el.textContent = Number(mon.slice(5)) + '月';
|
|
203
|
+
mEl.appendChild(el);
|
|
204
|
+
});
|
|
205
|
+
if (rangeEl) rangeEl.textContent = first + ' 至 ' + todayStr;
|
|
206
|
+
if (STATS.total !== undefined) document.getElementById('st-total').textContent = STATS.total;
|
|
207
|
+
if (STATS.streak !== undefined) document.getElementById('st-streak').textContent = STATS.streak + ' 天';
|
|
208
|
+
if (STATS.active !== undefined) document.getElementById('st-active').textContent = STATS.active;
|
|
209
|
+
if (STATS.topDay) document.getElementById('st-top').textContent = STATS.topDay + ' · ' + STATS.topCount + ' 次';
|
|
210
|
+
|
|
211
|
+
if (location.search.indexOf('shot') !== -1) {
|
|
212
|
+
document.documentElement.setAttribute('data-shot', '1');
|
|
213
|
+
document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; });
|
|
214
|
+
document.querySelector('.header-card').style.display = 'none';
|
|
215
|
+
document.getElementById('dock').style.display = 'none';
|
|
216
|
+
document.body.style.padding = '40px';
|
|
217
|
+
}
|
|
218
|
+
if ('IntersectionObserver' in window) {
|
|
219
|
+
var io = new IntersectionObserver(function(es){
|
|
220
|
+
es.forEach(function(e){ if (e.isIntersecting) { e.target.style.opacity = '1'; e.target.style.transform = 'none'; io.unobserve(e.target); } });
|
|
221
|
+
}, {threshold:.1});
|
|
222
|
+
document.querySelectorAll('.card').forEach(function(c){ io.observe(c); });
|
|
223
|
+
setTimeout(function(){ document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; }); }, 2000);
|
|
224
|
+
}
|
|
225
|
+
})();
|
|
226
|
+
</script>
|
|
227
|
+
</body>
|
|
228
|
+
</html>
|