diff --git a/.gitignore b/.gitignore index 18a8ff5..9083ece 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ yarn-error.log* # ZCode local config .zcodeignore +design-refs/mockup/single/ diff --git a/design-refs/mockup/assets/full-stack-frame.png b/design-refs/mockup/assets/full-stack-frame.png new file mode 100644 index 0000000..42028fe Binary files /dev/null and b/design-refs/mockup/assets/full-stack-frame.png differ diff --git a/design-refs/mockup/assets/hello-react-frame.png b/design-refs/mockup/assets/hello-react-frame.png new file mode 100644 index 0000000..d092deb Binary files /dev/null and b/design-refs/mockup/assets/hello-react-frame.png differ diff --git a/design-refs/mockup/assets/hello-world-frame.png b/design-refs/mockup/assets/hello-world-frame.png new file mode 100644 index 0000000..390fc9a Binary files /dev/null and b/design-refs/mockup/assets/hello-world-frame.png differ diff --git a/design-refs/mockup/build.sh b/design-refs/mockup/build.sh new file mode 100755 index 0000000..c001759 --- /dev/null +++ b/design-refs/mockup/build.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# 课程书架设计稿构建:course-shelf.html → 5 个单页 PDF → 合并 course-shelf.pdf +# 依赖:pdf skill 的 html2poster.js + pypdf(playwright + chromium 需可用) +set -euo pipefail +cd "$(dirname "$0")" + +PDF_SKILL_DIR="${PDF_SKILL_DIR:-$HOME/.zcode/cli/plugins/cache/zcode-plugins-official/pdf/0.1.7/skills/pdf}" +export PDF_SKILL_DIR + +# 1. 按 .page 拆成单页 HTML(固定布局必须走 html2poster,不能用 html2pdf-next) +python3 - <<'EOF' +import os, re +html = open("course-shelf.html", encoding="utf-8").read() +head, rest = html.split("", 1) +body_inner = rest.rsplit("", 1)[0] +pat = re.compile(r'(?=
)') +chunks = [c for c in pat.split(body_inner) if c.lstrip().startswith('
]+-->\s*$', '', page_html.rstrip()) + "\n" + page_html = page_html.replace("page-break-after: always;", "page-break-after: auto;") + open(f"single/page-{i}.html", "w", encoding="utf-8").write(head + "\n" + page_html + "\n\n") +print(f"split {len(chunks)} pages") +EOF + +# 2. 单页素材(img 相对路径以 single/ 为基准) +cp -r assets single/assets + +# 3. 逐页渲染 + 合并 +python3 - <<'EOF' +import glob, subprocess, sys +pages = sorted(glob.glob("single/page-*.html"), key=lambda p: int(__import__('re').search(r'(\d+)', p).group(1))) +for p in pages: + out = p.replace(".html", ".pdf") + subprocess.run(["node", f"{__import__('os').environ['PDF_SKILL_DIR']}/scripts/html2poster.js", p, "--output", out, "--width", "1280px"], check=True, capture_output=True) + print("rendered", out) +EOF + +python3 - <<'EOF' +import re +from pypdf import PdfWriter +w = PdfWriter() +for i in range(1, 6): + w.append(f"single/page-{i}.pdf") +w.add_metadata({"/Title": "课程书架设计稿 · stack idealjs", "/Author": "Z.ai", "/Subject": "全栈工程师教程课程预览重构设计稿", "/Creator": "Z.ai"}) +with open("course-shelf.pdf", "wb") as f: + w.write(f) +print("merged -> course-shelf.pdf") +EOF + +echo "done: course-shelf.pdf" diff --git a/design-refs/mockup/course-shelf.html b/design-refs/mockup/course-shelf.html new file mode 100644 index 0000000..3546cf5 --- /dev/null +++ b/design-refs/mockup/course-shelf.html @@ -0,0 +1,699 @@ + + + + +课程书架 设计稿 · stack idealjs + + + + + +
+
+
+
STACK IDEALJS · 全栈工程师教程
+
+
+

课程书架
设计稿

+
+ 课程预览从目录树改为卡片书架 · 每卡承载 title / desc / done / relations
+ 悬停卡片即循环播放该部分「学完能得到什么」的预期成果 GIF +
+
+
+
+
+
+
+
+
+
+ v1.0 · 2026-10
+ 分支 feat/course-shelf
+ 参考 00 · E-learning Learning Plan Dashboard(Dribbble,仅灵感) +
+
+ + +
+
+

