页面外观
每页 HTML = 内容 HTML + 模板函数拼装的页面外观。模板为纯 TypeScript 函数(renderLayout(data: TemplateData): string),零模板引擎依赖,类型安全,用户可控字符串统一转义。
布局结构
页面自上而下分三层:
- Header(通栏):站点品牌、搜索触发器、语言切换、主题切换;sticky 悬浮于整窗滚动内容之上,恒为悬浮盒(毛玻璃底 + 细边框);圆角随滚动量连续插值,页面顶部时为卡片级 14px,随向下滚动在前 120px 内按 easeOutCubic 扩张为胶囊(半高 28px)
- 子文档 Tab 栏(通栏):
docdoc.json声明多个子文档时渲染;普通流透明一行,不常驻,滚动时随内容向上滚出视口、钻入 Header 外层的不透明画布之下 - 主体(左右两栏):侧栏与文档区。侧栏趴在暖色画布上(宽度由
--sidebar-width变量驱动,可拖拽调宽并记忆);文档区是一张浮于画布上的白色卡片(圆角、细边框、微阴影,高度跟随内容),卡片内是文档正文、Minimap 与上一页/下一页导航;站点页脚(版权、构建时间)独立浮于卡片下方的画布上,视觉与正文脱离
整窗滚动模型:Header position: sticky 悬浮(外层铺不透明画布,遮蔽滚动经过的 Tab 栏与正文);Tab 栏不悬浮,随内容向上滚走;侧栏 sticky——滚动时与正文一起向上,触碰 Header 下沿(--header-height,72px)后固定,正文继续向上。视口高度一律采用 svh 动态视口单位(带 vh / -webkit-fill-available 回退),规避移动端浏览器大视口(lvh)大于可视区造成的底部多余滚动空间。html 的 scroll-padding-top 按 Header(--header-height)+ 16px 统一为锚点跳转与程序化滚动让位。
图标体系
界面图标全部使用 Phosphor Icons(MIT License)bold 字重,构建期内联为 SVG(currentColor 继承文字颜色),零运行时依赖、无字体文件。图标清单由 scripts/gen-icons.mjs 从 @phosphor-icons/core 生成到 src/chrome/icons.ts。
标题图标复用同一图标清单:任意级别的标题中可书写 <Icon name="rocket-launch" />,无论书写位置,图标永远呈现在标题最前;构建期标题净化把它从侧边栏条目、搜索索引与标题锚点中剥离,rehypeHeadingIcons 在 slug 计算前移除图标节点保证锚点干净。
组件与拼装时机
| 组件 | 拼装时机 | 内容 |
|---|---|---|
| Header | 构建期 | 站点图标与名称、搜索触发器(⌘ K pill)、语言切换器(多语言时)、主题三态切换(太阳 / 月亮 / 显示器图标按钮) |
| 子文档 Tab 栏 | 构建期 | docdoc.json 声明的子文档列表,多于一个时渲染为 Header 与主体之间的通栏一行,当前子文档高亮 |
| Sidebar | 构建期烘焙 | 三种渲染器逐页生效(doc.docdoc.json 的 renderer 定文档级缺省,各目录 metadata.docdoc.json 的 renderer 可覆盖、最深一级目录生效,同一文档内可混合出现):tree 可展开折叠树(折叠箭头 + 目录行 + 条目,当前页高亮、祖先目录展开);submenu 逐级进入(面包屑链 + 当前目录条目,点击目录行进入;目录首页以同标题条目呈现在条目列表首位;面包屑仅剩文档标题时(文档根页)不渲染该行,避免与子文档 Tab 重复);group 分组恒展(目录题作小号纯文本分组标签,目录首页以同标题条目呈现在组内首位,全部条目始终展开、无折叠,嵌套目录作缩进子分组)。选中态三形态统一为白卡片:tree 的目录行或页面行、submenu 与 group 的页面条目(含重复呈现的目录首页条目)。均支持拖拽调宽 |
| Minimap | 构建期烘焙 | 当前页标题大纲(带列表图标),滚动联动高亮 |
| 上一页/下一页 | 构建期烘焙 | 按目录序渲染相邻两页链接(左右箭头图标) |
| Try it 面板 | 构建期烘焙容器,客户端水合 | 接口文档专用,数据与语义见站内搜索 ?接口标记 |
| Footer | 构建期 | 独立于内容卡片、浮于画布上的站点页脚:版权信息(docdoc.json 顶层 copyright,缺省为 © 年份 + 站点名)、构建时间(构建机本地时区格式) |
构建期烘焙保证页面无闪烁、无客户端渲染依赖;模板函数的输入契约见站内搜索 ?TemplateData。
亮暗主题
首帧前内联脚本按 localStorage 记忆的选择或系统偏好设置 data-theme,避免错误主题闪现;CSS 变量驱动两套配色,代码块在两种主题下均保持深色外观。构建期不烘焙主题选择,切换即时生效。
rootPrefix 机制
每页按自身深度计算指回站点根的前缀(../..、./ 或 /my-docs/),所有资源引用、页间链接与内容接口请求都拼接该前缀。同一份产物因此无须改动即可在三种环境下正确工作:
| 环境 | 站点根 |
|---|---|
| 域名路由 | / |
| 路径前缀路由 | /:name/ |
| preview | 命令行指定的根 |
客户端脚本
assets/docdoc.js 为单文件 IIFE,零运行时依赖,只做交互增强:
| 行为 | 说明 |
|---|---|
| 搜索弹窗 | ⌘ K / Ctrl-K 唤起,防抖调用站点的全文搜索接口渲染命中列表,键盘上下选择、回车跳转 |
| 主题切换 | Light / Dark / System 三态,localStorage 记忆,跟随系统偏好变化 |
| Sidebar 折叠 | 目录节点的展开与收起、当前页高亮、拖拽调宽并记忆 |
| Header 滚动态 | 窗口滚动时切换 page-scrolled 类(阴影),并按滚动量逐帧插值 Header 悬浮盒圆角 |
| Minimap 联动 | 滚动时同步高亮标题大纲 |
| 代码块复制 | 代码块右上角复制按钮,成功后短暂勾选反馈 |
| Try it 面板水合 | 读取烘焙的 data-docdoc-try 数据构建表单;HTTP 面板实发请求,NATS 面板构建并复制请求载荷 |
纯静态打开(无服务端)时优雅降级:导航照常可用,搜索提示服务不可用。
