diff --git a/docs/superpowers/specs/2026-04-23-article-markdown-export-design.md b/docs/superpowers/specs/2026-04-23-article-markdown-export-design.md new file mode 100644 index 0000000..d3246cf --- /dev/null +++ b/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. 通过临时 `` 触发下载,文件名按规则生成。 + +该方案不新增接口,改动范围小,符合“仅导出正文、访客可用、快速交付”的目标。 + +## 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 时,可根据当前代码风格决定“内联实现”或“工具函数抽离”。