01 整体布局 · 首页桌面态

+ 视口 1440px · 卡片网格 auto-fill minmax(280px, 1fr) +
+ +
+
+
+
idealjs.github.io/stack/
+
+
+
stack idealjs
+
快速开始 - 5min ⏱参与讨论
+
+
+
全栈工程师教程 · 课程书架
+
共 6 个部分。悬停卡片,预览学完这一部分能得到什么。
+
+
+
▶ 悬停预览预期成果
+
快速开始 ✓ 已完成
+
写出第一个网页并在浏览器打开,跑起你的第一个 HTTP 服务器。
+
+
+
▶ 悬停预览预期成果
+
快速开始 React ✓ 已完成
+
用脚手架创建 React 应用,亲手拼出第一个 Todo List。
+
+
+
▶ 悬停预览预期成果
+
更多示例 ✓ 已完成
+
浮动布局等补充示例,巩固前面攒下的积木。
+
+
+
▶ 悬停预览预期成果
+
更多 ✓ 已完成
+
把示例工程构建为可发布产物,看清 build 到底做了什么。
+
+
+
▶ 悬停预览预期成果
+
全栈基础 写作中
+
从网页到服务与数据库,串起完整的最小全栈闭环。
+
+
+
▶ 悬停预览预期成果
+
高级教程 ✓ 已完成
+
数据流、纯函数、CAP——工程上的心智模型。
+
+
+
+ + 1 + 2 + 3 + 4 +
+ +
+
+

布局要点

+
1Hero 入口区:保留「快速开始 5min」与「参与讨论」双按钮,合并为单条 hero,去除旧版双 hero 叠放。
+
2书架标题行:交代总数与悬停玩法,读者未 hover 前即知道卡片有预期成果预览。
+
3卡片网格:六部分各一卡,颜色书脊区分;顺序 = 侧栏学习顺序(垃圾桶/归档不入架)。
+
4整卡可点:卡即链接,进入该部分分类索引页;hover 只做预览不导航。
+
+
+

响应式

+
A≥1140px 三列 · 760–1140px 两列 · <760px 单列(触屏降级策略见第 4 页)。
+
+
+ +
课程书架设计稿 · stack idealjs
+
02 / 05
+
+ + +
+
+

02 卡片解剖 · 默认态 → 悬停态

+ GIF 为动画,纸面以静帧 + 标注表达 +
+ + +
+ +
▶ 悬停预览预期成果
+
+
+

快速开始

+ ✓ 已完成 +
+

写出第一个网页并在浏览器打开,跑起你的第一个 HTTP 服务器。

+
关联章节整理中
+
+
+ + 1 + 2 + 3 + 4 + 5 + 6 +
+
+

默认态要素

+
1媒体区占位:16:9 深色底 + 播放提示,GIF 未加载,首屏零动图流量。
+
2标题:章节名,即侧栏分类 label。
+
3完成徽标:✓ 已完成 / 写作中,来自 courses.ts 的 done 字段。
+
4预期结果一句话:desc 写「学完能做出什么」。
+
5关系区:关系列出前显示「整理中」,之后渲染 chips。
+
+
+ + +
+ +
GIF 播放中静帧
+
+
+

快速开始

+ ✓ 已完成 +
+

写出第一个网页并在浏览器打开,跑起你的第一个 HTTP 服务器。

+
关联章节整理中
+
+
+
+
+

悬停态变化

+
6书脊高亮:主题色竖条透明度 45% → 100%。
+
7GIF 挂载:此刻才创建 <img>,按需加载并自动循环播放预期成果。
+
8上浮 + 染色:卡体上浮、阴影加深、描边与标题染主题色。
+
+
+ +
课程书架设计稿 · stack idealjs
+
03 / 05
+
+ + +
+
+

03 交互流程 · 触发矩阵 · GIF 资产规范

+ 预期成果 GIF = 靶子「预期结果」的非文字化 +
+ +
+
+

悬停播放时序

+
+
STEP 1
指针进入
mouseenter / focus-visible 触发 previewing=true。
+
STEP 2
挂载 img
此刻才渲染 GIF <img>,浏览器按需拉取,首屏不载动图。
+
STEP 3
循环播放
GIF loop=0 自动循环,无播放控件,静音无声。
+
STEP 4
移出保持缓存
mouseleave 卸载 <img>;HTTP 缓存仍在,再次悬停瞬时恢复。
+
+
+
+ +
+
+

