-
Notifications
You must be signed in to change notification settings - Fork 1
Make VitePress docs fully WCAG 2.1 AA accessible #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
82a37b8
7906646
800a06b
4d3d183
aa08d48
c9226f9
0d1cd68
8971570
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| # Accessibility audit — WCAG 2.1 AA | ||
| # | ||
| # Runs pa11y-ci against the built VitePress docs to ensure the homepage and | ||
| # key pages remain WCAG 2.1 AA compliant. | ||
| # | ||
| # Triggers: | ||
| # - push to main touching docs/** or this workflow / config | ||
| # - every pull_request touching the same paths | ||
| # - workflow_dispatch (manual run) | ||
| # | ||
| # Strategy: | ||
| # 1. Build the docs with `bun run docs:build:a11y` (sets VITEPRESS_HOSTNAME= | ||
| # http://localhost:4173 so the generated sitemap.xml contains localhost | ||
| # URLs that pa11y-ci can reach directly) | ||
| # 2. Start `vitepress preview` in the background (serves on port 4173) | ||
| # 3. Wait until the server is accepting connections | ||
| # 4. Run pa11y-ci configured in .pa11yci.json (WCAG 2.1 AA, errors only) | ||
| # | ||
| # Chrome: Ubuntu-latest ships google-chrome-stable. We skip Puppeteer's own | ||
| # Chromium download (PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1) and point directly to | ||
| # the system Chrome via PUPPETEER_EXECUTABLE_PATH at runtime. This cuts ~200 MB | ||
| # from every CI run. | ||
| name: Accessibility audit (WCAG 2.1 AA) | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - "docs/**" | ||
| - ".github/workflows/a11y.yml" | ||
| - ".pa11yci.json" | ||
| pull_request: | ||
| paths: | ||
| - "docs/**" | ||
| - ".github/workflows/a11y.yml" | ||
| - ".pa11yci.json" | ||
| workflow_dispatch: | ||
|
|
||
| # One audit at a time per branch; cancel stale runs on new push. | ||
| concurrency: | ||
| group: a11y-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| audit: | ||
| name: WCAG 2.1 AA pages audit | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3cf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3 | ||
| with: | ||
| bun-version: latest | ||
shouze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| - name: Install dependencies | ||
| run: bun install --frozen-lockfile | ||
|
|
||
| - name: Build docs (a11y — sitemap will use localhost URLs) | ||
| run: bun run docs:build:a11y | ||
|
|
||
| # Start VitePress preview in the background; base URL: /github-code-search/ | ||
| # --port 4173 matches the URLs in .pa11yci.json | ||
| - name: Start VitePress preview server | ||
| run: bun run docs:preview -- --port 4173 & | ||
|
|
||
| # Poll until the preview server responds (max 60 s = 30 × 2 s). | ||
| - name: Wait for preview server to be ready | ||
| run: | | ||
| echo "Waiting for VitePress preview on http://localhost:4173/github-code-search/ …" | ||
| for i in $(seq 1 30); do | ||
| if curl -sf http://localhost:4173/github-code-search/ > /dev/null 2>&1; then | ||
| echo "Server ready after $((i * 2)) seconds." | ||
| exit 0 | ||
| fi | ||
| echo "Attempt $i/30 — retrying in 2 s …" | ||
| sleep 2 | ||
| done | ||
| echo "ERROR: preview server did not start within 60 seconds." >&2 | ||
| exit 1 | ||
|
|
||
| # Run the audit. The env vars tell Puppeteer (used by pa11y) to use the | ||
| # pre-installed system Chrome instead of downloading a Chromium binary. | ||
| - name: Run accessibility audit (pa11y-ci) | ||
| env: | ||
| PUPPETEER_EXECUTABLE_PATH: /usr/bin/google-chrome-stable | ||
| PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "1" | ||
| run: bun run docs:a11y | ||
|
|
||
| # Upload the pa11y-ci JSON report as an artifact so failures are | ||
| # easy to inspect without re-running the workflow. | ||
| - name: Upload audit report | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: pa11y-ci-report | ||
| path: a11y-report.json | ||
| if-no-files-found: ignore | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ dist/ | |
| coverage/ | ||
| .env | ||
| *.local | ||
| a11y-report.json | ||
|
|
||
| # VitePress | ||
| docs/.vitepress/cache | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "defaults": { | ||
| "standard": "WCAG2AA", | ||
| "reporters": ["cli", ["json", { "fileName": "./a11y-report.json" }]], | ||
| "level": "error", | ||
| "wait": 1500, | ||
| "timeout": 60000, | ||
| "chromeLaunchConfig": { | ||
| "args": ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"] | ||
| }, | ||
| "ignore": [ | ||
| "WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.BgImage", | ||
| "WCAG2AA.Principle1.Guideline1_4.1_4_3.G145.BgImage", | ||
| "WCAG2AA.Principle4.Guideline4_1.4_1_1.F77" | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,7 +119,13 @@ export default defineConfig({ | |
| content: "https://fulll.github.io/github-code-search/social-preview.png", | ||
| }, | ||
| ], | ||
| ["meta", { property: "og:url", content: "https://fulll.github.io/github-code-search/" }], | ||
| [ | ||
| "meta", | ||
| { | ||
| property: "og:url", | ||
| content: "https://fulll.github.io/github-code-search/", | ||
| }, | ||
| ], | ||
| // ── Twitter Card ──────────────────────────────────────────────────────── | ||
| ["meta", { name: "twitter:card", content: "summary_large_image" }], | ||
| ["meta", { name: "twitter:title", content: "github-code-search" }], | ||
|
|
@@ -158,11 +164,40 @@ export default defineConfig({ | |
| const svgPath = fileURLToPath(new URL("../public/social-preview.svg", import.meta.url)); | ||
| const pngPath = fileURLToPath(new URL("../public/social-preview.png", import.meta.url)); | ||
| const svg = readFileSync(svgPath, "utf-8"); | ||
| const resvg = new Resvg(svg, { fitTo: { mode: "width", value: 1200 } }); | ||
| const resvg = new Resvg(svg, { | ||
| fitTo: { mode: "width", value: 1200 }, | ||
| }); | ||
| writeFileSync(pngPath, resvg.render().asPng()); | ||
| }, | ||
| }, | ||
| ], | ||
| // ── Chunk splitting ────────────────────────────────────────────────────── | ||
| // Mermaid alone is >900 kB minified; split it + the d3 sub-tree into | ||
| // dedicated async chunks to eliminate the Rollup 500 kB warning and | ||
| // improve long-term caching. No generic vendor catch-all — VitePress | ||
| // internals (mark.js etc.) need Rollup's default resolution. | ||
| build: { | ||
| // Mermaid (bundled with d3) is legitimately large (~2.4 MB minified). | ||
| // 2500 kB threshold avoids the Rollup warning without masking real bloat | ||
| // on other chunks (next largest is katex at ~260 kB). | ||
| chunkSizeWarningLimit: 2500, | ||
| rollupOptions: { | ||
| output: { | ||
| manualChunks(id: string) { | ||
| // Mermaid + d3 must be co-located (circular dependency between them). | ||
| if ( | ||
| id.includes("node_modules/mermaid") || | ||
| id.includes("node_modules/vitepress-plugin-mermaid") || | ||
| id.includes("node_modules/d3") || | ||
| id.includes("node_modules/dagre-d3-es") || | ||
| id.includes("node_modules/internmap") || | ||
| id.includes("node_modules/robust-predicates") | ||
| ) | ||
| return "mermaid"; | ||
shouze marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
|
|
||
| themeConfig: { | ||
|
|
@@ -305,13 +340,19 @@ export default defineConfig({ | |
| // ── Markdown ────────────────────────────────────────────────────────────── | ||
| markdown: { | ||
| theme: { | ||
| light: "github-light", | ||
| // github-light-high-contrast fixes WCAG AA contrast for Shiki tokens | ||
| // (github-light has #D73A49 4.24:1, #6A737D 4.46:1, #22863A 4.28:1 — all below 4.5:1) | ||
| light: "github-light-high-contrast", | ||
| dark: "github-dark", | ||
| }, | ||
| }, | ||
|
|
||
| // ── Sitemap ─────────────────────────────────────────────────────────────── | ||
| // VITEPRESS_HOSTNAME overrides the default for local/CI a11y audits: | ||
| // VITEPRESS_HOSTNAME=http://localhost:4173 vitepress build docs | ||
| // → sitemap.xml contains localhost URLs that pa11y-ci can reach directly. | ||
| sitemap: { | ||
| hostname: "https://fulll.github.io/github-code-search/", | ||
| hostname: | ||
| (process.env.VITEPRESS_HOSTNAME ?? "https://fulll.github.io") + "/github-code-search/", | ||
| }, | ||
|
Comment on lines
353
to
356
|
||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.