Files
stack/design-refs/mockup/course-shelf.html
cqh963852 47f1549a0b design: 课程白卡加 16:9 预期区,desc 定时自动翻转播放 GIF
- 白卡结构:图标+标题行 → 16:9 预期区(desc 常驻)→ 关系 chips → 状态行
- 翻转规则:定时 8s(flipInterval 可配)desc ⇄ GIF;hover/Tab 即时翻转并锁定;触屏/减动效不翻转
- 组件稿 P4 六变体重排(3×2,比例实测 1.78)、P5 播放态 512×288、目录口径更新
- 整页稿 P3 解剖同步(编号 1-4/5-7 与 pin 对齐)、P4 时序/触发矩阵改翻转口径
2026-10-02 14:36:11 +08:00

590 lines
31 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>课程书架 设计稿 v2 · stack idealjs</title>
<style>
/* ====== 画布与页面基座 ====== */
@page { size: 1280px 800px; margin: 0; }
*, *::before, *::after { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
width: 1280px;
background: #f0f0ef;
font-family: "Noto Sans CJK SC", "PingFang SC", "Microsoft YaHei", sans-serif;
color: #1a1a1a;
-webkit-font-smoothing: antialiased;
}
.page {
width: 1280px;
height: 800px;
position: relative;
background: #f0f0ef;
overflow: hidden;
page-break-after: always;
}
.page:last-child { page-break-after: auto; }
@media screen {
html { height: auto; display: flex; justify-content: center; background: #f0f0ef; }
body {
transform-origin: top center;
scale: min(1, calc(100vw / 1280px));
margin: 0 auto;
box-shadow: 0 0 48px rgba(15, 23, 42, 0.18);
}
}
/* ====== 通用元素 ====== */
.kicker { font-size: 15px; letter-spacing: 4px; font-weight: 500; color: #6b6b6b; text-transform: uppercase; }
.pagenum { position: absolute; bottom: 26px; right: 40px; font-size: 13px; color: #8a8a8a; letter-spacing: 2px; }
.footline { position: absolute; bottom: 26px; left: 40px; font-size: 13px; color: #8a8a8a; letter-spacing: 1px; }
.pagehead { position: absolute; top: 40px; left: 40px; right: 40px; display: flex; align-items: baseline; justify-content: space-between; }
.pagehead h2 { margin: 0; font-size: 30px; font-weight: 800; color: #1a1a1a; }
.pagehead .sub { font-size: 15px; color: #6b6b6b; }
.note { display: flex; gap: 10px; align-items: flex-start; margin-bottom: 10px; }
.note .idx {
flex: none; width: 22px; height: 22px; border-radius: 50%;
background: #1a1a1a; color: #ffffff; font-size: 13px; font-weight: 700;
display: flex; align-items: center; justify-content: center; margin-top: 1px;
}
.note .txt { font-size: 14px; line-height: 1.55; color: #3d3d3d; }
.note .txt b { color: #1a1a1a; }
.panel { background: #ffffff; border-radius: 18px; padding: 20px 22px; box-shadow: 0 1px 2px rgba(26,26,26,0.06); }
.panel h3 { margin: 0 0 12px; font-size: 17px; font-weight: 700; color: #1a1a1a; }
.pin {
position: absolute; width: 24px; height: 24px; border-radius: 50%;
background: #1a1a1a; color: #fff; font-size: 13px; font-weight: 700;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 0 0 4px rgba(26,26,26,0.12); z-index: 5;
}
/* ====== 复刻组件:黑色顶栏 ====== */
.topbar {
height: 46px;
background: #111111;
color: #b9b9b9;
border-radius: 12px 12px 0 0;
display: flex;
align-items: center;
padding: 0 16px;
gap: 22px;
font-size: 12.5px;
}
.topbar .logo { color: #ffffff; font-weight: 800; letter-spacing: 0.5px; font-size: 13.5px; }
.topbar .menu { display: flex; gap: 20px; margin: 0 auto; }
.topbar .menu span.active { color: #ffffff; font-weight: 600; }
.topbar .ava {
width: 24px; height: 24px; border-radius: 50%;
background: #6366f1;
display: flex; align-items: center; justify-content: center;
color: #fff; font-size: 11px; font-weight: 700;
}
.topbar .bell { font-size: 14px; }
/* ====== 复刻组件:统计卡 ====== */
.stats { display: flex; gap: 14px; }
.stat {
flex: 1; border-radius: 16px; padding: 10px 14px 8px;
display: flex; flex-direction: column; gap: 2px;
}
.stat .num { font-size: 24px; font-weight: 800; color: #1a1a1a; }
.stat .lab { font-size: 11px; color: #6b6b6b; letter-spacing: 0.5px; }
/* ====== 复刻组件:课程卡(白卡 / 高亮媒体卡) ====== */
.course-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; position: relative; }
.ccard {
background: #ffffff;
border-radius: 16px;
padding: 10px 12px 10px 14px;
box-shadow: 0 1px 2px rgba(26,26,26,0.06);
position: relative;
display: flex;
flex-direction: column;
gap: 5px;
}
.ccard .icorow { display: flex; justify-content: space-between; align-items: flex-start; }
.ccard .ico {
width: 26px; height: 26px; border-radius: 9px;
display: flex; align-items: center; justify-content: center;
font-size: 15px;
}
.ccard .ttl { font-size: 13.5px; font-weight: 700; color: #1a1a1a; margin: 0; }
.ccard .dsc { font-size: 11px; line-height: 1.4; color: #8a8a8a; margin: 0; flex: 1; }
.ccard .btm { display: flex; align-items: center; justify-content: space-between; }
.pill {
font-size: 10.5px; padding: 3px 11px; border-radius: 999px; font-weight: 600;
}
.pill.done { background: #efe6fb; color: #6d28d9; }
.pill.wip { background: #ffffff; color: #6b6b6b; border: 1px solid #d5d5d3; }
.pill.time { background: #ffffff; color: #1a1a1a; border: 1px solid #d5d5d3; }
.cbtn {
width: 26px; height: 26px; border-radius: 50%;
background: #1a1a1a; color: #ffffff;
display: flex; align-items: center; justify-content: center;
font-size: 12px;
}
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip { font-size: 10px; color: #555; border: 1px solid #cfcfcd; border-radius: 999px; padding: 1px 8px; }
/* 高亮媒体卡(hover 态复刻:原稿粉紫卡 → 我们用各章淡彩) */
.ccard.media { background: var(--tint, #e0e7ff); box-shadow: none; }
.ccard.media .player {
flex: 1; min-height: 54px; border-radius: 12px;
background: var(--tint, #e0e7ff);
display: flex; align-items: center; justify-content: center;
position: relative;
}
.playbtn {
width: 44px; height: 44px; border-radius: 50%;
background: #111111; color: #ffffff;
display: flex; align-items: center; justify-content: center;
font-size: 16px;
box-shadow: 0 4px 14px rgba(17,17,17,0.28);
}
/* ====== 复刻组件:左窄图标栏 ====== */
.rail {
width: 40px;
background: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
padding: 14px 0;
font-size: 14px;
color: #8a8a8a;
}
/* ====== 复刻组件:右侧事件栏 ====== */
.events { display: flex; flex-direction: column; gap: 10px; }
.events .hd { font-size: 14px; font-weight: 700; color: #1a1a1a; }
.ev {
border-radius: 14px; padding: 10px 12px;
display: flex; flex-direction: column; gap: 3px;
}
.ev .r1 { display: flex; justify-content: space-between; align-items: center; font-size: 10.5px; font-weight: 700; color: #1a1a1a; }
.ev .date { font-size: 9.5px; color: #6b6b6b; font-weight: 600; }
.ev .r2 { font-size: 10.5px; color: #555; line-height: 1.45; }
.ev .r3 { font-size: 9.5px; color: #6b6b6b; }
/* ====== P3 解剖大卡 ====== */
.bigcard {
position: absolute;
width: 396px;
background: #ffffff;
border-radius: 20px;
box-shadow: 0 1px 2px rgba(26,26,26,0.08);
padding: 20px 22px;
display: flex;
flex-direction: column;
gap: 10px;
}
.bigcard.media-card { background: #e0e7ff; box-shadow: none; }
.bigcard .zone16x9 {
aspect-ratio: 16 / 9; border-radius: 14px;
background: #f7f7f5; border: 1px solid #ececea;
display: flex; align-items: center; padding: 14px 16px;
font-size: 13.5px; color: #8a8a8a; line-height: 1.6;
}
.bigcard .m-player {
aspect-ratio: 16 / 9; border-radius: 14px; background: #e0e7ff;
display: flex; align-items: center; justify-content: center; position: relative;
}
.bigcard .m-playbtn { width: 56px; height: 56px; border-radius: 50%; background: #111; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 20px; box-shadow: 0 6px 18px rgba(17,17,17,0.3); }
.bigcard .m-time { position: absolute; left: 12px; bottom: 10px; background: #ffffff; border-radius: 999px; padding: 3px 12px; font-size: 12px; color: #1a1a1a; border: 1px solid #d5d5d3; }
.legendbox { position: absolute; width: 396px; }
/* ====== P4 流程 ====== */
.flow { display: flex; align-items: stretch; }
.flow .step {
flex: 1; background: #ffffff; border-radius: 14px; padding: 13px 14px 11px;
position: relative; margin-right: 26px;
box-shadow: 0 1px 2px rgba(26,26,26,0.06);
}
.flow .step:last-child { margin-right: 0; }
.flow .step::after {
content: ""; position: absolute; right: -20px; top: 50%;
width: 13px; height: 13px; border-top: 2px solid #8a8a8a; border-right: 2px solid #8a8a8a;
transform: translateY(-50%) rotate(45deg);
}
.flow .step:last-child::after { display: none; }
.flow .s-no { font-size: 11.5px; color: #6d28d9; font-weight: 700; letter-spacing: 1px; }
.flow .s-t { font-size: 15px; font-weight: 700; color: #1a1a1a; margin: 3px 0 5px; }
.flow .s-d { font-size: 12.5px; line-height: 1.55; color: #555; }
table.spec { width: 100%; border-collapse: collapse; font-size: 13.5px; color: #3d3d3d; }
table.spec th { text-align: left; font-weight: 700; color: #1a1a1a; border-bottom: 2px solid #d5d5d3; padding: 7px 10px 7px 0; }
table.spec td { border-bottom: 1px solid #ececea; padding: 8px 10px 8px 0; vertical-align: top; }
table.spec td.k { color: #1a1a1a; font-weight: 600; white-space: nowrap; }
/* ====== P5 tokens ====== */
.swatches { display: flex; gap: 12px; flex-wrap: wrap; }
.swatch { width: 104px; }
.swatch .c { height: 50px; border-radius: 12px; border: 1px solid rgba(26,26,26,0.08); }
.swatch .n { font-size: 12px; font-weight: 700; color: #1a1a1a; margin-top: 6px; }
.swatch .h { font-size: 11px; color: #8a8a8a; }
.statecard { width: 208px; border-radius: 14px; padding: 10px 12px; background: #fff; box-shadow: 0 1px 2px rgba(26,26,26,0.06); }
.statecard.hov { background: #e0e7ff; box-shadow: none; }
.statecard .m { height: 58px; border-radius: 10px; background: #ececea; display:flex; align-items:center; justify-content:center; color:#8a8a8a; font-size: 11px; }
.statecard.hov .m { background: #e0e7ff; color: #1a1a1a; }
.statecard .t { font-size: 12.5px; font-weight: 700; color: #1a1a1a; margin-top: 7px; }
/* ====== P1 封面 ====== */
.cover .bandtop { position: absolute; top: 0; left: 0; right: 0; height: 46px; background: #111; color: #b9b9b9; display: flex; align-items: center; padding: 0 40px; gap: 26px; font-size: 13px; }
.cover .bandtop .logo { color: #fff; font-weight: 800; font-size: 15px; }
.cover .bandtop .menu { display: flex; gap: 24px; margin: 0 auto; }
.cover .bandtop .menu .active { color: #fff; }
.cover .bandtop .ava { width: 26px; height: 26px; border-radius: 50%; background: #6366f1; }
</style>
</head>
<body>
<!-- ================= P1 封面 ================= -->
<div class="page cover">
<div class="bandtop">
<span class="logo">stack·idealjs</span>
<span class="menu"><span class="active">全栈教程 🎓</span><span>工具使用</span><span>博客</span></span>
<span class="ava"></span>
</div>
<div style="position:absolute; top: 118px; left: 80px;" class="kicker-box">
<div class="kicker">STACK IDEALJS · 全栈工程师教程</div>
</div>
<h1 style="position:absolute; top: 208px; left: 80px; margin:0; font-size:92px; line-height:1.12; font-weight:800; color:#1a1a1a; letter-spacing:2px;">课程书架<br>设计稿 v2</h1>
<div style="position:absolute; top: 448px; left: 80px; font-size:21px; color:#555; line-height:1.65;">
课程预览从目录树改为卡片书架 · 复刻 Learning Plan Dashboard 视觉语言<br>
每卡承载 title / desc / done / relations,悬停即在卡内循环播放预期成果 GIF
</div>
<div style="position:absolute; top: 586px; left: 80px; width: 560px;" class="stats">
<div class="stat" style="background:#c9e7f7;"><span class="num">6</span><span class="lab">Total Sections · 教程部分</span></div>
<div class="stat" style="background:#d2f5df;"><span class="num">5</span><span class="lab">Completed · 已完成 🎉</span></div>
<div class="stat" style="background:#efe6fb;"><span class="num">1</span><span class="lab">Upcoming · 写作中</span></div>
</div>
<div style="position:absolute; bottom: 40px; right: 80px; text-align:right; font-size:14.5px; color:#8a8a8a; line-height:1.9;">
v2.0 · 2026-10 · 分支 feat/course-shelf<br>
视觉复刻自 00 · E-learning Learning Plan Dashboard(Dribbble,仅风格参考)
</div>
<div class="pagenum">01 / 05</div>
</div>
<!-- ================= P2 整体布局(核心复刻页) ================= -->
<div class="page">
<div class="pagehead">
<h2>01 整体布局 · Learning Plan 式课程书架</h2>
<span class="sub">复刻要素:黑顶栏 · 统计卡行 · 双列课程卡 · 高亮媒体卡 · 右侧事件栏</span>
</div>
<!-- Dashboard 框 -->
<div style="position:absolute; top: 106px; left: 40px; width: 852px; height: 640px; background:#f0f0ef; border-radius:12px; box-shadow:0 8px 26px rgba(26,26,26,0.14);">
<div class="topbar">
<span class="logo">stack·idealjs</span>
<span class="menu"><span class="active">全栈教程 🎓</span><span>工具使用</span><span>实践经历</span><span>博客</span></span>
<span class="bell">🔔</span>
<span class="ava">初</span>
</div>
<div style="display:flex; height: 594px;">
<!-- 左窄图标栏 -->
<div class="rail" style="height:100%;">
<span>🏠</span><span>📚</span><span>🧩</span><span>⚙️</span>
</div>
<!-- 主区 -->
<div style="flex:1; padding: 14px 14px 10px 12px; display:flex; flex-direction:column; gap:10px;">
<div style="display:flex; align-items:center; justify-content:space-between;">
<div style="font-size:19px; font-weight:800; color:#1a1a1a;">全栈工程师教程 📚</div>
<div style="font-size:12px; color:#8a8a8a; background:#fff; border-radius:999px; padding:5px 16px; border:1px solid #d5d5d3;">Search…</div>
</div>
<div class="stats">
<div class="stat" style="background:#c9e7f7;"><span class="num">6</span><span class="lab">Total Sections</span></div>
<div class="stat" style="background:#d2f5df;"><span class="num">5</span><span class="lab">Completed 🎉</span></div>
<div class="stat" style="background:#efe6fb;"><span class="num">1</span><span class="lab">Upcoming</span></div>
</div>
<div class="course-grid" style="flex:1;">
<!-- 1 高亮媒体卡 = hover 态 -->
<div class="ccard media" style="--tint:#e0e7ff;">
<div class="player">
<div class="playbtn">▶</div>
<div class="pill time" style="position:absolute; right:10px; top:8px;">⏱ GIF loop</div>
</div>
<div>
<div class="ttl">快速开始</div>
<div class="dsc">悬停态:预期成果在卡内循环播放</div>
</div>
</div>
<!-- 2 -->
<div class="ccard">
<div class="icorow"><span class="ico" style="background:#fce7f3;">⚛️</span></div>
<div class="ttl">快速开始 React</div>
<div class="dsc">用脚手架创建 React 应用,亲手拼出第一个 Todo List。</div>
<div class="btm"><span class="pill done">✓ Completed 🎉</span><span class="cbtn">✓</span></div>
</div>
<!-- 3 -->
<div class="ccard">
<div class="icorow"><span class="ico" style="background:#fef3c7;">🧱</span></div>
<div class="ttl">更多示例</div>
<div class="dsc">浮动布局等补充示例,巩固前面攒下的积木。</div>
<div class="btm"><span class="pill done">✓ Completed 🎉</span><span class="cbtn">✓</span></div>
</div>
<!-- 4 -->
<div class="ccard">
<div class="icorow"><span class="ico" style="background:#d1fae5;">📦</span></div>
<div class="ttl">更多</div>
<div class="dsc">把示例工程构建为可发布产物,看清 build 做了什么。</div>
<div class="btm"><span class="pill done">✓ Completed 🎉</span><span class="cbtn">✓</span></div>
</div>
<!-- 5 -->
<div class="ccard">
<div class="icorow"><span class="ico" style="background:#e0f2fe;">🔗</span></div>
<div class="ttl">全栈基础</div>
<div class="dsc">从网页到服务与数据库,串起最小全栈闭环。</div>
<div class="btm"><span class="pill wip">Upcoming</span><span class="cbtn">→</span></div>
</div>
<!-- 6 -->
<div class="ccard">
<div class="icorow"><span class="ico" style="background:#ede9fe;">🧠</span></div>
<div class="ttl">高级教程</div>
<div class="dsc">数据流、纯函数、CAP——工程上的心智模型。</div>
<div class="btm"><span class="pill done">✓ Completed 🎉</span><span class="cbtn">✓</span></div>
</div>
</div>
</div>
<!-- 右侧事件栏 -->
<div style="width: 224px; padding: 16px 16px 12px 6px;">
<div class="events" style="height:100%;">
<div class="hd">最近更新 😊</div>
<div class="ev" style="background:#c9e7f7;">
<div class="r1"><span>新增 · Web</span><span class="date">OCT 02</span></div>
<div class="r2">「更多示例」补充浮动布局一文</div>
<div class="r3">09:00</div>
</div>
<div class="ev" style="background:#e9c8f5;">
<div class="r1"><span>章节 · 高级</span><span class="date">SEP 28</span></div>
<div class="r2">CAP 一讲更新配图与示例</div>
<div class="r3">14:30</div>
</div>
<div class="ev" style="background:#f5e6c4;">
<div class="r1"><span>计划 · 全栈</span><span class="date">SOON</span></div>
<div class="r2">「全栈基础」章节开写,占位卡已上架</div>
<div class="r3">即将开始</div>
</div>
<div class="ev" style="background:#d2f5df;">
<div class="r1"><span>讨论</span><span class="date">OCT 01</span></div>
<div class="r2">讨论区新增 3 帖,欢迎踩场</div>
<div class="r3">20:00</div>
</div>
</div>
</div>
</div>
</div>
<!-- 框外右侧标注 pin(走廊不压内容) -->
<span class="pin" style="top: 122px; left: 902px;">1</span>
<span class="pin" style="top: 262px; left: 902px;">2</span>
<span class="pin" style="top: 330px; left: 902px;">3</span>
<span class="pin" style="top: 388px; left: 902px;">4</span>
<!-- 右侧说明面板 -->
<div style="position:absolute; top: 106px; left: 948px; width: 292px;">
<div class="panel">
<h3>复刻要素对照</h3>
<div class="note"><span class="idx">1</span><span class="txt"><b>黑色顶栏</b>:白 logo + 居中菜单(当前项白色高亮)+ 🔔 与头像。</span></div>
<div class="note"><span class="idx">2</span><span class="txt"><b>统计卡行</b>:大数字 + 小灰标签,淡蓝/淡绿/淡紫底。</span></div>
<div class="note"><span class="idx">3</span><span class="txt"><b>双列课程卡</b>:白卡大圆角,彩色圆角图标、状态胶囊、黑圆确认钮。</span></div>
<div class="note"><span class="idx">4</span><span class="txt"><b>高亮媒体卡</b>:淡彩底 + 黑色圆形播放钮 + ⏱ 胶囊——即 hover 预览态。</span></div>
<div class="note"><span class="idx">5</span><span class="txt"><b>右侧事件栏</b>:彩色条目卡承载章节动态(类型 + 日期 + 描述 + 时间)。</span></div>
</div>
<div class="panel" style="margin-top: 14px;">
<h3>与 v1 的差异</h3>
<div class="note"><span class="idx">A</span><span class="txt">Docusaurus 浅蓝 hero 退场,骨架改为 Learning Plan 仪表盘;卡片语言从「书脊 + 媒体区」改为「图标 + 状态胶囊 + 黑圆按钮」。</span></div>
<div class="note"><span class="idx">B</span><span class="txt">新增统计行与事件栏,分别对应「积木清单规模」与「章节动态」。</span></div>
</div>
</div>
<div class="footline">课程书架设计稿 v2 · stack idealjs</div>
<div class="pagenum">02 / 05</div>
</div>
<!-- ================= P3 卡片解剖 · 默认态 vs 悬停态 ================= -->
<div class="page">
<div class="pagehead">
<h2>02 卡片解剖 · 默认白卡 → 播放态</h2>
<span class="sub">16:9 预期区定时翻转 desc ⇄ GIF,悬停锁定</span>
</div>
<!-- 左:默认白卡 -->
<div class="bigcard" style="left: 56px; top: 106px;">
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
<span style="width:38px;height:38px;border-radius:12px;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-size:18px;">🌐</span>
</div>
<div class="zone16x9">写出第一个网页并在浏览器打开,跑起你的第一个 HTTP 服务器。<br><span style="font-size:11.5px; color:#b1b1af;">16:9 预期区 · desc 常驻,定时 8s 翻转播放 GIF</span></div>
<div style="font-size:20px; font-weight:800; color:#1a1a1a;">快速开始</div>
<div class="chips"><span class="chip">前置:无</span><span class="chip">关联:快速开始 React</span></div>
<div style="display:flex; align-items:center; justify-content:space-between;">
<span class="pill done" style="font-size:12px; padding:4px 14px;">✓ Completed 🎉</span>
<span class="cbtn" style="width:32px;height:32px;font-size:14px;">✓</span>
</div>
</div>
<!-- 右:播放态(定时翻转/悬停锁定) -->
<div class="bigcard media-card" style="left: 700px; top: 106px;">
<div class="m-player">
<div class="m-playbtn">▶</div>
<div class="m-time">⏱ Preview · GIF loop</div>
</div>
<div style="font-size:20px; font-weight:800; color:#1a1a1a;">快速开始</div>
<div style="font-size:13.5px; color:#555;">预期成果正在预期区循环播放:浏览器打开第一个网页。</div>
<div style="display:flex; align-items:center; justify-content:space-between;">
<span class="pill time" style="font-size:12px; padding:4px 14px;">⏱ Watching</span>
<span class="cbtn" style="width:32px;height:32px;font-size:14px;">▶</span>
</div>
</div>
<!-- pin 标注:左卡 top106(icon≈118 / zone 166-388 / title≈398 / chips≈436)右卡同构 -->
<span class="pin" style="top: 120px; left: 470px;">1</span>
<span class="pin" style="top: 250px; left: 470px;">2</span>
<span class="pin" style="top: 402px; left: 470px;">3</span>
<span class="pin" style="top: 440px; left: 470px;">4</span>
<span class="pin" style="top: 120px; left: 1114px;">5</span>
<span class="pin" style="top: 260px; left: 1114px;">6</span>
<span class="pin" style="top: 428px; left: 1114px;">7</span>
<!-- 底部两说明面板 -->
<div class="legendbox" style="top: 544px; left: 56px;">
<div class="panel" style="padding: 14px 18px;">
<h3 style="margin-bottom: 8px;">默认白卡要素</h3>
<div class="note" style="margin-bottom: 4px;"><span class="idx">1</span><span class="txt"><b>彩色圆角图标</b>:每章一个 emoji,淡彩圆角底。</span></div>
<div class="note" style="margin-bottom: 4px;"><span class="idx">2</span><span class="txt"><b>16:9 预期区</b>:desc 常驻(写「学完能做出什么」),定时 8s 自动翻转为播放 GIF。</span></div>
<div class="note" style="margin-bottom: 4px;"><span class="idx">3</span><span class="txt"><b>标题 + 关系 chips</b>:前置 / 关联(示例占位)。</span></div>
<div class="note" style="margin-bottom: 0;"><span class="idx">4</span><span class="txt"><b>状态胶囊 + 黑圆确认钮</b>:✓ / Upcoming。</span></div>
</div>
</div>
<div class="legendbox" style="top: 530px; left: 700px;">
<div class="panel" style="padding: 14px 18px;">
<h3 style="margin-bottom: 6px;">播放态(定时翻转 / 悬停锁定)</h3>
<div class="note" style="margin-bottom: 4px;"><span class="idx">5</span><span class="txt"><b>淡彩预期区</b>:翻转为该章主题淡彩播放态。</span></div>
<div class="note" style="margin-bottom: 4px;"><span class="idx">6</span><span class="txt"><b>黑色圆形播放钮 + ⏱ 胶囊</b>:复刻原稿标志元素,此刻才挂载 GIF 循环。</span></div>
<div class="note" style="margin-bottom: 0;"><span class="idx">7</span><span class="txt"><b>翻转规则</b>:定时 8s 或 hover/Tab 即时翻转并锁定;到期/移出还原 desc,缓存保留。</span></div>
</div>
</div>
<div class="footline">课程书架设计稿 v2 · stack idealjs</div>
<div class="pagenum">03 / 05</div>
</div>
<!-- ================= P4 交互与资产 ================= -->
<div class="page">
<div class="pagehead">
<h2>03 交互流程 · 触发矩阵 · GIF 资产规范</h2>
<span class="sub">16:9 预期区 · desc ⇄ GIF 定时轮换 · 悬停锁定</span>
</div>
<div style="position:absolute; top: 118px; left: 40px; right: 40px;">
<div class="panel" style="padding-bottom: 18px;">
<h3>翻转播放时序</h3>
<div class="flow">
<div class="step"><div class="s-no">STEP 1</div><div class="s-t">定时 / 指针进入</div><div class="s-d">8s 定时到期,或 mouseenter / focus 即时触发,预期区翻为淡彩播放态。</div></div>
<div class="step"><div class="s-no">STEP 2</div><div class="s-t">挂载播放器</div><div class="s-d">此刻才渲染 GIF,按需拉取;悬停/聚焦期间锁定在播放态。</div></div>
<div class="step"><div class="s-no">STEP 3</div><div class="s-t">循环播放</div><div class="s-d">GIF loop=0 自动循环,卡内嵌播放,无控件无声音。</div></div>
<div class="step"><div class="s-no">STEP 4</div><div class="s-t">到期 / 移出还原</div><div class="s-d">定时到期或移出还原 desc;GIF 卸载,HTTP 缓存保留。</div></div>
</div>
</div>
</div>
<div style="position:absolute; top: 372px; left: 40px; width: 590px;">
<div class="panel">
<h3>触发矩阵</h3>
<table class="spec">
<tr><th>设备 / 输入</th><th>行为</th></tr>
<tr><td class="k">桌面 · 鼠标 hover</td><td>即时翻转并锁定 GIF;点击卡片进入章节。</td></tr>
<tr><td class="k">键盘 · Tab focus</td><td>与 hover 同态(可访问性),Enter 进入章节。</td></tr>
<tr><td class="k">触屏 · 无 hover</td><td>不自动翻转;点击直接进入章节,避免误触耗流量。</td></tr>
<tr><td class="k">减弱动效偏好</td><td>prefers-reduced-motion 时不自动翻转,仅显示 desc。</td></tr>
</table>
</div>
</div>
<div style="position:absolute; top: 372px; left: 662px; width: 578px;">
<div class="panel">
<h3>GIF 资产规范(6 张占位已入库)</h3>
<table class="spec">
<tr><th>项</th><th>约定</th></tr>
<tr><td class="k">尺寸 / 画幅</td><td>640 × 360 · 16:9 覆盖媒体区,object-fit: cover。</td></tr>
<tr><td class="k">时长与循环</td><td>3–8s · 无限循环(loop=0)· 无声。</td></tr>
<tr><td class="k">体积</td><td>单张 ≤ 300KB(当前占位 72–101KB)。</td></tr>
<tr><td class="k">命名替换</td><td>static/gifs/&lt;id&gt;.gif 同名覆盖即换片,零代码改动。</td></tr>
<tr><td class="k">内容口径</td><td>拍「学完后的真实产物」:跑起来的页面、终端输出、可核对结果。</td></tr>
</table>
</div>
</div>
<div class="footline">课程书架设计稿 v2 · stack idealjs</div>
<div class="pagenum">04 / 05</div>
</div>
<!-- ================= P5 设计 Tokens ================= -->
<div class="page">
<div class="pagehead">
<h2>04 设计 Tokens · 复刻配色 / 课程色 / 状态</h2>
<span class="sub">骨架色取自 Learning Plan Dashboard,课程色沿用六章映射</span>
</div>
<div style="position:absolute; top: 118px; left: 40px; width: 566px;">
<div class="panel">
<h3>骨架色(复刻)</h3>
<div class="swatches">
<div class="swatch"><div class="c" style="background:#111111"></div><div class="n">顶栏黑</div><div class="h">#111111</div></div>
<div class="swatch"><div class="c" style="background:#f0f0ef; border:1px solid #d5d5d3;"></div><div class="n">页面米白</div><div class="h">#F0F0EF</div></div>
<div class="swatch"><div class="c" style="background:#ffffff; border:1px solid #d5d5d3;"></div><div class="n">卡白</div><div class="h">#FFFFFF</div></div>
<div class="swatch"><div class="c" style="background:#1a1a1a"></div><div class="n">文字主黑</div><div class="h">#1A1A1A</div></div>
<div class="swatch"><div class="c" style="background:#8a8a8a"></div><div class="n">文字次灰</div><div class="h">#8A8A8A</div></div>
</div>
<h3 style="margin-top:16px;">淡彩底(统计卡 / 媒体卡 / 事件栏)</h3>
<div class="swatches">
<div class="swatch"><div class="c" style="background:#c9e7f7"></div><div class="n">事件蓝</div><div class="h">#C9E7F7</div></div>
<div class="swatch"><div class="c" style="background:#e9c8f5"></div><div class="n">事件紫</div><div class="h">#E9C8F5</div></div>
<div class="swatch"><div class="c" style="background:#f5e6c4"></div><div class="n">事件黄</div><div class="h">#F5E6C4</div></div>
<div class="swatch"><div class="c" style="background:#d2f5df"></div><div class="n">事件绿</div><div class="h">#D2F5DF</div></div>
<div class="swatch"><div class="c" style="background:#e0e7ff"></div><div class="n">媒体卡 indigo</div><div class="h">#E0E7FF</div></div>
</div>
</div>
</div>
<div style="position:absolute; top: 118px; left: 646px; width: 594px;">
<div class="panel">
<h3>课程色 → 淡彩底映射(图标底 / 媒体卡底)</h3>
<table class="spec">
<tr><th>章节</th><th>图标底(淡彩)</th><th>强调色</th></tr>
<tr><td class="k">快速开始</td><td>#E0E7FF</td><td>#6366F1</td></tr>
<tr><td class="k">快速开始 React</td><td>#FCE7F3</td><td>#EC4899</td></tr>
<tr><td class="k">更多示例</td><td>#FEF3C7</td><td>#F59E0B</td></tr>
<tr><td class="k">更多</td><td>#D1FAE5</td><td>#10B981</td></tr>
<tr><td class="k">全栈基础</td><td>#E0F2FE</td><td>#0EA5E9</td></tr>
<tr><td class="k">高级教程</td><td>#EDE9FE</td><td>#8B5CF6</td></tr>
</table>
</div>
<div class="panel" style="margin-top: 14px;">
<h3>状态示意</h3>
<div style="display:flex; gap: 24px; align-items:flex-start;">
<div class="statecard">
<div class="m">白卡 · 静止</div>
<div class="t">default</div>
</div>
<div class="statecard hov">
<div class="m">▶ 播放中</div>
<div class="t">hover / focus</div>
</div>
</div>
<div style="margin-top: 12px; font-size:12.5px; color:#555; line-height:1.7;">
hover:白卡翻为该章淡彩媒体卡,黑色圆形播放钮与 ⏱ 胶囊出现;键盘 Tab 与鼠标悬停共享同一态。圆角 14–20px,阴影仅 0 1px 2px 极轻一级。
</div>
</div>
</div>
<div class="footline">课程书架设计稿 v2 · stack idealjs · relations 待产品列出后填充</div>
<div class="pagenum">05 / 05</div>
</div>
</body>
</html>