触发矩阵

+ + + + + + +
设备 / 输入行为
桌面 · 鼠标 hover播放预览,移出停止;点击卡片进入章节。
键盘 · Tab focus与 hover 同态(可访问性),Enter 进入章节。
触屏 · 无 hover不做预览态;首次点击直接进入章节,避免误触消耗流量。
弱网 / 关闭动图偏好后续可选:prefers-reduced-motion 时不自动播放,显示静帧。
+
+
+ +
+
+

GIF 资产规范(6 张占位已入库)

+ + + + + + + +
项约定
尺寸 / 画幅640 × 360 · 16:9 覆盖媒体区,object-fit: cover。
时长与循环3–8s · 无限循环(loop=0)· 无声。
体积单张 ≤ 300KB(当前占位 72–101KB)。
命名替换static/gifs/<id>.gif 同名覆盖即换片,零代码改动。
内容口径拍「学完后的真实产物」:浏览器里跑起来的页面、终端输出、可核对的结果。
+
+
+ +
课程书架设计稿 · stack idealjs
+
04 / 05
+
+ + +
+
+

04 设计 Tokens · 色板 / 字号 / 状态

+ 与组件 CourseShelf/styles.module.css 一一对应 +
+ +
+
+

课程色板(书脊 / 徽标 / chips 主题色)

+
+
快速开始
#6366F1 indigo
+
React
#EC4899 pink
+
更多示例
#F59E0B amber
+
更多
#10B981 emerald
+
全栈基础
#0EA5E9 sky
+
高级教程
#8B5CF6 violet
+
+
+ + + + + +
中性色值
标题 / 正文 / 弱文字#0F172A · #334155 · #64748B(slate 900/700/500)
边框 / 页底#E2E8F0 · 背景白卡 #FFFFFF 页底 #F8FAFC
完成 / 写作中徽标字 #047857/#92400E · 底 #D1FAE5/#FEF3C7(暗色主题见组件)
+
+
+ +
+
+

字号 · 间距 · 圆角

+ + + + + + + + +
Token值用途
卡标题16.8px / 700卡片标题行
卡描述14.4px / 1.6预期结果一句话
徽标 / chips11.5pxdone 徽标与关系 chips
网格间距 / 内边距20px / 16·18·20pxgrid gap / 卡内边距
圆角卡 12px · 媒体区随卡 · chips 999px通用
书脊宽 4px,透明度 45%→100%左缘主题色条
+
+
+

状态示意

+
+
default
+
hover / focus
+
+
+ hover / focus-visible:卡体上浮,阴影加深至 0 6px 20px,边框与标题染主题色,书脊透明度升至 100%。键盘 Tab 与鼠标悬停共享同一态。 +
+
+
+ +
课程书架设计稿 · stack idealjs · 关系 relations 待产品列出后填充 courses.ts
+
05 / 05
+
+ + + diff --git a/design-refs/mockup/course-shelf.pdf b/design-refs/mockup/course-shelf.pdf new file mode 100644 index 0000000..d1b4eb6 Binary files /dev/null and b/design-refs/mockup/course-shelf.pdf differ diff --git a/design-refs/mockup/page-1.png b/design-refs/mockup/page-1.png new file mode 100644 index 0000000..1541462 Binary files /dev/null and b/design-refs/mockup/page-1.png differ diff --git a/design-refs/mockup/page-2.png b/design-refs/mockup/page-2.png new file mode 100644 index 0000000..13fbb0b Binary files /dev/null and b/design-refs/mockup/page-2.png differ diff --git a/design-refs/mockup/page-3.png b/design-refs/mockup/page-3.png new file mode 100644 index 0000000..1f3ee72 Binary files /dev/null and b/design-refs/mockup/page-3.png differ diff --git a/design-refs/mockup/page-4.png b/design-refs/mockup/page-4.png new file mode 100644 index 0000000..64ab1a0 Binary files /dev/null and b/design-refs/mockup/page-4.png differ diff --git a/design-refs/mockup/page-5.png b/design-refs/mockup/page-5.png new file mode 100644 index 0000000..2ef1a10 Binary files /dev/null and b/design-refs/mockup/page-5.png differ