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,23 @@
|
|
|
1
|
+
# 收集数据(阶段 1)
|
|
2
|
+
|
|
3
|
+
## 数据来源(三种,可混用)
|
|
4
|
+
|
|
5
|
+
1. **口述**:用户直接说「张三:今日做了 A,明日做 B,无风险」「李四的日报:…」→ 逐人整理为字段
|
|
6
|
+
2. **文件批量**:用户给 md/txt/csv/xlsx 文件(每位成员一段/一行)→ Read/解析后按人拆条;csv/xlsx 表头需含 成员/日期/进展/计划/风险 任几列,缺失列留空
|
|
7
|
+
3. **页面导出导入**:用户在收集台页面填完点「导出 JSON」得到 reports.json → 用户发回该文件时以它为准合并(同成员同日期覆盖旧值)
|
|
8
|
+
|
|
9
|
+
## 字段规范
|
|
10
|
+
|
|
11
|
+
| 字段 | 说明 |
|
|
12
|
+
|:---|:---|
|
|
13
|
+
| name | 成员名(显示用) |
|
|
14
|
+
| date | 日报日期 YYYY-MM-DD(缺省用 REPORT_DATE 或今天) |
|
|
15
|
+
| progress | 今日进展(做了什么) |
|
|
16
|
+
| plan | 明日计划(准备做什么) |
|
|
17
|
+
| risk | 风险阻塞(无则空字符串,不写「无」之外的套话) |
|
|
18
|
+
|
|
19
|
+
## 合并去重
|
|
20
|
+
|
|
21
|
+
- 同一成员(name)+ 同一天(date)多条 → 合并:progress 以「;」拼接、plan 同样拼接、risk 合并去重
|
|
22
|
+
- 日期统一 YYYY-MM-DD;成员名保留用户原话写法(不擅自改花名/英文名)
|
|
23
|
+
- 收集结果清单(成员数 / 日报条数 / 缺报成员提示——TEAM 只影响标题不影响名单,名单以本次收集实际成员为准)展示给用户确认后进阶段 2
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# 生成产物(阶段 2)
|
|
2
|
+
|
|
3
|
+
## 三件套(全部落盘到 DIR)
|
|
4
|
+
|
|
5
|
+
1. **reports.json**(数据真相源):数组结构 `[{"name":"张工","date":"2026-11-12","progress":"…","plan":"…","risk":""}]`;每次生成整体重写该文件,页面导出的更新以它为准合并
|
|
6
|
+
2. **team-report.html**(收集台):先 Read `resources/reference.html` 全文,以其为骨架模板逐处替换数据——①头部 meta:`sf-template` 版本戳保持当前模板版本、`trc-id` 换成新 UUID(crypto.randomUUID() 标准 v4,落盘前顺扫落盘目录下本技能命名的 html 读 id meta 查重,撞号重掷)②`<title>` 与头部标题卡文字换成 TITLE ③`window.TRC_DATA = [...]` 初始数据数组换成本次收集结果(JSON 序列化,注意转义引号)④日期徽章换成 REPORT_DATE。其余(CSS/JS/结构)一律不许动;样式参数解释与禁止项见 `resources/html-rules.md`
|
|
7
|
+
3. **summary.md**(汇总):按日期分组的 Markdown 汇总——`## 2026-11-12(N 人已报)` 下每位成员一段(进展/计划/风险三行),末尾「风险集中项」小节聚合非空 risk 条目;对话中照常输出汇总正文
|
|
8
|
+
|
|
9
|
+
## 落盘纪律
|
|
10
|
+
|
|
11
|
+
- 文件名:`team-report.html` + `reports.json` + `summary.md`(同目录并存,目录已存在直接复用,只覆盖本清单内同名文件)
|
|
12
|
+
- OPEN_HTML: true 且落盘了 html 时自动打开浏览器(macOS:open <html文件>;Windows PowerShell:Start-Process <html文件>)
|
|
13
|
+
- **落盘完成后对话报告落盘位置**:完整路径清单(三件套),并注明 html 是否已在浏览器打开
|
|
14
|
+
- 同一目录重复生成时:以最新收集数据为准重写三件套;页面里用户新增但未导出的本地数据无法读取,提示用户「先导出 JSON 再发我,我帮你并入」
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
> ⛔ **Reference 铁律(最高优先)**:本目录 `reference.html` 是定稿样式源码。生成 HTML 时必须先 Read `resources/reference.html` 与本文件两份,以 reference.html 为骨架模板逐处替换数据(标题/日期徽章/TRC_DATA 数组/trc-id UUID),本文件的描述是参数解释、变体规则与禁止项;两者冲突时**以 reference.html 为准**。修改本 skill 的 HTML 效果时,必须同步更新 `resources/reference.html` 与本文档的对应描述,禁止只改一处。
|
|
2
|
+
|
|
3
|
+
# 收集台 HTML 版式(五主题令牌 + 科技感背景层,与日报/周报同体系)
|
|
4
|
+
|
|
5
|
+
## 版式总览
|
|
6
|
+
|
|
7
|
+
- 五主题令牌:tech(深蓝科技,默认)/ biz(浅色商务)/ mono(IDEA 黑亮)/ light(IDEA 白亮)/ warm(温暖渐变),色值与 daily-report 同一套 12 核心契约(另含收集台扩展 --panel2 列表条目底、--input-bg 表单输入底);`html[data-theme]` 运行时切换;右下角换肤坞五色点随点随换、localStorage 记忆(键 `trc:<ID>-theme`,ID = 页内嵌 trc-id meta,多份产物互不串台、改名/移动目录记忆不丢)
|
|
8
|
+
- 字体全用系统本地字体栈(ui-monospace/'SF Mono'/SFMono-Regular/Menlo/Consolas/system-ui,品牌字体 PingFang/YaHei/apple-system 零出现),禁止 CDN、@import、外链 CSS/JS/图片/网络字体——页面离线双击可开
|
|
9
|
+
- 三张卡:标题卡(团队名 + 日期徽章 + 统计三数:成员数/日报条数/风险条数)+ 表单卡(姓名/日期/进展/计划/风险五字段 + 保存按钮)+ 汇总列表卡(按日期分组的成员条目 + 导出 JSON / 导入 JSON 按钮)
|
|
10
|
+
- 多文件隔离(必植):头部写 `<meta name="trc-id" content="<UUID>">`(crypto.randomUUID() 标准 UUID v4);localStorage 键一律 `trc:<ID>-xxx`(xxx 为具体用途后缀 theme/reports),禁止裸通用键名;页面 JS 启动时校验 id meta——非法或缺失(占位残留/手写变体/误沿用旧值)时按路径键(`'sf-heal:' + location.pathname`)自愈为 crypto.randomUUID() 标准 v4 并回写 meta,console.warn 显性报警;路径键持久化保证同文件跨打开稳定复用;合法 UUID 原样放行
|
|
11
|
+
- 版本戳:`<meta name="sf-template" content="team-report-collector@1">`(模板升级递增 @N)
|
|
12
|
+
- 入场动画:三张卡错峰上浮淡入(标题 0s/表单 0.13s/列表 0.26s);卡片入场动画 fill-mode 必须用 backwards 严禁 both(both 使动画结束帧覆盖 hover transform);滚动入场用 IntersectionObserver + 2s 兜底 setTimeout 强制全显(headless 截图 / 打印预览 / PDF 导出环境卡片不得永久隐藏)
|
|
13
|
+
- 科技感背景层四件套(与日报/周报同款):SVG 微噪点(opacity .04,mono 退隐)+ 60px 网格底纹 + 星点(biz/light/warm 退隐 .28、mono 灰白化)+ 全屏扫描线 + 循环光带;容器 .wrap 宽 clamp(640px, 60%, 1200px)(移动端 100%);卡片面板实色 + 8px 水平条纹 + 上下高光线 + 圆角 6px + 卡阴影;头部卡含光晕呼吸(.card-glow)与四边扫描线(.scanline-el);标题渐变文字(--title-grad)+ 光晕
|
|
14
|
+
- ?shot 截图模式:页面 JS 检测 location.search 含 shot 时给 html 挂 data-shot 属性(CSS 关闭入场动画直接终态,headless 虚拟时间下动画帧不推进会停在初始帧导致截图空白)、强制全部卡片 opacity 1、隐藏换肤坞,body 四周 padding 统一 40px,供主体内容截图
|
|
15
|
+
- 页脚 10px muted 文字,署名固定 GENERATED BY AI TEAM(禁止真实团队名/项目名)
|
|
16
|
+
|
|
17
|
+
## 数据流(TRC_DATA)
|
|
18
|
+
|
|
19
|
+
- `window.TRC_DATA`:生成时内嵌的初始数据数组(字段 name/date/progress/plan/risk,JSON 序列化注意转义);页面启动时优先读 localStorage `trc:<ID>-reports`,有则覆盖初始数组展示
|
|
20
|
+
- 页面「保存」:表单提交 → 追加/合并进本地数组(同 name+date 合并)→ 写 localStorage
|
|
21
|
+
- 「导出 JSON」:Blob 下载 reports.json(含本地最新数据);「导入 JSON」:file input 读 json 合并进本地数组
|
|
22
|
+
- 渲染:按 date 分组倒序、组内按 name 排序;每条显示进展/计划/风险三行(风险空则不显该行),风险行强调色标
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN" data-theme="tech">
|
|
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="team-report-collector@1">
|
|
7
|
+
<meta name="trc-id" content="REF-TRC-0000">
|
|
8
|
+
<title>示例团队日报收集台</title>
|
|
9
|
+
<style>
|
|
10
|
+
/* ═══ 五主题令牌:与 daily-report 同一套 12 核心契约(--bg/--bg2/--panel/--panel-solid/--card-shadow/--text/--muted/--accent/--accent2/--border/--glow/--glow-soft)+ 收集台扩展(--panel2/--input-bg);html[data-theme] 运行时切换,THEME 生成时定默认 ═══ */
|
|
11
|
+
:root, [data-theme="tech"]{
|
|
12
|
+
--bg:#0a1929; --bg2:#071525; --panel:rgba(11,30,55,.9); --panel-solid:#0b1e37;
|
|
13
|
+
--panel2:#0d2236; --input-bg:rgba(2,12,27,.85);
|
|
14
|
+
--card-shadow:0 1px 0 rgba(255,255,255,.05) inset, 0 12px 32px rgba(1,6,16,.5), 0 0 24px rgba(14,165,233,.15);
|
|
15
|
+
--text:#bae6fd; --muted:#5b7fa5; --accent:#0ea5e9; --accent2:#14b8a6;
|
|
16
|
+
--border:rgba(14,165,233,.18); --glow:rgba(14,165,233,.35); --glow-soft:rgba(14,165,233,.15);
|
|
17
|
+
--title-grad:linear-gradient(90deg,#7dd3fc,#0ea5e9 45%,#818cf8);
|
|
18
|
+
--tag-bg:rgba(14,165,233,.12);
|
|
19
|
+
--scan:rgba(0,240,255,.2); --scan-dim:rgba(0,240,255,.05);
|
|
20
|
+
--green:#14b8a6; --orange:#f97316; --rose:#f43f5e;
|
|
21
|
+
}
|
|
22
|
+
[data-theme="biz"]{
|
|
23
|
+
--bg:#e8ecf5; --bg2:#dde3ef; --panel:rgba(255,255,255,.97); --panel-solid:#ffffff;
|
|
24
|
+
--panel2:#f1f5f9; --input-bg:#f8fafc;
|
|
25
|
+
--card-shadow:0 1px 2px rgba(15,23,42,.05), 0 10px 28px rgba(15,23,42,.12);
|
|
26
|
+
--text:#1e293b; --muted:#64748b; --accent:#2563eb; --accent2:#0891b2;
|
|
27
|
+
--border:rgba(37,99,235,.14); --glow:rgba(37,99,235,.18); --glow-soft:rgba(37,99,235,.12);
|
|
28
|
+
--title-grad:linear-gradient(90deg,#1e40af,#2563eb 55%,#0891b2);
|
|
29
|
+
--tag-bg:rgba(37,99,235,.08);
|
|
30
|
+
--scan:rgba(37,99,235,.14); --scan-dim:rgba(37,99,235,.04);
|
|
31
|
+
--green:#0d9488; --orange:#ea580c; --rose:#e11d48;
|
|
32
|
+
}
|
|
33
|
+
[data-theme="mono"]{ /* IDEA 黑亮:JetBrains New UI Dark 官方(编辑区 #1e1f22 + 面板 #2b2d30 + 描边 #3c3f41) */
|
|
34
|
+
--bg:#1e1f22; --bg2:#2b2d30; --panel:rgba(43,45,48,.95); --panel-solid:#2b2d30;
|
|
35
|
+
--panel2:#34373a; --input-bg:#26282b;
|
|
36
|
+
--card-shadow:0 1px 0 rgba(255,255,255,.06) inset, 0 12px 32px rgba(0,0,0,.5), 0 0 24px rgba(53,116,240,.16);
|
|
37
|
+
--text:#dfe1e5; --muted:#9aa0a6; --accent:#3574f0; --accent2:#5e9aff;
|
|
38
|
+
--border:rgba(53,116,240,.26); --glow:rgba(53,116,240,.3); --glow-soft:rgba(53,116,240,.13);
|
|
39
|
+
--title-grad:linear-gradient(90deg,#dfe1e5,#5e9aff 50%,#3574f0);
|
|
40
|
+
--tag-bg:rgba(53,116,240,.13);
|
|
41
|
+
--scan:rgba(223,225,229,.18); --scan-dim:rgba(223,225,229,.07);
|
|
42
|
+
--green:#4da36b; --orange:#d09645; --rose:#d85f73;
|
|
43
|
+
}
|
|
44
|
+
[data-theme="light"]{ /* IDEA 白亮:IntelliJ Light 官方(白编辑区 + 浅灰面板 #f2f2f2 + IDEA 蓝 #2675bf) */
|
|
45
|
+
--bg:#ffffff; --bg2:#f2f2f2; --panel:rgba(255,255,255,.98); --panel-solid:#ffffff;
|
|
46
|
+
--panel2:#f2f2f2; --input-bg:#ffffff;
|
|
47
|
+
--card-shadow:0 1px 2px rgba(30,31,34,.06), 0 10px 28px rgba(30,31,34,.12);
|
|
48
|
+
--text:#1e1f22; --muted:#6e7781; --accent:#2675bf; --accent2:#4a9be0;
|
|
49
|
+
--border:rgba(38,117,191,.18); --glow:rgba(38,117,191,.2); --glow-soft:rgba(38,117,191,.1);
|
|
50
|
+
--title-grad:linear-gradient(90deg,#1e5f9f,#2675bf 55%,#4a9be0);
|
|
51
|
+
--tag-bg:rgba(38,117,191,.08);
|
|
52
|
+
--scan:rgba(38,117,191,.12); --scan-dim:rgba(38,117,191,.04);
|
|
53
|
+
--green:#2f8a5b; --orange:#d97706; --rose:#d6336c;
|
|
54
|
+
}
|
|
55
|
+
[data-theme="warm"]{
|
|
56
|
+
--bg:#f7ebd9; --bg2:#efe0c8; --panel:rgba(255,250,243,.97); --panel-solid:#fffaf3;
|
|
57
|
+
--panel2:#f5ead7; --input-bg:#fffbf4;
|
|
58
|
+
--card-shadow:0 1px 2px rgba(120,72,24,.07), 0 10px 28px rgba(120,72,24,.13);
|
|
59
|
+
--text:#43301f; --muted:#8a7565; --accent:#d97706; --accent2:#ea580c;
|
|
60
|
+
--border:rgba(217,119,6,.18); --glow:rgba(217,119,6,.22); --glow-soft:rgba(217,119,6,.14);
|
|
61
|
+
--title-grad:linear-gradient(90deg,#b45309,#d97706 50%,#ea580c);
|
|
62
|
+
--tag-bg:rgba(217,119,6,.08);
|
|
63
|
+
--scan:rgba(217,119,6,.16); --scan-dim:rgba(217,119,6,.04);
|
|
64
|
+
--green:#3f8f4f; --orange:#c2410c; --rose:#be123c;
|
|
65
|
+
}
|
|
66
|
+
/* 浅色主题下星点氛围自然退隐 */
|
|
67
|
+
[data-theme="biz"] .stars, [data-theme="light"] .stars, [data-theme="warm"] .stars{ opacity:.28; }
|
|
68
|
+
/* mono 黑亮下氛围换装:星点改中性灰白,噪点层同退(不泛蓝) */
|
|
69
|
+
[data-theme="mono"] .stars{ background-image:
|
|
70
|
+
radial-gradient(1px 1px at 12% 18%, rgba(223,225,229,.32), transparent),
|
|
71
|
+
radial-gradient(1px 1px at 28% 64%, rgba(223,225,229,.28), transparent),
|
|
72
|
+
radial-gradient(1.5px 1.5px at 41% 32%, rgba(223,225,229,.26), transparent),
|
|
73
|
+
radial-gradient(1px 1px at 56% 78%, rgba(223,225,229,.24), transparent),
|
|
74
|
+
radial-gradient(1px 1px at 67% 12%, rgba(223,225,229,.26), transparent),
|
|
75
|
+
radial-gradient(1.5px 1.5px at 79% 52%, rgba(223,225,229,.28), transparent),
|
|
76
|
+
radial-gradient(1px 1px at 88% 86%, rgba(223,225,229,.3), transparent),
|
|
77
|
+
radial-gradient(1px 1px at 93% 24%, rgba(223,225,229,.3), transparent); }
|
|
78
|
+
[data-theme="mono"] body::before{ display:none; }
|
|
79
|
+
|
|
80
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
81
|
+
html,body{background:var(--bg)}
|
|
82
|
+
body{
|
|
83
|
+
color:var(--text); font-family:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,system-ui,sans-serif;
|
|
84
|
+
min-height:100vh; padding:40px 20px; position:relative; overflow-x:hidden;
|
|
85
|
+
}
|
|
86
|
+
body::before{
|
|
87
|
+
content:''; position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.04;
|
|
88
|
+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
89
|
+
}
|
|
90
|
+
.grid-pattern{
|
|
91
|
+
position:fixed; inset:0; z-index:0; pointer-events:none;
|
|
92
|
+
background-image:linear-gradient(var(--scan-dim) 1px, transparent 1px),linear-gradient(90deg, var(--scan-dim) 1px, transparent 1px);
|
|
93
|
+
background-size:60px 60px;
|
|
94
|
+
}
|
|
95
|
+
.stars{
|
|
96
|
+
position:fixed; inset:0; z-index:0; pointer-events:none;
|
|
97
|
+
background-image:
|
|
98
|
+
radial-gradient(1px 1px at 12% 18%, rgba(255,255,255,.38), transparent),
|
|
99
|
+
radial-gradient(1px 1px at 28% 64%, rgba(0,240,255,.48), transparent),
|
|
100
|
+
radial-gradient(1.5px 1.5px at 41% 32%, rgba(255,255,255,.3), transparent),
|
|
101
|
+
radial-gradient(1px 1px at 56% 78%, rgba(168,85,247,.4), transparent),
|
|
102
|
+
radial-gradient(1px 1px at 67% 12%, rgba(0,255,136,.4), transparent),
|
|
103
|
+
radial-gradient(1.5px 1.5px at 79% 52%, rgba(0,240,255,.45), transparent),
|
|
104
|
+
radial-gradient(1px 1px at 88% 86%, rgba(255,255,255,.34), transparent),
|
|
105
|
+
radial-gradient(1px 1px at 93% 24%, rgba(0,240,255,.5), transparent);
|
|
106
|
+
}
|
|
107
|
+
.scanlines{
|
|
108
|
+
position:fixed; inset:0; z-index:999; pointer-events:none;
|
|
109
|
+
background:repeating-linear-gradient(0deg, transparent 0 2px, var(--scan-dim) 2px 4px);
|
|
110
|
+
}
|
|
111
|
+
.scanband{
|
|
112
|
+
position:fixed; left:0; right:0; height:150px; z-index:998; pointer-events:none;
|
|
113
|
+
background:linear-gradient(180deg, transparent, var(--scan-dim) 50%, transparent);
|
|
114
|
+
animation:scanMove 11s linear infinite;
|
|
115
|
+
}
|
|
116
|
+
@keyframes scanMove{ from{top:-22%;} to{top:112%;} }
|
|
117
|
+
.wrap{width:clamp(640px,60%,1200px);margin:0 auto;position:relative;z-index:1}
|
|
118
|
+
.card{
|
|
119
|
+
position:relative; background:var(--panel-solid);
|
|
120
|
+
background-image:repeating-linear-gradient(180deg, rgba(255,255,255,.012) 0 1px, transparent 1px 8px);
|
|
121
|
+
border-top:1px solid var(--border); border-bottom:1px solid var(--border);
|
|
122
|
+
border-radius:6px; padding:24px; margin-bottom:18px; overflow:hidden;
|
|
123
|
+
box-shadow:var(--card-shadow);
|
|
124
|
+
animation:riseIn .5s ease backwards;
|
|
125
|
+
}
|
|
126
|
+
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
|
|
127
|
+
.header-card{animation-delay:0s}
|
|
128
|
+
.form-card{animation-delay:.13s}
|
|
129
|
+
.list-card{animation-delay:.26s}
|
|
130
|
+
.card-glow{
|
|
131
|
+
position:absolute; inset:0; pointer-events:none; transform-origin:top center;
|
|
132
|
+
background:radial-gradient(ellipse at 50% 10%, var(--glow), transparent 70%);
|
|
133
|
+
opacity:.5; animation:cardGlow 3s ease-in-out infinite;
|
|
134
|
+
}
|
|
135
|
+
@keyframes cardGlow{ 0%,100%{opacity:.5; transform:scale(1);} 50%{opacity:1; transform:scale(1.6);} }
|
|
136
|
+
.scanline-el{ position:absolute; pointer-events:none; z-index:3; }
|
|
137
|
+
.scan-x{ left:0; right:0; height:1px; background:linear-gradient(90deg, transparent, var(--accent), transparent); }
|
|
138
|
+
.scan-y{ top:0; bottom:0; width:1px; background:linear-gradient(180deg, transparent, var(--accent), transparent); }
|
|
139
|
+
.scan-top{ top:0; animation:scanX 3s linear infinite; }
|
|
140
|
+
.scan-right{ right:0; animation:scanY 3s linear infinite; }
|
|
141
|
+
.scan-bottom{ bottom:0; animation:scanXrev 3s linear infinite; }
|
|
142
|
+
.scan-left{ left:0; animation:scanYrev 3s linear infinite; }
|
|
143
|
+
@keyframes scanX{ from{transform:translateX(-100%);} to{transform:translateX(100%);} }
|
|
144
|
+
@keyframes scanXrev{ from{transform:translateX(100%);} to{transform:translateX(-100%);} }
|
|
145
|
+
@keyframes scanY{ from{transform:translateY(-100%);} to{transform:translateY(100%);} }
|
|
146
|
+
@keyframes scanYrev{ from{transform:translateY(100%);} to{transform:translateY(-100%);} }
|
|
147
|
+
.header-card{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px}
|
|
148
|
+
.header-card h1{
|
|
149
|
+
position:relative; z-index:2; font-size:22px; font-weight:900; letter-spacing:.5px;
|
|
150
|
+
background:var(--title-grad);
|
|
151
|
+
-webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
|
|
152
|
+
text-shadow:0 0 16px var(--glow), 0 0 40px var(--glow-soft);
|
|
153
|
+
}
|
|
154
|
+
.badges{position:relative;z-index:2;display:flex;gap:8px;flex-wrap:wrap}
|
|
155
|
+
.badge{font-size:11.5px;color:var(--muted);background:var(--tag-bg);border:1px solid var(--border);border-radius:20px;padding:4px 12px}
|
|
156
|
+
.stats{position:relative;z-index:2;display:flex;gap:18px;flex-wrap:wrap;margin-top:10px;width:100%}
|
|
157
|
+
.stat{font-size:12px;color:var(--muted)}
|
|
158
|
+
.stat b{color:var(--accent);font-size:18px;margin-right:4px}
|
|
159
|
+
.field{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
|
|
160
|
+
.field label{font-size:12px;color:var(--muted)}
|
|
161
|
+
.field input,.field textarea{background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);padding:9px 12px;font-size:14px;font-family:inherit;outline:none;transition:border-color .2s ease}
|
|
162
|
+
.field input:focus,.field textarea:focus{border-color:var(--accent)}
|
|
163
|
+
.field textarea{min-height:56px;resize:vertical}
|
|
164
|
+
.row2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
|
165
|
+
.btn{background:linear-gradient(90deg,var(--accent),var(--accent2));color:#fff;border:none;border-radius:6px;padding:10px 22px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;transition:transform .15s ease,box-shadow .2s ease;box-shadow:0 0 18px var(--glow)}
|
|
166
|
+
.btn:hover{transform:translateY(-1px)}
|
|
167
|
+
.btn:active{transform:translateY(1px)}
|
|
168
|
+
.btn.ghost{background:transparent;color:var(--accent);border:1px solid var(--border);box-shadow:none}
|
|
169
|
+
.toolbar{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap}
|
|
170
|
+
.day-group{margin-bottom:18px}
|
|
171
|
+
.day-title{font-size:13px;color:var(--accent);margin-bottom:10px;display:flex;align-items:center;gap:8px}
|
|
172
|
+
.day-title::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent)}
|
|
173
|
+
.item{background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:14px 16px;margin-bottom:10px;transition:background .2s ease}
|
|
174
|
+
.item:hover{background:var(--tag-bg)}
|
|
175
|
+
.item .who{font-size:14px;font-weight:600;color:var(--text);margin-bottom:8px}
|
|
176
|
+
.item .line{font-size:13px;line-height:1.7;color:var(--text);margin-bottom:3px}
|
|
177
|
+
.item .line span{color:var(--muted);font-size:12px;margin-right:6px}
|
|
178
|
+
.item .line.risk{color:var(--rose)}
|
|
179
|
+
.empty{color:var(--muted);font-size:13px;text-align:center;padding:28px 0}
|
|
180
|
+
footer{text-align:center;color:var(--muted);font-size:10px;margin-top:26px}
|
|
181
|
+
.theme-dock{position:fixed;right:18px;bottom:18px;z-index:1001;display:flex;gap:8px;background:var(--panel-solid);border:1px solid var(--border);border-radius:999px;padding:8px 10px;box-shadow:0 4px 18px rgba(0,0,0,.3)}
|
|
182
|
+
.th-dot{width:22px;height:22px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0;transition:transform .15s ease,border-color .15s ease}
|
|
183
|
+
.th-dot:hover{transform:scale(1.18)}
|
|
184
|
+
.th-dot.on{border-color:var(--text)}
|
|
185
|
+
.th-dot[data-theme="tech"]{background:#0ea5e9}
|
|
186
|
+
.th-dot[data-theme="biz"]{background:#2563eb}
|
|
187
|
+
.th-dot[data-theme="mono"]{background:#1e1f22}
|
|
188
|
+
.th-dot[data-theme="light"]{background:#ffffff}
|
|
189
|
+
.th-dot[data-theme="warm"]{background:#d97706}
|
|
190
|
+
html[data-shot] .card{animation:none!important}
|
|
191
|
+
@media (max-width:680px){body{padding:24px 12px}.wrap{width:100%}.row2{grid-template-columns:1fr}.header-card h1{font-size:18px}}
|
|
192
|
+
@media print{.theme-dock,.btn{display:none}}
|
|
193
|
+
</style>
|
|
194
|
+
</head>
|
|
195
|
+
<body>
|
|
196
|
+
<div class="grid-pattern"></div>
|
|
197
|
+
<div class="stars"></div>
|
|
198
|
+
<div class="scanband"></div>
|
|
199
|
+
<div class="scanlines"></div>
|
|
200
|
+
<div class="wrap">
|
|
201
|
+
<div class="card header-card">
|
|
202
|
+
<div class="card-glow"></div>
|
|
203
|
+
<span class="scanline-el scan-x scan-top"></span>
|
|
204
|
+
<span class="scanline-el scan-y scan-right"></span>
|
|
205
|
+
<span class="scanline-el scan-x scan-bottom"></span>
|
|
206
|
+
<span class="scanline-el scan-y scan-left"></span>
|
|
207
|
+
<h1>示例团队日报收集台</h1>
|
|
208
|
+
<div class="badges">
|
|
209
|
+
<span class="badge">📅 <span id="d-badge">2026-11-12</span></span>
|
|
210
|
+
<span class="badge" id="t-badge">tech</span>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="stats">
|
|
213
|
+
<span class="stat"><b id="s-members">2</b>成员</span>
|
|
214
|
+
<span class="stat"><b id="s-reports">2</b>日报</span>
|
|
215
|
+
<span class="stat"><b id="s-risks">1</b>风险</span>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="card form-card">
|
|
219
|
+
<div class="row2">
|
|
220
|
+
<div class="field"><label>成员姓名</label><input id="f-name" placeholder="张工"></div>
|
|
221
|
+
<div class="field"><label>日期</label><input id="f-date" type="date"></div>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="field"><label>今日进展</label><textarea id="f-progress" placeholder="完成了什么"></textarea></div>
|
|
224
|
+
<div class="field"><label>明日计划</label><textarea id="f-plan" placeholder="准备做什么"></textarea></div>
|
|
225
|
+
<div class="field"><label>风险阻塞</label><textarea id="f-risk" placeholder="无则留空"></textarea></div>
|
|
226
|
+
<div style="display:flex;gap:10px">
|
|
227
|
+
<button class="btn" id="save-btn">保存日报</button>
|
|
228
|
+
<button class="btn ghost" id="clear-btn">清空表单</button>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="card list-card">
|
|
232
|
+
<div class="toolbar">
|
|
233
|
+
<button class="btn ghost" id="export-btn">导出 JSON</button>
|
|
234
|
+
<button class="btn ghost" id="import-btn">导入 JSON</button>
|
|
235
|
+
<input type="file" id="import-file" accept=".json" style="display:none">
|
|
236
|
+
</div>
|
|
237
|
+
<div id="list"></div>
|
|
238
|
+
</div>
|
|
239
|
+
<footer>GENERATED BY AI TEAM · 2026-11</footer>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="theme-dock" id="themeDock">
|
|
242
|
+
<button class="th-dot" type="button" data-theme="tech" title="深蓝科技"></button>
|
|
243
|
+
<button class="th-dot" type="button" data-theme="biz" title="浅色商务"></button>
|
|
244
|
+
<button class="th-dot" type="button" data-theme="mono" title="IDEA 黑亮"></button>
|
|
245
|
+
<button class="th-dot" type="button" data-theme="light" title="IDEA 白亮"></button>
|
|
246
|
+
<button class="th-dot" type="button" data-theme="warm" title="温暖渐变"></button>
|
|
247
|
+
</div>
|
|
248
|
+
<script>
|
|
249
|
+
window.TRC_DATA = [
|
|
250
|
+
{"name":"张工","date":"2026-11-12","progress":"完成登录模块接口联调","plan":"补单元测试并提测","risk":"测试环境不稳定"},
|
|
251
|
+
{"name":"李工","date":"2026-11-12","progress":"日报模块前端页面初稿","plan":"接入接口与交互细节","risk":""}
|
|
252
|
+
];
|
|
253
|
+
(function(){
|
|
254
|
+
var KEY = 'sf-heal:' + location.pathname;
|
|
255
|
+
var m = document.querySelector('meta[name="trc-id"]');
|
|
256
|
+
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 : '');
|
|
257
|
+
var ID;
|
|
258
|
+
if (ok) { ID = m.content; }
|
|
259
|
+
else {
|
|
260
|
+
var v = localStorage.getItem(KEY);
|
|
261
|
+
if (!v) { v = crypto.randomUUID(); localStorage.setItem(KEY, v); }
|
|
262
|
+
ID = v;
|
|
263
|
+
m.setAttribute('content', v);
|
|
264
|
+
console.warn('[trc] 非法 id meta 已自愈为 ' + v);
|
|
265
|
+
}
|
|
266
|
+
var REPORTS_KEY = 'trc:' + ID + '-reports';
|
|
267
|
+
var THEME_KEY = 'trc:' + ID + '-theme';
|
|
268
|
+
var seed = window.TRC_DATA || [];
|
|
269
|
+
var saved = localStorage.getItem(REPORTS_KEY);
|
|
270
|
+
var reports = saved ? JSON.parse(saved) : seed;
|
|
271
|
+
|
|
272
|
+
function esc(s){ return String(s == null ? '' : s).replace(/[&<>"]/g, function(c){ return {'&':'&','<':'<','>':'>','"':'"'}[c]; }); }
|
|
273
|
+
function today(){ var d = new Date(); var p = function(n){ return n < 10 ? '0' + n : n; }; return d.getFullYear() + '-' + p(d.getMonth()+1) + '-' + p(d.getDate()); }
|
|
274
|
+
function persist(){ localStorage.setItem(REPORTS_KEY, JSON.stringify(reports)); }
|
|
275
|
+
function render(){
|
|
276
|
+
var groups = {};
|
|
277
|
+
reports.forEach(function(r){
|
|
278
|
+
(groups[r.date] = groups[r.date] || []).push(r);
|
|
279
|
+
});
|
|
280
|
+
var dates = Object.keys(groups).sort().reverse();
|
|
281
|
+
var html = '';
|
|
282
|
+
if (!dates.length) { html = '<div class="empty">暂无日报,填写表单开始收集</div>'; }
|
|
283
|
+
dates.forEach(function(d){
|
|
284
|
+
html += '<div class="day-group"><div class="day-title">' + esc(d) + ' · ' + groups[d].length + ' 人已报</div>';
|
|
285
|
+
groups[d].forEach(function(r){
|
|
286
|
+
html += '<div class="item"><div class="who">' + esc(r.name) + '</div>';
|
|
287
|
+
if (r.progress) html += '<div class="line"><span>进展</span>' + esc(r.progress) + '</div>';
|
|
288
|
+
if (r.plan) html += '<div class="line"><span>计划</span>' + esc(r.plan) + '</div>';
|
|
289
|
+
if (r.risk) html += '<div class="line risk"><span>风险</span>' + esc(r.risk) + '</div>';
|
|
290
|
+
html += '</div>';
|
|
291
|
+
});
|
|
292
|
+
html += '</div>';
|
|
293
|
+
});
|
|
294
|
+
document.getElementById('list').innerHTML = html;
|
|
295
|
+
var names = {}; var risks = 0;
|
|
296
|
+
reports.forEach(function(r){ names[r.name] = 1; if (r.risk) risks++; });
|
|
297
|
+
document.getElementById('s-members').textContent = Object.keys(names).length;
|
|
298
|
+
document.getElementById('s-reports').textContent = reports.length;
|
|
299
|
+
document.getElementById('s-risks').textContent = risks;
|
|
300
|
+
}
|
|
301
|
+
document.getElementById('save-btn').addEventListener('click', function(){
|
|
302
|
+
var name = document.getElementById('f-name').value.trim();
|
|
303
|
+
var date = document.getElementById('f-date').value || today();
|
|
304
|
+
var progress = document.getElementById('f-progress').value.trim();
|
|
305
|
+
var plan = document.getElementById('f-plan').value.trim();
|
|
306
|
+
var risk = document.getElementById('f-risk').value.trim();
|
|
307
|
+
if (!name) { alert('请填写成员姓名'); return; }
|
|
308
|
+
if (!progress && !plan && !risk) { alert('进展/计划/风险至少填一项'); return; }
|
|
309
|
+
var ex = reports.filter(function(r){ return r.name === name && r.date === date; })[0];
|
|
310
|
+
if (ex) {
|
|
311
|
+
if (progress) ex.progress = ex.progress ? ex.progress + ';' + progress : progress;
|
|
312
|
+
if (plan) ex.plan = ex.plan ? ex.plan + ';' + plan : plan;
|
|
313
|
+
if (risk) ex.risk = ex.risk ? ex.risk + ';' + risk : risk;
|
|
314
|
+
} else {
|
|
315
|
+
reports.push({name:name, date:date, progress:progress, plan:plan, risk:risk});
|
|
316
|
+
}
|
|
317
|
+
persist(); render();
|
|
318
|
+
['f-name','f-progress','f-plan','f-risk'].forEach(function(id){ document.getElementById(id).value = ''; });
|
|
319
|
+
document.getElementById('f-date').value = today();
|
|
320
|
+
});
|
|
321
|
+
document.getElementById('clear-btn').addEventListener('click', function(){
|
|
322
|
+
['f-name','f-progress','f-plan','f-risk'].forEach(function(id){ document.getElementById(id).value = ''; });
|
|
323
|
+
});
|
|
324
|
+
document.getElementById('export-btn').addEventListener('click', function(){
|
|
325
|
+
var blob = new Blob([JSON.stringify(reports, null, 2)], {type:'application/json'});
|
|
326
|
+
var a = document.createElement('a');
|
|
327
|
+
a.href = URL.createObjectURL(blob);
|
|
328
|
+
a.download = 'reports.json';
|
|
329
|
+
a.click();
|
|
330
|
+
URL.revokeObjectURL(a.href);
|
|
331
|
+
});
|
|
332
|
+
document.getElementById('import-btn').addEventListener('click', function(){
|
|
333
|
+
document.getElementById('import-file').click();
|
|
334
|
+
});
|
|
335
|
+
document.getElementById('import-file').addEventListener('change', function(ev){
|
|
336
|
+
var f = ev.target.files[0];
|
|
337
|
+
if (!f) return;
|
|
338
|
+
var rd = new FileReader();
|
|
339
|
+
rd.onload = function(){
|
|
340
|
+
try {
|
|
341
|
+
var arr = JSON.parse(rd.result);
|
|
342
|
+
if (!Array.isArray(arr)) throw new Error('not array');
|
|
343
|
+
arr.forEach(function(r){ reports.push(r); });
|
|
344
|
+
persist(); render();
|
|
345
|
+
} catch(e) { alert('导入失败:不是合法的 reports.json 数组'); }
|
|
346
|
+
};
|
|
347
|
+
rd.readAsText(f);
|
|
348
|
+
});
|
|
349
|
+
/* 主题换肤:五套配色随点随换;记忆上次选择(localStorage,失败静默);?shot 截图模式隐藏坞 */
|
|
350
|
+
var THEMES = ['tech','biz','mono','light','warm'];
|
|
351
|
+
var dock = document.getElementById('themeDock');
|
|
352
|
+
var tBadge = document.getElementById('t-badge');
|
|
353
|
+
function applyTheme(t){
|
|
354
|
+
document.documentElement.setAttribute('data-theme', t);
|
|
355
|
+
try { localStorage.setItem(THEME_KEY, t); } catch(e) {}
|
|
356
|
+
tBadge.textContent = t;
|
|
357
|
+
dock.querySelectorAll('.th-dot').forEach(function(d){ d.classList.toggle('on', d.getAttribute('data-theme') === t); });
|
|
358
|
+
}
|
|
359
|
+
var savedTheme = null;
|
|
360
|
+
try { savedTheme = localStorage.getItem(THEME_KEY); } catch(e) {}
|
|
361
|
+
var initial = (savedTheme && THEMES.indexOf(savedTheme) !== -1) ? savedTheme : 'tech';
|
|
362
|
+
applyTheme(initial);
|
|
363
|
+
dock.querySelectorAll('.th-dot').forEach(function(d){
|
|
364
|
+
d.addEventListener('click', function(){ applyTheme(d.getAttribute('data-theme')); });
|
|
365
|
+
});
|
|
366
|
+
document.getElementById('d-badge').textContent = '2026-11-12';
|
|
367
|
+
if (location.search.indexOf('shot') !== -1) {
|
|
368
|
+
document.documentElement.setAttribute('data-shot', '1');
|
|
369
|
+
document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; });
|
|
370
|
+
dock.style.display = 'none';
|
|
371
|
+
document.body.style.padding = '40px';
|
|
372
|
+
}
|
|
373
|
+
render();
|
|
374
|
+
if ('IntersectionObserver' in window) {
|
|
375
|
+
var io = new IntersectionObserver(function(es){
|
|
376
|
+
es.forEach(function(e){ if (e.isIntersecting) { e.target.style.opacity = '1'; e.target.style.transform = 'none'; io.unobserve(e.target); } });
|
|
377
|
+
}, {threshold:.1});
|
|
378
|
+
document.querySelectorAll('.card').forEach(function(c){ io.observe(c); });
|
|
379
|
+
setTimeout(function(){ document.querySelectorAll('.card').forEach(function(c){ c.style.opacity = '1'; c.style.transform = 'none'; }); }, 2000);
|
|
380
|
+
}
|
|
381
|
+
})();
|
|
382
|
+
</script>
|
|
383
|
+
</body>
|
|
384
|
+
</html>
|