|
| 1 | +# Documentation skill — github-code-search |
| 2 | + |
| 3 | +Deep reference for writing and maintaining VitePress documentation in this project. |
| 4 | +This skill complements `.github/instructions/documentation.instructions.md` (the step-by-step workflow). |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## VitePress theme architecture |
| 9 | + |
| 10 | +Custom components live in `docs/.vitepress/theme/`: |
| 11 | + |
| 12 | +| File / folder | Role | |
| 13 | +| ------------------------ | -------------------------------------------------------------------- | |
| 14 | +| `index.ts` | Theme entry point — imports components and global CSS | |
| 15 | +| `custom.css` | All CSS overrides — brand colours, typography, responsive, a11y | |
| 16 | +| `Layout.vue` | Root layout wrapper (adds `RichFooter`, manages slot injection) | |
| 17 | +| `TerminalDemo.vue` | Animated terminal on the hero — `aria-hidden="true"` (decorative) | |
| 18 | +| `ComparisonTable.vue` | Feature comparison table with responsive 3-column layout | |
| 19 | +| `UseCaseTabs.vue` | WAI-ARIA Tabs pattern (roving tabindex, ArrowLeft/Right/Home/End) | |
| 20 | +| `InstallSection.vue` | Install command snippets with OS tabs | |
| 21 | +| `HowItWorks.vue` | 3-step explainer with responsive card layout | |
| 22 | +| `TestimonialsSection.vue`| Community testimonials carousel | |
| 23 | +| `ProductionCta.vue` | "Used in production?" CTA banner (`<section aria-labelledby="…">`) | |
| 24 | +| `VersionBadge.vue` | Release badge — reads `version` from `package.json` at build time | |
| 25 | +| `RichFooter.vue` | Custom footer replacing VitePress default | |
| 26 | + |
| 27 | +**Extending a component:** |
| 28 | +1. Locate the `.vue` file above. |
| 29 | +2. Follow the existing scoped `<style>` conventions (no global selectors inside `<style scoped>`). |
| 30 | +3. Add responsive styles inside the component's `<style>` or in `custom.css` if the rule is global. |
| 31 | +4. Never import additional NPM packages for styling — only `picocolors` (CLI) and VitePress built-ins. |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## CSS variable system |
| 36 | + |
| 37 | +Always use VitePress CSS variables — never hard-code colours in component `<style>` blocks: |
| 38 | + |
| 39 | +| Variable | Meaning | |
| 40 | +| --------------------- | ------------------------------------ | |
| 41 | +| `--vp-c-brand-1` | Violet `#9933FF` / `#cc88ff` (dark) | |
| 42 | +| `--vp-c-brand-2` | Hover darkening | |
| 43 | +| `--vp-c-brand-soft` | Soft tint for backgrounds | |
| 44 | +| `--vp-c-text-1` | Primary text (≥ WCAG AA on bg) | |
| 45 | +| `--vp-c-text-2` | Secondary text (≥ WCAG AA on bg) | |
| 46 | +| `--vp-c-text-3` | **Do not use for text** — 2.87:1 contrast, fails WCAG AA | |
| 47 | +| `--vp-c-divider` | Border / separator | |
| 48 | +| `--vp-c-bg-soft` | Card / inset background | |
| 49 | +| `--vp-font-family-mono` | Monospace (code blocks) | |
| 50 | + |
| 51 | +Dark mode: VitePress applies a `.dark` class on `<html>`. Use `.dark .selector { … }` — never `@media (prefers-color-scheme: dark)`. |
| 52 | + |
| 53 | +--- |
| 54 | + |
| 55 | +## Accessibility (WCAG 2.1 AA) |
| 56 | + |
| 57 | +This project maintains **zero pa11y-ci violations** at WCAG 2.1 AA level. |
| 58 | + |
| 59 | +### Tool |
| 60 | + |
| 61 | +```bash |
| 62 | +bun run docs:build:a11y # build with VITEPRESS_HOSTNAME=http://localhost:4173 |
| 63 | +bun run docs:preview -- --port 4173 & |
| 64 | +bun run docs:a11y # pa11y-ci via sitemap — must report 0 errors |
| 65 | +``` |
| 66 | + |
| 67 | +Config: `.pa11yci.json`. F77 (Mermaid duplicate SVG IDs) is ignored — not blocking for AT users. |
| 68 | + |
| 69 | +### Common patterns |
| 70 | + |
| 71 | +| Pattern | Correct implementation | |
| 72 | +| ------------------------------------------ | ------------------------------------------------------------------ | |
| 73 | +| Landmark regions | `<section aria-labelledby="id">` + matching `id` on heading | |
| 74 | +| Icon-only buttons / links | `aria-label="Descriptive text"` | |
| 75 | +| Decorative images / SVG | `aria-hidden="true"` and no `alt` (or `alt=""`) | |
| 76 | +| External links (open in new tab) | `aria-label="Label (opens in a new tab)"` or `.sr-only` suffix | |
| 77 | +| Check / cross icons in tables | `aria-label="Yes"` / `aria-label="No"` | |
| 78 | +| Table column headers | `<th scope="col">` + `<caption class="sr-only">` on `<table>` | |
| 79 | +| Interactive tabs | Full WAI-ARIA Tabs: `role="tablist"`, `role="tab"`, `role="tabpanel"`, roving `tabindex`, keyboard nav | |
| 80 | +| Screen-reader-only text | `.sr-only` utility class defined in `custom.css` | |
| 81 | +| Focus visibility | `:focus-visible` ring defined globally in `custom.css` | |
| 82 | + |
| 83 | +### Contrast minimums (WCAG AA) |
| 84 | + |
| 85 | +- Normal text (< 18pt): **4.5:1** |
| 86 | +- Large text (≥ 18pt bold or ≥ 24pt): **3:1** |
| 87 | +- UI components and icons: **3:1** |
| 88 | + |
| 89 | +Avoid `var(--vp-c-text-3)` for any visible text — it is ~2.87:1 against default VitePress backgrounds. |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +## Responsive (mobile-first) |
| 94 | + |
| 95 | +This project maintains **zero horizontal overflow** across 4 tested viewports via Playwright. |
| 96 | + |
| 97 | +### Tested viewports |
| 98 | + |
| 99 | +| Label | Width | Height | |
| 100 | +| --------------- | ------ | ------ | |
| 101 | +| Galaxy S21 | 360px | 800px | |
| 102 | +| iPhone SE | 375px | 667px | |
| 103 | +| iPhone 14 | 390px | 844px | |
| 104 | +| Tablet portrait | 768px | 1024px | |
| 105 | + |
| 106 | +### Tool |
| 107 | + |
| 108 | +```bash |
| 109 | +bun run docs:build |
| 110 | +bun run docs:preview -- --port 4173 & |
| 111 | +bun run docs:test:responsive # 20 tests (4 viewports × 5 pages) — must all pass |
| 112 | +``` |
| 113 | + |
| 114 | +Config: `playwright.config.ts`. Spec: `scripts/responsive.pw.ts`. Screenshots on failure: `test-results/screenshots/` (gitignored). |
| 115 | + |
| 116 | +### VitePress quirks at 768px |
| 117 | + |
| 118 | +VitePress hides its hamburger at `≥768px` and shows desktop nav links — which overflow the viewport at exactly 768px on this project's config. The fix in `custom.css`: |
| 119 | + |
| 120 | +```css |
| 121 | +@media (max-width: 960px) { |
| 122 | + .VPNavBarMenu, .VPNavBarExtra { display: none !important; } |
| 123 | + .VPNavBarHamburger { display: flex !important; } |
| 124 | +} |
| 125 | +@media (min-width: 768px) and (max-width: 960px) { |
| 126 | + .VPNavScreen { display: block !important; } |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +### Responsive patterns for components |
| 131 | + |
| 132 | +| Problem | Solution | |
| 133 | +| ------------------------------------------- | ------------------------------------------------------------ | |
| 134 | +| Table columns too wide on mobile | `table-layout: fixed`, abbreviated headers via `.ct-name-short` / `.ct-name-long` toggle | |
| 135 | +| Long feature descriptions push rows wider | `display: none` on `.ct-feature-desc` at `≤640px` | |
| 136 | +| Terminal/code blocks cause page scroll | `overflow-x: auto` on the scroll container, `max-width: 100%` on the block | |
| 137 | +| Long strings in `<pre>` overflow | `pre { max-width: 100%; overflow-x: auto; }` in `custom.css` | |
| 138 | + |
| 139 | +Never use `overflow-x: hidden` on the page root — it silently clips content. Apply it only to specific containers where clipping is intentional. |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## Validation checklist |
| 144 | + |
| 145 | +Before opening a PR for any docs change: |
| 146 | + |
| 147 | +```bash |
| 148 | +bun run docs:build # must complete without errors or dead-link warnings |
| 149 | +bun run docs:build:a11y # build for a11y audit |
| 150 | +bun run docs:preview -- --port 4173 & |
| 151 | +bun run docs:a11y # 0 pa11y violations |
| 152 | +bun run docs:test:responsive # 20/20 Playwright tests green |
| 153 | +bun run format:check # oxfmt — no formatting diff |
| 154 | +``` |
0 commit comments