Files
blog/docs/research/05-极客交互设计案例与实现.md
T
wait4xandGLM-5.3 0fbb023375 docs: 落库博客重设计调研报告 v1.8 与视觉样板 v2
调研收官产物入库:主报告(架构 C''=Astro SSG+gitea 双写作流、
Artalk 评论、分片 webfont、双语预译管线、多端适配规格、
Phase 0-5 实施规划)+ 五份侦察原稿 + 可交互单文件样板
(三路线×明暗×五页型,命令面板/终端/热力图/masonry)。

Co-authored-by: GLM-5.3
2026-10-24 21:48:11 +08:00

237 lines
18 KiB
Markdown
Raw 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.
# task-2 · 极客交互设计侦察报告(极客精神设计语言:真实案例 × 可落地实现)
> 侦察员 @agent-aeff1b · 2026-10-24
> 方法:所有案例均于本次用 curl 实际抓取验证(HTTP 状态 / 页面源码标记 / 开源仓源码 / npm registry / caniuse 官方数据),命令面板与终端站深挖到 JS bundle 与命令表。**抓不到、不命中的一律如实标注为负发现**。技术基线:Astro SSG + 自托管 Gitea,视觉路线「灰阶骨架×分轨正文」。
---
## 1. 命令面板 Ctrl+K
### 实测案例
| 站点 | 抓取证据 | 说明 |
|---|---|---|
| **Starlight / Astro 官方文档** starlight.astro.build | HTTP 200;页面源码含 `aria-keyshortcuts="Control+K"` ×1 + `pagefind` ×3 | **静态站 + Pagefind + 自定义模态的官方参考实现**,MIT 源码:`withastro/starlight` → `packages/starlight/src/components/Search.astro`(已实抓源码头 25 行:按钮 `aria-keyshortcuts="Control+K"` + pagefind 翻译注入 + `data-open-modal`) |
| **spectre.lou.gg**(louisescher/spectre,164★) | HTTP 200;**服务端 HTML 直接含** `<input id="search" placeholder="Search (Ctrl+K)">`,且 HTML 内有 `pagefind-ignore=` 属性、`pagefindInitialized = false`(首次聚焦才懒加载 Pagefind) | **Astro 原生终端风主题**,与本博客技术栈同源,Ctrl+K 搜索框静态可抓,是「静态站 Ctrl+K + Pagefind」最佳抄写对象 |
| **paco.me**(Paco Coursey,cmdk 作者本人站) | HTTP 200;源码含 `⌘K`、`command menu`、`cmdk` 字样 | cmdk 生态的活样本 |
| **blog.maximeheckel.com**(Maxime Heckel 博客) | 开源仓 `MaximeHeckel/blog.maximeheckel.com` package.json 实抓:依赖 `cmdk ^1.1.1` | 个人博客用 cmdk 的实证 |
**未验证(如实说明)**:leerob.com / rauchg.com / kentcdodds.com / brianlovin.com / joshwcomeau.com 首页静态 HTML 均无面板标记(客户端懒渲染),未继续深挖各自 bundle,不作案例引用。kentcdodds/kentcdodds.com 与 sreetamdas/sreetamdas.com 的 package.json 中均无 kbar/cmdk。
### 库与取舍(npm registry 实抓数据)
- **cmdk**:React 无样式 primitive(UI 全自理),周下载 **26,647,174**。适合已有 React 岛的站。
- **kbar**:即插即用 React 面板(自带动画/快捷键注册/持久化),周下载 **226,077**;README 实抓:「plug-n-play React component…built in animations and fully customizable components」。
- **静态站推荐:自写 vanilla TS(~150–200 行,零运行时框架)**。Pagefind 官方 JS API 文档实抓(pagefind.app/docs/api/,HTTP 200):`pagefind.search()` ×8、`pagefind.debouncedSearch()` ×3、`pagefind.options()` ×3、`pagefind.filters()` ×1 —— 程序化搜索接口完备,就是为自定义 UI 准备的。
### Pagefind 聚合进面板的实现路径
1. `astro build` 后跑 `pagefind --site dist` 出索引(或用 `astro-pagefind` 集成,567★,README 实抓:构建时自动建索引 + **官方声明支持 Astro View Transitions**)。
2. 自写模态:全局 `keydown` 监听 Ctrl/Cmd+K 与 `/` → 打开 `<div role="dialog">`(或 `<dialog>`)。
3. 面板数据三层:**动作项**(静态数组:切主题、跳 gitea、复制 RSS)+ **页面/文章**(Pagefind `search(query)` 返回 pages + 文内摘要)+ **分组渲染**。
4. spectre 的懒加载模式值得抄:`pagefindInitialized=false`,首次打开面板才 `import('/pagefind/pagefind.js')`,不拖首屏。
### 对本博客的适配建议
Astro 零框架站**不要为面板引 React**(cmdk/kbar 都会把 React runtime 拖进来)。抄 Starlight `Search.astro` 的结构 + spectre 的懒加载,自写 ~200 行 vanilla 模态。灰阶骨架下,面板天然「一整层黑底等宽字浮层」,视觉零违和。
---
## 2. 键盘快捷键惯例
### 实测案例(GitHub 官方文档页逐字取证)
`docs.github.com/en/get-started/accessibility/keyboard-shortcuts`(HTTP 200)HTML 表格实抓:
- `<kbd>S</kbd> or <kbd>/</kbd>` → "Focus the search bar"(**/ 聚焦搜索**实锤)
- `<kbd>G</kbd> <kbd>N</kbd>` → notifications;`<kbd>G</kbd> <kbd>C</kbd>` → Code tab;`G P` → PRs;`G A` → Actions;`G W` → Wiki(**g-chords 和弦导航**实锤)
- `<kbd>?</kbd>` → "brings up a dialog box that lists the keyboard shortcuts available"(**? 帮助浮层**实锤)
- `<kbd>Esc</kbd>` → 关闭悬浮卡
**未验证(如实说明)**:Gmail(support.google.com/mail/answer/6594)与 Linear(linear.app/keyboard-shortcuts 与 /docs/shortcuts 404)键位页均为客户端渲染,静态抓取零命中,不能引用为抓取实证;GitHub 证据已足够作键位锚点。
**负发现**:「t 切主题」「g h 回首页」**未找到可验证的个人博客公开实例**——这反而是原创空间:惯例来自 GitHub/Gmail,移植到博客即成特色。
### 实现路径
- **自写(推荐,~120–150 行)**:一个 `keydown` 监听 + 200ms 和弦缓冲(识别 `g h`)+ 输入框聚焦时旁路 + `?` 帮助浮层。无依赖。
- 或配 **tinykeys**(jamiebuilds,周下载 193,770,约 400B)管绑定,自写部分只剩 chord 逻辑与浮层。
- 主题切换若想配 View Transitions 圆形扩散动画:**ocavue/astro-theme-toggle**(62★,"ripple-style theme toggle animation to your Astro project",GitHub API 实抓)。
### 对本博客的适配建议
P0 键位集:`/` 聚焦搜索、`?` 帮助浮层(**可发现性的关键,务必做**)、`t` 切主题、`g h` 回首页、`Esc` 关一切浮层。键位表数据与 `?` 浮层同源生成,永不失同步。灰阶骨架 + 等宽字提示角标(如导航项旁的 `g h` 小字)本身就是极客视觉语言的一部分。
---
## 3. 构建透明化(页脚 commit hash · 构建时间)
### 实测案例
| 站点 | 抓取证据 |
|---|---|
| **sreetamdas.com**(sreetamdas/sreetamdas.com,Next.js,MIT) | 仓内 `scripts/generate-build-info.mjs` **全文实抓**:`WORKERS_CI_COMMIT_SHA / CF_PAGES_COMMIT_SHA / GITHUB_SHA / git rev-parse HEAD` 四重回退 → 写 `src/build-info.json`,字段 `{branch, commit(前7位), commitUrl, time: ISO时间}`。注:其站静态 HTML 页脚未见 hash(该信息主要供 CI 冒烟/接口用),展示环节未验证 |
| **mldangelo.com**(mldangelo/personal-site,**1695★** 个人站模板,Next 静态导出) | sourcegraph 实抓源码:`src/components/Stats/Site.tsx` 含 `built_commit: builtCommit()`;配套测试断言页面上存在 `'Built from commit'` 行 —— **个人站模板直接内置「构建透明化」区块**,live 站 HTTP 200 |
**负发现**:gwern.net、survivejs.com、search.nixos.org、notes.eatonphil.com、drewdevault.com、mxb.dev、darekkay.com、fasterthanli.me、joshfinnie.com、stefanjudis.com 十个极客向站首页/页脚抓取均**无** commit hash —— 说明这在主流个人站里**罕见,做了反而差异化**。
### Astro 实现路径
1. **零依赖自写(推荐,~20 行)**:`astro.config.mjs` 里
```js
vite: { define: {
'import.meta.env.GIT_COMMIT_SHA': JSON.stringify(execSync('git rev-parse HEAD').toString().trim()),
'import.meta.env.GIT_COMMIT_DATE': JSON.stringify(execSync('git log -1 --format=%cI').toString().trim()),
}}
```
页脚组件读 `import.meta.env.GIT_COMMIT_SHA.slice(0,7)`。sreetamdas 的四重回退模式(CI 环境变量优先)值得照抄。
2. 现成包(npm registry 实证存在,但体积/维护一般):`vite-plugin-git-revision-info`@1.1.0、`git-revision-vite-plugin`、`@jinixx/vite-plugin-git-revision`。
3. CI 注意:Gitea Actions 的 checkout 步骤默认浅克隆也能拿到 HEAD sha(或直接用 `gitea.event.head_commit.id` 注入环境变量)。
### 对本博客的适配建议
页脚一行灰字:`built from a1b2c3d · 2026-10-24 18:51 UTC`,hash 链接到自托管 gitea 的 commit 页。半小时代价,极客气质浓度极高。
---
## 4. 贡献活动图(自托管 Gitea 数据从哪来)
### 核心实测结论:Gitea/Forgejo 原生就有热力图 API
- `gitea.com/swagger.v1.json` 实抓:存在**唯一**热力图路由 `GET /api/v1/users/{username}/heatmap`,schema `UserHeatmapData = {contributions, timestamp}`。
- **真实数据双验证**:`gitea.com/api/v1/users/lunny/heatmap` 与 `codeberg.org/api/v1/users/6543/heatmap` 均 HTTP 200,返回 `[{"timestamp":1760616000,"contributions":6},…]`(事件级 Unix 秒粒度,前端自行聚合到日/周格子)。
- **CORS 实测**:gitea.com 与 codeberg.org 对 API 请求均返回 `access-control-allow-origin: *` → 静态站**构建时**拉没问题,甚至浏览器运行时直拉也通。
### GitHub 工具能否指过来?
**不能直接换标**。github-readme-stats / contribution-graph 类方案依赖 GitHub GraphQL 的 `contributionsCollection`(REST 根本没有贡献端点),无法指向 Gitea。生态佐证(GitHub 搜索实抓):`oliver-drewing/forgeheat`(Forgejo 热力图挂件)、`BenevolentFutures/forgejo-github-sync`(反向把自托管提交同步养 GitHub 图)——「自托管后贡献图怎么办」是真实普遍痛点,各自造轮子。
### 自建数据源方案(git log 统计 → JSON)
```bash
git -C /path/repo log --all --pretty=format:'%ad' --date=unix \
| awk -v d=$(date +%s) '{day=strftime("%Y-%m-%d",$1); c[day]++} END {for(k in c) print k, c[k]}' > contrib.json
```
- 多仓循环合并即可;**优点**:算本地全历史(含从 GitHub 迁移来的仓、heatmap 端点统计不到的活动)、无网络依赖、CI 里必成。
- 也可和 heatmap API 并用:API 为主、git log 兜底。
### 对本博客的适配建议
构建时 fetch `https://<自家gitea>/api/v1/users/<user>/heatmap` → 聚合成 53×7 格 SVG/CSS grid,**灰阶色阶恰好是热力图的完美配色**(从 #ececec 到 #111 的七档)。失败时回退 git log 本地统计。~120 行 + 一个聚合函数。
---
## 5. 终端彩蛋页
### 实测案例(GitHub search "terminal portfolio" + 首页/JS bundle 抓取)
| 站点 | 抓取证据 |
|---|---|
| **terminal.satnaing.dev**(satnaing/terminal-portfolio,**824★**,React+TS) | bundle(277KB)实抓,命令表坐实:`help` ×3、`whoami`、`pwd`、`history`、`echo`、`about`、`projects`、`clear`、`welcome` —— 真·可交互终端站 |
| **codenerve.github.io**(CodeNerve,188★,纯 vanilla) | `index.js` **全文仅 2,999 字节**:keydown 监听 + `ls` ×10 等命令 —— **自写 switch 方案极轻的活实证** |
| **term.fathi.me**(m4tt72/terminal,**1564★**,"Terminal style website") | SPA 壳站,31KB bundle 未能静态取证命令表(如实注明);star 数佐证品类成熟度 |
| **spectre.lou.gg**(louisescher/spectre,164★) | Astro 原生终端风主题(见 §1,还带 Ctrl+K),**与技术栈同源**,可整主题借鉴或只借 its CSS |
### 实现路径
1. **自写 switch(推荐,~150–300 行,零依赖)**:隐藏 input 捕获 + 命令注册表(`{help, whoami, ls, cat, clear, exit…}`)+ 上下历史。codenerve 的 3KB 证明下限极低。
2. 库:jQuery Terminal(jcubic,老牌全功能,自带多级命令/表单支持,风格偏 jQuery 时代)、react-terminal(需 React)、xterm.js(真终端模拟器,VS Code 同款——能跑、但过重,用于彩蛋页杀鸡用牛刀)。
### 对本博客的适配建议
`/terminal` 路由作彩蛋:不进主导航,藏在 `?` 帮助浮层提示一句 `hint: try /terminal`(极客自己会发现的秘密)。命令组:`help` / `whoami`(输出个人签名档)/ `ls blog` / `cat about.txt` / `gpg --recv-key <指纹>`(真指纹,链接到 key 文件)/ `exit`(动画后跳回首页)。CRT 扫描线 + 琥珀色单色可选(灰阶骨架里允许一处 CRT 绿或琥珀做点睛)。
---
## 6. 页面转场(Astro View Transitions)
### 实测案例
| 站点 | 抓取证据 |
|---|---|
| **mazipan.space**(mazipan/mazipan.space,**102★** 个人站+博客) | 线上 HTML 实抓(HTTP 200):含 `ClientRouter` ×1 + `view-transition` 标记 ×3 —— **个人博客真实用例** |
| **astro-theme-reimu**(D-Sketon,79★,demo: d-sketon.github.io/astro-theme-reimu) | sourcegraph 全网代码检索命中该仓 `.astro` 文件含 `ClientRouter` —— 中文圈在用的博客主题实证 |
| 官方文档 docs.astro.build/en/guides/view-transitions/ | 实抓:`ClientRouter` ×45、**`prefers-reduced-motion` 独立章节** ×12、`transition:animate` ×13、不支持的浏览器的 `fallback` 行为章节 |
### 浏览器兼容(caniuse 官方数据实抓,`view-transitions.json`)
- Chrome **111+** ✅、Safari **18.0+** ✅、Firefox **144+** ✅(143 仍在 flag 后)。
- 2026 年现状:三大引擎全绿。Astro 的 `ClientRouter` 用的是同文档转场(MPA 导航模拟),落在上述支持范围内;更老浏览器走 `fallback`(默认 animate 模拟 / 可设 none 直切)+ reduced-motion 降级,**无破坏性**。
### 对本博客的适配建议
`<ClientRouter />` 一行接入 + 一段保险 CSS:
```css
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
```
转场动画克制:正文区轻微 fade/slide(呼应「分轨」——轨道间的内容流动),骨架(顶栏/页脚)用 `transition:persist` 常驻不闪。主题切换想加圆形扩散可参考 ocavue/astro-theme-toggle 的 ripple 方案与 VT 打配。
---
## 7. 开源项目墙(自托管 Gitea 动态拉卡片)
### 数据面实测(codeberg.org / gitea.com 同源 API)
`GET /api/v1/repos/search?limit=2` 实抓返回字段(Forgejo/Gitea 通用):
```json
{ "full_name": "...", "description": "...", "website": "...", "language": "C",
"stars_count": 1, "forks_count": 0, "html_url": "...", "avatar_url": "", "updated_at": "..." }
```
**主语言、star、描述、网站全有**,卡片所需字段一次到位。`GET /api/v1/users/{user}/repos` 同理。CORS `*`(§4 实测)→ 构建时拉、运行时拉皆可。
### 消费者案例(诚实负发现 = 差异化机会)
- sourcegraph 全网代码检索 `api/v1/repos/search`:消费者仅 **linuxserver/Heimdall-Apps**(应用目录元数据脚本),无个人博客。
- `gitea lang:astro` 全网:仅 **RayLabsHQ/gitea-mirror**(镜像工具,API 用法可参考)。
- **结论:个人博客从自托管 git 动态拉项目墙,没有现成公开案例** —— 没得抄,但也意味着做出来就是独一无二的开源自证。
- 语言颜色:Gitea API 不带色值;用 github-linguist/linguist 的 `languages.yml` 作映射(实抓样本:Go `#00ADD8`、TypeScript `#3178c6`)。
### Astro SSG 实现路径(~80 行)
```astro
---
// src/pages/projects.astro(frontmatter 在构建时执行)
const GITEA = 'https://git.example.com';
const repos = await fetch(`${GITEA}/api/v1/users/me/repos?limit=30`)
.then(r => r.json()).catch(() => JSON.parse(cachedFallback)); // 失败读上次缓存 JSON
---
```
构建时执行 = 零 CORS 问题、零客户端 JS;Gitea Actions 上 push 触发重建保证新鲜度;`pinned` 置顶仓用手动数组覆盖排序。
### 对本博客的适配建议
`/projects` 分轨页:卡片 = 语言色点(灰阶骨架里唯一允许的品牌色点缀,恰与「开源」语义互文)+ star 数 + 一行描述 + `updated_at`。页脚 `built from <hash>`(§3)→ 点击即达同源 gitea commit——**构建透明化与项目墙共享同一自托管源,叙事闭环**。
---
## 极客设计语言清单(性价比分级)
| 级别 | 项 | 实现方式 | 工作量 | 实证锚点 |
|---|---|---|---|---|
| **P0** | 键盘基础集:`/` 搜索、`?` 帮助浮层、`t` 主题、`g h` 回首页 | 自写 vanilla(keydown+chord buffer+浮层) | ~120–150 行,半天 | GitHub 键位表逐字实抓 |
| **P0** | 页脚构建信息(hash+时间+commit 链接) | vite.define 注入或抄 sreetamdas 脚本 | ~20 行,半小时 | sreetamdas/mldangelo 源码实抓 |
| **P0** | View Transitions + reduced-motion 降级 | `<ClientRouter />` + 5 行 CSS | 半小时 | mazipan.space 实抓;三引擎全绿 |
| **P0** | 开源项目墙 | 构建时 fetch gitea API 渲染卡片 | ~80 行,半天 | API 字段/CORS 实测 |
| **P1** | Ctrl+K 命令面板(搜索+动作聚合) | 自写 vanilla 模态 + Pagefind JS API(懒加载) | ~200 行,一天 | Starlight Search.astro / spectre 实抓 |
| **P1** | Gitea 贡献热力图 | heatmap API(或 git log 兜底)→ 灰阶 SVG 格 | ~120 行,一天 | heatmap 端点双站 200 实测 |
| **P2** | `/terminal` 终端彩蛋页 | 自写命令 switch | ~200–300 行,一天 | codenerve 3KB 实证;satnaing 824★ |
| **P2** | 全 g-chords 体系(g p 项目 / g b 博客) | 扩展 §2 chord 表 | +30 行 | GitHub G+N/C/P 模式移植 |
**协同叙事**:所有键位汇聚在 `?` 浮层(可发现性)→ 面板是极客动线中枢(搜索+动作+彩蛋入口)→ 页脚 hash 与项目墙共享自托管 gitea 源(开源自证闭环)→ 热力图是这套语言里唯一的「数据可视化」,用灰阶色阶呈现正好。「艺术文学的美观」由灰阶骨架承担,「极客精神」由这层可交互的等宽字神经系统承担——两者不抢戏。
## 未验证/存疑清单(全部如实声明)
1. leerob.com / rauchg.com / kentcdodds.com / brianlovin.com / joshwcomeau.com 的面板:静态 HTML 无标记(客户端渲染),未逐一深挖 bundle。
2. Gmail / Linear 键位官方页:JS 渲染无法静态取证(GitHub 证据已足为键位锚点)。
3. term.fathi.me 的命令表:bundle 未能静态取证。
4. 「t 切主题」「g h 导航」在**个人博客**上:未找到可验证公开实例(属 GitHub/Gmail 惯例移植,无先例包袱)。
5. 「个人博客动态拉自托管 git 项目墙」:全网无现成公开案例(负发现,同时是机会点)。
6. sreetamdas.com 的 build-info:生成脚本实抓确凿,但页脚展示环节未在静态 HTML 验证到。