Browse Source

docs: add article markdown export design spec

Document the public post detail markdown export design, including visitor access, image URL normalization to absolute links, UX states, and acceptance criteria.

Made-with: Cursor
main
npmrun 2 weeks ago
parent
commit
b8d2a9c332
  1. 117
      docs/superpowers/specs/2026-04-23-article-markdown-export-design.md

117
docs/superpowers/specs/2026-04-23-article-markdown-export-design.md

@ -0,0 +1,117 @@
# 设计:个人主页文章详情页导出 Markdown
**日期**:2026-04-23
**状态**:已定稿(待你最终确认后进入实现计划)
## 1. 背景与目标
当前个人主页文章详情页支持阅读与评论,但缺少“导出原始 Markdown”能力。
本期目标是在公开文章详情页新增导出能力,满足“访客可直接下载 `.md` 文件”的需求。
## 2. 本期确认范围
- 导出格式:仅 `Markdown (.md)`
- 入口位置:个人主页文章详情页(`/@[publicSlug]/posts/[postSlug]`)。
- 权限:所有访客可导出(无需登录)。
- 导出内容:仅正文 `bodyMarkdown`
- 图片处理:导出时将站内相对图片链接转换为绝对 URL。
## 3. 非目标
- 不导出 PDF / HTML。
- 不附带 Front Matter 元数据。
- 不打包图片文件到本地,仅处理 Markdown 内图片链接文本。
- 不新增后端导出 API(本期前端本地导出)。
## 4. 技术方案
采用前端本地导出(Blob + download):
1. 在详情页数据加载完成后显示 `导出 .md` 按钮。
2. 点击按钮时读取当前已加载的 `data.bodyMarkdown`
3. 仅对 Markdown 图片语法 `![](...)` 中的链接做归一化:
- 若为站内相对路径(如 `/public/assets/...`),替换为 `window.location.origin + path`
- 其他链接类型保持不变。
4. 生成 `Blob(['...'], { type: 'text/markdown;charset=utf-8' })`
5. 通过临时 `<a download>` 触发下载,文件名按规则生成。
该方案不新增接口,改动范围小,符合“仅导出正文、访客可用、快速交付”的目标。
## 5. URL 归一化规则
### 5.1 处理对象
- 仅处理 Markdown 图片语法:`![](...)`。
- 普通链接语法 `[](...)` 不处理。
### 5.2 保持不变
- `http://...`、`https://...`
- `//...`(协议相对)
- `data:image...`
### 5.3 转换条件
- 以 `/` 开头的站内相对路径(重点覆盖 `/public/assets/...`)。
### 5.4 基地址来源
- 使用 `window.location.origin` 作为导出时站点基地址。
### 5.5 示例
- 输入:`![](/public/assets/u1/a.webp)`
- 当前访问域名:`https://example.com`
- 输出:`![](https://example.com/public/assets/u1/a.webp)`
## 6. 交互与错误处理
- 按钮位置:详情页顶部操作区,与“返回主页 / 编辑”同级。
- 显示与可用性:
- `pending` 状态禁用按钮。
- `error && !data` 时不显示按钮。
- `data` 就绪后访客可点击导出。
- 成功反馈:导出完成后给轻量 Toast(如“已导出 Markdown”)。
- 失败反馈:捕获异常并提示“导出失败,请稍后重试”,不影响页面其他功能。
- 空正文:允许导出空 `.md` 文件。
## 7. 文件命名规则
- 优先:`${postSlug}.md`
- 回退:`post-${id}.md`
确保命名稳定、可预测,便于用户归档。
## 8. 验收标准
### 8.1 功能验收
- 公开文章详情页可见 `导出 .md` 按钮,未登录访客可使用。
- 点击后下载文件名符合规则。
- 导出正文与 `bodyMarkdown` 一致(仅图片链接归一化除外)。
### 8.2 图片链接验收
- `![](/public/assets/xxx.png)` 转换为当前域名下绝对 URL。
- 已是绝对地址、协议相对地址、data URI 的图片链接保持不变。
- 普通链接 `[](...)` 不被误改。
### 8.3 状态与异常
- 加载中按钮禁用;加载失败场景不显示导出按钮。
- 成功/失败提示可见且文案清晰。
- 异常不导致页面崩溃。
### 8.4 回归检查
- 原有“返回主页”“编辑(作者可见)”“评论”功能不受影响。
- 移动端与桌面端按钮布局保持可用。
## 9. 实现建议(供下一步计划使用)
- 修改页面:`app/pages/@[publicSlug]/posts/[postSlug].vue`
- 可抽离工具函数(可选):`app/utils/markdown-export.ts`
- `normalizeMarkdownImageUrls(markdown: string, origin: string): string`
- `downloadMarkdownFile(filename: string, content: string): void`
后续进入 implementation plan 时,可根据当前代码风格决定“内联实现”或“工具函数抽离”。
Loading…
Cancel
Save