feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
5
skills/vitepress/GENERATION.md
Normal file
5
skills/vitepress/GENERATION.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Generation Info
|
||||
|
||||
- **Source:** `sources/vitepress`
|
||||
- **Git SHA:** `d4796a0373eb486766cf48e63fdf461681424d43`
|
||||
- **Generated:** 2026-01-28
|
||||
65
skills/vitepress/SKILL.md
Normal file
65
skills/vitepress/SKILL.md
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: vitepress
|
||||
description: VitePress static site generator powered by Vite and Vue. Use when building documentation sites, configuring themes, or writing Markdown with Vue components.
|
||||
metadata:
|
||||
author: Anthony Fu
|
||||
version: "2026.1.28"
|
||||
source: Generated from https://github.com/vuejs/vitepress, scripts located at https://github.com/antfu/skills
|
||||
---
|
||||
|
||||
VitePress is a Static Site Generator (SSG) built on Vite and Vue 3. It takes Markdown content, applies a theme, and generates static HTML that becomes an SPA for fast navigation. Perfect for documentation, blogs, and marketing sites.
|
||||
|
||||
**Key Characteristics:**
|
||||
- File-based routing with `.md` files
|
||||
- Vue components work directly in Markdown
|
||||
- Fast HMR with instant updates (<100ms)
|
||||
- Default theme optimized for documentation
|
||||
- Built-in search (local or Algolia)
|
||||
|
||||
**Before working with VitePress projects:**
|
||||
- Check `.vitepress/config.ts` for site configuration
|
||||
- Look at `.vitepress/theme/` for custom theme extensions
|
||||
- The `public/` directory contains static assets served as-is
|
||||
|
||||
> The skill is based on VitePress 1.x, generated at 2026-01-28.
|
||||
|
||||
## Core
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Configuration | Config file setup, defineConfig, site metadata | [core-config](references/core-config.md) |
|
||||
| CLI | Command-line interface: dev, build, preview, init | [core-cli](references/core-cli.md) |
|
||||
| Routing | File-based routing, source directory, rewrites | [core-routing](references/core-routing.md) |
|
||||
| Markdown | Frontmatter, containers, tables, anchors, includes | [core-markdown](references/core-markdown.md) |
|
||||
|
||||
## Features
|
||||
|
||||
### Code & Content
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Code Blocks | Syntax highlighting, line highlighting, diffs, focus | [features-code-blocks](references/features-code-blocks.md) |
|
||||
| Vue in Markdown | Components, script setup, directives, templating | [features-vue](references/features-vue.md) |
|
||||
| Data Loading | Build-time data loaders, createContentLoader | [features-data-loading](references/features-data-loading.md) |
|
||||
| Dynamic Routes | Generate pages from data, paths loader files | [features-dynamic-routes](references/features-dynamic-routes.md) |
|
||||
|
||||
## Theme
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Theme Config | Nav, sidebar, search, social links, footer | [theme-config](references/theme-config.md) |
|
||||
| Customization | CSS variables, slots, fonts, global components | [theme-customization](references/theme-customization.md) |
|
||||
| Custom Theme | Building themes from scratch, theme interface | [theme-custom](references/theme-custom.md) |
|
||||
|
||||
## Advanced
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Internationalization | Multi-language sites, locale configuration | [advanced-i18n](references/advanced-i18n.md) |
|
||||
| SSR Compatibility | Server-side rendering, ClientOnly, dynamic imports | [advanced-ssr](references/advanced-ssr.md) |
|
||||
|
||||
## Recipes
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Deployment | GitHub Pages, Netlify, Vercel, Cloudflare, Nginx | [recipes-deploy](references/recipes-deploy.md) |
|
||||
299
skills/vitepress/references/advanced-i18n.md
Normal file
299
skills/vitepress/references/advanced-i18n.md
Normal file
@@ -0,0 +1,299 @@
|
||||
---
|
||||
name: vitepress-internationalization
|
||||
description: Setting up multi-language sites with locale configuration and RTL support
|
||||
---
|
||||
|
||||
# Internationalization
|
||||
|
||||
VitePress supports multi-language sites through locale configuration.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
Organize content by locale:
|
||||
|
||||
```
|
||||
docs/
|
||||
├─ en/
|
||||
│ ├─ guide.md
|
||||
│ └─ index.md
|
||||
├─ zh/
|
||||
│ ├─ guide.md
|
||||
│ └─ index.md
|
||||
└─ fr/
|
||||
├─ guide.md
|
||||
└─ index.md
|
||||
```
|
||||
|
||||
Or with root as default language:
|
||||
|
||||
```
|
||||
docs/
|
||||
├─ guide.md # English (root)
|
||||
├─ index.md
|
||||
├─ zh/
|
||||
│ ├─ guide.md
|
||||
│ └─ index.md
|
||||
└─ fr/
|
||||
├─ guide.md
|
||||
└─ index.md
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
locales: {
|
||||
root: {
|
||||
label: 'English',
|
||||
lang: 'en'
|
||||
},
|
||||
zh: {
|
||||
label: '简体中文',
|
||||
lang: 'zh-CN',
|
||||
link: '/zh/'
|
||||
},
|
||||
fr: {
|
||||
label: 'Français',
|
||||
lang: 'fr',
|
||||
link: '/fr/'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Locale-Specific Config
|
||||
|
||||
Override site config per locale:
|
||||
|
||||
```ts
|
||||
locales: {
|
||||
root: {
|
||||
label: 'English',
|
||||
lang: 'en',
|
||||
title: 'My Docs',
|
||||
description: 'Documentation site',
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{ text: 'Guide', link: '/guide/' }
|
||||
],
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{ text: 'Introduction', link: '/guide/' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
zh: {
|
||||
label: '简体中文',
|
||||
lang: 'zh-CN',
|
||||
link: '/zh/',
|
||||
title: '我的文档',
|
||||
description: '文档站点',
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{ text: '指南', link: '/zh/guide/' }
|
||||
],
|
||||
sidebar: {
|
||||
'/zh/guide/': [
|
||||
{ text: '介绍', link: '/zh/guide/' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Locale-Specific Properties
|
||||
|
||||
Each locale can override:
|
||||
|
||||
```ts
|
||||
interface LocaleSpecificConfig {
|
||||
lang?: string
|
||||
dir?: string // 'ltr' or 'rtl'
|
||||
title?: string
|
||||
titleTemplate?: string | boolean
|
||||
description?: string
|
||||
head?: HeadConfig[] // Merged with existing
|
||||
themeConfig?: ThemeConfig // Shallow merged
|
||||
}
|
||||
```
|
||||
|
||||
## Search i18n
|
||||
|
||||
### Local Search
|
||||
|
||||
```ts
|
||||
themeConfig: {
|
||||
search: {
|
||||
provider: 'local',
|
||||
options: {
|
||||
locales: {
|
||||
zh: {
|
||||
translations: {
|
||||
button: {
|
||||
buttonText: '搜索',
|
||||
buttonAriaLabel: '搜索'
|
||||
},
|
||||
modal: {
|
||||
noResultsText: '没有结果',
|
||||
resetButtonTitle: '重置搜索',
|
||||
footer: {
|
||||
selectText: '选择',
|
||||
navigateText: '导航',
|
||||
closeText: '关闭'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Algolia Search
|
||||
|
||||
```ts
|
||||
themeConfig: {
|
||||
search: {
|
||||
provider: 'algolia',
|
||||
options: {
|
||||
appId: '...',
|
||||
apiKey: '...',
|
||||
indexName: '...',
|
||||
locales: {
|
||||
zh: {
|
||||
placeholder: '搜索文档',
|
||||
translations: {
|
||||
button: { buttonText: '搜索文档' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Separate Locale Directories
|
||||
|
||||
For fully separated locales without root fallback:
|
||||
|
||||
```
|
||||
docs/
|
||||
├─ en/
|
||||
│ └─ index.md
|
||||
├─ zh/
|
||||
│ └─ index.md
|
||||
└─ fr/
|
||||
└─ index.md
|
||||
```
|
||||
|
||||
Requires server redirect for `/` → `/en/`. Netlify example:
|
||||
|
||||
```
|
||||
/* /en/:splat 302 Language=en
|
||||
/* /zh/:splat 302 Language=zh
|
||||
/* /en/:splat 302
|
||||
```
|
||||
|
||||
## Persisting Language Choice
|
||||
|
||||
Set cookie on language change:
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/Layout.vue -->
|
||||
<script setup>
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { useData, inBrowser } from 'vitepress'
|
||||
import { watchEffect } from 'vue'
|
||||
|
||||
const { lang } = useData()
|
||||
|
||||
watchEffect(() => {
|
||||
if (inBrowser) {
|
||||
document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultTheme.Layout />
|
||||
</template>
|
||||
```
|
||||
|
||||
## RTL Support (Experimental)
|
||||
|
||||
For right-to-left languages:
|
||||
|
||||
```ts
|
||||
locales: {
|
||||
ar: {
|
||||
label: 'العربية',
|
||||
lang: 'ar',
|
||||
dir: 'rtl'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Requires PostCSS plugin like `postcss-rtlcss`:
|
||||
|
||||
```ts
|
||||
// postcss.config.js
|
||||
import rtlcss from 'postcss-rtlcss'
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
rtlcss({
|
||||
ltrPrefix: ':where([dir="ltr"])',
|
||||
rtlPrefix: ':where([dir="rtl"])'
|
||||
})
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Organizing Config
|
||||
|
||||
Split config into separate files:
|
||||
|
||||
```
|
||||
.vitepress/
|
||||
├─ config/
|
||||
│ ├─ index.ts # Main config, merges locales
|
||||
│ ├─ en.ts # English config
|
||||
│ ├─ zh.ts # Chinese config
|
||||
│ └─ shared.ts # Shared config
|
||||
```
|
||||
|
||||
```ts
|
||||
// .vitepress/config/index.ts
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { shared } from './shared'
|
||||
import { en } from './en'
|
||||
import { zh } from './zh'
|
||||
|
||||
export default defineConfig({
|
||||
...shared,
|
||||
locales: {
|
||||
root: { label: 'English', ...en },
|
||||
zh: { label: '简体中文', ...zh }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Use `locales` object in config with `root` for default language
|
||||
- Each locale can override title, description, and themeConfig
|
||||
- `themeConfig` is shallow merged (define complete nav/sidebar per locale)
|
||||
- Don't override `themeConfig.algolia` at locale level
|
||||
- `dir: 'rtl'` enables RTL with PostCSS plugin
|
||||
- Language switcher appears automatically in nav
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/i18n
|
||||
-->
|
||||
228
skills/vitepress/references/advanced-ssr.md
Normal file
228
skills/vitepress/references/advanced-ssr.md
Normal file
@@ -0,0 +1,228 @@
|
||||
---
|
||||
name: vitepress-ssr-compatibility
|
||||
description: Server-side rendering compatibility, ClientOnly component, and handling browser-only code
|
||||
---
|
||||
|
||||
# SSR Compatibility
|
||||
|
||||
VitePress pre-renders pages on the server during build. All Vue code must be SSR-compatible.
|
||||
|
||||
## The Rule
|
||||
|
||||
Only access browser/DOM APIs in Vue lifecycle hooks:
|
||||
- `onMounted()`
|
||||
- `onBeforeMount()`
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const windowWidth = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
// Safe - runs only in browser
|
||||
windowWidth.value = window.innerWidth
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
**Do NOT** access at top level:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
// WRONG - runs during SSR where window doesn't exist
|
||||
const width = window.innerWidth
|
||||
</script>
|
||||
```
|
||||
|
||||
## ClientOnly Component
|
||||
|
||||
Wrap non-SSR-friendly components:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<BrowserOnlyComponent />
|
||||
</ClientOnly>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Libraries That Access Browser on Import
|
||||
|
||||
Some libraries access `window` or `document` when imported:
|
||||
|
||||
### Dynamic Import in onMounted
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
onMounted(async () => {
|
||||
const lib = await import('browser-only-library')
|
||||
lib.doSomething()
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### Conditional Import
|
||||
|
||||
```ts
|
||||
if (!import.meta.env.SSR) {
|
||||
const lib = await import('browser-only-library')
|
||||
lib.doSomething()
|
||||
}
|
||||
```
|
||||
|
||||
### In enhanceApp
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
export default {
|
||||
async enhanceApp({ app }) {
|
||||
if (!import.meta.env.SSR) {
|
||||
const plugin = await import('browser-plugin')
|
||||
app.use(plugin.default)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## defineClientComponent
|
||||
|
||||
Helper for components that access browser on import:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { defineClientComponent } from 'vitepress'
|
||||
|
||||
const BrowserComponent = defineClientComponent(() => {
|
||||
return import('browser-only-component')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BrowserComponent />
|
||||
</template>
|
||||
```
|
||||
|
||||
With props and slots:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { ref, h } from 'vue'
|
||||
import { defineClientComponent } from 'vitepress'
|
||||
|
||||
const componentRef = ref(null)
|
||||
|
||||
const BrowserComponent = defineClientComponent(
|
||||
() => import('browser-only-component'),
|
||||
// Props passed to h()
|
||||
[
|
||||
{ ref: componentRef, someProp: 'value' },
|
||||
{
|
||||
default: () => 'Default slot content',
|
||||
header: () => h('div', 'Header slot')
|
||||
}
|
||||
],
|
||||
// Callback after component loads
|
||||
() => {
|
||||
console.log('Component loaded', componentRef.value)
|
||||
}
|
||||
)
|
||||
</script>
|
||||
```
|
||||
|
||||
## Teleports
|
||||
|
||||
Teleport to body only with SSG:
|
||||
|
||||
```vue
|
||||
<ClientOnly>
|
||||
<Teleport to="body">
|
||||
<div class="modal">Modal content</div>
|
||||
</Teleport>
|
||||
</ClientOnly>
|
||||
```
|
||||
|
||||
For other targets, use `postRender` hook:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
async postRender(context) {
|
||||
// Inject teleport content into final HTML
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Common SSR Errors
|
||||
|
||||
### "window is not defined"
|
||||
|
||||
Code accesses `window` at module level:
|
||||
|
||||
```ts
|
||||
// BAD
|
||||
const width = window.innerWidth
|
||||
|
||||
// GOOD
|
||||
let width: number
|
||||
onMounted(() => {
|
||||
width = window.innerWidth
|
||||
})
|
||||
```
|
||||
|
||||
### "document is not defined"
|
||||
|
||||
Same issue with `document`:
|
||||
|
||||
```ts
|
||||
// BAD
|
||||
const el = document.querySelector('#app')
|
||||
|
||||
// GOOD
|
||||
onMounted(() => {
|
||||
const el = document.querySelector('#app')
|
||||
})
|
||||
```
|
||||
|
||||
### Hydration Mismatch
|
||||
|
||||
Server and client render different content:
|
||||
|
||||
```vue
|
||||
<!-- BAD - different on server vs client -->
|
||||
<div>{{ typeof window !== 'undefined' ? 'client' : 'server' }}</div>
|
||||
|
||||
<!-- GOOD - consistent -->
|
||||
<ClientOnly>
|
||||
<div>Client only content</div>
|
||||
</ClientOnly>
|
||||
```
|
||||
|
||||
## Checking Environment
|
||||
|
||||
```ts
|
||||
// In Vue component
|
||||
import.meta.env.SSR // true on server, false on client
|
||||
|
||||
// In VitePress
|
||||
import { inBrowser } from 'vitepress'
|
||||
if (inBrowser) {
|
||||
// Client-only code
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Access browser APIs only in `onMounted` or `onBeforeMount`
|
||||
- Use `<ClientOnly>` for non-SSR components
|
||||
- Use `defineClientComponent` for libraries that access browser on import
|
||||
- Check `import.meta.env.SSR` for environment-specific code
|
||||
- Teleport to body only, or use `postRender` hook
|
||||
- Consistent rendering prevents hydration mismatches
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/ssr-compat
|
||||
-->
|
||||
119
skills/vitepress/references/core-cli.md
Normal file
119
skills/vitepress/references/core-cli.md
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: vitepress-cli
|
||||
description: Command-line interface for development, building, and previewing VitePress sites
|
||||
---
|
||||
|
||||
# CLI Commands
|
||||
|
||||
VitePress provides four main commands: `dev`, `build`, `preview`, and `init`.
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the dev server with hot module replacement:
|
||||
|
||||
```bash
|
||||
# In current directory (dev command is optional)
|
||||
vitepress
|
||||
|
||||
# Or explicitly
|
||||
vitepress dev
|
||||
|
||||
# With project in subdirectory
|
||||
vitepress dev docs
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--open [path]` | Open browser on startup |
|
||||
| `--port <port>` | Specify port number |
|
||||
| `--base <path>` | Override base URL |
|
||||
| `--cors` | Enable CORS |
|
||||
| `--strictPort` | Exit if port is in use |
|
||||
| `--force` | Ignore cache and re-bundle |
|
||||
|
||||
```bash
|
||||
vitepress dev docs --port 3000 --open
|
||||
```
|
||||
|
||||
## Production Build
|
||||
|
||||
Build static files for production:
|
||||
|
||||
```bash
|
||||
vitepress build docs
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--base <path>` | Override base URL |
|
||||
| `--target <target>` | Transpile target (default: `modules`) |
|
||||
| `--outDir <dir>` | Output directory (relative to cwd) |
|
||||
| `--assetsInlineLimit <n>` | Asset inline threshold in bytes |
|
||||
| `--mpa` | Build in MPA mode (no client hydration) |
|
||||
|
||||
```bash
|
||||
vitepress build docs --outDir dist
|
||||
```
|
||||
|
||||
## Preview Production Build
|
||||
|
||||
Locally preview the production build:
|
||||
|
||||
```bash
|
||||
vitepress preview docs
|
||||
```
|
||||
|
||||
**Options:**
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--port <port>` | Specify port number |
|
||||
| `--base <path>` | Override base URL |
|
||||
|
||||
```bash
|
||||
vitepress preview docs --port 4173
|
||||
```
|
||||
|
||||
## Initialize Project
|
||||
|
||||
Start the setup wizard:
|
||||
|
||||
```bash
|
||||
vitepress init
|
||||
```
|
||||
|
||||
This creates the basic file structure:
|
||||
- `.vitepress/config.js` - Configuration
|
||||
- `index.md` - Home page
|
||||
- Optional example pages
|
||||
|
||||
## Package.json Scripts
|
||||
|
||||
Typical scripts configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Dev server runs at `http://localhost:5173` by default
|
||||
- Preview server runs at `http://localhost:4173`
|
||||
- Production output goes to `.vitepress/dist` by default
|
||||
- The `docs` argument specifies the project root directory
|
||||
- Use `--base` to override base path without modifying config
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/reference/cli
|
||||
-->
|
||||
189
skills/vitepress/references/core-config.md
Normal file
189
skills/vitepress/references/core-config.md
Normal file
@@ -0,0 +1,189 @@
|
||||
---
|
||||
name: vitepress-configuration
|
||||
description: Config file setup, defineConfig helper, site metadata, and build options
|
||||
---
|
||||
|
||||
# Configuration
|
||||
|
||||
VitePress configuration is defined in `.vitepress/config.[js|ts|mjs|mts]`. Use `defineConfig` for TypeScript intellisense.
|
||||
|
||||
## Basic Config
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
// Site metadata
|
||||
title: 'My Docs',
|
||||
description: 'Documentation site',
|
||||
lang: 'en-US',
|
||||
|
||||
// URL base path (for GitHub Pages: '/repo-name/')
|
||||
base: '/',
|
||||
|
||||
// Theme configuration
|
||||
themeConfig: {
|
||||
// See theme-config.md
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Site Metadata
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
title: 'VitePress', // Displayed in nav, used in page titles
|
||||
titleTemplate: ':title - Docs', // Page title format (:title = h1)
|
||||
description: 'Site description', // Meta description
|
||||
lang: 'en-US', // HTML lang attribute
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', href: '/favicon.ico' }],
|
||||
['meta', { name: 'theme-color', content: '#5f67ee' }],
|
||||
['script', { async: '', src: 'https://analytics.example.com/script.js' }]
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
## Build Options
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
// Source files directory (relative to project root)
|
||||
srcDir: './src',
|
||||
|
||||
// Exclude patterns from source
|
||||
srcExclude: ['**/README.md', '**/TODO.md'],
|
||||
|
||||
// Output directory
|
||||
outDir: './.vitepress/dist',
|
||||
|
||||
// Cache directory
|
||||
cacheDir: './.vitepress/cache',
|
||||
|
||||
// Clean URLs without .html extension (requires server support)
|
||||
cleanUrls: true,
|
||||
|
||||
// Ignore dead links during build
|
||||
ignoreDeadLinks: true,
|
||||
// Or specific patterns:
|
||||
ignoreDeadLinks: ['/playground', /^https?:\/\/localhost/],
|
||||
|
||||
// Get last updated timestamp from git
|
||||
lastUpdated: true
|
||||
})
|
||||
```
|
||||
|
||||
## Route Rewrites
|
||||
|
||||
Map source paths to different output paths:
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
rewrites: {
|
||||
// Static mapping
|
||||
'packages/pkg-a/src/index.md': 'pkg-a/index.md',
|
||||
|
||||
// Dynamic parameters
|
||||
'packages/:pkg/src/:slug*': ':pkg/:slug*'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Appearance (Dark Mode)
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
appearance: true, // Enable toggle (default)
|
||||
appearance: 'dark', // Dark by default
|
||||
appearance: 'force-dark', // Always dark, no toggle
|
||||
appearance: 'force-auto', // Always follow system preference
|
||||
appearance: false // Disable dark mode
|
||||
})
|
||||
```
|
||||
|
||||
## Vite & Vue Configuration
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
// Pass options to Vite
|
||||
vite: {
|
||||
plugins: [],
|
||||
resolve: { alias: {} },
|
||||
css: { preprocessorOptions: {} }
|
||||
},
|
||||
|
||||
// Pass options to @vitejs/plugin-vue
|
||||
vue: {
|
||||
template: { compilerOptions: {} }
|
||||
},
|
||||
|
||||
// Configure markdown-it
|
||||
markdown: {
|
||||
lineNumbers: true,
|
||||
toc: { level: [1, 2, 3] },
|
||||
math: true, // Requires markdown-it-mathjax3
|
||||
container: {
|
||||
tipLabel: 'TIP',
|
||||
warningLabel: 'WARNING',
|
||||
dangerLabel: 'DANGER'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Build Hooks
|
||||
|
||||
```ts
|
||||
export default defineConfig({
|
||||
// Transform page data
|
||||
transformPageData(pageData, { siteConfig }) {
|
||||
pageData.frontmatter.head ??= []
|
||||
pageData.frontmatter.head.push([
|
||||
'meta', { name: 'og:title', content: pageData.title }
|
||||
])
|
||||
},
|
||||
|
||||
// Transform head before generating each page
|
||||
async transformHead(context) {
|
||||
return [['meta', { name: 'custom', content: context.page }]]
|
||||
},
|
||||
|
||||
// After build completes
|
||||
async buildEnd(siteConfig) {
|
||||
// Generate sitemap, RSS, etc.
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Dynamic Config
|
||||
|
||||
For async configuration:
|
||||
|
||||
```ts
|
||||
export default async () => {
|
||||
const data = await fetch('https://api.example.com/data').then(r => r.json())
|
||||
|
||||
return defineConfig({
|
||||
title: data.title,
|
||||
themeConfig: {
|
||||
sidebar: data.sidebar
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Config file supports `.js`, `.ts`, `.mjs`, `.mts` extensions
|
||||
- Use `defineConfig` for TypeScript support
|
||||
- `base` must start and end with `/` for sub-path deployments
|
||||
- `srcDir` separates source files from project root
|
||||
- Build hooks enable custom transformations and post-processing
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/reference/site-config
|
||||
- https://vitepress.dev/guide/getting-started
|
||||
-->
|
||||
277
skills/vitepress/references/core-markdown.md
Normal file
277
skills/vitepress/references/core-markdown.md
Normal file
@@ -0,0 +1,277 @@
|
||||
---
|
||||
name: vitepress-markdown
|
||||
description: Markdown extensions including frontmatter, custom containers, tables, anchors, and file includes
|
||||
---
|
||||
|
||||
# Markdown Extensions
|
||||
|
||||
VitePress extends standard markdown with additional features for documentation.
|
||||
|
||||
## Frontmatter
|
||||
|
||||
YAML metadata at the top of markdown files:
|
||||
|
||||
```md
|
||||
---
|
||||
title: Page Title
|
||||
description: Page description for SEO
|
||||
layout: doc
|
||||
outline: [2, 3]
|
||||
---
|
||||
|
||||
# Content starts here
|
||||
```
|
||||
|
||||
Access frontmatter in templates:
|
||||
|
||||
```md
|
||||
# {{ $frontmatter.title }}
|
||||
```
|
||||
|
||||
Or in script:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
const { frontmatter } = useData()
|
||||
</script>
|
||||
```
|
||||
|
||||
## Custom Containers
|
||||
|
||||
Styled callout blocks:
|
||||
|
||||
```md
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details Click to expand
|
||||
Hidden content here.
|
||||
:::
|
||||
```
|
||||
|
||||
Custom titles:
|
||||
|
||||
```md
|
||||
::: danger STOP
|
||||
Do not proceed!
|
||||
:::
|
||||
|
||||
::: details Click me {open}
|
||||
Open by default with {open} attribute.
|
||||
:::
|
||||
```
|
||||
|
||||
## GitHub-flavored Alerts
|
||||
|
||||
Alternative syntax using blockquotes:
|
||||
|
||||
```md
|
||||
> [!NOTE]
|
||||
> Highlights information users should know.
|
||||
|
||||
> [!TIP]
|
||||
> Optional information for success.
|
||||
|
||||
> [!WARNING]
|
||||
> Critical content requiring attention.
|
||||
|
||||
> [!CAUTION]
|
||||
> Negative potential consequences.
|
||||
```
|
||||
|
||||
## Header Anchors
|
||||
|
||||
Headers get automatic anchor links. Custom anchors:
|
||||
|
||||
```md
|
||||
# My Heading {#custom-anchor}
|
||||
|
||||
[Link to heading](#custom-anchor)
|
||||
```
|
||||
|
||||
## Table of Contents
|
||||
|
||||
Generate a TOC with:
|
||||
|
||||
```md
|
||||
[[toc]]
|
||||
```
|
||||
|
||||
## GitHub-Style Tables
|
||||
|
||||
```md
|
||||
| Feature | Status |
|
||||
|---------|--------|
|
||||
| SSR | ✅ |
|
||||
| HMR | ✅ |
|
||||
```
|
||||
|
||||
## Emoji
|
||||
|
||||
Use shortcodes:
|
||||
|
||||
```md
|
||||
:tada: :rocket: :100:
|
||||
```
|
||||
|
||||
## File Includes
|
||||
|
||||
Include content from other files:
|
||||
|
||||
```md
|
||||
<!--@include: ./shared/header.md-->
|
||||
```
|
||||
|
||||
With line ranges:
|
||||
|
||||
```md
|
||||
<!--@include: ./code.md{3,10}--> <!-- Lines 3-10 -->
|
||||
<!--@include: ./code.md{3,}--> <!-- From line 3 -->
|
||||
<!--@include: ./code.md{,10}--> <!-- Up to line 10 -->
|
||||
```
|
||||
|
||||
With regions:
|
||||
|
||||
```md
|
||||
<!-- In parts/basics.md -->
|
||||
<!-- #region usage -->
|
||||
Usage content here
|
||||
<!-- #endregion usage -->
|
||||
|
||||
<!-- Include just that region -->
|
||||
<!--@include: ./parts/basics.md#usage-->
|
||||
```
|
||||
|
||||
## Code Snippet Import
|
||||
|
||||
Import code from files:
|
||||
|
||||
```md
|
||||
<<< @/snippets/example.js
|
||||
```
|
||||
|
||||
With line highlighting:
|
||||
|
||||
```md
|
||||
<<< @/snippets/example.js{2,4-6}
|
||||
```
|
||||
|
||||
With language override:
|
||||
|
||||
```md
|
||||
<<< @/snippets/example.cs{1,2 c#:line-numbers}
|
||||
```
|
||||
|
||||
Import specific region:
|
||||
|
||||
```md
|
||||
<<< @/snippets/example.js#regionName{1,2}
|
||||
```
|
||||
|
||||
## Code Groups
|
||||
|
||||
Tab groups for code variants:
|
||||
|
||||
````md
|
||||
::: code-group
|
||||
|
||||
```js [config.js]
|
||||
export default { /* ... */ }
|
||||
```
|
||||
|
||||
```ts [config.ts]
|
||||
export default defineConfig({ /* ... */ })
|
||||
```
|
||||
|
||||
:::
|
||||
````
|
||||
|
||||
Import files in code groups:
|
||||
|
||||
```md
|
||||
::: code-group
|
||||
|
||||
<<< @/snippets/config.js
|
||||
<<< @/snippets/config.ts
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
## Math Equations
|
||||
|
||||
Requires setup:
|
||||
|
||||
```bash
|
||||
npm add -D markdown-it-mathjax3@^4
|
||||
```
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
markdown: {
|
||||
math: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then use LaTeX:
|
||||
|
||||
```md
|
||||
Inline: $E = mc^2$
|
||||
|
||||
Block:
|
||||
$$
|
||||
\frac{-b \pm \sqrt{b^2-4ac}}{2a}
|
||||
$$
|
||||
```
|
||||
|
||||
## Image Lazy Loading
|
||||
|
||||
```ts
|
||||
export default {
|
||||
markdown: {
|
||||
image: {
|
||||
lazyLoading: true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Raw Container
|
||||
|
||||
Prevent VitePress style conflicts:
|
||||
|
||||
```md
|
||||
::: raw
|
||||
<CustomComponent />
|
||||
:::
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Frontmatter supports YAML or JSON format
|
||||
- Custom containers support info, tip, warning, danger, details
|
||||
- `[[toc]]` generates table of contents
|
||||
- `@` in imports refers to source root (or `srcDir` if configured)
|
||||
- Code groups create tabbed code blocks
|
||||
- Math support requires markdown-it-mathjax3 package
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/markdown
|
||||
- https://vitepress.dev/guide/frontmatter
|
||||
-->
|
||||
169
skills/vitepress/references/core-routing.md
Normal file
169
skills/vitepress/references/core-routing.md
Normal file
@@ -0,0 +1,169 @@
|
||||
---
|
||||
name: vitepress-routing
|
||||
description: File-based routing, source directory structure, clean URLs, and route rewrites
|
||||
---
|
||||
|
||||
# Routing
|
||||
|
||||
VitePress uses file-based routing where markdown files map directly to HTML pages.
|
||||
|
||||
## File to URL Mapping
|
||||
|
||||
```
|
||||
.
|
||||
├─ index.md → /index.html (/)
|
||||
├─ about.md → /about.html
|
||||
├─ guide/
|
||||
│ ├─ index.md → /guide/index.html (/guide/)
|
||||
│ └─ getting-started.md → /guide/getting-started.html
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
.
|
||||
├─ docs # Project root
|
||||
│ ├─ .vitepress # VitePress directory
|
||||
│ │ ├─ config.ts # Configuration
|
||||
│ │ ├─ theme/ # Custom theme
|
||||
│ │ ├─ cache/ # Dev server cache (gitignore)
|
||||
│ │ └─ dist/ # Build output (gitignore)
|
||||
│ ├─ public/ # Static assets (copied as-is)
|
||||
│ ├─ index.md # Home page
|
||||
│ └─ guide/
|
||||
│ └─ intro.md
|
||||
```
|
||||
|
||||
## Source Directory
|
||||
|
||||
Separate source files from project root:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
srcDir: './src' // Markdown files live in ./src/
|
||||
}
|
||||
```
|
||||
|
||||
With `srcDir: 'src'`:
|
||||
|
||||
```
|
||||
.
|
||||
├─ .vitepress/ # Config stays at project root
|
||||
└─ src/ # Source directory
|
||||
├─ index.md → /
|
||||
└─ guide/intro.md → /guide/intro.html
|
||||
```
|
||||
|
||||
## Linking Between Pages
|
||||
|
||||
Use relative or absolute paths. Omit file extensions:
|
||||
|
||||
```md
|
||||
<!-- Recommended -->
|
||||
[Getting Started](./getting-started)
|
||||
[Guide](/guide/)
|
||||
|
||||
<!-- Works but not recommended -->
|
||||
[Getting Started](./getting-started.md)
|
||||
[Getting Started](./getting-started.html)
|
||||
```
|
||||
|
||||
## Clean URLs
|
||||
|
||||
Remove `.html` extension from URLs (requires server support):
|
||||
|
||||
```ts
|
||||
export default {
|
||||
cleanUrls: true
|
||||
}
|
||||
```
|
||||
|
||||
**Server requirements:**
|
||||
- Netlify, GitHub Pages: Supported by default
|
||||
- Vercel: Enable `cleanUrls` in `vercel.json`
|
||||
- Nginx: Configure `try_files $uri $uri.html $uri/ =404`
|
||||
|
||||
## Route Rewrites
|
||||
|
||||
Customize the mapping between source and output paths:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
rewrites: {
|
||||
// Static mapping
|
||||
'packages/pkg-a/src/index.md': 'pkg-a/index.md',
|
||||
'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',
|
||||
|
||||
// Dynamic parameters
|
||||
'packages/:pkg/src/:slug*': ':pkg/:slug*'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This maps `packages/pkg-a/src/intro.md` → `/pkg-a/intro.html`.
|
||||
|
||||
**Important:** Relative links in rewritten files should be based on the rewritten path, not the source path.
|
||||
|
||||
Rewrites can also be a function:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
rewrites(id) {
|
||||
return id.replace(/^packages\/([^/]+)\/src\//, '$1/')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Public Directory
|
||||
|
||||
Files in `public/` are copied to output root as-is:
|
||||
|
||||
```
|
||||
docs/public/
|
||||
├─ favicon.ico → /favicon.ico
|
||||
├─ robots.txt → /robots.txt
|
||||
└─ images/logo.png → /images/logo.png
|
||||
```
|
||||
|
||||
Reference with absolute paths:
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
## Base URL
|
||||
|
||||
For sub-path deployment (e.g., GitHub Pages):
|
||||
|
||||
```ts
|
||||
export default {
|
||||
base: '/repo-name/'
|
||||
}
|
||||
```
|
||||
|
||||
All absolute paths are automatically prefixed with base. For dynamic paths in components, use `withBase`:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { withBase } from 'vitepress'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<img :src="withBase('/logo.png')" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- `index.md` files map to directory root (`/guide/` instead of `/guide/index`)
|
||||
- Use paths without extensions in links for flexibility
|
||||
- `srcDir` separates source from config
|
||||
- `cleanUrls` removes `.html` but requires server support
|
||||
- `rewrites` enables complex source structures with clean output URLs
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/routing
|
||||
- https://vitepress.dev/guide/asset-handling
|
||||
-->
|
||||
243
skills/vitepress/references/features-code-blocks.md
Normal file
243
skills/vitepress/references/features-code-blocks.md
Normal file
@@ -0,0 +1,243 @@
|
||||
---
|
||||
name: vitepress-code-blocks
|
||||
description: Syntax highlighting, line highlighting, colored diffs, focus, and line numbers
|
||||
---
|
||||
|
||||
# Code Blocks
|
||||
|
||||
VitePress uses Shiki for syntax highlighting with powerful code block features.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
Specify language after opening backticks:
|
||||
|
||||
````md
|
||||
```js
|
||||
export default {
|
||||
name: 'MyComponent'
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Supports [all languages](https://shiki.style/languages) available in Shiki.
|
||||
|
||||
## Line Highlighting
|
||||
|
||||
Highlight specific lines:
|
||||
|
||||
````md
|
||||
```js{4}
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Highlighted!' // Line 4 highlighted
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Multiple lines and ranges:
|
||||
|
||||
````md
|
||||
```js{1,4,6-8}
|
||||
// Line 1 highlighted
|
||||
export default {
|
||||
data() {
|
||||
return { // Line 4
|
||||
msg: 'Hi',
|
||||
foo: 'bar', // Lines 6-8
|
||||
baz: 'qux'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Inline highlighting with comment:
|
||||
|
||||
````md
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Highlighted!' // [!code highlight]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Focus
|
||||
|
||||
Blur other code and focus specific lines:
|
||||
|
||||
````md
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Focused!' // [!code focus]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Focus multiple lines:
|
||||
|
||||
```js
|
||||
// [!code focus:3]
|
||||
```
|
||||
|
||||
## Colored Diffs
|
||||
|
||||
Show additions and removals:
|
||||
|
||||
````md
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Removed' // [!code --]
|
||||
msg: 'Added' // [!code ++]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Errors and Warnings
|
||||
|
||||
Color lines as errors or warnings:
|
||||
|
||||
````md
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msg: 'Error', // [!code error]
|
||||
msg: 'Warning' // [!code warning]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Line Numbers
|
||||
|
||||
Enable globally:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
markdown: {
|
||||
lineNumbers: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Per-block override:
|
||||
|
||||
````md
|
||||
```ts:line-numbers
|
||||
// Line numbers enabled
|
||||
const a = 1
|
||||
```
|
||||
|
||||
```ts:no-line-numbers
|
||||
// Line numbers disabled
|
||||
const b = 2
|
||||
```
|
||||
````
|
||||
|
||||
Start from specific number:
|
||||
|
||||
````md
|
||||
```ts:line-numbers=5
|
||||
// Starts at line 5
|
||||
const a = 1 // This is line 5
|
||||
const b = 2 // This is line 6
|
||||
```
|
||||
````
|
||||
|
||||
## Code Groups
|
||||
|
||||
Tabbed code blocks:
|
||||
|
||||
````md
|
||||
::: code-group
|
||||
|
||||
```js [JavaScript]
|
||||
export default { /* ... */ }
|
||||
```
|
||||
|
||||
```ts [TypeScript]
|
||||
export default defineConfig({ /* ... */ })
|
||||
```
|
||||
|
||||
:::
|
||||
````
|
||||
|
||||
## Import Code Snippets
|
||||
|
||||
From external files:
|
||||
|
||||
```md
|
||||
<<< @/snippets/snippet.js
|
||||
```
|
||||
|
||||
With highlighting:
|
||||
|
||||
```md
|
||||
<<< @/snippets/snippet.js{2,4-6}
|
||||
```
|
||||
|
||||
Specific region:
|
||||
|
||||
```md
|
||||
<<< @/snippets/snippet.js#regionName{1,2}
|
||||
```
|
||||
|
||||
With language and line numbers:
|
||||
|
||||
```md
|
||||
<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}
|
||||
```
|
||||
|
||||
In code groups:
|
||||
|
||||
```md
|
||||
::: code-group
|
||||
|
||||
<<< @/snippets/config.js [JavaScript]
|
||||
<<< @/snippets/config.ts [TypeScript]
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
## File Labels
|
||||
|
||||
Add filename labels to code blocks:
|
||||
|
||||
````md
|
||||
```js [vite.config.js]
|
||||
export default defineConfig({})
|
||||
```
|
||||
````
|
||||
|
||||
## Key Points
|
||||
|
||||
- Use `// [!code highlight]` for inline highlighting
|
||||
- Use `// [!code focus]` to focus with blur effect
|
||||
- Use `// [!code ++]` and `// [!code --]` for diffs
|
||||
- Use `// [!code error]` and `// [!code warning]` for status
|
||||
- `:line-numbers` and `:no-line-numbers` control line numbers per block
|
||||
- `@` in imports refers to source root
|
||||
- Code groups create tabbed interfaces
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/markdown#syntax-highlighting-in-code-blocks
|
||||
- https://vitepress.dev/guide/markdown#line-highlighting-in-code-blocks
|
||||
-->
|
||||
220
skills/vitepress/references/features-data-loading.md
Normal file
220
skills/vitepress/references/features-data-loading.md
Normal file
@@ -0,0 +1,220 @@
|
||||
---
|
||||
name: vitepress-data-loading
|
||||
description: Build-time data loaders for fetching remote data or processing local files
|
||||
---
|
||||
|
||||
# Data Loading
|
||||
|
||||
VitePress data loaders run at build time to load arbitrary data that's serialized as JSON in the client bundle.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Create a file ending with `.data.js` or `.data.ts`:
|
||||
|
||||
```ts
|
||||
// example.data.ts
|
||||
export default {
|
||||
load() {
|
||||
return {
|
||||
hello: 'world',
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Import the `data` named export:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { data } from './example.data.ts'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<pre>{{ data }}</pre>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Async Data
|
||||
|
||||
Fetch remote data:
|
||||
|
||||
```ts
|
||||
// api.data.ts
|
||||
export default {
|
||||
async load() {
|
||||
const response = await fetch('https://api.example.com/data')
|
||||
return response.json()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Local Files with Watch
|
||||
|
||||
Process local files with hot reload:
|
||||
|
||||
```ts
|
||||
// posts.data.ts
|
||||
import fs from 'node:fs'
|
||||
import { parse } from 'csv-parse/sync'
|
||||
|
||||
export default {
|
||||
watch: ['./data/*.csv'],
|
||||
load(watchedFiles) {
|
||||
// watchedFiles = array of absolute paths
|
||||
return watchedFiles.map(file => {
|
||||
return parse(fs.readFileSync(file, 'utf-8'), {
|
||||
columns: true,
|
||||
skip_empty_lines: true
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## createContentLoader
|
||||
|
||||
Helper for loading markdown content (common for blogs/archives):
|
||||
|
||||
```ts
|
||||
// posts.data.ts
|
||||
import { createContentLoader } from 'vitepress'
|
||||
|
||||
export default createContentLoader('posts/*.md')
|
||||
```
|
||||
|
||||
Returns array of `ContentData`:
|
||||
|
||||
```ts
|
||||
interface ContentData {
|
||||
url: string // e.g. /posts/hello.html
|
||||
frontmatter: Record<string, any>
|
||||
src?: string // raw markdown (opt-in)
|
||||
html?: string // rendered HTML (opt-in)
|
||||
excerpt?: string // excerpt HTML (opt-in)
|
||||
}
|
||||
```
|
||||
|
||||
With options:
|
||||
|
||||
```ts
|
||||
// posts.data.ts
|
||||
import { createContentLoader } from 'vitepress'
|
||||
|
||||
export default createContentLoader('posts/*.md', {
|
||||
includeSrc: true, // Include raw markdown
|
||||
render: true, // Include rendered HTML
|
||||
excerpt: true, // Include excerpt (content before first ---)
|
||||
|
||||
transform(rawData) {
|
||||
// Sort by date, newest first
|
||||
return rawData
|
||||
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
|
||||
.map(page => ({
|
||||
title: page.frontmatter.title,
|
||||
url: page.url,
|
||||
date: page.frontmatter.date,
|
||||
excerpt: page.excerpt
|
||||
}))
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Usage Example: Blog Index
|
||||
|
||||
```ts
|
||||
// posts.data.ts
|
||||
import { createContentLoader } from 'vitepress'
|
||||
|
||||
export default createContentLoader('posts/*.md', {
|
||||
excerpt: true,
|
||||
transform(data) {
|
||||
return data
|
||||
.filter(post => !post.frontmatter.draft)
|
||||
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- posts/index.md -->
|
||||
<script setup>
|
||||
import { data as posts } from './posts.data.ts'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="post in posts" :key="post.url">
|
||||
<a :href="post.url">{{ post.frontmatter.title }}</a>
|
||||
<span>{{ post.frontmatter.date }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Typed Data Loaders
|
||||
|
||||
```ts
|
||||
// example.data.ts
|
||||
import { defineLoader } from 'vitepress'
|
||||
|
||||
export interface Data {
|
||||
posts: Array<{ title: string; url: string }>
|
||||
}
|
||||
|
||||
declare const data: Data
|
||||
export { data }
|
||||
|
||||
export default defineLoader({
|
||||
watch: ['./posts/*.md'],
|
||||
async load(): Promise<Data> {
|
||||
// ...
|
||||
return { posts: [] }
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## In Build Hooks
|
||||
|
||||
Use in config for generating additional files:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
import { createContentLoader } from 'vitepress'
|
||||
|
||||
export default {
|
||||
async buildEnd() {
|
||||
const posts = await createContentLoader('posts/*.md').load()
|
||||
// Generate RSS feed, sitemap, etc.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Accessing Config
|
||||
|
||||
```ts
|
||||
// example.data.ts
|
||||
import type { SiteConfig } from 'vitepress'
|
||||
|
||||
export default {
|
||||
load() {
|
||||
const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG
|
||||
return { base: config.site.base }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Data loaders run only at build time in Node.js
|
||||
- File must end with `.data.js` or `.data.ts`
|
||||
- Import the `data` named export (not default)
|
||||
- Use `watch` for local file hot reload during dev
|
||||
- `createContentLoader` simplifies loading markdown collections
|
||||
- Keep data small - it's inlined in the client bundle
|
||||
- Heavy data should use `transform` to reduce payload
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/data-loading
|
||||
-->
|
||||
235
skills/vitepress/references/features-dynamic-routes.md
Normal file
235
skills/vitepress/references/features-dynamic-routes.md
Normal file
@@ -0,0 +1,235 @@
|
||||
---
|
||||
name: vitepress-dynamic-routes
|
||||
description: Generate multiple pages from a single markdown template using paths loader files
|
||||
---
|
||||
|
||||
# Dynamic Routes
|
||||
|
||||
Generate many pages from a single markdown file and dynamic data. Useful for blogs, package docs, or any data-driven pages.
|
||||
|
||||
## Basic Setup
|
||||
|
||||
Create a template file with parameter in brackets and a paths loader:
|
||||
|
||||
```
|
||||
.
|
||||
└─ packages/
|
||||
├─ [pkg].md # Route template
|
||||
└─ [pkg].paths.js # Paths loader
|
||||
```
|
||||
|
||||
The paths loader exports a `paths` method returning route parameters:
|
||||
|
||||
```js
|
||||
// packages/[pkg].paths.js
|
||||
export default {
|
||||
paths() {
|
||||
return [
|
||||
{ params: { pkg: 'foo' }},
|
||||
{ params: { pkg: 'bar' }},
|
||||
{ params: { pkg: 'baz' }}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated pages:
|
||||
- `/packages/foo.html`
|
||||
- `/packages/bar.html`
|
||||
- `/packages/baz.html`
|
||||
|
||||
## Multiple Parameters
|
||||
|
||||
```
|
||||
.
|
||||
└─ packages/
|
||||
├─ [pkg]-[version].md
|
||||
└─ [pkg]-[version].paths.js
|
||||
```
|
||||
|
||||
```js
|
||||
// packages/[pkg]-[version].paths.js
|
||||
export default {
|
||||
paths() {
|
||||
return [
|
||||
{ params: { pkg: 'foo', version: '1.0.0' }},
|
||||
{ params: { pkg: 'foo', version: '2.0.0' }},
|
||||
{ params: { pkg: 'bar', version: '1.0.0' }}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Dynamic Path Generation
|
||||
|
||||
From local files:
|
||||
|
||||
```js
|
||||
// packages/[pkg].paths.js
|
||||
import fs from 'node:fs'
|
||||
|
||||
export default {
|
||||
paths() {
|
||||
return fs.readdirSync('packages').map(pkg => ({
|
||||
params: { pkg }
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
From remote API:
|
||||
|
||||
```js
|
||||
// packages/[pkg].paths.js
|
||||
export default {
|
||||
async paths() {
|
||||
const packages = await fetch('https://api.example.com/packages').then(r => r.json())
|
||||
|
||||
return packages.map(pkg => ({
|
||||
params: {
|
||||
pkg: pkg.name,
|
||||
version: pkg.version
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Accessing Params in Page
|
||||
|
||||
Template globals:
|
||||
|
||||
```md
|
||||
<!-- packages/[pkg].md -->
|
||||
# Package: {{ $params.pkg }}
|
||||
|
||||
Version: {{ $params.version }}
|
||||
```
|
||||
|
||||
In script:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
const { params } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ params.pkg }}</h1>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Passing Content
|
||||
|
||||
For heavy content (raw markdown/HTML from CMS), use `content` instead of params to avoid bloating the client bundle:
|
||||
|
||||
```js
|
||||
// posts/[slug].paths.js
|
||||
export default {
|
||||
async paths() {
|
||||
const posts = await fetch('https://cms.example.com/posts').then(r => r.json())
|
||||
|
||||
return posts.map(post => ({
|
||||
params: { slug: post.slug },
|
||||
content: post.content // Raw markdown or HTML
|
||||
}))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Render content in template:
|
||||
|
||||
```md
|
||||
<!-- posts/[slug].md -->
|
||||
---
|
||||
title: {{ $params.title }}
|
||||
---
|
||||
|
||||
<!-- @content -->
|
||||
```
|
||||
|
||||
The `<!-- @content -->` placeholder is replaced with the content from the paths loader.
|
||||
|
||||
## Watch Option
|
||||
|
||||
Auto-rebuild when template or data files change:
|
||||
|
||||
```js
|
||||
// posts/[slug].paths.js
|
||||
export default {
|
||||
watch: [
|
||||
'./templates/**/*.njk',
|
||||
'../data/**/*.json'
|
||||
],
|
||||
|
||||
paths(watchedFiles) {
|
||||
const dataFiles = watchedFiles.filter(f => f.endsWith('.json'))
|
||||
|
||||
return dataFiles.map(file => {
|
||||
const data = JSON.parse(fs.readFileSync(file, 'utf-8'))
|
||||
return {
|
||||
params: { slug: data.slug },
|
||||
content: renderTemplate(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Example: Blog
|
||||
|
||||
```js
|
||||
// posts/[slug].paths.js
|
||||
import fs from 'node:fs'
|
||||
import matter from 'gray-matter'
|
||||
|
||||
export default {
|
||||
watch: ['./posts/*.md'],
|
||||
|
||||
paths(files) {
|
||||
return files
|
||||
.filter(f => !f.includes('[slug]'))
|
||||
.map(file => {
|
||||
const content = fs.readFileSync(file, 'utf-8')
|
||||
const { data, content: body } = matter(content)
|
||||
const slug = file.match(/([^/]+)\.md$/)[1]
|
||||
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
title: data.title,
|
||||
date: data.date
|
||||
},
|
||||
content: body
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```md
|
||||
<!-- posts/[slug].md -->
|
||||
---
|
||||
layout: doc
|
||||
---
|
||||
|
||||
# {{ $params.title }}
|
||||
|
||||
<time>{{ $params.date }}</time>
|
||||
|
||||
<!-- @content -->
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Template file uses `[param]` syntax in filename
|
||||
- Paths loader file must be named `[param].paths.js` or `.ts`
|
||||
- `paths()` returns array of `{ params: {...}, content?: string }`
|
||||
- Use `$params` in templates or `useData().params` in scripts
|
||||
- Use `content` for heavy data to avoid client bundle bloat
|
||||
- `watch` enables HMR for template/data file changes
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/routing#dynamic-routes
|
||||
-->
|
||||
224
skills/vitepress/references/features-vue.md
Normal file
224
skills/vitepress/references/features-vue.md
Normal file
@@ -0,0 +1,224 @@
|
||||
---
|
||||
name: vue-in-vitepress-markdown
|
||||
description: Using Vue components, script setup, directives, and templating in markdown files
|
||||
---
|
||||
|
||||
# Vue in Markdown
|
||||
|
||||
VitePress markdown files are compiled as Vue Single-File Components, enabling full Vue functionality.
|
||||
|
||||
## Interpolation
|
||||
|
||||
Vue expressions work in markdown:
|
||||
|
||||
```md
|
||||
{{ 1 + 1 }}
|
||||
|
||||
{{ new Date().toLocaleDateString() }}
|
||||
```
|
||||
|
||||
## Directives
|
||||
|
||||
HTML with Vue directives:
|
||||
|
||||
```md
|
||||
<span v-for="i in 3">{{ i }}</span>
|
||||
|
||||
<div v-if="$frontmatter.showBanner">
|
||||
Banner content
|
||||
</div>
|
||||
```
|
||||
|
||||
## Script and Style
|
||||
|
||||
Add `<script setup>` and `<style>` after frontmatter:
|
||||
|
||||
```md
|
||||
---
|
||||
title: My Page
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
const count = ref(0)
|
||||
</script>
|
||||
|
||||
# {{ $frontmatter.title }}
|
||||
|
||||
Count: {{ count }}
|
||||
|
||||
<button @click="count++">Increment</button>
|
||||
|
||||
<MyComponent />
|
||||
|
||||
<style module>
|
||||
.button {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**Note:** Use `<style module>` instead of `<style scoped>` to avoid bloating page size.
|
||||
|
||||
## Importing Components
|
||||
|
||||
Local import (code-split per page):
|
||||
|
||||
```md
|
||||
<script setup>
|
||||
import CustomComponent from '../components/CustomComponent.vue'
|
||||
</script>
|
||||
|
||||
<CustomComponent />
|
||||
```
|
||||
|
||||
## Global Components
|
||||
|
||||
Register in theme for use everywhere:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyGlobalComponent from './MyGlobalComponent.vue'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
app.component('MyGlobalComponent', MyGlobalComponent)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then use in any markdown:
|
||||
|
||||
```md
|
||||
<MyGlobalComponent />
|
||||
```
|
||||
|
||||
**Important:** Component names must contain a hyphen or be PascalCase to avoid being treated as inline HTML elements.
|
||||
|
||||
## Runtime API
|
||||
|
||||
Access VitePress data:
|
||||
|
||||
```md
|
||||
<script setup>
|
||||
import { useData, useRoute, useRouter } from 'vitepress'
|
||||
|
||||
const { page, frontmatter, theme, site } = useData()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
</script>
|
||||
|
||||
Current page: {{ page.relativePath }}
|
||||
```
|
||||
|
||||
## Global Variables
|
||||
|
||||
Available without import:
|
||||
|
||||
```md
|
||||
# {{ $frontmatter.title }}
|
||||
|
||||
Params: {{ $params.id }}
|
||||
```
|
||||
|
||||
## Components in Headers
|
||||
|
||||
```md
|
||||
# My Title <Badge type="tip" text="v2.0" />
|
||||
```
|
||||
|
||||
## Escaping Vue Syntax
|
||||
|
||||
Prevent Vue interpolation:
|
||||
|
||||
```md
|
||||
<span v-pre>{{ will be displayed as-is }}</span>
|
||||
```
|
||||
|
||||
Or use container:
|
||||
|
||||
```md
|
||||
::: v-pre
|
||||
{{ this won't be processed }}
|
||||
:::
|
||||
```
|
||||
|
||||
## Vue in Code Blocks
|
||||
|
||||
Enable Vue processing in fenced code with `-vue` suffix:
|
||||
|
||||
````md
|
||||
```js-vue
|
||||
Hello {{ 1 + 1 }}
|
||||
```
|
||||
````
|
||||
|
||||
## CSS Pre-processors
|
||||
|
||||
Supported out of the box (install the preprocessor):
|
||||
|
||||
```bash
|
||||
npm install -D sass # for .scss/.sass
|
||||
npm install -D less # for .less
|
||||
npm install -D stylus # for .styl/.stylus
|
||||
```
|
||||
|
||||
```vue
|
||||
<style lang="scss">
|
||||
.title {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Using Teleports
|
||||
|
||||
Teleport to body only with SSG:
|
||||
|
||||
```md
|
||||
<ClientOnly>
|
||||
<Teleport to="#modal">
|
||||
<div>Modal content</div>
|
||||
</Teleport>
|
||||
</ClientOnly>
|
||||
```
|
||||
|
||||
## VS Code IntelliSense
|
||||
|
||||
Enable Vue language features for `.md` files:
|
||||
|
||||
```json
|
||||
// tsconfig.json
|
||||
{
|
||||
"include": ["docs/**/*.ts", "docs/**/*.vue", "docs/**/*.md"],
|
||||
"vueCompilerOptions": {
|
||||
"vitePressExtensions": [".md"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// .vscode/settings.json
|
||||
{
|
||||
"vue.server.includeLanguages": ["vue", "markdown"]
|
||||
}
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Markdown files are Vue SFCs - use `<script setup>` and `<style>`
|
||||
- Access page data via `useData()` or `$frontmatter` global
|
||||
- Import components locally or register globally in theme
|
||||
- Use `<style module>` instead of `<style scoped>`
|
||||
- Wrap non-SSR components in `<ClientOnly>`
|
||||
- Component names must be PascalCase or contain hyphens
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/using-vue
|
||||
- https://vitepress.dev/reference/runtime-api
|
||||
-->
|
||||
240
skills/vitepress/references/recipes-deploy.md
Normal file
240
skills/vitepress/references/recipes-deploy.md
Normal file
@@ -0,0 +1,240 @@
|
||||
---
|
||||
name: vitepress-deployment
|
||||
description: Deploying VitePress sites to various platforms including GitHub Pages, Netlify, Vercel, and more
|
||||
---
|
||||
|
||||
# Deployment
|
||||
|
||||
Deploy VitePress static sites to various hosting platforms.
|
||||
|
||||
## Build and Preview
|
||||
|
||||
```bash
|
||||
# Build production files
|
||||
npm run docs:build
|
||||
|
||||
# Preview locally
|
||||
npm run docs:preview
|
||||
```
|
||||
|
||||
Output is in `.vitepress/dist` by default.
|
||||
|
||||
## Setting Base Path
|
||||
|
||||
For sub-path deployment (e.g., `https://user.github.io/repo/`):
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
base: '/repo/'
|
||||
}
|
||||
```
|
||||
|
||||
## GitHub Pages
|
||||
|
||||
Create `.github/workflows/deploy.yml`:
|
||||
|
||||
```yaml
|
||||
name: Deploy VitePress
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
- run: npm run docs:build
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/.vitepress/dist
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/deploy-pages@v4
|
||||
id: deployment
|
||||
```
|
||||
|
||||
Enable GitHub Pages in repository settings → Pages → Source: "GitHub Actions".
|
||||
|
||||
For pnpm, add before setup-node:
|
||||
|
||||
```yaml
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
```
|
||||
|
||||
## Netlify / Vercel / Cloudflare Pages
|
||||
|
||||
Configure in dashboard:
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Build Command | `npm run docs:build` |
|
||||
| Output Directory | `docs/.vitepress/dist` |
|
||||
| Node Version | `20` (or above) |
|
||||
|
||||
**Warning:** Don't enable "Auto Minify" for HTML - it removes Vue hydration comments.
|
||||
|
||||
### Vercel Configuration
|
||||
|
||||
For clean URLs, add `vercel.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"cleanUrls": true
|
||||
}
|
||||
```
|
||||
|
||||
## GitLab Pages
|
||||
|
||||
Create `.gitlab-ci.yml`:
|
||||
|
||||
```yaml
|
||||
image: node:18
|
||||
|
||||
pages:
|
||||
cache:
|
||||
paths:
|
||||
- node_modules/
|
||||
script:
|
||||
- npm install
|
||||
- npm run docs:build
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
Set `outDir: '../public'` in config if needed.
|
||||
|
||||
## Firebase
|
||||
|
||||
```json
|
||||
// firebase.json
|
||||
{
|
||||
"hosting": {
|
||||
"public": "docs/.vitepress/dist",
|
||||
"ignore": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run docs:build
|
||||
firebase deploy
|
||||
```
|
||||
|
||||
## Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml;
|
||||
|
||||
listen 80;
|
||||
server_name _;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
root /app;
|
||||
try_files $uri $uri.html $uri/ =404;
|
||||
error_page 404 /404.html;
|
||||
error_page 403 /404.html;
|
||||
}
|
||||
|
||||
# Cache hashed assets
|
||||
location ~* ^/assets/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Important:** Don't default to `index.html` like SPAs - use `$uri.html` for clean URLs.
|
||||
|
||||
## HTTP Cache Headers
|
||||
|
||||
For hashed assets (immutable):
|
||||
|
||||
```
|
||||
Cache-Control: max-age=31536000, immutable
|
||||
```
|
||||
|
||||
### Netlify `_headers`
|
||||
|
||||
Place in `docs/public/_headers`:
|
||||
|
||||
```
|
||||
/assets/*
|
||||
cache-control: max-age=31536000
|
||||
cache-control: immutable
|
||||
```
|
||||
|
||||
### Vercel `vercel.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"headers": [
|
||||
{
|
||||
"source": "/assets/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "max-age=31536000, immutable"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Other Platforms
|
||||
|
||||
| Platform | Guide |
|
||||
|----------|-------|
|
||||
| Azure Static Web Apps | Set `app_location: /`, `output_location: docs/.vitepress/dist` |
|
||||
| Surge | `npx surge docs/.vitepress/dist` |
|
||||
| Heroku | Use `heroku-buildpack-static` |
|
||||
| Render | Build: `npm run docs:build`, Publish: `docs/.vitepress/dist` |
|
||||
| Kinsta | Follow [Kinsta docs](https://kinsta.com/docs/vitepress-static-site-example/) |
|
||||
|
||||
## Key Points
|
||||
|
||||
- Set `base` for sub-path deployments
|
||||
- GitHub Pages requires workflow file and enabling Pages in settings
|
||||
- Most platforms: Build `npm run docs:build`, output `docs/.vitepress/dist`
|
||||
- Don't enable HTML minification (breaks hydration)
|
||||
- Cache `/assets/*` with immutable headers
|
||||
- For clean URLs on Nginx, use `try_files $uri $uri.html $uri/ =404`
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/deploy
|
||||
-->
|
||||
315
skills/vitepress/references/theme-config.md
Normal file
315
skills/vitepress/references/theme-config.md
Normal file
@@ -0,0 +1,315 @@
|
||||
---
|
||||
name: vitepress-theme-configuration
|
||||
description: Default theme configuration for navigation, sidebar, search, social links, and footer
|
||||
---
|
||||
|
||||
# Theme Configuration
|
||||
|
||||
Configure the default theme via `themeConfig` in your VitePress config.
|
||||
|
||||
## Navigation
|
||||
|
||||
```ts
|
||||
export default {
|
||||
themeConfig: {
|
||||
// Site title in nav (overrides config.title)
|
||||
siteTitle: 'My Docs',
|
||||
siteTitle: false, // Hide title
|
||||
|
||||
// Logo
|
||||
logo: '/logo.svg',
|
||||
logo: { light: '/light-logo.svg', dark: '/dark-logo.svg', alt: 'Logo' },
|
||||
|
||||
// Nav links
|
||||
nav: [
|
||||
{ text: 'Guide', link: '/guide/' },
|
||||
{ text: 'API', link: '/api/' },
|
||||
{ text: 'GitHub', link: 'https://github.com/...' }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dropdown Menu
|
||||
|
||||
```ts
|
||||
nav: [
|
||||
{
|
||||
text: 'Dropdown',
|
||||
items: [
|
||||
{ text: 'Item A', link: '/item-a' },
|
||||
{ text: 'Item B', link: '/item-b' }
|
||||
]
|
||||
},
|
||||
// With sections
|
||||
{
|
||||
text: 'Versions',
|
||||
items: [
|
||||
{
|
||||
text: 'v2.x',
|
||||
items: [
|
||||
{ text: 'v2.0', link: '/v2/' },
|
||||
{ text: 'v2.1', link: '/v2.1/' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Active Match
|
||||
|
||||
Control when nav item shows as active:
|
||||
|
||||
```ts
|
||||
nav: [
|
||||
{
|
||||
text: 'Guide',
|
||||
link: '/guide/',
|
||||
activeMatch: '/guide/' // Regex pattern
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Sidebar
|
||||
|
||||
### Simple Sidebar
|
||||
|
||||
```ts
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Guide',
|
||||
items: [
|
||||
{ text: 'Introduction', link: '/guide/' },
|
||||
{ text: 'Getting Started', link: '/guide/getting-started' }
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Multiple Sidebars
|
||||
|
||||
Different sidebar per section:
|
||||
|
||||
```ts
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{
|
||||
text: 'Guide',
|
||||
items: [
|
||||
{ text: 'Introduction', link: '/guide/' },
|
||||
{ text: 'Getting Started', link: '/guide/getting-started' }
|
||||
]
|
||||
}
|
||||
],
|
||||
'/api/': [
|
||||
{
|
||||
text: 'API Reference',
|
||||
items: [
|
||||
{ text: 'Config', link: '/api/config' },
|
||||
{ text: 'Methods', link: '/api/methods' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Collapsible Groups
|
||||
|
||||
```ts
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Section A',
|
||||
collapsed: false, // Open by default, can collapse
|
||||
items: [...]
|
||||
},
|
||||
{
|
||||
text: 'Section B',
|
||||
collapsed: true, // Collapsed by default
|
||||
items: [...]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Base Path
|
||||
|
||||
Simplify links with common base:
|
||||
|
||||
```ts
|
||||
sidebar: {
|
||||
'/guide/': {
|
||||
base: '/guide/',
|
||||
items: [
|
||||
{ text: 'Intro', link: 'intro' }, // /guide/intro
|
||||
{ text: 'Setup', link: 'getting-started' } // /guide/getting-started
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Search
|
||||
|
||||
### Local Search
|
||||
|
||||
```ts
|
||||
themeConfig: {
|
||||
search: {
|
||||
provider: 'local'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With options:
|
||||
|
||||
```ts
|
||||
search: {
|
||||
provider: 'local',
|
||||
options: {
|
||||
miniSearch: {
|
||||
searchOptions: {
|
||||
fuzzy: 0.2,
|
||||
prefix: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Algolia DocSearch
|
||||
|
||||
```ts
|
||||
search: {
|
||||
provider: 'algolia',
|
||||
options: {
|
||||
appId: 'YOUR_APP_ID',
|
||||
apiKey: 'YOUR_API_KEY',
|
||||
indexName: 'YOUR_INDEX_NAME'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Social Links
|
||||
|
||||
```ts
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/...' },
|
||||
{ icon: 'twitter', link: 'https://twitter.com/...' },
|
||||
{ icon: 'discord', link: 'https://discord.gg/...' },
|
||||
// Custom SVG
|
||||
{
|
||||
icon: { svg: '<svg>...</svg>' },
|
||||
link: 'https://...',
|
||||
ariaLabel: 'Custom Link'
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Footer
|
||||
|
||||
```ts
|
||||
footer: {
|
||||
message: 'Released under the MIT License.',
|
||||
copyright: 'Copyright © 2024 My Project'
|
||||
}
|
||||
```
|
||||
|
||||
Footer only displays on pages without sidebar.
|
||||
|
||||
## Edit Link
|
||||
|
||||
```ts
|
||||
editLink: {
|
||||
pattern: 'https://github.com/org/repo/edit/main/docs/:path',
|
||||
text: 'Edit this page on GitHub'
|
||||
}
|
||||
```
|
||||
|
||||
`:path` is replaced with the page's source file path.
|
||||
|
||||
## Last Updated
|
||||
|
||||
Enable in site config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
lastUpdated: true // Get timestamp from git
|
||||
}
|
||||
```
|
||||
|
||||
Customize display:
|
||||
|
||||
```ts
|
||||
themeConfig: {
|
||||
lastUpdated: {
|
||||
text: 'Updated at',
|
||||
formatOptions: {
|
||||
dateStyle: 'full',
|
||||
timeStyle: 'medium'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Outline (Table of Contents)
|
||||
|
||||
```ts
|
||||
outline: {
|
||||
level: [2, 3], // Which heading levels to show
|
||||
label: 'On this page'
|
||||
}
|
||||
```
|
||||
|
||||
Or just the level:
|
||||
|
||||
```ts
|
||||
outline: 'deep' // Same as [2, 6]
|
||||
outline: 2 // Only h2
|
||||
outline: [2, 4] // h2 through h4
|
||||
```
|
||||
|
||||
## Doc Footer Navigation
|
||||
|
||||
```ts
|
||||
docFooter: {
|
||||
prev: 'Previous page',
|
||||
next: 'Next page'
|
||||
}
|
||||
// Or disable:
|
||||
docFooter: {
|
||||
prev: false,
|
||||
next: false
|
||||
}
|
||||
```
|
||||
|
||||
## External Link Icon
|
||||
|
||||
```ts
|
||||
externalLinkIcon: true // Show icon on external links
|
||||
```
|
||||
|
||||
## Appearance Toggle Labels
|
||||
|
||||
```ts
|
||||
darkModeSwitchLabel: 'Appearance',
|
||||
lightModeSwitchTitle: 'Switch to light theme',
|
||||
darkModeSwitchTitle: 'Switch to dark theme',
|
||||
sidebarMenuLabel: 'Menu',
|
||||
returnToTopLabel: 'Return to top'
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- `nav` defines top navigation links
|
||||
- `sidebar` can be array (single) or object (multiple sidebars)
|
||||
- Use `collapsed` for collapsible sidebar sections
|
||||
- Local search works out of the box
|
||||
- `editLink.pattern` uses `:path` placeholder
|
||||
- Enable `lastUpdated` in site config, customize in themeConfig
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/reference/default-theme-config
|
||||
- https://vitepress.dev/reference/default-theme-nav
|
||||
- https://vitepress.dev/reference/default-theme-sidebar
|
||||
- https://vitepress.dev/reference/default-theme-search
|
||||
-->
|
||||
269
skills/vitepress/references/theme-custom.md
Normal file
269
skills/vitepress/references/theme-custom.md
Normal file
@@ -0,0 +1,269 @@
|
||||
---
|
||||
name: vitepress-custom-themes
|
||||
description: Building custom themes from scratch with the theme interface, Layout component, and enhanceApp
|
||||
---
|
||||
|
||||
# Custom Themes
|
||||
|
||||
Build a theme from scratch when the default theme doesn't fit your needs.
|
||||
|
||||
## Theme Entry
|
||||
|
||||
Create `.vitepress/theme/index.ts`:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import Layout from './Layout.vue'
|
||||
|
||||
export default {
|
||||
Layout,
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
// Register global components, plugins, etc.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Theme Interface
|
||||
|
||||
```ts
|
||||
interface Theme {
|
||||
// Required: Root layout component
|
||||
Layout: Component
|
||||
|
||||
// Optional: Enhance Vue app instance
|
||||
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
|
||||
|
||||
// Optional: Extend another theme
|
||||
extends?: Theme
|
||||
}
|
||||
|
||||
interface EnhanceAppContext {
|
||||
app: App // Vue app instance
|
||||
router: Router // VitePress router
|
||||
siteData: Ref<SiteData> // Site-level metadata
|
||||
}
|
||||
```
|
||||
|
||||
## Basic Layout
|
||||
|
||||
The Layout component must render `<Content />` for markdown:
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/Layout.vue -->
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
const { page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
<header>
|
||||
<nav>My Site</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div v-if="page.isNotFound">
|
||||
<h1>404 - Page Not Found</h1>
|
||||
</div>
|
||||
|
||||
<div v-else-if="frontmatter.layout === 'home'">
|
||||
<h1>Welcome!</h1>
|
||||
</div>
|
||||
|
||||
<article v-else>
|
||||
<Content />
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© 2024 My Site</p>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Runtime API
|
||||
|
||||
Access VitePress data in your theme:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { useData, useRoute, useRouter } from 'vitepress'
|
||||
|
||||
// Page and site data
|
||||
const {
|
||||
site, // Site config (title, description, etc.)
|
||||
theme, // Theme config
|
||||
page, // Current page data
|
||||
frontmatter, // Current page frontmatter
|
||||
title, // Page title
|
||||
description, // Page description
|
||||
lang, // Current language
|
||||
isDark, // Dark mode state
|
||||
params // Dynamic route params
|
||||
} = useData()
|
||||
|
||||
// Routing
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// Navigate programmatically
|
||||
const goToGuide = () => router.go('/guide/')
|
||||
</script>
|
||||
```
|
||||
|
||||
## Built-in Components
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { Content } from 'vitepress'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Renders markdown content -->
|
||||
<Content />
|
||||
|
||||
<!-- Renders slot only on client (SSR-safe) -->
|
||||
<ClientOnly>
|
||||
<NonSSRComponent />
|
||||
</ClientOnly>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Extend Another Theme
|
||||
|
||||
Build on top of default theme or any other:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
// Your customizations
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Register Plugins and Components
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import Layout from './Layout.vue'
|
||||
import GlobalComponent from './GlobalComponent.vue'
|
||||
|
||||
export default {
|
||||
Layout,
|
||||
enhanceApp({ app }) {
|
||||
// Register global component
|
||||
app.component('GlobalComponent', GlobalComponent)
|
||||
|
||||
// Register plugin
|
||||
app.use(MyPlugin)
|
||||
|
||||
// Provide/inject
|
||||
app.provide('key', value)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Async enhanceApp
|
||||
|
||||
For plugins that need async initialization:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
Layout,
|
||||
async enhanceApp({ app }) {
|
||||
if (!import.meta.env.SSR) {
|
||||
// Client-only plugin
|
||||
const plugin = await import('browser-only-plugin')
|
||||
app.use(plugin.default)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Theme-Aware Layout
|
||||
|
||||
Handle different page layouts:
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
import Home from './Home.vue'
|
||||
import Doc from './Doc.vue'
|
||||
import Page from './Page.vue'
|
||||
import NotFound from './NotFound.vue'
|
||||
|
||||
const { page, frontmatter } = useData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NotFound v-if="page.isNotFound" />
|
||||
<Home v-else-if="frontmatter.layout === 'home'" />
|
||||
<Page v-else-if="frontmatter.layout === 'page'" />
|
||||
<Doc v-else />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Distributing a Theme
|
||||
|
||||
As npm package:
|
||||
|
||||
```ts
|
||||
// my-theme/index.ts
|
||||
import Layout from './Layout.vue'
|
||||
export default { Layout }
|
||||
|
||||
// Export types for config
|
||||
export type { ThemeConfig } from './types'
|
||||
```
|
||||
|
||||
Consumer usage:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import Theme from 'my-vitepress-theme'
|
||||
|
||||
export default Theme
|
||||
|
||||
// Or extend it
|
||||
export default {
|
||||
extends: Theme,
|
||||
enhanceApp({ app }) {
|
||||
// Additional customization
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Theme Config Types
|
||||
|
||||
For custom theme config types:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
import { defineConfigWithTheme } from 'vitepress'
|
||||
import type { ThemeConfig } from 'my-theme'
|
||||
|
||||
export default defineConfigWithTheme<ThemeConfig>({
|
||||
themeConfig: {
|
||||
// Type-checked theme config
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Theme must export `Layout` component
|
||||
- `<Content />` renders the markdown content
|
||||
- Use `useData()` to access page/site data
|
||||
- `enhanceApp` runs on both server and client
|
||||
- Check `import.meta.env.SSR` for client-only code
|
||||
- Use `extends` to build on existing themes
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/custom-theme
|
||||
-->
|
||||
290
skills/vitepress/references/theme-customization.md
Normal file
290
skills/vitepress/references/theme-customization.md
Normal file
@@ -0,0 +1,290 @@
|
||||
---
|
||||
name: extending-vitepress-default-theme
|
||||
description: Customize CSS variables, use layout slots, register global components, and override theme fonts
|
||||
---
|
||||
|
||||
# Extending Default Theme
|
||||
|
||||
Customize the default theme through CSS, slots, and Vue components.
|
||||
|
||||
## Theme Entry File
|
||||
|
||||
Create `.vitepress/theme/index.ts` to extend the default theme:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './custom.css'
|
||||
|
||||
export default DefaultTheme
|
||||
```
|
||||
|
||||
## CSS Variables
|
||||
|
||||
Override root CSS variables:
|
||||
|
||||
```css
|
||||
/* .vitepress/theme/custom.css */
|
||||
:root {
|
||||
/* Brand colors */
|
||||
--vp-c-brand-1: #646cff;
|
||||
--vp-c-brand-2: #747bff;
|
||||
--vp-c-brand-3: #9499ff;
|
||||
|
||||
/* Backgrounds */
|
||||
--vp-c-bg: #ffffff;
|
||||
--vp-c-bg-soft: #f6f6f7;
|
||||
|
||||
/* Text */
|
||||
--vp-c-text-1: #213547;
|
||||
--vp-c-text-2: #476582;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-c-brand-1: #747bff;
|
||||
--vp-c-bg: #1a1a1a;
|
||||
}
|
||||
```
|
||||
|
||||
See [all CSS variables](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css).
|
||||
|
||||
## Home Hero Customization
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Gradient name color */
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: linear-gradient(120deg, #bd34fe, #41d1ff);
|
||||
|
||||
/* Hero image glow */
|
||||
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
|
||||
--vp-home-hero-image-filter: blur(44px);
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Fonts
|
||||
|
||||
Remove Inter font and use your own:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme-without-fonts'
|
||||
import './fonts.css'
|
||||
|
||||
export default DefaultTheme
|
||||
```
|
||||
|
||||
```css
|
||||
/* .vitepress/theme/fonts.css */
|
||||
@font-face {
|
||||
font-family: 'MyFont';
|
||||
src: url('/fonts/myfont.woff2') format('woff2');
|
||||
}
|
||||
|
||||
:root {
|
||||
--vp-font-family-base: 'MyFont', sans-serif;
|
||||
--vp-font-family-mono: 'Fira Code', monospace;
|
||||
}
|
||||
```
|
||||
|
||||
Preload fonts in config:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
export default {
|
||||
transformHead({ assets }) {
|
||||
const fontFile = assets.find(file => /myfont\.[\w-]+\.woff2/.test(file))
|
||||
if (fontFile) {
|
||||
return [
|
||||
['link', { rel: 'preload', href: fontFile, as: 'font', type: 'font/woff2', crossorigin: '' }]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Global Components
|
||||
|
||||
Register components available in all markdown:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyComponent from './components/MyComponent.vue'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
app.component('MyComponent', MyComponent)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use in markdown:
|
||||
|
||||
```md
|
||||
<MyComponent :prop="value" />
|
||||
```
|
||||
|
||||
## Layout Slots
|
||||
|
||||
Inject content into specific locations:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyLayout from './MyLayout.vue'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout: MyLayout
|
||||
}
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/MyLayout.vue -->
|
||||
<script setup>
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
const { Layout } = DefaultTheme
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<template #aside-outline-before>
|
||||
<div>Above outline</div>
|
||||
</template>
|
||||
|
||||
<template #doc-before>
|
||||
<div>Before doc content</div>
|
||||
</template>
|
||||
|
||||
<template #doc-after>
|
||||
<div>After doc content</div>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Available Slots
|
||||
|
||||
**Doc layout (`layout: doc`):**
|
||||
- `doc-top`, `doc-bottom`
|
||||
- `doc-before`, `doc-after`
|
||||
- `doc-footer-before`
|
||||
- `sidebar-nav-before`, `sidebar-nav-after`
|
||||
- `aside-top`, `aside-bottom`
|
||||
- `aside-outline-before`, `aside-outline-after`
|
||||
- `aside-ads-before`, `aside-ads-after`
|
||||
|
||||
**Home layout (`layout: home`):**
|
||||
- `home-hero-before`, `home-hero-after`
|
||||
- `home-hero-info-before`, `home-hero-info`, `home-hero-info-after`
|
||||
- `home-hero-actions-after`, `home-hero-image`
|
||||
- `home-features-before`, `home-features-after`
|
||||
|
||||
**Page layout (`layout: page`):**
|
||||
- `page-top`, `page-bottom`
|
||||
|
||||
**Always available:**
|
||||
- `layout-top`, `layout-bottom`
|
||||
- `nav-bar-title-before`, `nav-bar-title-after`
|
||||
- `nav-bar-content-before`, `nav-bar-content-after`
|
||||
- `not-found` (404 page)
|
||||
|
||||
## Using Render Functions
|
||||
|
||||
Alternative to template slots:
|
||||
|
||||
```ts
|
||||
// .vitepress/theme/index.ts
|
||||
import { h } from 'vue'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout() {
|
||||
return h(DefaultTheme.Layout, null, {
|
||||
'aside-outline-before': () => h(MyComponent)
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Override Internal Components
|
||||
|
||||
Replace default theme components with Vite aliases:
|
||||
|
||||
```ts
|
||||
// .vitepress/config.ts
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
export default {
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: /^.*\/VPNavBar\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
new URL('./theme/components/CustomNavBar.vue', import.meta.url)
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## View Transitions
|
||||
|
||||
Custom dark mode toggle animation:
|
||||
|
||||
```vue
|
||||
<!-- .vitepress/theme/Layout.vue -->
|
||||
<script setup>
|
||||
import { useData } from 'vitepress'
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { nextTick, provide } from 'vue'
|
||||
|
||||
const { isDark } = useData()
|
||||
|
||||
provide('toggle-appearance', async ({ clientX: x, clientY: y }) => {
|
||||
if (!document.startViewTransition) {
|
||||
isDark.value = !isDark.value
|
||||
return
|
||||
}
|
||||
|
||||
const clipPath = [
|
||||
`circle(0px at ${x}px ${y}px)`,
|
||||
`circle(${Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y))}px at ${x}px ${y}px)`
|
||||
]
|
||||
|
||||
await document.startViewTransition(async () => {
|
||||
isDark.value = !isDark.value
|
||||
await nextTick()
|
||||
}).ready
|
||||
|
||||
document.documentElement.animate(
|
||||
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
|
||||
{ duration: 300, easing: 'ease-in', pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)` }
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultTheme.Layout />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Import `vitepress/theme-without-fonts` to use custom fonts
|
||||
- Use layout slots to inject content without overriding components
|
||||
- Global components are registered in `enhanceApp`
|
||||
- Override CSS variables for theming
|
||||
- Use Vite aliases to replace internal components
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitepress.dev/guide/extending-default-theme
|
||||
-->
|
||||
Reference in New Issue
Block a user