obsidian md github站点

会自动渲染md 到 gh-pages 分支,然后到pages (注意,需要public 仓库)

源码:

复制代码
name: Deploy Docs to GitHub Pages

on:
  push:
    branches:
      - main
    paths:
      - "**/*.md"
      - ".obsidian/workspace.json"
      - "book.json"
      - ".github/workflows/deploy-pages.yml"
  workflow_dispatch:

permissions:
  contents: write

concurrency:
  group: deploy-pages
  cancel-in-progress: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Build with HonKit
        shell: bash
        run: |
          set -euo pipefail

          ordered_md_file="$(mktemp)"
          all_md_file="$(mktemp)"
          candidate_md_file="$(mktemp)"

          # Collect all markdown files in repository (relative paths).
          while IFS= read -r -d '' md; do
            printf '%s\n' "${md#./}" >> "$all_md_file"
          done < <(
            find . -type f -name '*.md' \
              -not -path './.git/*' \
              -not -path './node_modules/*' \
              -print0 | sort -z
          )

          # Prefer Obsidian workspace order: active doc -> main tabs -> last open files.
          if [ -f .obsidian/workspace.json ]; then
            node <<'NODE' > "$ordered_md_file"
          const fs = require('fs');
          const wsPath = '.obsidian/workspace.json';
          let ws;
          try {
            ws = JSON.parse(fs.readFileSync(wsPath, 'utf8'));
          } catch {
            process.exit(0);
          }

          const output = [];
          const idToMarkdown = new Map();

          function walk(node, fn) {
            if (!node || typeof node !== 'object') return;
            fn(node);
            if (Array.isArray(node.children)) {
              for (const child of node.children) walk(child, fn);
            }
          }

          walk(ws, (node) => {
            if (node.type !== 'leaf') return;
            const file = node?.state?.state?.file;
            if (node?.state?.type === 'markdown' && typeof file === 'string' && file.endsWith('.md')) {
              if (typeof node.id === 'string') idToMarkdown.set(node.id, file);
            }
          });

          if (typeof ws.active === 'string' && idToMarkdown.has(ws.active)) {
            output.push(idToMarkdown.get(ws.active));
          }

          function collectMainTabs(node) {
            if (!node || typeof node !== 'object') return;
            if (node.type === 'tabs' && Array.isArray(node.children)) {
              const currentIndex = Number.isInteger(node.currentTab) ? node.currentTab : -1;
              if (currentIndex >= 0 && currentIndex < node.children.length) {
                const activeFile = node.children[currentIndex]?.state?.state?.file;
                if (typeof activeFile === 'string' && activeFile.endsWith('.md')) output.push(activeFile);
              }
              for (const child of node.children) {
                const tabFile = child?.state?.state?.file;
                if (typeof tabFile === 'string' && tabFile.endsWith('.md')) output.push(tabFile);
              }
            }
            if (Array.isArray(node.children)) {
              for (const child of node.children) collectMainTabs(child);
            }
          }

          collectMainTabs(ws.main);

          if (Array.isArray(ws.lastOpenFiles)) {
            for (const file of ws.lastOpenFiles) {
              if (typeof file === 'string' && file.endsWith('.md')) output.push(file);
            }
          }

          for (const file of output) {
            if (typeof file === 'string' && file.length > 0) {
              console.log(file.replace(/^\.\//, ''));
            }
          }
          NODE
          fi

          # Merge and deduplicate while preserving order.
          cat "$ordered_md_file" "$all_md_file" | awk 'NF && !seen[$0]++' > "$candidate_md_file"

          home_source=""
          if [ ! -f README.md ]; then
            if [ -s "$ordered_md_file" ]; then
              first_preferred="$(head -n 1 "$ordered_md_file")"
              if [ -n "$first_preferred" ] && [ -f "$first_preferred" ]; then
                home_source="$first_preferred"
                cp "$home_source" README.md
              fi
            fi

            if [ ! -f README.md ] && [ -f Welcome.md ]; then
              home_source="Welcome.md"
              cp Welcome.md README.md
            fi

            if [ ! -f README.md ]; then
              first_md="$(head -n 1 "$all_md_file")"
              if [ -n "$first_md" ] && [ -f "$first_md" ]; then
                home_source="$first_md"
                cp "$home_source" README.md
              fi
            fi
          fi

          {
            echo "# Summary"
            echo
            echo "* [Home](README.md)"
            while IFS= read -r md; do
              [ -z "$md" ] && continue
              [ "$md" = "README.md" ] && continue
              [ "$md" = "SUMMARY.md" ] && continue
              [ -n "$home_source" ] && [ "$md" = "$home_source" ] && continue
              [ -f "$md" ] || continue
              title="$(basename "${md%.md}")"
              printf "* [%s](%s)\n" "$title" "$md"
            done < "$candidate_md_file"
          } > SUMMARY.md

          # Ensure Osiris theme plugin is configured, even if book.json is absent.
          node <<'NODE'
          const fs = require('fs');
          const path = 'book.json';
          let book = {};
          if (fs.existsSync(path)) {
            try {
              book = JSON.parse(fs.readFileSync(path, 'utf8'));
            } catch (err) {
              throw new Error(`Invalid book.json: ${err.message}`);
            }
          }

          const targetPlugin = 'honkit-plugin-theme-osiris';
          const plugins = Array.isArray(book.plugins) ? book.plugins : [];
          const filtered = plugins.filter(
            (p) => p !== targetPlugin && p !== 'theme-osiris'
          );
          filtered.push(targetPlugin);
          book.plugins = filtered;
          fs.writeFileSync(path, `${JSON.stringify(book, null, 2)}\n`);
          NODE

          npm install --no-save honkit@5.1.4 honkit-plugin-theme-osiris@1.0.3
          ./node_modules/.bin/honkit build . _book

          # Workaround: plugin generates osiris.css under gitbook-plugin-* path,
          # but HonKit references it from honkit-plugin-* path.
          osiris_generated="_book/gitbook/gitbook-plugin-honkit-plugin-theme-osiris/osiris.css"
          osiris_expected_dir="_book/gitbook/honkit-plugin-theme-osiris"
          if [ -f "$osiris_generated" ]; then
            mkdir -p "$osiris_expected_dir"
            cp "$osiris_generated" "$osiris_expected_dir/osiris.css"
          fi

          touch _book/.nojekyll

      - name: Deploy to gh-pages
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./_book
          publish_branch: gh-pages
          force_orphan: true
相关推荐
dong_junshuai9 小时前
每天一个开源项目#152 Auto Ontology:让业务口径进入SQL生成链
github
一条Go11 小时前
两套权限目录,三重闸门:Alioth 的多租户 RBAC 为什么这么拧
后端·程序员·github
imythu11 小时前
让 Claude Code 在家跑,我在外面用手机盯着:做一个开源工具踩过的几个坑
人工智能·github
艾迪的技术之路12 小时前
16k 条慢查询,128 张分表,我这么解决
后端·github
lsc_blog12 小时前
年底还在招的岗位,先确认缺口和到岗要求
git·缓存·ci/cd·职场和发展·github
GitHub实测笔记12 小时前
bat 本机实测:6.7MB JS 开语法高亮要 12.4s,cat 只要 1.2ms;关颜色约慢 24 倍
github
徐小夕16 小时前
下载量超 30 万的开源智能体 Prime Agent:它把自己从 TypeScript 重写成了 Rust
前端·vue.js·github
miofly18 小时前
GitHub 日榜趋势速报 | 2026-11-05
开源·github
wflynn1 天前
GitHub 日榜趋势速报 | 2026-11-03
开源·github
u1301301 天前
GitHub 热榜项目:日榜(2026-11-03)
人工智能·github