diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index adfc30014..593a213ec 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -28,6 +28,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || (inputs.operation == 'staging-next' && 'asf-staging-oink' || 'asf-site') }} + # A newer commit supersedes previous work for the same PR or publish target. cancel-in-progress: true env: @@ -231,7 +232,7 @@ jobs: restore-keys: ${{ runner.os }}-hugo-${{ env.HUGO_VERSION }}-${{ matrix.version.id }}- - name: Verify pinned OINK module run: | - python3 scripts/oink_module.py + python3 scripts/update_oink.py --check-baseline - name: Build isolated version artifact env: OINK_PYTHON: python3 @@ -256,11 +257,14 @@ jobs: if-no-files-found: error overwrite: true + # Assembly and browser checks are serial; reuse one runner and its local output. aggregate: needs: [prepare, build] runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 35 permissions: { contents: read } + env: + HUGO_CACHEDIR: /tmp/hugo-cache-${{ github.run_id }}-${{ github.run_attempt }}-aggregate steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: @@ -309,18 +313,6 @@ jobs: if-no-files-found: error overwrite: true - e2e: - needs: [prepare, aggregate] - runs-on: ubuntu-latest - timeout-minutes: 20 - permissions: { contents: read } - env: - HUGO_CACHEDIR: /tmp/hugo-cache-${{ github.run_id }}-${{ github.run_attempt }}-e2e - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - ref: ${{ needs.prepare.outputs.source_sha }} - persist-credentials: false - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "24" @@ -335,10 +327,6 @@ jobs: with: hugo-version: ${{ env.HUGO_VERSION }} extended: true - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - name: hugegraph-site-${{ needs.prepare.outputs.artifact_prefix }}-${{ github.run_id }} - path: public-site - name: Install Chromium test workspace working-directory: tests/e2e run: | @@ -358,12 +346,12 @@ jobs: - name: Run blocking Chromium contracts working-directory: tests/e2e env: - SITE_ROOT: ${{ github.workspace }}/public-site + SITE_ROOT: ${{ runner.temp }}/public-site AI_SITE_ROOT: ${{ runner.temp }}/ai-site EXPECTED_VERSIONS: ${{ needs.prepare.outputs.selection }} run: npm run test:ci - name: Upload E2E report - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: playwright-report-${{ github.run_id }}-${{ github.run_attempt }} @@ -402,7 +390,7 @@ jobs: npx playwright install --with-deps chromium npm run test:visual - name: Upload advisory visual evidence - if: always() + if: ${{ !cancelled() }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: visual-evidence-${{ github.run_id }}-${{ github.run_attempt }} @@ -412,8 +400,8 @@ jobs: # Required check name in .asf.yaml. It gates artifacts without write access. deploy: - if: always() - needs: [prepare, build, aggregate, e2e] + if: ${{ !cancelled() }} + needs: [prepare, build, aggregate] runs-on: ubuntu-latest timeout-minutes: 5 permissions: { contents: read } @@ -423,12 +411,10 @@ jobs: PREPARE_RESULT: ${{ needs.prepare.result }} BUILD_RESULT: ${{ needs.build.result }} AGGREGATE_RESULT: ${{ needs.aggregate.result }} - E2E_RESULT: ${{ needs.e2e.result }} run: | test "$PREPARE_RESULT" = success test "$BUILD_RESULT" = success test "$AGGREGATE_RESULT" = success - test "$E2E_RESULT" = success publish: if: needs.prepare.outputs.publish_branch != '' diff --git a/.goal-task/oink-1.1-guide/handoff.md b/.goal-task/oink-1.1-guide/handoff.md new file mode 100644 index 000000000..8daf2e5a8 --- /dev/null +++ b/.goal-task/oink-1.1-guide/handoff.md @@ -0,0 +1,29 @@ +# Handoff: OINK 1.1 与 Ask AI 建站入门指南 + +## 来源会话 +- 原始会话 ID: `01a0c9c0-a17b-7e60-8014-b312f6997484` +- 原始任务名: 写作:OINK 1.1 与 Ask AI 建站入门 +- 原始工作区: `~/.codex/worktrees/d61b/hugegraph-doc` +- 会话状态: 文章初稿与 8 张配图均已就绪并通过自主核验,因宿主机 Codex 达到使用上限而交接。 + +## 产物清单 +1. **文章主体**: `oink-1.1-website-guide.md` + - 面向没有建站经验、但会写代码/Markdown 的开发者。 + - 介绍 Hugo + OINK 1.1 + 可选 Ask AI(Kapa)的文档网站体系。 + - 包含市面文档库对比(Docsy 单独对比表,已剔除 Notion/语雀)。 + - 遵循 `writing-human` 规范(无套话口号,基于 HugeGraph 实际升级经验)。 +2. **配图及 Prompt 记录**: `oink-1.1-illustrations/` + - `01-build.png`: 构建与部署机制 + - `02-language-version.png`: 多语言与多版本 + - `03-maintenance.png`: 维护与定制边界 + - `04-ai.png`: Ask AI / Kapa 接入机制 + - `05-overview.png`: Markdown 到静态网站全景 + - `06-features.png`: 交互功能(目录、本地搜索、代码标签页、步骤、图表) + - `07-publishing.png`: 多形态发布(网页、打印、RSS、llms.txt) + - `08-optional-ai.png`: 本地搜索与可选 Ask AI 接入区分 + - `final-prompts.md`, `general-prompts.md`, `prompts.md`: 绘图 Prompt 记录 + +## 接力后续工作建议 +- 根据主线需要,决定是否将该文章排版并整合入网站正式路由(如 `content/cn/docs/...` 或博客/社区板块)。 +- 校验图片相对路径与网站静态资源目录映射。 +- 最终合入 PR 前,从分支中清理 `.goal-task/oink-1.1-guide`。 diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/01-build.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/01-build.png new file mode 100644 index 000000000..3e6868784 Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/01-build.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/02-language-version.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/02-language-version.png new file mode 100644 index 000000000..87b92757b Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/02-language-version.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/03-maintenance.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/03-maintenance.png new file mode 100644 index 000000000..aa4e603f6 Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/03-maintenance.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/04-ai.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/04-ai.png new file mode 100644 index 000000000..467f58e5e Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/04-ai.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/05-overview.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/05-overview.png new file mode 100644 index 000000000..9024ce1b4 Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/05-overview.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/06-features.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/06-features.png new file mode 100644 index 000000000..8e3ab74bd Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/06-features.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/07-publishing.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/07-publishing.png new file mode 100644 index 000000000..e10dad697 Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/07-publishing.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/08-optional-ai.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/08-optional-ai.png new file mode 100644 index 000000000..f5517690f Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/08-optional-ai.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/final-prompts.md b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/final-prompts.md new file mode 100644 index 000000000..b3ef466ef --- /dev/null +++ b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/final-prompts.md @@ -0,0 +1,27 @@ +# 正文配图提示词 + +使用内置 image_gen。四图统一技术手绘风,生成后逐张检查文字、箭头和事实边界。 + +## 01-build + +Use case: infographic-diagram. Generate one finished informative Chinese editorial illustration for an introductory HugeGraph / Hugo / OINK 1.1 article. Landscape 16:9, high resolution. Consistent sophisticated technical hand-sketch style: warm ivory paper, fine black ink outlines, lavender highlight for software/theme, muted amber for site-owned choices, pale gray backgrounds. Large impeccable readable Chinese sans-serif labels integrated with careful hand-drawn diagrams. Prioritize explanatory information, clear arrow direction and hierarchy. No people, no coffee, no books, no plants, no scenery, no fake logos, no slogans. No tiny filler text. This is a conceptual diagram, never a real screenshot. Render only requested labels. Title "一篇 Markdown 怎样变成文档网站". Layout: left inputs -> central Hugo engine -> right output browser, with bottom publishing step. Left two sheets labeled "content/cn" and "content/en", caption "作者维护正文与翻译". Another input card "站点配置" with "导航 · 版本 · 项目样式". The central large unit "Hugo" caption "读取内容并生成静态文件". ABOVE it separate card "OINK 1.1" caption "模板 · 侧栏 · 搜索界面", with arrow INTO Hugo clearly making theme an input, NOT a processing step after Hugo. Hugo arrow -> output labeled "public/" and "网页 · 样式 · 脚本 · 搜索索引". Browser illustration contains meaningful sidebar, heading, search bar and content blocks, no placeholder gibberish. Output arrow downward to "发布到静态托管". Bottom distinct two-note strip "本地预览 ≠ 已发布" and "基础文档阅读不依赖 Kapa". Every shape has explanatory function. + +修订要求:背景改为完整不透明的暖白纸色,保留图中结构和标签。Remove the small explanatory sentence claiming local preview is only accessible on your computer. Keep only the note 本地预览 ≠ 已发布. Remove the promotional subtitle 构建高性能的图数据库 in the mock browser. + +## 02-language-version + +Use case: infographic-diagram. Generate one finished informative Chinese editorial illustration for an introductory HugeGraph / Hugo / OINK 1.1 article. Landscape 16:9, high resolution. Consistent sophisticated technical hand-sketch style: warm ivory paper, fine black ink outlines, lavender highlight for software/theme, muted amber for site-owned choices, pale gray backgrounds. Large impeccable readable Chinese sans-serif labels integrated with careful hand-drawn diagrams. Prioritize explanatory information, clear arrow direction and hierarchy. No people, no coffee, no books, no plants, no scenery, no fake logos, no slogans. No tiny filler text. This is a conceptual diagram, never a real screenshot. Render only requested labels. Title "语言与版本是两个选择". Draw a crisp conceptual documentation browser in upper left with two independent controls "语言" showing "中文 / English", and "版本" showing "latest / 1.7 / 1.5 / 1.3 / 1.0". Main content a legible matrix with columns "latest" and "1.7", rows "English" and "中文". Four cells exact paths "/docs/…" and "/versions/1.7/docs/…" in English row, "/cn/docs/…" and "/versions/1.7/cn/docs/…" in Chinese row. Avoid automatic translation imagery. Below matrix two input cards: "content/cn + content/en" caption "两份正文,分别维护"; "versions.json" caption "版本 → 发布分支与路径". These cards feed the matrix. Bottom small search card labeled "本地搜索" with note "当前使用摘要索引" and second note "不等于完整正文检索". Note "路径为结构示意" in lower corner. No invented feature claims. + +修订要求:背景改为完整不透明的暖白纸色,保留图中结构和标签。Preserve all paths and labels exactly. + +## 03-maintenance + +Use case: infographic-diagram. Generate one finished informative Chinese editorial illustration for an introductory HugeGraph / Hugo / OINK 1.1 article. Landscape 16:9, high resolution. Consistent sophisticated technical hand-sketch style: warm ivory paper, fine black ink outlines, lavender highlight for software/theme, muted amber for site-owned choices, pale gray backgrounds. Large impeccable readable Chinese sans-serif labels integrated with careful hand-drawn diagrams. Prioritize explanatory information, clear arrow direction and hierarchy. No people, no coffee, no books, no plants, no scenery, no fake logos, no slogans. No tiny filler text. This is a conceptual diagram, never a real screenshot. Render only requested labels. Title "OINK 1.1 让定制各有归属". Two large comparison columns labeled "OINK 1.0 时的站点适配" and "OINK 1.1 的公开接口". Left amber site box "HugeGraph 本地代码", showing two crossed overlapping responsibility wires leading to "目录展开与页面状态" and "搜索结果行与键盘交互", visual indicates overlapping responsibility not complete failure. Right two separated neat responsibility boxes. Purple "OINK 负责" contains "展开状态与页面交互" and "搜索结果行、键盘、焦点". Amber "HugeGraph 负责" contains "按版本与语言保存展开记忆" and "AI 同意、取消与重试". Between these right boxes a narrow interface bridge labeled "OinkSidebar" and "registerSearchTail", no other API names needed. Small footer card "升级仍需检查" followed by three distinct compact items "固定主题版本" "适配本地覆盖" "构建与浏览器回归". Bottom note "减少重复维护,不承诺零维护". Clear typography, arrows show communication between owners, not Hugo version upgrade. + +修订要求:背景改为完整不透明的暖白纸色,保留图中结构和标签。Replace the left speech bubble 责任交织 需要同时修改 with 本地适配较多. Remove both small subtitles beneath the two main column headings, retaining main headings and functional content. + +## 04-ai + +Use case: infographic-diagram. Generate one finished informative Chinese editorial illustration for an introductory HugeGraph / Hugo / OINK 1.1 article. Landscape 16:9, high resolution. Consistent sophisticated technical hand-sketch style: warm ivory paper, fine black ink outlines, lavender highlight for software/theme, muted amber for site-owned choices, pale gray backgrounds. Large impeccable readable Chinese sans-serif labels integrated with careful hand-drawn diagrams. Prioritize explanatory information, clear arrow direction and hierarchy. No people, no coffee, no books, no plants, no scenery, no fake logos, no slogans. No tiny filler text. This is a conceptual diagram, never a real screenshot. Render only requested labels. Title "Ask AI 是可选的外部服务". Top compact amber status pill "本文核对时生产开关关闭". Main decision flow accurate: "站内搜索" leads right to "阅读本地结果" and separately downward via dashed arrow labeled "可选" to "Ask AI". Ask AI -> diamond "是否同意连接外部服务". Diamond NO branch label "取消" -> "返回站内搜索" with NO route to Kapa. YES branch label "同意" -> boundary line labeled "外部服务" -> "加载 Kapa 并提问" -> "查看回答与来源". Ensure no external service connected before consent. Bottom three small check cards clearly distinct from flow: "上线前" / "语料与索引验收"; "语言分组" / "核查 Global sources"; "历史版页面" / "提示回答使用 latest". Small footer "中文界面 ≠ 仅检索中文资料". Strong reading order, dotted external boundary, simple hand-drawn UI panels. No implication deployed or guaranteed correct. + +修订要求:背景改为完整不透明的暖白纸色,保留图中结构和标签。Replace the three circular check marks on bottom cards with neutral numbered circles 1, 2, 3. These are requirements, NOT completed acceptance. Preserve all arrows and decision logic. diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/general-prompts.md b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/general-prompts.md new file mode 100644 index 000000000..a4e773f5e --- /dev/null +++ b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/general-prompts.md @@ -0,0 +1,24 @@ +# 通用介绍配图 + +使用内置 image_gen 生成。本文使用 05 至 08 四张配图;01 至 04 为前稿素材,不再引用。 + +## 05-overview + +Generate an informative Chinese technical hand-drawn editorial infographic, landscape 16:9, fully opaque warm ivory rectangular paper background, no transparency or cutout edges. Fine ink outlines, lavender and muted amber highlights, crisp large readable Chinese type, generous spacing. No decorative scenery or objects. No HugeGraph branding, no OINK release numbers, no version-upgrade comparisons. Generic explanatory illustration not a screenshot. Only the specified short labels, no invented prose. Title "用 Hugo + OINK 发布文档". Three-stage workflow. Left "编写" with tangible Markdown sheet and image card labeled "Markdown · 图片 · 配置", small Git branch symbol "Git 评审". Center "生成" with a single large module labeled "Hugo + OINK", inside two connected subpanels "内容生成" and "阅读界面". Right "发布" with browser and server labeled "静态网站", bottom "网页与资源 → 静态托管". Across bottom three clear feature cards "无需 npm 构建" "本地搜索" "多语言". Small note "依赖需预先安装,功能按需配置". No AI and no automatic translation symbolism. + +## 06-features + +Generate an informative Chinese technical hand-drawn editorial infographic, landscape 16:9, fully opaque warm ivory rectangular paper background, no transparency or cutout edges. Fine ink outlines, lavender and muted amber highlights, crisp large readable Chinese type, generous spacing. No decorative scenery or objects. No HugeGraph branding, no OINK release numbers, no version-upgrade comparisons. Generic explanatory illustration not a screenshot. Only the specified short labels, no invented prose. Title "让技术文档更好读". A large conceptual documentation browser with six annotated feature callouts arranged cleanly. Sidebar highlighted connects to label "目录与页内导航". Search top connects to "本地搜索". Content has code panel with visible "Linux" "macOS" tabs and generic code lines connects to "代码块与标签页". Below numbered steps labeled "1" "2" "3" connects to "步骤与提示". Small diagram with three connected nodes connects to "图表与公式". Bottom print sheet icon outside browser connects to "整章或整本打印". Main mock page heading "安装指南". No claims all enabled by default. Different example areas, not six identical empty cards. + +## 07-publishing + +Generate an informative Chinese technical hand-drawn editorial infographic, landscape 16:9, fully opaque warm ivory rectangular paper background, no transparency or cutout edges. Fine ink outlines, lavender and muted amber highlights, crisp large readable Chinese type, generous spacing. No decorative scenery or objects. No HugeGraph branding, no OINK release numbers, no version-upgrade comparisons. Generic explanatory illustration not a screenshot. Only the specified short labels, no invented prose. Title "同一套内容,多种阅读方式". Central stack "Markdown 内容". Three arrows lead to three richly informative panels. Left panel "面向读者" containing documentation browser and labels "网页 · 搜索 · 导航". Middle panel "面向发布" containing a printed chapter and RSS symbol labeled "打印 · RSS". Right panel "面向工具" containing text document icons labeled "Markdown · llms.txt". Bottom distinct horizontal two controls "语言" with "中文 / English" and "产品版本" with "当前版 / 历史版". Footer two notes "输出按需启用" and "翻译与历史版本仍需维护". Do not show AI generating translations or automatically making history. No arrows between language and version. + +## 08-optional-ai + +Generate an informative Chinese technical hand-drawn editorial infographic, landscape 16:9, fully opaque warm ivory rectangular paper background, no transparency or cutout edges. Fine ink outlines, lavender and muted amber highlights, crisp large readable Chinese type, generous spacing. No decorative scenery or objects. No HugeGraph branding, no OINK release numbers, no version-upgrade comparisons. Generic explanatory illustration not a screenshot. Only the specified short labels, no invented prose. Title "需要时,再接入 Ask AI". Clear flow starts "读者提问". Top solid arrow to "本地搜索" then "打开原文". Separate bottom dashed branch labeled "可选扩展" to "用户同意" then across dotted boundary "外部服务" to "Kapa" then "回答与来源". A separate arrow from 用户同意 labeled "取消" returns to 本地搜索, never reaches Kapa. Footer three informational cards "准备知识来源" "核验语言与版本" "检查隐私与访问策略". Bottom note "外部问答需要站点另行接入". No status badges, no completion checkmarks, no claim Kapa ships enabled with OINK. Keep flow comprehensible and enough whitespace. + +## 05-overview 修订 + +Edit only the left input document illustrations. Change config.toml to hugo.yaml and remove pseudo-code, replacing it with three plain gray lines. Change README.md to guide.md. Preserve everything else. + diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/prompts.md b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/prompts.md new file mode 100644 index 000000000..af454fc74 --- /dev/null +++ b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/prompts.md @@ -0,0 +1,16 @@ +# 配图风格候选 + +生成方式为内置 image_gen,当前三张仅用于选择风格,尚未插入正文。 + +## A + +Create one polished landscape 16:9 editorial illustration as a style proposal for a Chinese developer article about HugeGraph documentation using Hugo + OINK 1.1, optional Kapa. Depict Markdown source sheets transforming into a documentation browser with sidebar, search, bilingual CN/EN tabs, version tabs latest and 1.7. Show optional external AI as a small separate disconnected dotted-line module marked "Optional AI", not active or live. This is a conceptual illustration, not an actual screenshot. Only these short labels allowed: "Markdown", "Hugo", "OINK 1.1", "CN / EN", "latest", "1.7", "Optional AI". No invented logos, no robots, no people, no marketing claims, no dense text. Strong visual hierarchy, generous whitespace, readable restrained typography. Use case: illustration-story. Style: sophisticated editorial print illustration, warm ivory paper, flat cut-paper geometry, restrained HugeGraph-inspired plum purple and charcoal accents, subtle grain, crisp shapes, mature technical magazine art. Source sheets left, finished browser right, modular transformation center. + +## B + +Create one polished landscape 16:9 editorial illustration as a style proposal for a Chinese developer article about HugeGraph documentation using Hugo + OINK 1.1, optional Kapa. Depict Markdown source sheets transforming into a documentation browser with sidebar, search, bilingual CN/EN tabs, version tabs latest and 1.7. Show optional external AI as a small separate disconnected dotted-line module marked "Optional AI", not active or live. This is a conceptual illustration, not an actual screenshot. Only these short labels allowed: "Markdown", "Hugo", "OINK 1.1", "CN / EN", "latest", "1.7", "Optional AI". No invented logos, no robots, no people, no marketing claims, no dense text. Strong visual hierarchy, generous whitespace, readable restrained typography. Use case: stylized-concept. Style: elegant isometric 3D miniature, matte white and purple physical document cards and browser panels, soft studio shadows on light neutral background, precise beveled edges, understated technical product illustration. Arrange a spatial workflow of modular parts, not a toy city. + +## C + +Create one polished landscape 16:9 editorial illustration as a style proposal for a Chinese developer article about HugeGraph documentation using Hugo + OINK 1.1, optional Kapa. Depict Markdown source sheets transforming into a documentation browser with sidebar, search, bilingual CN/EN tabs, version tabs latest and 1.7. Show optional external AI as a small separate disconnected dotted-line module marked "Optional AI", not active or live. This is a conceptual illustration, not an actual screenshot. Only these short labels allowed: "Markdown", "Hugo", "OINK 1.1", "CN / EN", "latest", "1.7", "Optional AI". No invented logos, no robots, no people, no marketing claims, no dense text. Strong visual hierarchy, generous whitespace, readable restrained typography. Use case: illustration-story. Style: careful technical notebook illustration, hand-drawn ink outlines, warm white paper, lavender and muted amber marker highlights, small hand-drawn connectors, sophisticated explanatory sketch, clean and deliberate rather than childish. Workflow with tangible document sheets and browser window. + diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-a.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-a.png new file mode 100644 index 000000000..fdab7af3f Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-a.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-b.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-b.png new file mode 100644 index 000000000..1e0d1f012 Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-b.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-c.png b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-c.png new file mode 100644 index 000000000..e21ee291c Binary files /dev/null and b/.goal-task/oink-1.1-guide/oink-1.1-illustrations/style-c.png differ diff --git a/.goal-task/oink-1.1-guide/oink-1.1-website-guide.md b/.goal-task/oink-1.1-guide/oink-1.1-website-guide.md new file mode 100644 index 000000000..83d135da6 --- /dev/null +++ b/.goal-task/oink-1.1-guide/oink-1.1-website-guide.md @@ -0,0 +1,86 @@ +# 会写 Markdown,就能开始的文档网站 + +一个开发项目的文档,往往从 README 开始。安装说明、配置参数和使用示例逐渐多起来,就需要目录、搜索和独立页面;有了不同语言的读者,还要安排翻译。Hugo + OINK 可以把这些 Markdown 组织成一套完整的网站,让开发者沿用熟悉的文件与 Git 工作方式,不用先搭一套前端应用。 + +我对照了 OINK 的官方文档和入门模板。这套组合值得关注的地方,是把技术内容常用的阅读功能准备得比较齐全,同时让构建与部署保持简单。下面的图片均为功能示意,界面与示例命令不代表实际产品页面。 + +![从 Markdown 编写、Git 评审,到 Hugo 与 OINK 生成和发布静态网站](oink-1.1-illustrations/05-overview.png) + +Hugo 是静态网站生成器,负责读取内容并生成网页。OINK 是配合它使用的主题,提供文档布局和交互组件。对作者来说,可以把两者当成一套文档发布工具使用。你维护正文和配置,构建得到 HTML、样式、脚本等文件,再将它们放到静态网站托管服务上。普通文档访问无需运行内容管理后台或数据库。 + +这让文档能直接进入代码评审流程。一段说明改了什么,Git 中看得见;发布前可以在本地预览,出错后也能回退源文件。网站内容留在项目自己的目录里,团队可以选择托管平台。OINK 的普通站点构建不要求安装 Node.js、npm 或 PostCSS,字体、图标和相关交互资源随主题提供。首次使用仍需准备 Hugo、主题及必要依赖,另行接入的外部服务也有自己的网络要求。[Hugo 官方介绍](https://gohugo.io/about/introduction/)与 [OINK 项目说明](https://github.com/pgsty/oink)解释了这套构建方式。 + +文档好不好用,还要看读者进来以后能不能找到内容。 + +OINK 提供侧栏目录、页内大纲和面包屑,长文可以按章节定位,读完一页也有前后页入口。桌面和手机共用同一套内容,界面会适应屏幕。对内容较多的项目,这些导航能让安装指南、概念解释和参数参考各有位置,读者不用在一个很长的 README 里反复滚动。 + +![文档页面中的目录、本地搜索、代码标签页、步骤、图表与打印功能](oink-1.1-illustrations/06-features.png) + +搜索可以留在浏览器里完成。启用 OINK 的本地搜索后,Hugo 在构建时为不同语言生成索引,浏览器下载索引,再查询相关页面,无需单独部署搜索服务器。站点可以选择索引标题、摘要或完整正文。小型文档用全文索引容易起步,内容增长以后则要权衡索引大小和首次加载时间。中文搜索也值得用实际问题试一遍,给文档补上常用术语和别名,比只检查搜索框能否打开更有用。具体选项见[搜索说明](https://oink.pgsty.com/docs/customize/search/)。 + +写技术内容时,组件能省掉不少排版工作。一份安装指南可以把 Linux 和 macOS 的命令放进标签页,用步骤组件标出顺序,再用提示块说明前提条件。讲目录结构时有文件树,讲系统关系时可以放 Mermaid 图,数学内容也有相应支持。这些内容仍围绕 Markdown 编写,作者按需学习组件语法,不必为每个页面写一套界面代码。[组件文档](https://oink.pgsty.com/docs/components/)提供了具体写法。 + +内容也可以有不同的组织形式。教程适合按章节连续阅读,API 参考需要方便查字段,项目动态则适合按时间发布。OINK 提供文档、博客和书籍等页面类型,也支持 OpenAPI 文档与下载页面。一个项目因此可以把使用手册和发布信息放在同一个站点里,继续共用导航和视觉样式。 + +![同一套 Markdown 按需生成网页、打印、RSS 和供工具读取的文本输出](oink-1.1-illustrations/07-publishing.png) + +打印是一个容易被忽略的实用功能。读者可以打印当前页;站点配置整节或整本打印后,还能把分散的章节汇成连续文档,再通过浏览器保存为 PDF。培训材料、长篇教程或需要留存的操作手册,都能用到它。交互内容打印时会调整呈现方式,复杂图表仍应检查打印结果,不能只看网页正常就认为纸面也合适。[打印说明](https://oink.pgsty.com/docs/customize/print/)列出了配置与组件行为。 + +按需启用 Markdown 输出和 `llms.txt`,还能给工具提供更直接的文本入口。网页继续服务读者,其他程序可以读取较少界面干扰的内容。它有利于复用文档,但不会自动保证某个 AI 助手收录网站或回答正确。RSS 则给关注项目更新的人提供订阅入口。这些输出都应按用途选择,团队维护好一份正文,就能供不同阅读方式使用。 + +双语与多版本解决的是另外两个问题。语言切换方便不同读者访问对应译文,正文翻译仍需有人维护。产品版本切换让使用旧版本的人找到当时的说明,主题提供切换入口和归档提示,各版本的内容保存、构建与发布由站点安排。文档结构变化较大时,还要检查切换后落到哪里,避免菜单能点开却到处是失效链接。[版本说明](https://oink.pgsty.com/docs/customize/versions/)把这部分分工讲得很清楚。 + +HugeGraph 是其中一个实例。它用中英文内容服务不同读者,并把安装、客户端、配置等文档组织到同一站点;历史发布分支和版本清单支撑了旧版文档的构建。这样的项目能说明这套方案如何承载多组件、多版本资料。自己的项目只有一种语言、一个版本时,完全可以从更小的结构开始,无需照搬它的目录和脚本。 + +如果希望再加一个自然语言问答入口,可以考虑 Kapa 一类外部服务。它适合帮助读者从多篇资料中寻找答案,也需要团队准备知识来源、核验回答和处理版本差异。Hugo + OINK 的基本文档与搜索可以独立运行,Ask AI 由站点另外接入。 + +![本地搜索直接打开原文,可选问答在用户同意后连接外部 Kapa 服务](oink-1.1-illustrations/08-optional-ai.png) + +接入时要让读者清楚何时会连接第三方服务,并按适用要求处理同意、隐私和访问策略。语言界面与语料范围也要分别核验,中文窗口不保证只查询中文资料。Kapa 的费用、网络可达性和索引维护都属于额外成本。以 Apache 项目为例,ASF 的[隐私 FAQ](https://privacy.apache.org/faq/committers.html#can-i-use-kapaai-on-our-website-answer-machine)要求 Kapa 在用户同意后加载。普通文档站可以先把内容与搜索做好,再决定是否需要这项扩展。 + +把它放到其他选择旁边看,选型会更清楚。开发者维护的公开手册,通常重视 Git 评审、发布版本和界面定制;团队日常知识库还要照顾非开发人员的编辑习惯,以及成员权限和内容负责人。两种需求可以由不同工具承担,也可以组合使用。 + +下面按这些差异比较。表中的适用判断基于工作方式,不是性能排名,也不意味着某项能力只有一个产品具备。 + +| 方案 | 编辑与发布方式 | 更值得考虑的情况 | 需要承担或核对的成本 | +| --- | --- | --- | --- | +| **Hugo + OINK** | Markdown 与 Git,生成静态站点,自选托管 | 希望使用现成技术写作组件,同时简化构建依赖;还需要博客、书籍或打印输出 | 配置、部署和主题升级由团队维护;在线协作编辑与细粒度权限需另行安排 | +| **Hugo + Docsy** | Markdown 与 Hugo,可通过 Hugo Module 引入主题 | 已有 Docsy 站点及定制,或偏好它的文档结构和短代码组件 | 按当前官方流程准备 npm 资源和 Dart Sass;迁移主题时检查模板与内容语法 | +| **Docusaurus** | Markdown/MDX 与 React,走 Node.js 构建流程 | 团队熟悉 React,需要在文档里嵌入自定义交互,并使用文档版本管理 | 维护前端依赖与组件;版本快照增多也会增加内容和构建负担 | +| **VitePress** | Markdown 中使用 Vue 组件,构建为可部署的静态站点 | 团队熟悉 Vue,希望文档直接复用 Vue 交互组件 | 接受 Vite/Vue 工具链,按项目需要补齐发布与内容管理流程 | +| **MkDocs + Material** | Markdown、YAML 与 Python 工具链,可自选托管 | 已有 MkDocs 内容和插件,团队熟悉其写作流程 | Material 已进入维护模式;新项目还应评估 Zensical,并检查所需插件的兼容性 | +| **GitBook** | 在线可视化编辑,可结合 Git Sync 发布文档 | 开发者与技术写作者一起维护对外文档,希望少管构建和托管 | 核对套餐、定制范围以及 Git 同步和内容导出的限制 | +| **BookStack** | 自托管 Wiki,支持可视化与 Markdown 编辑,按书、章、页组织 | 希望自己托管内部文档,并使用内置角色权限和身份认证 | 运维应用与数据库,安排备份、安全更新及账号管理 | + +Docsy 值得单独比较,因为它与 OINK 都使用 Hugo,OINK 也起源于 Docsy,后来独立演进。两者都能组织技术文档,Docsy 已有多语言、版本入口和打印支持,也提供本地 Lunr 搜索。选 OINK 的理由需要落到具体的构建与写作体验上,不能把这些共同能力都算成 OINK 的独有优势。 + +| 比较点 | Hugo + Docsy | Hugo + OINK | +| --- | --- | --- | +| 构建依赖 | 当前官方流程通过 npm 获取 Bootstrap、Font Awesome 等资源,使用 Dart Sass;PostCSS 为可选项 | 普通站点构建无需 npm 或 PostCSS,相关资源随主题提供 | +| 内容组件 | 通过 Hugo 短代码编写提示块、标签页、卡片和 API 展示等内容 | 提供围绕 Markdown 的步骤、字段、文件树等组件,并组织文档、书籍等页面类型 | +| 搜索入口 | 可选本地 Lunr、Algolia 等搜索方案 | 将本地搜索与命令面板结合,可配置索引范围与页面关键词 | +| 采用与迁移 | 已有模板覆盖和短代码使用稳定时,继续维护可避免迁移成本 | 看重其组件和构建方式时可试用,但必须核对配置、短代码及本地模板的差异 | + +以上按当前[安装依赖](https://www.docsy.dev/docs/get-started/docsy-as-module/installation-prerequisites/)、[Docsy 组件](https://www.docsy.dev/docs/content/shortcodes/)和[搜索文档](https://www.docsy.dev/docs/content/search/)核对。OINK 的[项目说明](https://github.com/pgsty/oink)也明确要求迁移时检查兼容性。已有 Docsy 网站可以先选一篇包含代码标签页、图表和打印内容的文档,在两套主题下比较作者要改多少、读者使用起来是否更方便,再决定是否迁移。 + +若团队已经会用 React,文档里又需要可操作的演示,Docusaurus 的 MDX 能直接嵌入 React 组件,文档插件也有版本快照流程。Vue 团队可以优先试 VitePress,它允许在 Markdown 中使用 Vue 组件。Hugo + OINK 的吸引力在于现成的内容组件和较少的构建依赖;已有前端组件需要复用时,沿用团队熟悉的框架往往更省事。相关能力可分别查阅 [Docusaurus 的 MDX](https://docusaurus.io/docs/markdown-features/react)、[版本管理](https://docusaurus.io/docs/versioning)和 [VitePress 介绍](https://vitepress.dev/guide/what-is-vitepress)。 + +本地搜索、Markdown 和静态部署也并非 OINK 独有。Material for MkDocs 同样提供浏览器端搜索,已有站点运行良好时,没有必要只为这些功能迁移。截至 2026 年 9 月核对,维护者已宣布将开发重点转向 Zensical。准备新建站点的团队,应把项目维护状态和插件适配纳入评估,而不能只看主题截图。可对照其[搜索实现](https://github.com/squidfunk/mkdocs-material/blob/master/docs/plugins/search.md)、[维护说明](https://squidfunk.github.io/mkdocs-material/blog/2025/11/11/insiders-now-free-for-everyone/)与 [Zensical 迁移文档](https://zensical.org/docs/compatibility/mkdocs/migration/)。 + +GitBook 提供了另一种取舍。作者可以在网页编辑器里改内容,开发者也可以使用 Git Sync,团队减少了自己维护发布工具的工作。选型时可以拿一份真实文档试编辑、评审与导出,核对套餐和同步限制,再判断是否适合长期使用。参见 [GitBook 编辑流程](https://gitbook.com/docs/getting-started/quickstart)。 + +需要自托管知识库时,也不必从静态站点开始拼装账号系统。[BookStack](https://www.bookstackapp.com/)已有角色权限及身份认证,提供书、章、页的内容结构,不过它需要运行应用和数据库。Hugo + OINK 的静态部署较简单,面向个人或部门的细粒度授权则要另行设计。决定采用哪种方式,要看团队更愿意维护哪部分工作。 + +公开产品文档和内部知识库还可以并存。安装指南与 API 说明跟代码走 Git 评审,会议记录和未定稿方案留在协作文档平台。需要明确哪一处是正式来源,避免同一份操作手册在两个地方各改一遍。已有 Hugo 网站迁移主题时,也应先检查原有模板、组件语法和链接,别只比较新站首页。 + +想判断这些取舍是否适合自己,最快的办法是拿一篇现有文档试写。官方的 OINK Starter 已准备好示例内容和部署工作流,比直接从复杂项目里删文件更容易看清哪些配置是必要的。当前模板要求 Git、Go 1.27+ 和 Hugo Extended 0.165.0+,首次启动会下载固定版本的主题模块。安装环境以[模板说明](https://github.com/pgsty/oink-starter)为准。 + +```sh +git clone https://github.com/pgsty/oink-starter.git +cd oink-starter +hugo server +``` + +打开 `http://localhost:1313/`,把一篇示例替换成自己的安装指南,查看目录和搜索,再用手机宽度读一遍。模板中的项目名称、首页内容和站点地址也需要换成自己的。确认阅读效果以后,再按模板提供的流程发布到 GitHub Pages 或 Cloudflare Pages。先让这篇指南从修改到发布完整走通,就能判断后续维护是否顺手。 + +继续阅读可从 [OINK 官方文档](https://oink.pgsty.com/)进入;需要参考较完整的工程项目组织方式时,再看 [HugeGraph 文档源码](https://github.com/apache/hugegraph-doc)。 diff --git a/AGENTS.md b/AGENTS.md index c4a054515..6e8981708 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,110 +1,38 @@ -# AGENTS.md - -This file provides guidance to AI coding assistants (Claude Code, Cursor, GitHub Copilot, etc.) when working with code in this repository. - -## Project Overview - -Apache HugeGraph documentation website built with Hugo static site generator and the Docsy theme. The site is bilingual (Chinese/English) and covers the complete HugeGraph graph database ecosystem. - -## Development Commands - -```bash -# Install dependencies -npm install - -# Start development server (auto-reload enabled) -hugo server - -# Build production site (output to ./public) -hugo --minify - -# Clean build -rm -rf public/ - -# Production build with garbage collection -HUGO_ENV="production" hugo --gc - -# Custom server configuration -hugo server -b http://127.0.0.1 -p 80 --bind=0.0.0.0 -``` - -## Prerequisites - -- **Hugo Extended** v0.95.0 recommended (v0.102.3 in CI) - must be the "extended" version for SASS/SCSS support -- **Node.js** v16+ and npm -- Download Hugo from: https://github.com/gohugoio/hugo/releases - -## Architecture - -``` -content/ -├── cn/ # Chinese documentation (default language) -│ ├── docs/ # Main documentation -│ ├── blog/ # Blog posts -│ ├── community/ -│ └── about/ -└── en/ # English documentation (parallel structure) - -themes/docsy/ # Docsy theme (submodule) -layouts/ # Custom template overrides -assets/ # Processed assets (SCSS, images) -static/ # Static files served directly -config.toml # Main site configuration -``` - -### Content Structure - -Documentation sections in `content/{cn,en}/docs/`: -- `quickstart/` - Getting started guides for HugeGraph components -- `config/` - Configuration documentation -- `clients/` - Client API documentation (Gremlin, RESTful) -- `guides/` - User guides and tutorials -- `performance/` - Benchmarks and optimization -- `language/` - Query language docs -- `contribution-guidelines/` - Contributing guides -- `changelog/` - Release notes -- `download/` - Download instructions - -## Key Configuration Files - -- `config.toml` - Site-wide settings, language config, menu structure, version (currently 0.13) -- `package.json` - Node dependencies for CSS processing (postcss, autoprefixer, mermaid) -- `.editorconfig` - UTF-8, LF line endings, spaces for indentation - -## Working with Content - -When editing documentation: -1. Maintain parallel structure between `content/cn/` and `content/en/` -2. Use Markdown with Hugo front matter (title, weight, description) -3. For bilingual changes, update both Chinese and English versions -4. Include mermaid diagrams where appropriate (mermaid.js is available) - -## Deployment - -- **CI/CD**: GitHub Actions (`.github/workflows/hugo.yml`) -- **Trigger**: Push to `master` branch or pull requests -- **Build**: `npm i && hugo --minify` with Node v16 and Hugo v0.102.3 extended -- **Deploy**: Publishes to `asf-site` branch (GitHub Pages) -- **PR Requirements**: Include screenshots showing before/after changes - -## HugeGraph Ecosystem Context - -This documentation covers: -- **HugeGraph-Server** - Core graph database with REST API -- **HugeGraph-Store** - Distributed storage engine -- **HugeGraph-PD** - Placement Driver for metadata -- **Toolchain** - Client, Loader, Hubble (web UI), Tools -- **HugeGraph-Computer** - Distributed OLAP graph processing -- **HugeGraph-AI** - GNN, LLM/RAG components - -## Troubleshooting - -**"TOCSS: failed to transform scss/main.scss"** -- Install Hugo Extended (not standard Hugo) - -**Theme/module not found** -- Run: `git submodule update --init --recursive` - -**CI build fails but works locally** -- Match Hugo version (v0.102.3) and Node.js (v16) -- Verify npm dependencies are installed +# HugeGraph documentation + +Bilingual Hugo site using OINK as a pinned Go module. English routes live under +`/docs/`, Chinese routes under `/cn/docs/`; historical releases share the current +site shell. + +## Task entry points + +- Preview or build: `scripts/hugo.sh server` / `scripts/hugo.sh build`. +- Content and contribution checks: [contribution.md](contribution.md). +- OINK upgrades, customization boundaries and recovery: + [scripts/oink-upgrade.md](scripts/oink-upgrade.md). +- Version assembly and publishing: `scripts/versioning.py` and + `.github/workflows/hugo.yml`; release selection comes from `versions.json`. +- Browser regression: `tests/e2e/package.json` and its Playwright configuration. + Node dependencies are for tests, not the Hugo site build. + +Read the entry relevant to the task; small content edits do not require the full +upgrade or deployment workflow. Use `go.mod` / `go.sum` and CI for pinned versions. + +## Project constraints + +- Keep English and Chinese documentation aligned when a change applies to both. +- Preserve public routes, historical-version navigation and language switching. +- Keep HugeGraph branding and behavior in site configuration, data, hooks and + public OINK APIs. Do not edit the module cache or vendor a theme fork. +- Record necessary upstream template overrides in the upgrade inventory; when + upstream changes them, reconcile the customization with the new implementation. +- AI resources load only after explicit user consent; disabled AI must make no + third-party AI requests. +- Validate behavior affected by the change. Theme/runtime changes require strict + builds and browser checks; visual/navigation changes also need before/after + screenshots. A rendered site alone does not prove interaction compatibility. +- Independent work may run in parallel. Review the final combined diff independently + for changes affecting runtime behavior or multiple components; local content + edits can use self-review. +- Local builds and disposable tests may run without repeated confirmation. Remote + writes and publishing follow the user's explicit task scope. diff --git a/NOTICE b/NOTICE index 91cb6e33a..c7bce531b 100644 --- a/NOTICE +++ b/NOTICE @@ -6,5 +6,5 @@ The Apache Software Foundation (http://www.apache.org/). The initial codebase was donated to the ASF by HugeGraph Authors, copyright 2017-2021. -This product includes OINK v1.0.0 (https://github.com/pgsty/oink), +This product includes OINK (https://github.com/pgsty/oink), Copyright 2026 PGSTY contributors, licensed under the Apache License 2.0. diff --git a/README.md b/README.md index 6b2b71db2..1e618d088 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ scripts/hugo.sh server Open http://localhost:1313 to preview. -The module graph must resolve `github.com/pgsty/oink@v1.0.0`. For a production-equivalent check, run the strict build command shown below. +The module graph must resolve the OINK version pinned in `go.mod`; verify it with `python3 scripts/oink_module.py`. For a production-equivalent check, run the strict build command shown below. ## Repository Structure @@ -51,7 +51,7 @@ hugegraph-doc/ │ └── en/ # 🇺🇸 English documentation (mirrors cn/ structure) │ ├── data/ # 🧭 Landing-page and footer data -├── i18n/zh-CN.yaml # 🌐 OINK interface strings for the /cn/ locale +├── i18n/zh-CN.yaml # 🌐 HugeGraph labels for the /cn/ locale ├── assets/ # 🖼️ Project brand assets ├── layouts/ # 📐 Hugo template overrides ├── static/ # 📁 Static files @@ -79,6 +79,7 @@ hugegraph-doc/ ### Detailed Guide See [contribution.md](./contribution.md) for the pinned toolchain, strict build, OINK customization, and translation rules. +For theme updates, compatibility review and rollback, use the [OINK upgrade SOP](./scripts/oink-upgrade.md). ## Commands @@ -87,6 +88,7 @@ See [contribution.md](./contribution.md) for the pinned toolchain, strict build, | `scripts/hugo.sh server` | Start the manifest-aware dev server (hot reload) | | `scripts/hugo.sh build` | Strict, production-equivalent build to `./public/` | | `scripts/hugo.sh server -p 8080` | Start the dev server on a custom port | +| `scripts/update-oink.sh v1.1.0` | Update the theme and run compatibility checks (see the SOP) | --- @@ -116,7 +118,7 @@ scripts/hugo.sh server 打开 http://localhost:1313 预览网站。 -模块图必须解析为 `github.com/pgsty/oink@v1.0.0`。需要执行与生产一致的检查时,请运行下方的严格构建命令。 +模块图必须解析为 `go.mod` 固定的 OINK 版本,可运行 `python3 scripts/oink_module.py` 校验。需要执行与生产一致的检查时,请运行下方的严格构建命令。 ### 仓库结构 @@ -135,7 +137,7 @@ hugegraph-doc/ │ └── en/ # 🇺🇸 英文文档(与 cn/ 结构一致) │ ├── data/ # 🧭 首页与页尾数据 -├── i18n/zh-CN.yaml # 🌐 /cn/ 语言的 OINK 界面文案 +├── i18n/zh-CN.yaml # 🌐 /cn/ 语言的 HugeGraph 专属文案 ├── assets/ # 🖼️ 项目品牌资源 ├── layouts/ # 📐 Hugo 模板覆盖 ├── static/ # 📁 静态文件 @@ -163,6 +165,7 @@ hugegraph-doc/ #### 详细指南 查看 [contribution.md](./contribution.md) 了解固定工具链、严格构建、OINK 定制和翻译要求。 +主题升级、兼容适配和回退请按 [OINK 升级 SOP](./scripts/oink-upgrade.md) 操作。 ### 常用命令 @@ -171,6 +174,7 @@ hugegraph-doc/ | `scripts/hugo.sh server` | 启动读取版本清单的开发服务器(支持热重载) | | `scripts/hugo.sh build` | 严格构建与生产等价的站点到 `./public/` | | `scripts/hugo.sh server -p 8080` | 在指定端口启动开发服务器 | +| `scripts/update-oink.sh v1.1.0` | 更新主题并执行兼容检查(详见升级 SOP) | --- diff --git a/assets/js/hugegraph-shell.js b/assets/js/hugegraph-shell.js index 09240eb54..f01ba349b 100644 --- a/assets/js/hugegraph-shell.js +++ b/assets/js/hugegraph-shell.js @@ -2,8 +2,7 @@ * HugeGraph additions around OINK's shell. * * This file deliberately does not replace OINK's command palette. It only - * persists authored tree disclosures, makes a collapsed/dismissed sidebar - * inert, and adds an explicit retry control to the existing search error. + * persists authored tree disclosures through OINK's public API and adds an explicit retry control to the existing search error. */ (function (global) { 'use strict'; @@ -32,245 +31,59 @@ } } - function setTreeExpanded(button, expanded, documentObject) { - var target = documentObject.getElementById( - button.getAttribute('aria-controls'), - ); - if (!target) return; - button.setAttribute('aria-expanded', expanded ? 'true' : 'false'); - target.classList.toggle('td-is-open', expanded); - var label = expanded - ? button.dataset.tdLabelCollapse - : button.dataset.tdLabelExpand; - if (label) button.setAttribute('aria-label', label); - } - function initTreePersistence(windowObject, documentObject, config) { - var buttons = Array.prototype.slice.call( - documentObject.querySelectorAll('[data-td-shell-tree-toggle][aria-controls]'), - ); - if (!buttons.length) return; - var storage = safeStorage(windowObject); - var key = - 'oink.sidebar.v2.' + - String(config.version || 'latest') + - '.' + - String(config.locale || 'en'); - var valid = new Set( - buttons.map(function (button) { + var sidebar = windowObject.OinkSidebar; + if (!sidebar) return; + return sidebar.ready.then(function () { + var buttons = Array.prototype.slice.call(documentObject.querySelectorAll( + '#td-shell-sidebar [data-td-shell-tree-toggle][aria-controls]', + )); + if (!buttons.length) return; + var storage = safeStorage(windowObject); + var key = 'oink.sidebar.v2.' + String(config.version || 'latest') + + '.' + String(config.locale || 'en'); + var valid = new Set(buttons.map(function (button) { return button.getAttribute('aria-controls'); - }), - ); - var saved = []; - var hasSavedState = false; - if (storage) { - try { - var stored = storage.getItem(key); - var parsed = JSON.parse(stored || '[]'); - if (Array.isArray(parsed)) { - hasSavedState = stored !== null; - saved = parsed.filter(function (id) { - return typeof id === 'string' && valid.has(id); - }); - } - } catch (_) { - saved = []; - } - } - var remembered = new Set(saved); - var docsRoot = /(?:^|\/)(?:cn\/)?docs\/?$/.test(windowObject.location.pathname); - - buttons.forEach(function (button) { - var item = button.closest('li'); - var activePath = item && item.classList.contains('td-active-path'); - var control = button.getAttribute('aria-controls') || ''; - var defaultOpen = - !hasSavedState && - docsRoot && - /_nav(?:start|components)-children$/.test(control); - setTreeExpanded( - button, - Boolean(activePath || remembered.has(control) || defaultOpen), - documentObject, - ); - button.addEventListener('click', function () { - global.setTimeout(function () { - if (!storage) return; - var expanded = buttons - .filter(function (candidate) { - var candidateItem = candidate.closest('li'); - return ( - candidate.getAttribute('aria-expanded') === 'true' && - !(candidateItem && - candidateItem.classList.contains('td-active-path')) - ); - }) - .map(function (candidate) { - return candidate.getAttribute('aria-controls'); - }); - try { - storage.setItem(key, JSON.stringify(expanded)); - } catch (_) { - /* Active-path expansion remains the storage-free fallback. */ + })); + var remembered = new Set(); + var hasSavedState = false; + if (storage) { + try { + var stored = storage.getItem(key); + var parsed = JSON.parse(stored || '[]'); + if (Array.isArray(parsed)) { + hasSavedState = stored !== null; + remembered = new Set(parsed.filter(function (id) { + return typeof id === 'string' && valid.has(id); + })); } - }, 0); - }); - }); - - // Seed the new persistence schema once so the docs-home defaults survive - // reloads; later clicks replace this set with the user's choices. - if (storage && !hasSavedState) { - try { - var initial = buttons - .filter(function (button) { - var item = button.closest('li'); - return ( - button.getAttribute('aria-expanded') === 'true' && - !(item && item.classList.contains('td-active-path')) - ); - }) - .map(function (button) { - return button.getAttribute('aria-controls'); - }); - storage.setItem(key, JSON.stringify(initial)); - } catch (_) { - /* Ignore storage becoming unavailable after the probe. */ + } catch (_) { /* Keep active-path and docs-home defaults. */ } } - } - } - - function initSidebarIsolation(windowObject, documentObject) { - var html = documentObject.documentElement; - var sidebar = documentObject.getElementById('td-shell-sidebar'); - if (!sidebar) return; - var restore = documentObject.querySelector('.hg-sidebar-restore'); - var desktop = windowObject.matchMedia('(min-width: 768px)'); - - var panel = sidebar.querySelector('.td-shell-sidebar__panel'); - // The native 16px panel edge cannot receive pointers while the sidebar is - // inert. Keep an equivalent pointer-only strip outside the inert subtree; - // the labelled navbar button remains the keyboard/touch equivalent. - var edge = documentObject.createElement('div'); - edge.className = 'hg-sidebar-edge d-print-none'; - edge.setAttribute('aria-hidden', 'true'); - documentObject.body.appendChild(edge); - var closeTimer; - var pointerLockUntil = 0; - function dynamic() { - return desktop.matches && - html.getAttribute('data-td-shell-sidebar') === 'collapsed'; - } - function preview() { - if (!dynamic()) return; - windowObject.clearTimeout(closeTimer); - sidebar.classList.add('td-shell-sidebar--overlay'); - sync(); - } - function closePreview() { - windowObject.clearTimeout(closeTimer); - closeTimer = windowObject.setTimeout(function () { - if (!sidebar.contains(documentObject.activeElement)) { - sidebar.classList.remove('td-shell-sidebar--overlay'); - sync(); - } - }, 350); - } - edge.addEventListener('pointerenter', function (event) { - if (event.pointerType !== 'touch' && Date.now() >= pointerLockUntil) preview(); - }); - edge.addEventListener('pointerleave', closePreview); - if (restore) { - restore.addEventListener('pointerenter', function (event) { - if (event.pointerType !== 'touch' && Date.now() >= pointerLockUntil) preview(); - }); - restore.addEventListener('pointerleave', closePreview); - restore.addEventListener('keydown', function (event) { - if (event.key !== 'ArrowRight' || !dynamic()) return; - event.preventDefault(); - preview(); - var first = sidebar.querySelector('a[href], button'); - if (first) first.focus(); - }); - } - if (panel) { - panel.addEventListener('pointerenter', function () { - windowObject.clearTimeout(closeTimer); + var docsRoot = /(?:^|\/)(?:cn\/)?docs\/?$/.test(windowObject.location.pathname); + buttons.forEach(function (button) { + var id = button.getAttribute('aria-controls'); + var defaultOpen = !hasSavedState && docsRoot && + /_nav(?:start|components)-children$/.test(id); + // OINK preserves the active path and owns DOM, inert and ARIA state. + sidebar.setExpanded(id, remembered.has(id) || defaultOpen, { source: 'api' }); }); - panel.addEventListener('pointerleave', closePreview); - panel.addEventListener('focusout', closePreview); - panel.addEventListener('keydown', function (event) { - if (event.key !== 'Escape' || !dynamic()) return; - event.preventDefault(); - if (restore) restore.focus(); - sidebar.classList.remove('td-shell-sidebar--overlay'); - sync(); - }); - } - function sync() { - var collapsed = - html.getAttribute('data-td-shell-sidebar') === 'collapsed'; - var drawerOpen = - html.getAttribute('data-td-shell-drawer') === 'open'; - // OINK owns the persistent collapsed mode and pointer overlay. Keep - // focus inside an open preview safe when its native pointerleave fires. - if (desktop.matches && collapsed && - !sidebar.classList.contains('td-shell-sidebar--overlay') && - sidebar.contains(documentObject.activeElement)) { - sidebar.classList.add('td-shell-sidebar--overlay'); - } - var overlay = sidebar.classList.contains('td-shell-sidebar--overlay'); - var isolated = desktop.matches ? collapsed && !overlay : !drawerOpen; - edge.hidden = !desktop.matches || !collapsed; - if (restore) restore.setAttribute('aria-expanded', String(!isolated)); - if (restore) restore.hidden = !desktop.matches || !collapsed; - sidebar.inert = isolated; - if (isolated) sidebar.setAttribute('aria-hidden', 'true'); - else sidebar.removeAttribute('aria-hidden'); - if ( - isolated && - sidebar.contains(documentObject.activeElement) && - restore && - restore.offsetParent !== null - ) { - restore.focus(); + function persist() { + if (!storage) return; + var expanded = buttons.filter(function (button) { + var item = button.closest('li'); + var state = sidebar.getState(button.getAttribute('aria-controls')); + return state && state.expanded && + !(item && item.classList.contains('td-active-path')); + }).map(function (button) { return button.getAttribute('aria-controls'); }); + try { storage.setItem(key, JSON.stringify(expanded)); } + catch (_) { /* Storage can become unavailable after initialization. */ } } - } - - new MutationObserver(sync).observe(html, { - attributes: true, - attributeFilter: ['data-td-shell-sidebar', 'data-td-shell-drawer'], - }); - new MutationObserver(sync).observe(sidebar, { attributes: true, attributeFilter: ['class'] }); - desktop.addEventListener('change', sync); - documentObject - .querySelectorAll('[data-td-shell-sidebar-toggle], [data-td-shell-drawer-close]') - .forEach(function (button) { - button.addEventListener('click', function () { - var hadFocus = documentObject.activeElement === button; - // Match OINK's cooldown so a newly visible trigger under the pointer - // does not immediately undo an explicit keyboard collapse. - pointerLockUntil = Date.now() + 150; - // Run after OINK's native click listener regardless of chunk order. - global.setTimeout(function () { - if (dynamic() && sidebar.contains(button) && restore) { - restore.hidden = false; - restore.focus(); - sidebar.classList.remove('td-shell-sidebar--overlay'); - } - sync(); - // Both external restore controls disappear when pinned. Transfer - // their focus after making the sidebar operable; hover and clicks - // that did not focus a trigger must not steal unrelated focus. - if (hadFocus && desktop.matches && !dynamic() && - !sidebar.contains(button) && button.offsetParent === null) { - var collapse = sidebar.querySelector('.td-shell-sidebar__collapse'); - if (collapse) collapse.focus(); - } - }, 0); - }, true); + documentObject.addEventListener('oink:sidebar-disclosure', function (event) { + if (event.detail && event.detail.source === 'user' && valid.has(event.detail.id)) persist(); }); - sync(); + if (!hasSavedState) persist(); + }); } function initScrollableTables(documentObject) { @@ -455,7 +268,6 @@ consumeVersionFallback(windowObject, documentObject, config); initVersionSwitching(windowObject, documentObject); initTreePersistence(windowObject, documentObject, config); - initSidebarIsolation(windowObject, documentObject); initScrollableTables(documentObject); initSearchRetry(windowObject, documentObject); } @@ -464,7 +276,7 @@ init: init, readConfig: readConfig, safeStorage: safeStorage, - setTreeExpanded: setTreeExpanded, + initTreePersistence: initTreePersistence, versionTarget: versionTarget, initVersionSwitching: initVersionSwitching, consumeVersionFallback: consumeVersionFallback, diff --git a/assets/js/kapa-adapter.js b/assets/js/kapa-adapter.js index b5d191343..552ac9dfd 100644 --- a/assets/js/kapa-adapter.js +++ b/assets/js/kapa-adapter.js @@ -115,6 +115,7 @@ var lastTrigger = null; var activeScript = null; var activeQueue = null; + var operation = null; var status = documentObject.querySelector('[data-hg-ai-status]'); function renderState(next, message) { @@ -133,6 +134,15 @@ } } + function settle(error) { + if (!operation) return; + var current = operation; + operation = null; + current.signal.removeEventListener('abort', current.abort); + if (error) current.reject(error); + else current.resolve(); + } + function openWidget(query, submit) { invokeKapa(windowObject, 'setSourceGroupIDs', [config.sourceGroupId]); invokeKapa(windowObject, 'open', { @@ -140,6 +150,7 @@ query: query, submit: submit, }); + settle(); } function discardAttempt(serial) { @@ -172,6 +183,7 @@ windowObject.clearTimeout(timer); discardAttempt(serial); renderState('error', config.labels.error); + settle(new Error(config.labels.error)); } function ready(serial, query, submit) { @@ -230,7 +242,7 @@ openWidget(query, Boolean(submit && query)); return; } - var retrying = state === 'error'; + var retrying = attempt > 0; var serial = ++attempt; renderState('loading', ''); timer = windowObject.setTimeout(function () { @@ -244,23 +256,49 @@ renderState('idle', ''); if (consent && consent.open) consent.close(); restoreFocus(); + settle(); } - function activate(query, submit, trigger) { + function activate(query, submit, trigger, context) { if (state === 'loading' || state === 'consent') return; + if (context && context.signal.aborted) return Promise.resolve(); lastTrigger = trigger || documentObject.activeElement; + var completion; + if (context) { + completion = new Promise(function (resolve, reject) { + operation = { signal: context.signal, resolve: resolve, reject: reject }; + operation.abort = function () { + windowObject.clearTimeout(timer); + if (state === 'loading') discardAttempt(attempt); + attempt += 1; + pending = null; + if (consent && consent.open) consent.close(); + renderState('idle', ''); + settle(); + }; + context.signal.addEventListener('abort', operation.abort, { once: true }); + }); + // Transfer focus before opening a dialog; OINK keeps cancellation alive + // until this promise settles, including when search is opened again. + if (!context.handoff()) { + settle(); + return completion; + } + } if (consented) { load(query, submit); - return; + return completion; } // Fail closed if the local consent panel is unavailable. if (!consent || typeof consent.showModal !== 'function') { renderState('error', config.labels.error); - return; + settle(new Error(config.labels.error)); + return completion; } pending = { query: trimmedQuery(query), submit: submit }; renderState('consent', ''); consent.showModal(); + return completion; } if (consent) { @@ -306,119 +344,32 @@ var config = readConfig(documentObject); if (!config) return null; var controller = createController(windowObject, documentObject, config); - var root = documentObject.getElementById('td-shell-search'); - var input = root && root.querySelector('.td-shell-search__input'); - var list = root && root.querySelector('.td-shell-search__list'); - var syncing = false; - - function bind(button) { + documentObject.querySelectorAll('[data-hg-ask-ai]').forEach(function (button) { if (button.dataset.hgAiBound !== undefined) return; button.dataset.hgAiBound = ''; button.addEventListener('click', function () { - controller.activate( - button.dataset.hgAiQuery || '', - button.dataset.hgAiSubmit === 'true', - button, - ); + controller.activate('', false, button); }); - } - documentObject.querySelectorAll('[data-hg-ask-ai]').forEach(bind); - - if (!input || !list) return controller; + }); - // Keep the OINK palette untouched: only intercept Enter when local search - // is empty and the site-owned Ask AI tail is the available follow-up. - input.addEventListener('keydown', function (event) { - if (event.isComposing || event.keyCode === 229 || event.key !== 'Enter') return; - var empty = list.querySelector('.td-shell-search__empty'); - var localRow = list.querySelector('.td-shell-search__item:not(.hg-ai-search-tail__button)'); - var tailButton = list.querySelector('[data-hg-ai-search-tail] [data-hg-ask-ai]'); - if (!empty || localRow || !tailButton) return; - event.preventDefault(); - event.stopImmediatePropagation(); - controller.activate(input.value, true, tailButton); - }, true); - - function syncTail() { - syncing = false; - if (!root || !input || !list || root.hidden) return; - var old = list.querySelector('[data-hg-ai-search-tail]'); - var query = trimmedQuery(input.value); - if (!query || query.charAt(0) === '>') { - if (old) old.remove(); - return; - } - var choiceLabel = root.dataset.tdTChoice || ''; - if ( - choiceLabel && - Array.prototype.some.call( - list.querySelectorAll('.td-shell-search__group-label'), - function (label) { return label.textContent.trim() === choiceLabel; }, - ) - ) { - if (old) old.remove(); - return; - } - var loading = root.dataset.tdTLoading || ''; - if ( - loading && - Array.prototype.some.call( - list.querySelectorAll('.td-shell-search__empty'), - function (node) { return node.textContent.trim() === loading; }, - ) - ) { - if (old) old.remove(); - return; - } - var empty = list.querySelector('.td-shell-search__empty'); - if (empty && config.labels.noResults) empty.textContent = config.labels.noResults; - var oldButton = old && old.querySelector('[data-hg-ask-ai]'); - if (oldButton && oldButton.dataset.hgAiQuery === query) return; - if (old) old.remove(); - - var group = documentObject.createElement('div'); - group.className = 'td-shell-search__group hg-ai-search-tail'; - group.dataset.hgAiSearchTail = ''; - group.setAttribute('role', 'group'); - var label = documentObject.createElement('div'); - label.className = 'td-shell-search__group-label'; - label.textContent = config.labels.ask; - var row = documentObject.createElement('button'); - row.type = 'button'; - row.className = 'td-shell-search__item hg-ai-search-tail__button'; - row.dataset.hgAskAi = ''; - row.dataset.hgAiQuery = query; - row.dataset.hgAiSubmit = 'true'; - var icon = documentObject.createElement('i'); - icon.className = - 'fa-solid fa-wand-magic-sparkles td-shell-search__item-icon'; - icon.setAttribute('aria-hidden', 'true'); - var meta = documentObject.createElement('span'); - meta.className = 'td-shell-search__item-meta'; - var title = documentObject.createElement('span'); - title.className = 'td-shell-search__item-title'; - title.textContent = config.labels.ask + ': “' + query + '”'; - var detail = documentObject.createElement('span'); - detail.className = 'td-shell-search__item-ref'; - detail.textContent = config.historical ? config.labels.latest + '.' : ''; - meta.appendChild(title); - meta.appendChild(detail); - row.appendChild(icon); - row.appendChild(meta); - group.appendChild(label); - group.appendChild(row); - list.appendChild(group); - bind(row); - } - - if (list) { - new MutationObserver(function () { - if (syncing) return; - syncing = true; - windowObject.requestAnimationFrame(syncTail); - }).observe(list, { childList: true, subtree: true }); - input.addEventListener('input', syncTail); - syncTail(); + var palette = windowObject.OinkCommandPalette; + if (palette && typeof palette.registerSearchTail === 'function') { + palette.registerSearchTail({ + id: 'hugegraph-ai', + rows: function (context) { + return [{ + id: 'ask', + title: config.labels.ask + ': “' + context.query + '”', + description: config.historical ? config.labels.latest + '.' : '', + icon: 'fa-solid fa-wand-magic-sparkles', + }]; + }, + activate: function (_, context) { + // Search options are ephemeral and become hidden on handoff. + var trigger = documentObject.querySelector('.hg-ask-ai-launcher'); + return controller.activate(context.query, true, trigger, context); + }, + }); } return controller; } diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 9ebca8f7c..29fbad69f 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -507,30 +507,6 @@ display: none; } -.td-nav-util.hg-sidebar-restore { - display: none; -} - -.hg-sidebar-edge { - position: fixed; - inset-inline-start: 0; - top: 64px; - bottom: 0; - width: 16px; - z-index: 121; - border-inline-start: 3px solid var(--bs-border-color); - - &:hover { border-inline-start-color: var(--bs-primary); } -} - -@media (min-width: 768px) { - [data-td-shell-sidebar='collapsed'] { - .td-nav-util.hg-sidebar-restore:not([hidden]) { - display: inline-flex; - } - } -} - .hg-version-overflow { color: var(--bs-body-color); summary { @@ -556,42 +532,6 @@ font-size: 0.84rem; } -.hg-ai-search-tail { - position: sticky; - bottom: 0; - z-index: 1; - margin-inline: -6px; - padding-inline: 6px; - background: var(--td-shell-popover); - box-shadow: 0 -8px 16px color-mix(in srgb, var(--td-shell-popover) 88%, transparent); - border-block-start: 1px solid var(--bs-border-color); - - &__button { - width: 100%; - border: 0; - background: transparent; - color: inherit; - text-align: start; - - &:hover, - &:focus-visible { - background: var(--hg-theme-color-soft); - color: inherit; - } - } -} - -/* Keep the optional Ask AI tail discoverable without changing the OINK theme. */ -.td-shell-search__panel { - max-height: unquote('min(84vh, 720px)'); -} - -@media (max-width: 767.98px) { - .td-shell-search__panel { - max-height: unquote('min(86vh, 680px)'); - } -} - .hg-ask-ai-launcher { position: fixed; z-index: 1040; diff --git a/contribution.md b/contribution.md index cd95f7ce4..3b239726c 100644 --- a/contribution.md +++ b/contribution.md @@ -14,23 +14,23 @@ For the short workflow, start with [README.md](./README.md). This file records t The site uses the Hugo Module recorded in `go.mod` and `go.sum`: -```text -Go: 1.27.0 or newer -Hugo Extended: 0.165.0 -OINK: v1.0.0 -``` - -Node.js, npm, PostCSS, and a vendored Docsy checkout are not part of the build. +Toolchain versions are maintained in `go.mod` and `.github/workflows/hugo.yml`; +`go.mod` / `go.sum` pin the theme. Node.js is needed only for the browser tests, +with its version declared by `tests/e2e/package.json` and CI. -Verify the resolved theme before editing: +Verify the installed toolchain and locked module: ```bash hugo version go version -hugo mod graph +python3 scripts/oink_module.py ``` -The module graph must contain exactly the pinned `github.com/pgsty/oink@v1.0.0` dependency for this site. +For theme updates and breaking-change recovery, follow +[scripts/oink-upgrade.md](scripts/oink-upgrade.md). + +For Kapa staging, consent/CSP checks and production activation, follow +[scripts/kapa-rollout.md](scripts/kapa-rollout.md). ## Local preview @@ -65,13 +65,26 @@ the generated local origin. A successful command proves that Hugo rendered the configured outputs. It does not replace browser checks for navigation, search, language switching, accessibility, mobile layout, print, or Content Security Policy behavior. +## CI queue and reruns + +Each PR has its own concurrency group; a new commit cancels its previous run. +Cancelled runs skip report uploads and the final gate instead of holding the +queue with `always()`. A queued job with no runner has not started testing; +repeated reruns do not resolve runner capacity shortages. + +Version builds remain parallel. Site assembly and blocking browser tests share +one runner and the same local artifact. The required `deploy` check still +requires all blocking jobs to succeed; visual captures remain advisory and +publication alone receives write permission. For a test failure, rerun failed +jobs after inspecting the cause; artifact names remain stable within the run. + ## Repository structure - `content/en/` and `content/cn/` contain the bilingual source pages. - `hugo.yaml` owns routing, languages, outputs, search, navigation, and OINK parameters. - `data/home/.yaml` owns the bilingual homepage. - `data/footer/.yaml` owns the bilingual footer. -- `i18n/zh-CN.yaml` carries the Simplified Chinese OINK interface catalogue for the preserved `cn` URL language key; the file is named after the `zh-CN` locale because Hugo resolves translations by locale, not by the URL key. +- `i18n/zh-CN.yaml` carries only HugeGraph-specific Simplified Chinese labels; generic interface translations come from OINK for the preserved `cn` URL language key; the file is named after the `zh-CN` locale because Hugo resolves translations by locale, not by the URL key. - `assets/` and `static/` contain site-owned brand and compatibility assets. OINK is a module dependency. Do not copy or edit generated module-cache files. Site-specific overrides belong in the corresponding root `layouts/`, `assets/`, or data path and require focused regression evidence. diff --git a/go.mod b/go.mod index 685c7ce27..d4cb4ccab 100644 --- a/go.mod +++ b/go.mod @@ -2,5 +2,4 @@ module github.com/apache/hugegraph-doc go 1.27.0 -require github.com/pgsty/oink v1.0.0 - +require github.com/pgsty/oink v1.1.0 diff --git a/go.sum b/go.sum index 8bd5c21c7..946ebedd7 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,2 @@ -github.com/pgsty/oink v1.0.0 h1:E+WHFP9zSRT+5RKoIkWNp+ASRGS1BKG+rDEi9by/BjE= -github.com/pgsty/oink v1.0.0/go.mod h1:pHvbUhJCfseB41n5RGwsF7abT3i32VSTpofLQoq4b7Y= - +github.com/pgsty/oink v1.1.0 h1:121L5g57ChRCPyidzEBBcln2Co+0zYRQ+XDDXjymd0Q= +github.com/pgsty/oink v1.1.0/go.mod h1:pHvbUhJCfseB41n5RGwsF7abT3i32VSTpofLQoq4b7Y= diff --git a/hugo.yaml b/hugo.yaml index 93a313c00..6ff0d3976 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -112,8 +112,8 @@ params: provider: kapa website_id: 0b277570-4740-451e-96fa-1e4ac1ac5e88 source_groups: - en: '' - cn: '' + en: 32769e2a-abfc-42f6-891f-09af6c123eb2 + cn: ddce6795-32c8-40ac-8b27-73d73facd042 footer_center_info: '' # The compact ASF footer owns the legal line; global controls stay in header. copyright: false diff --git a/i18n/en.yaml b/i18n/en.yaml index 254499546..ad2a00080 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -2,7 +2,6 @@ ui_version_fallback: This page is not available in the selected version. You hav ui_ask_ai: Ask AI ui_ask_ai_description: Powered by Kapa; only your question is sent. ui_ask_ai_latest: Answers use the latest documentation -ui_ask_ai_no_results: No results found. Try AI mode. ui_retry: Retry ui_ai_error: AI is temporarily unavailable. Local search is unaffected. ui_more_versions: More versions @@ -20,7 +19,6 @@ download_component_ai: AI download_component_computer: Computer download_component_commons: Common download_asf_note: Source archives are the official Apache Software Foundation releases; binary packages are convenience builds made from them. All files are served from ASF mirrors, with signatures and checksums hosted on downloads.apache.org. Source archives generated automatically by GitHub are not ASF releases. -ui_assets_download: Download asset ui_ai_consent_description: "Continuing loads Kapa, a third-party service. Your question will be sent to Kapa to generate an answer." ui_ai_consent_continue: "Continue to Ask AI" diff --git a/i18n/zh-CN.yaml b/i18n/zh-CN.yaml index f373dc0d9..a75023877 100644 --- a/i18n/zh-CN.yaml +++ b/i18n/zh-CN.yaml @@ -1,244 +1,8 @@ -# Alert labels -callout_caution: 注意 -callout_important: 重要 -callout_note: 说明 -callout_tip: 提示 -callout_warning: 警告 -callout_success: 成功 -callout_danger: 危险 -callout_question: 问题 -callout_example: 示例 -callout_quote: 引用 -callout_details: 详情 - -# UI strings. Buttons and similar. -ui_pager_prev: 上一页 -ui_pager_next: 下一页 -ui_search: 搜索… -ui_search_empty: 未找到结果 -ui_search_loading: 正在加载搜索索引…… -ui_search_results: '找到 {count} 条结果' -ui_search_nav: 选择 -ui_search_open: 打开 -ui_search_close: 关闭 -ui_palette_actions: 操作 -ui_palette_page_actions: 页面操作 -ui_palette_preferences: 偏好设置 -ui_palette_commands: 命令 -ui_palette_quick_links: 快速链接 -ui_palette_no_commands: 未找到匹配命令 -ui_palette_choose: 请选择一项 -ui_palette_action_failed: 无法完成此操作 -ui_palette_pages: 页面 -ui_palette_index_unavailable: 页面索引暂不可用,操作仍可使用 -ui_sidebar_nav: 章节导航 -ui_heading_self_link: 标题锚点 -ui_field_self_link: 链接到此字段 -ui_preview_source: Markdown -ui_preview_rendered: 渲染结果 -ui_main_nav: 主导航 -ui_home: 首页 -ui_sidebar_expand: 展开侧栏 -ui_sidebar_collapse: 收起侧栏 -ui_drawer_open: 打开导航 -ui_drawer_close: 关闭导航 -ui_root_menu_label: 选择栏目 -ui_tags_title: 标签 -ui_tag_title: 标签 -ui_categories_title: 分类 -ui_category_title: 分类 -ui_modules_title: 模块 -ui_module_title: 模块 -ui_authors_title: 作者 -ui_author_title: 作者 -ui_theme_toggle: 切换配色 -ui_language: 语言切换 -ui_theme: 主题颜色 -ui_theme_auto: 跟随系统 -ui_theme_light: 亮色 -ui_theme_dark: 暗色 -ui_toc_hide: 隐藏目录 -ui_toc_show: 显示目录 -ui_language_select: 选择语言 -ui_language_switch: 切换语言 -ui_skip_to_content: 跳转到主要内容 -ui_page_actions: 操作 -ui_open_in_chatgpt: 在 ChatGPT 中打开 -ui_open_in_claude: 在 Claude 中打开 -ui_open_in_prompt: 请阅读 %s 的内容,以便我就此向你提问。 -ui_copy_markdown: 复制 Markdown 文本 -ui_copy_success: 已复制 Markdown -ui_copy_error: 无法复制 Markdown -ui_share: 分享 -ui_share_email: 邮件 -ui_copy_link: 复制链接 -ui_copy_link_success: 已复制链接 -ui_copy_link_error: 无法复制链接 -ui_code_copy: 复制 -ui_code_copy_label: 复制代码 -ui_code_copied: 已复制 -ui_code_copy_error: 复制失败 -ui_code_show_all: 显示全部 {{ .Count }} 行 -ui_code_collapse: 收起代码 -ui_tabs_label: 选项卡 -ui_pricing_featured: 推荐 -ui_pricing_included: 包含 -ui_pricing_excluded: 不包含 -ui_marquee_pause: 暂停滚动 -ui_kbd_with: 加 -ui_keyboard_shortcuts: 键盘快捷键 -ui_shortcut_tree_move: 在侧栏中移动 -ui_shortcut_tree_toggle: 收起或展开章节 -ui_shortcut_tree_open: 打开当前页面 -ui_shortcut_heading_move: 上一个或下一个标题 -ui_shortcut_page_move: 上一页或下一页 -ui_shortcut_search: 搜索 -ui_shortcut_commands: 命令面板 -ui_shortcut_reading_mode: 专注阅读模式 -ui_shortcut_language: 切换语言 -ui_shortcut_theme: 切换主题 -ui_shortcut_route: 切换顶层页面 -ui_page_annotation: 页面信息 -ui_backlinks: 反链 -ui_backlinks_more: "再显示 {{ . }} 条" -ui_field_required: 必填 -ui_action_unavailable: 暂不可用 -ui_image_zoom_dialog: 图片预览 -ui_image_zoom_open: 打开图片预览 -ui_image_zoom_close: 关闭图片预览 -ui_print_page: 打印此页面 -ui_sidebar_expand_section: 展开章节 -ui_sidebar_collapse_section: 收起章节 -ui_asciinema_timer: 播放时间 -ui_openapi_spec: OpenAPI 规格文件 -ui_release_view: 查看发布 -ui_release_source: 源码 -ui_release_compare: 比较变更 -ui_release_released: 发布于 -ui_release_checksums: 校验和 -ui_assets_file: 文件 -ui_assets_checksum: 校验和 -ui_assets_copy: 复制校验和 -ui_assets_copied: 已复制 -ui_assets_copy_all: 复制全部校验和 -ui_assets_download: 下载资产 -ui_download_channels: 下载渠道 -ui_download_unpublished: 待发布 - -# Used in sentences such as "All Tags" -ui_all: 全部 - -# Footer text -footer_all_rights_reserved: 保留所有权利 - -ui_footer_collapse: 收起页脚链接 -ui_footer_expand: 展开页脚链接 - -# Post (blog, article, etc.) -post_last_mod: 最后修改 -post_upstream: "{{ .work }},{{ .copyright }},依 {{ .license }} 授权使用,详见{{ .notice }}。" -post_upstream_adapted: 本页改编自 {{ .work }},{{ .copyright }},依 {{ .license }} 授权,详见{{ .notice }}与{{ .history }}。 -post_upstream_adapted_plain: 本页改编自 {{ .work }},{{ .copyright }},依 {{ .license }} 授权,详见{{ .notice }}。 -post_upstream_notice: 归属声明 -post_upstream_history: 修改历史 -post_translated: 本页为译文,如有出入以{{ .original }}为准。 -post_translated_original: 原文 -post_edit_this: 编辑当前页面 -post_view_markdown: 查阅 Markdown 源码 -post_create_child_page: 添加子页面 -post_create_issue: 提交文档议题 -post_create_project_issue: 提交项目议题 -post_reading_time: 分钟阅读 -post_less_than_a_minute_read: 1分钟内可阅读完 -post_word_count: '{{ .Count }} 字' -post_reading_minutes: '{{ .Minutes }} 分钟' -post_read_original: 阅读原文 - -# Print support -print_printable_section: 这是本节的多页打印视图。 -print_click_to_print: 点击此处打印 -print_show_regular: 返回本页常规视图 -print_entire_section: 打印完整章节 - -# Feedback -feedback_question: 这篇文档解决了你的问题吗? -feedback_positive: 是 -feedback_negative: 否 -feedback_thanks: 感谢反馈,我们会据此改进这篇文档。 -feedback_reason_prompt: 哪里没有解决?(可选) -feedback_reason_missing: 缺少必要信息 -feedback_reason_outdated: 内容错误或已过时 -feedback_reason_failed: 操作步骤没有生效 -feedback_reason_unclear: 内容难以理解 -feedback_details: 在评论区补充详情 -feedback_change: 修改反馈 - -# Table of contents -toc_on_this_page: 目录 - -# Error pages -error_404_title: 页面不存在 -error_404_body: >- - 抱歉,该页面不存在。可以从首页重新开始。 -error_404_home: 返回首页 - -# Version banner -version_banner_archived: >- - 文档 {{ .Version }} 版本已不再积极维护,你当前浏览的是一份归档快照。 -version_banner_latest: 最新文档请参阅 {{ .Link }}。 -version_banner_latest_link: 最新版本 - -# Comments -comments_noscript: 加载评论需要启用 JavaScript。 -comments_noscript_link: 在 GitHub 上查看讨论。 - -# LLM 页面操作 -ui_open_in_prompt_label: 就本页提问 -ui_view_history: 查阅编辑历史 -ui_table_scroll: "可横向滚动的表格" -ui_filetree_divider: "拖动以调整目录树备注列宽度" -book_figure: 图 -book_table: 表 -book_equation: 公式 -book_example: 示例 -book_toc: 全书目录 -book_draft: 草稿 -book_draft_notice: 本章仍在修订中。 -contributors_count: 位贡献者 - -# Article series -ui_series_title: 系列 -ui_series_part: 第 {{ .Part }} / 共 {{ .Total }} 篇 - -# Replace these values with reviewed translations when available. -ui_list_separator: 、 - -# Footer text -post_meta_by_in: "{{ .Authors }} 发布于 {{ .Section }}" -post_meta_in: "发布于 {{ .Section }}" - -# Replace these values with reviewed translations when available. -ui_blog_index_toggle: 切换布局 - -# Markdown output -markdown_llms_index: "LLMS 索引:" -markdown_backlinks: "反链:" -markdown_section_pages: "本节页面:" - -# Explicit English fallbacks for untranslated OINK UI strings. -# Replace these values with reviewed translations when available. -ui_diagram_expand: 放大图表 -ui_diagram_zoom_dialog: 图表预览 -ui_diagram_zoom_close: 关闭图表预览 -ui_diagram_zoom_in: 放大 -ui_diagram_zoom_out: 缩小 -ui_diagram_zoom_reset: 复位视图 -ui_diagram_error: 图表无法渲染 +# HugeGraph-specific labels. Generic UI translations come from OINK. ui_version_fallback: 目标版本没有此页面,已转到该版本的文档首页。 ui_ask_ai: 询问 AI ui_ask_ai_description: 由 Kapa 提供;仅发送你的问题。 ui_ask_ai_latest: 回答基于 latest 文档 -ui_ask_ai_no_results: 未找到结果,可以试试 Ask AI 模式。 ui_retry: 重试 ui_ai_error: AI 暂时不可用,本地搜索不受影响。 ui_more_versions: 更多版本 diff --git a/layouts/_partials/hooks/body-end.html b/layouts/_partials/hooks/body-end.html index fff6e6dd2..06d57502b 100644 --- a/layouts/_partials/hooks/body-end.html +++ b/layouts/_partials/hooks/body-end.html @@ -24,8 +24,6 @@ "ask" (T "ui_ask_ai") "description" (T "ui_ask_ai_description") "latest" (T "ui_ask_ai_latest") - "noResults" (T "ui_ask_ai_no_results") - "retry" (T "ui_retry") "error" (T "ui_ai_error") -}} {{- $clientConfig := dict diff --git a/layouts/_partials/navbar-item.html b/layouts/_partials/navbar-item.html index d07dd32d2..74c9b0ca3 100644 --- a/layouts/_partials/navbar-item.html +++ b/layouts/_partials/navbar-item.html @@ -1,4 +1,4 @@ -{{- /* OINK v1.0.0 override: Documentation gains manifest-driven versions. +{{- /* OINK override (reviewed against v1.1.0): Documentation gains manifest-driven versions. One top-level Hugo Menu item. Leaves keep the historical link path; parents add a separate disclosure and one dropdown/accordion panel. */ -}} {{- $page := .page -}} diff --git a/layouts/_partials/navbar.html b/layouts/_partials/navbar.html index 9eeb35de0..74dfc846c 100644 --- a/layouts/_partials/navbar.html +++ b/layouts/_partials/navbar.html @@ -53,13 +53,6 @@ {{- /* Right zone: the search box leads as the elastic boundary before the fixed controls — version, language, theme, GitHub. */ -}}