[
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [yyx990803, kiaking, brc-dd, posva]\nopen_collective: vuejs\npatreon: evanyou\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: \"\\U0001F41E Bug report\"\ndescription: Create a report to help us improve\nlabels: ['bug: pending triage']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        \"Thanks for taking the time to fill out this bug report!\n        VitePress is still WIP, and it is not compatible with VuePress.\n        Please do not open issue about default theme missing features or something doesn't work like VuePress.\"\n  - type: textarea\n    id: bug-description\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!\n      placeholder: Bug description\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: Reproduction\n      description: Steps to reproduce the behavior. [vitepress.new](https://vitepress.new/) can be used as a starter template.\n      placeholder: Reproduction\n    validations:\n      required: true\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected behavior\n      description: A clear and concise description of what you expected to happen.\n      placeholder: Expected behavior\n    validations:\n      required: true\n  - type: textarea\n    id: system-info\n    attributes:\n      label: System Info\n      description: Output of `npx envinfo --system --npmPackages vitepress --binaries --browsers`\n      render: Text\n      placeholder: System, Binaries, Browsers\n    validations:\n      required: true\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the bug report here.\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: Check if you're on the [latest VitePress version](https://github.com/vuejs/vitepress/releases/latest).\n          required: true\n        - label: Follow our [Code of Conduct](https://vuejs.org/about/coc.html)\n          required: true\n        - label: Read the [docs](https://vitepress.dev).\n          required: true\n        - label: Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: \"\\U0001F680 New feature proposal\"\ndescription: Suggest an idea for this project\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in the project and taking the time to fill out this feature report!\n  - type: textarea\n    id: feature-description\n    attributes:\n      label: Is your feature request related to a problem? Please describe.\n      description: \"A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\"\n    validations:\n      required: true\n  - type: textarea\n    id: suggested-solution\n    attributes:\n      label: Describe the solution you'd like\n      description: A clear and concise description of what you want to happen.\n    validations:\n      required: true\n  - type: textarea\n    id: alternative\n    attributes:\n      label: Describe alternatives you've considered\n      description: A clear and concise description of any alternative solutions or features you've considered.\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the feature request here.\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: Follow our [Code of Conduct](https://vuejs.org/about/coc.html)\n          required: true\n        - label: Read the [docs](https://vitepress.dev).\n          required: true\n        - label: Read the [Contributing Guidelines](https://github.com/vuejs/vitepress/blob/main/.github/contributing.md).\n          required: true\n        - label: Check that there isn't already an issue that asks for the same feature to avoid creating a duplicate.\n          required: true\n"
  },
  {
    "path": ".github/commit-convention.md",
    "content": "## Git Commit Message Convention\n\n> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).\n\n#### TL;DR:\n\nMessages must be matched by the following regex:\n\n```js\n/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\\(.+\\))?: .{1,50}/\n```\n\n#### Examples\n\nAppears under \"Features\" header, `theme` subheader:\n\n```\nfeat(theme): add home page feature\n```\n\nAppears under \"Bug Fixes\" header, `theme` subheader, with a link to issue #28:\n\n```\nfix(theme): remove underline on sidebar hover style\n\nclose #28\n```\n\nAppears under \"Performance Improvements\" header, and under \"Breaking Changes\" with the breaking change explanation:\n\n```\nperf: improve store getters performance by removing 'foo' option\n\nBREAKING CHANGE: The 'foo' option has been removed.\n```\n\nThe following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the \"Reverts\" header.\n\n```\nrevert: feat(theme): add home page feature\n\nThis reverts commit 667ecc1654a317a13331b17617d973392f415f02.\n```\n\n### Full Message Format\n\nA commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:\n\n```\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nThe **header** is mandatory and the **scope** of the header is optional.\n\n### Revert\n\nIf the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.\n\n### Type\n\nIf the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.\n\nOther prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.\n\n### Scope\n\nThe scope could be anything specifying the place of the commit change. For example `theme`, `compiler`, `ssr`, etc...\n\n### Subject\n\nThe subject contains a succinct description of the change:\n\n- use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n- don't capitalize the first letter\n- no dot (.) at the end\n\n### Body\n\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\".\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n### Footer\n\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\n**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.\n"
  },
  {
    "path": ".github/contributing.md",
    "content": "# VitePress Contributing Guide\n\nHi! We're really excited that you are interested in contributing to VitePress. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:\n\n- [Code of Conduct](https://github.com/vuejs/vue/blob/dev/.github/CODE_OF_CONDUCT.md)\n- [Pull Request Guidelines](#pull-request-guidelines)\n\n## Pull Request Guidelines\n\n- Checkout a topic branch from the relevant branch, e.g. `main`, and merge back against that branch.\n\n- If adding a new feature:\n\n  - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.\n\n- If fixing bug:\n\n  - Provide a detailed description of the bug in the PR. Live demo preferred.\n\n- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.\n\n- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated.\n\n## Development Setup\n\nYou will need [Node.js](https://nodejs.org) v20 or higher and [pnpm](https://pnpm.io).\n\nAfter cloning the repo, run:\n\n```sh\n# install the dependencies of the project\n$ pnpm install\n# setup git hooks\n$ pnpm simple-git-hooks\n```\n\n### Setup VitePress Dev Environment\n\nThe easiest way to start testing out VitePress is to tweak the VitePress docs. You may run `pnpm run docs` to boot up VitePress documentation site locally, with live reloading of the source code.\n\n```sh\n$ pnpm run docs\n```\n\nAfter executing the above command, visit http://localhost:5173 and try modifying the source code. You'll get live update.\n\nIf you don't need docs site up and running, you may start VitePress local dev environment with `pnpm run dev`.\n\n```sh\n$ pnpm run dev\n```\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### Description\n\n<!-- Please insert your description here and provide info about the \"what\" this PR is solving. -->\n\n### Linked Issues\n\n<!-- e.g. fixes #123 -->\n\n### Additional Context\n\n<!-- Is there anything you would like the reviewers to focus on? -->\n\n---\n\n> [!TIP]\n> The author of this PR can publish a _preview release_ by commenting `/publish` below.\n"
  },
  {
    "path": ".github/workflows/cr-comment.yml",
    "content": "name: Add continuous release label\n\non:\n  issue_comment:\n    types: [created]\n\npermissions:\n  pull-requests: write\n\njobs:\n  label:\n    if: ${{ github.event.issue.pull_request && (github.event.comment.user.id == github.event.issue.user.id || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') && startsWith(github.event.comment.body, '/publish') }}\n    runs-on: ubuntu-latest\n\n    steps:\n      - run: gh issue edit ${{ github.event.issue.number }} --add-label cr-tracked --repo ${{ github.repository }}\n        env:\n          GITHUB_TOKEN: ${{ secrets.CR_PAT }}\n"
  },
  {
    "path": ".github/workflows/cr.yml",
    "content": "name: CR\n\nenv:\n  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'\n\non:\n  pull_request:\n    branches: [main]\n    types: [opened, synchronize, labeled, ready_for_review]\n    paths-ignore:\n      - '.github/**'\n      - '!.github/workflows/cr.yml'\n      - '__tests__/**'\n      - 'art/**'\n      - 'docs/**'\n      - '*.md'\n  push:\n    branches: [main]\n    paths-ignore:\n      - '.github/**'\n      - '!.github/workflows/cr.yml'\n      - '__tests__/**'\n      - 'art/**'\n      - 'docs/**'\n      - '*.md'\n    tags-ignore:\n      - '*'\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}\n  cancel-in-progress: true\n\njobs:\n  release:\n    if: ${{ ((github.event_name == 'pull_request' && !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'cr-tracked') && !contains(github.event.pull_request.labels.*.name, 'spam') && !contains(github.event.pull_request.labels.*.name, 'invalid')) || (github.event_name == 'push' && !startsWith(github.event.head_commit.message, 'release:'))) && github.repository == 'vuejs/vitepress' }}\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v5\n      - uses: pnpm/action-setup@v4\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          cache: pnpm\n      - run: pnpm install\n      - run: pnpm build\n      - run: npx pkg-pr-new publish --compact --no-template --pnpm\n"
  },
  {
    "path": ".github/workflows/lock-threads.yml",
    "content": "name: Lock Threads\n\non:\n  schedule:\n    - cron: 38 4 * * *\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  pull-requests: write\n  discussions: write\n\nconcurrency:\n  group: lock\n\njobs:\n  action:\n    if: github.repository == 'vuejs/vitepress'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: dessant/lock-threads@v5\n        with:\n          issue-inactive-days: 7\n          pr-inactive-days: 7\n          exclude-any-issue-labels: 'keep-open'\n          exclude-any-pr-labels: 'keep-open'\n"
  },
  {
    "path": ".github/workflows/release-tag.yml",
    "content": "name: Release\n\non:\n  push:\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\njobs:\n  release:\n    if: github.repository == 'vuejs/vitepress'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n\n      - name: Create Release for Tag\n        id: release_tag\n        uses: yyx990803/release-tag@master\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          tag_name: ${{ github.ref }}\n          body: |\n            Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md) for details.\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Close stale issues and PRs\non:\n  schedule:\n    - cron: '0 12 1,15 * *'\n  workflow_dispatch:\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v10\n        with:\n          days-before-stale: 30\n          days-before-close: -1\n          stale-issue-label: stale\n          stale-pr-label: stale\n          # action has a bug that keeps removing the stale label from stale PRs\n          # it's thinking that the PR is updated when the stale label is added\n          remove-pr-stale-when-updated: false\n          operations-per-run: 1000\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n  workflow_dispatch:\n\npermissions: {}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        node_version: [20, 22, 24, latest]\n        include:\n          - os: windows-latest\n            node_version: 24\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n\n      - name: Set node version to ${{ matrix.node_version }}\n        uses: actions/setup-node@v6\n        with:\n          node-version: ${{ matrix.node_version }}\n          cache: pnpm\n\n      - name: Install deps\n        run: pnpm install\n        env:\n          PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1\n\n      - name: Install Playwright\n        run: pnpm playwright install chromium\n\n      - name: Check\n        run: pnpm check\n"
  },
  {
    "path": ".gitignore",
    "content": "/coverage\n/src/client/shared.ts\n/src/node/shared.ts\n*.log\n*.tgz\n.DS_Store\n.idea\n.temp\n.vite_opt_cache\n.vscode\ndist\ncache\ntemp\nexamples-temp\nnode_modules\npnpm-global\nTODOs.md\n*.timestamp-*.mjs\n"
  },
  {
    "path": ".prettierignore",
    "content": "*.md\n*.vue\ndist\npnpm-lock.yaml\ncache\ntemplate\ntemp\n!CHANGELOG.md\n.temp\n"
  },
  {
    "path": ".prettierrc.yml",
    "content": "semi: false\nsingleQuote: true\nprintWidth: 80\ntrailingComma: none\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [2.0.0-alpha.17](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.16...v2.0.0-alpha.17) (2026-03-19)\n\n### Bug Fixes\n\n- **build:** `processIncludes` no longer swallows errors ([fb21fdf](https://github.com/vuejs/vitepress/commit/fb21fdf6759b7c88ac98456820b75286936fbf87))\n- **build:** deterministic local search indexing and non-blocking initial scan (closes [#4081](https://github.com/vuejs/vitepress/issues/4081)) ([fc0f203](https://github.com/vuejs/vitepress/commit/fc0f203f0ac451ec039850b920f0684c1695d161))\n- **client:** await `clipboard.writeText` so that fallback works in non-secure contexts ([#5119](https://github.com/vuejs/vitepress/issues/5119)) ([b544df8](https://github.com/vuejs/vitepress/commit/b544df802d256aef10d4da94631967b0fcab68d2))\n- disable brotli compression in preview server ([ca1e875](https://github.com/vuejs/vitepress/commit/ca1e87512924acdd8d39ca0f530a424ad933b701))\n- **theme:** add `rel=\"alternate\"` and `hreflang` to links in language menu ([#5108](https://github.com/vuejs/vitepress/issues/5108)) ([f09593b](https://github.com/vuejs/vitepress/commit/f09593b073e42fa9d8de1e744a9f2a0e5c8170fc))\n- **theme:** add margin to images in vp-doc (closes [#5136](https://github.com/vuejs/vitepress/issues/5136)) ([896e49a](https://github.com/vuejs/vitepress/commit/896e49a777bb983de2cbef82c1c295db2dba3dbe))\n- **theme:** close sidebar on resize (closes [#5145](https://github.com/vuejs/vitepress/issues/5145)) ([17696c3](https://github.com/vuejs/vitepress/commit/17696c358b88335c4f6bb516bbcdf774aaf7deee))\n- **theme:** disable text autospace in `<pre>` (closes [#5115](https://github.com/vuejs/vitepress/issues/5115)) ([21a5fb6](https://github.com/vuejs/vitepress/commit/21a5fb6a96549564fcf698d0e7256181eac3919b))\n- **theme:** enable `line-break: strict` for `<li>` too ([f811d58](https://github.com/vuejs/vitepress/commit/f811d581a164fa330b17cdb85270effa39bdb3fd))\n- **theme:** keep pnum,tnum features in Inter ([f1bef95](https://github.com/vuejs/vitepress/commit/f1bef95eee453bb18cc160741a11513678015cd6)), closes [#5096](https://github.com/vuejs/vitepress/issues/5096)\n- **theme:** navbar menu group is incorrectly highlighted ([#5113](https://github.com/vuejs/vitepress/issues/5113)) ([b28667b](https://github.com/vuejs/vitepress/commit/b28667b6b03d50c4be0d509ec5e7d780f29f8042))\n- **theme:** strip system-ui from font-family-base ([#4988](https://github.com/vuejs/vitepress/issues/4988)) ([8096eac](https://github.com/vuejs/vitepress/commit/8096eaca4f1d9eef00101e42f7159da1e12ca3de))\n\n### Features\n\n- **theme:** add `home-hero-actions-before-actions` slot ([#5151](https://github.com/vuejs/vitepress/issues/5151)) ([74a73d8](https://github.com/vuejs/vitepress/commit/74a73d869ca61f2c64f9dcbd9912a0461e8d4bfe))\n- support text-fragments ([#5140](https://github.com/vuejs/vitepress/issues/5140)) ([44e2675](https://github.com/vuejs/vitepress/commit/44e2675889588b54dea771a0c82e2db64739364c))\n- **theme:** add Japanese translation for \"copied\" label ([#5106](https://github.com/vuejs/vitepress/issues/5106)) ([a01bba0](https://github.com/vuejs/vitepress/commit/a01bba0cad70bb089918adab105f0a5b5ff85918))\n- **theme:** enable text-autospace and text-spacing-trim (closes [#4996](https://github.com/vuejs/vitepress/issues/4996)) ([d7effff](https://github.com/vuejs/vitepress/commit/d7effffdbb9ea6bdeda31e26dea0f1ed32ddd51e))\n- **theme:** support specifying list of details in home page features (closes [#5101](https://github.com/vuejs/vitepress/issues/5101)) ([3146ce4](https://github.com/vuejs/vitepress/commit/3146ce48ed3ad684ddfbf1194de3a2200082eb92))\n\n### BREAKING CHANGES\n\nThe previous `<!-- @include: ./path/to/file -->` syntax silently ignored errors when files did not exist. This behavior was originally intended as an escape hatch while documenting includes, but better solutions now exist using Shiki transformers.\n\nFor most users, no code changes are required. If you now see errors, it means your includes are broken and were previously not being reported.\n\nUsers who intentionally reference non-existent files or want to document includes without resolving them can configure `markdown.codeTransformers` with a `postprocess` hook. See `docs/.vitepress/config.ts` in this repo for an example.\n\n## [2.0.0-alpha.16](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) (2026-01-31)\n\n### Bug Fixes\n\n- always log error when failed to fetch page ([66cf64e](https://github.com/vuejs/vitepress/commit/66cf64e6d127dd8473e582d11e1133acda6c3bc8))\n- **theme:** add fallback for `heroImageSlotExists` ([#5076](https://github.com/vuejs/vitepress/issues/5076)) ([f119b18](https://github.com/vuejs/vitepress/commit/f119b18e39b545f39e29358913fe9ed1fd69bc55))\n- **theme:** align badges in h1 and h2 ([#5087](https://github.com/vuejs/vitepress/issues/5087)) (closes [#5063](https://github.com/vuejs/vitepress/issues/5063)) ([b200865](https://github.com/vuejs/vitepress/commit/b2008654ffaf0d8f8c425e88592e9ed2f8791506))\n- **theme:** highlight active link in mobile nav menu ([#5086](https://github.com/vuejs/vitepress/issues/5086)) (closes [#5068](https://github.com/vuejs/vitepress/issues/5068), closes [#5074](https://github.com/vuejs/vitepress/issues/5074)) ([923aa90](https://github.com/vuejs/vitepress/commit/923aa902523739bfb9d77aed376ebc73c32eeb33))\n- **theme:** overflow clip is buggy on safari ([8ed6ea0](https://github.com/vuejs/vitepress/commit/8ed6ea048cb49256e3302de2de0edfbe635afd32)), closes [#5050](https://github.com/vuejs/vitepress/issues/5050) [#5039](https://github.com/vuejs/vitepress/issues/5039) [#5027](https://github.com/vuejs/vitepress/issues/5027)\n- **theme:** remove margin between code groups and blocks in markdown containers ([a28e171](https://github.com/vuejs/vitepress/commit/a28e171604605713a221d0eb2bbdce211930d94f)), closes [#5099](https://github.com/vuejs/vitepress/issues/5099)\n\n### Features\n\n- **theme:** upgrade DocSearch to 4.5 with sidepanel ([#5092](https://github.com/vuejs/vitepress/issues/5092)) ([0d646a6](https://github.com/vuejs/vitepress/commit/0d646a66cd44e97adef516a6a36e03365f179906))\n- **theme:** use `@layer __vitepress_base` to wrap the styles in base.css ([#4905](https://github.com/vuejs/vitepress/issues/4905)) ([f8d8c0d](https://github.com/vuejs/vitepress/commit/f8d8c0d712fba4728c750e1f44c5ba9596979ba1))\n\n## [2.0.0-alpha.15](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.14...v2.0.0-alpha.15) (2025-11-22)\n\n### Bug Fixes\n\n- **theme:** navbar overflowing on mobile devices ([06f0e1a](https://github.com/vuejs/vitepress/commit/06f0e1a5c92e36d86fd2e037c335af04d75384e7)), closes [#5039](https://github.com/vuejs/vitepress/issues/5039)\n\n## [2.0.0-alpha.14](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2025-11-21)\n\n### Bug Fixes\n\n- log dead links in dev mode too ([179ee62](https://github.com/vuejs/vitepress/commit/179ee621d99b3c14e2e098e3b786465cbeaeab9a)), closes [#4419](https://github.com/vuejs/vitepress/issues/4419)\n- **theme:** sidebar alignment when scrollbar is there on page ([0ee7158](https://github.com/vuejs/vitepress/commit/0ee71588de2b1691b1a9287aa1daa729197fd3ca)), closes [#5027](https://github.com/vuejs/vitepress/issues/5027)\n\n### Features\n\n- **client:** emit `vitepress:codeGroupTabActivate` custom event when a code group tab is activated ([dfb02a4](https://github.com/vuejs/vitepress/commit/dfb02a479f19afbee9e292b15c3c2beef271e57f)), closes [#5023](https://github.com/vuejs/vitepress/issues/5023)\n\n## [2.0.0-alpha.13](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2025-11-13)\n\n### Bug Fixes\n\n- **client,a11y:** improve focus handling and scrolling behavior in router ([#4943](https://github.com/vuejs/vitepress/issues/4943)) ([d46107f](https://github.com/vuejs/vitepress/commit/d46107fa254d662d297b1362aa0d3b898ef96e2c))\n- disable markdown-it-attrs for fenced code blocks ([0899618](https://github.com/vuejs/vitepress/commit/089961855653f862b71747e8179ef2647e06d626))\n- git log parsing when there are empty commits in history ([#4965](https://github.com/vuejs/vitepress/issues/4965)) ([612c458](https://github.com/vuejs/vitepress/commit/612c45895df79a0c0e87ca040564bfe88ce04f62))\n- print full path in dead links check ([2b77fb3](https://github.com/vuejs/vitepress/commit/2b77fb3a72058129edbaddd3c6f0f6ee24f983d5)), closes [#4919](https://github.com/vuejs/vitepress/issues/4919)\n- rename `markdown.cjkFriendly` to `markdown.cjkFriendlyEmphasis` ([bce0b53](https://github.com/vuejs/vitepress/commit/bce0b53659fa3a57b2ed8431a0861939dadd118a)), closes [#4952](https://github.com/vuejs/vitepress/issues/4952)\n- respect markdown.cache = false on build too ([6d7422f](https://github.com/vuejs/vitepress/commit/6d7422f8fa321c641b1d5be3fa0c382400a2b78f))\n- simplify lang extraction logic; use markdown-it plugins in type-safe manner; bump deps ([4e548f5](https://github.com/vuejs/vitepress/commit/4e548f542469a366f327cdef1530bdb1a31542ad))\n- **theme:** add lang and dir attributes to language picker ([f0b29d7](https://github.com/vuejs/vitepress/commit/f0b29d7ef32a33f61c355d19561176411ede4b48))\n- **theme:** adjust margin of code blocks inside containers ([82fac5d](https://github.com/vuejs/vitepress/commit/82fac5d22c9e2b28d18dafcd458741a4b4d7a86b)), closes [#4921](https://github.com/vuejs/vitepress/issues/4921)\n- **theme:** avoid use of `:where` in selector list for now ([c2eaccd](https://github.com/vuejs/vitepress/commit/c2eaccd0d2109a6c64cee9fe615e48daaf4eda0e)), closes [#4923](https://github.com/vuejs/vitepress/issues/4923)\n- **theme:** disable whitespace wrapping for VPBadge ([#4968](https://github.com/vuejs/vitepress/issues/4968)) ([113d230](https://github.com/vuejs/vitepress/commit/113d2304784586028d9733036ccb585374731397))\n- **theme:** use nav height css var for curtain top in sidebar ([#4993](https://github.com/vuejs/vitepress/issues/4993)) ([be260fd](https://github.com/vuejs/vitepress/commit/be260fda6efc1d6c4b56219d7a17a19ab7a4ba76))\n\n### Features\n\n- export cacheAllGitTimestamps and getGitTimestamp ([31d87e2](https://github.com/vuejs/vitepress/commit/31d87e27387ebdceb22c047cc5f821761276d5f7))\n- **i18n,a11y:** change last update logic ([#4935](https://github.com/vuejs/vitepress/issues/4935)) ([187bf25](https://github.com/vuejs/vitepress/commit/187bf250e6496554fca0b070a5aba55484f7fc0b))\n- **markdown:** support custom display-name for fenced code blocks ([#4960](https://github.com/vuejs/vitepress/issues/4960)) ([3d61619](https://github.com/vuejs/vitepress/commit/3d61619ec0f0458c7ae04e7954b72a8e2ff399c0))\n- prevent `$` symbol selection in shell code ([#5025](https://github.com/vuejs/vitepress/issues/5025)) ([bf2715e](https://github.com/vuejs/vitepress/commit/bf2715ed67f290726fc6d4c85c203ca8f74cc907))\n- **theme:** allow passing functions for nav links ([#4963](https://github.com/vuejs/vitepress/issues/4963)) ([34cfa91](https://github.com/vuejs/vitepress/commit/34cfa91b6f14d8adfaa2d3c9f3eb6ad8b889ef1c))\n\n### Performance Improvements\n\n- make a single git call for timestamps instead of calling it for each file ([#4958](https://github.com/vuejs/vitepress/issues/4958)) ([6dfcdd3](https://github.com/vuejs/vitepress/commit/6dfcdd3fe8dc73e7b4ad7783df9530dedac1f6bd))\n\n### BREAKING CHANGES\n\n- `markdown-it-attrs` is disabled for fenced code blocks. For most users no change is required. If you want to add classes to code blocks, do it using shiki transformers instead.\n- Rename `cjkFriendly` to `cjkFriendlyEmphasis` in your vitepress config. Most people should be unaffected unless they want to disable the CJK emphasis behavior added v2.0.0-alpha.12.\n\n## [2.0.0-alpha.12](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.11...v2.0.0-alpha.12) (2025-08-20)\n\n### Bug Fixes\n\n- **hmr:** don't load config twice on server restart ([d1a8061](https://github.com/vuejs/vitepress/commit/d1a8061eb438c730ccc62ce2d7158dbe89cc5292))\n- **hmr:** no need for server restart on theme change ([d3a1567](https://github.com/vuejs/vitepress/commit/d3a15673bd0846c7837bcc4ff5a2e3239a02f1f9))\n- **hmr:** hmr not working for snippet imports in dynamic routes ([914467e](https://github.com/vuejs/vitepress/commit/914467e17fb759a9722951a3fd7568eb3bc4d4e6))\n- **theme:** fix local nav alignment and increase touch area ([43b36c0](https://github.com/vuejs/vitepress/commit/43b36c0c19c2b4696f8c38fdaf4318786ea7ae8e))\n- **theme:** nav background doesn't extend fully and gap after sidebar with non-overlay scrollbars ([7df3052](https://github.com/vuejs/vitepress/commit/7df30525121a28a46cc6c802f3155ccff8effaca)), closes [#4653](https://github.com/vuejs/vitepress/issues/4653)\n- **theme:** use clipboard-check instead of clipboard-copy for code copied icon ([1c8815d](https://github.com/vuejs/vitepress/commit/1c8815d53ed2d56b07938260df6566f1514f4bfc))\n\n### Features\n\n- add markdown-it-cjk-friendly ([9fc8462](https://github.com/vuejs/vitepress/commit/9fc8462726ccf1cdb78b6171c9f1f5964e79ca22)), closes [#3762](https://github.com/vuejs/vitepress/issues/3762) [#4752](https://github.com/vuejs/vitepress/issues/4752)\n- make postcssIsolateStyles idempotent ([0944777](https://github.com/vuejs/vitepress/commit/094477789328b80cff45cd973efa16b6a4db0a27))\n\n### BREAKING CHANGES\n\n- [markdown-it-cjk-friendly](https://www.npmjs.com/package/markdown-it-cjk-friendly) is enabled by default. This intentionally deviates from the official commonmark spec for the benefit of CJK users. **For most users, no change is required.** If you were using hacks to patch `scanDelims`, you can remove those. To disable the plugin, set `markdown: { cjkFriendly: false }` in your vitepress config.\n- `includeFiles` option in `postcssIsolateStyles` now defaults to `[/vp-doc\\.css/, /base\\.css/]`. You can remove explicit `includeFiles` if you were using it just to run it on `vp-doc.css`. To revert back to older behavior pass `includeFiles: [/base\\.css/]`. The underlying implementation is changed and `transform` and `exclude` options are no longer supported. Use `postcss-prefix-selector` directly if you've advanced use cases.\n\n## [2.0.0-alpha.11](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2025-08-14)\n\n### Bug Fixes\n\n- hmr working only once for markdown files ([8d8a5ac](https://github.com/vuejs/vitepress/commit/8d8a5ac281f090cd097bece792d9dd3ef00e5545)), closes [#4909](https://github.com/vuejs/vitepress/issues/4909)\n- html entities encoded twice in toc plugin ([8abbe29](https://github.com/vuejs/vitepress/commit/8abbe298d545de17d34a9bc1eb72af4c5a4b41b8)), closes [#4908](https://github.com/vuejs/vitepress/issues/4908)\n\n## [2.0.0-alpha.10](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2025-08-11)\n\n### Bug Fixes\n\n- **client:** base not stripped from relativePath in 404 pages ([b840877](https://github.com/vuejs/vitepress/commit/b840877aa83a5a24ffc1222e8a5a3dbf3e5105e8)), closes [#4850](https://github.com/vuejs/vitepress/issues/4850)\n- hmr of style blocks in dynamic routes ([#4903](https://github.com/vuejs/vitepress/issues/4903)) ([3d0fafb](https://github.com/vuejs/vitepress/commit/3d0fafba545f4b5028cf43d86027dd44dab14421))\n- make paths in `watchedFiles` absolute as mentioned in the docs ([318c14f](https://github.com/vuejs/vitepress/commit/318c14fa7c9fb949d74b7d9fae416e917766cf05))\n- module graph causing unnecessary route regeneration on every update ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43))\n- preserve externally added dynamic routes and pages ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43))\n- **search:** input placeholder being cut off in smaller viewports ([162c6a6](https://github.com/vuejs/vitepress/commit/162c6a69bf56945daa20d126aa034c59ee0c8a2e))\n- **search:** style tweaks for when searches are empty ([8b23217](https://github.com/vuejs/vitepress/commit/8b232171cc321bd3dc86b4357622815269f0b6f4))\n- **types:** externalize markdown-it types ([5bf835b](https://github.com/vuejs/vitepress/commit/5bf835b5074e9567852d552bfb5115c6456026e8))\n- **types:** pass generics deeply to user config ([777e2ca](https://github.com/vuejs/vitepress/commit/777e2caaacd93ce41b046f6c9d5ba80cc43ba37c))\n\n### Features\n\n- add source param to the deadlink check fn ([#4870](https://github.com/vuejs/vitepress/issues/4870)) ([8c027c2](https://github.com/vuejs/vitepress/commit/8c027c2a7c443074fd0d4890f7736b444f9254aa))\n- **theme:** add `rel=\"me\"` to social links by default ([#4873](https://github.com/vuejs/vitepress/issues/4873)) ([34886c6](https://github.com/vuejs/vitepress/commit/34886c667d1305a79d64c957f8c52931ea122f47))\n\n## [2.0.0-alpha.9](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.8...v2.0.0-alpha.9) (2025-07-26)\n\n### Bug Fixes\n\n- **md:** pass container option to gitHubAlertsPlugin ([#4848](https://github.com/vuejs/vitepress/issues/4848)) ([52f0eaa](https://github.com/vuejs/vitepress/commit/52f0eaa0849344aa45efbf7258a6287597e55a9a))\n- **theme:** remove duplicate text in sponsors grid ([3c51b22](https://github.com/vuejs/vitepress/commit/3c51b22ac98a12f193081d23799cb9f3f2ecf682)), closes [#4854](https://github.com/vuejs/vitepress/issues/4854)\n\n### Features\n\n- **search:** upgrade search to DocSearch v4-beta ([#4843](https://github.com/vuejs/vitepress/issues/4843)) ([ac61abe](https://github.com/vuejs/vitepress/commit/ac61abe7d7be5ef8b6939f18192896538eba1b8c))\n\n### BREAKING CHANGES\n\n- **search:** Uses DocSearch v4 beta. No change is required if you're not customizing the styles of navbar search button or modal. DocSearch AI features are in private beta, you can apply for them at https://forms.gle/iyfb5pC2CiiwszUKA\n\n## [2.0.0-alpha.8](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.7...v2.0.0-alpha.8) (2025-07-08)\n\n### Bug Fixes\n\n- adjust glob logic to always resolve glob relative to base ([5d41785](https://github.com/vuejs/vitepress/commit/5d41785ff7b016b08f587f1ef3318fc18d58f6ab)), closes [#4822](https://github.com/vuejs/vitepress/issues/4822)\n- **build:** ignore escaped `:` when splitting selector in `postcssIsolateStyles` ([#4830](https://github.com/vuejs/vitepress/issues/4830)) ([a629b03](https://github.com/vuejs/vitepress/commit/a629b03f0ee8a29d73a18481399d7de1c992faf2))\n- font preload not being generated in rolldown-vite ([ed387e8](https://github.com/vuejs/vitepress/commit/ed387e89d42a08c15a9f45c9c5e11c6750245490))\n- **theme:** remove extra slash when concatenating base with sidebar links ([c8fc80e](https://github.com/vuejs/vitepress/commit/c8fc80e438fffd98feaf7c72263bc3077792c4a2))\n\n## [2.0.0-alpha.7](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.6...v2.0.0-alpha.7) (2025-06-24)\n\n### Bug Fixes\n\n- **local-search:** parse headings with non-anchor `a` tags as titles properly ([#4809](https://github.com/vuejs/vitepress/issues/4809)) ([5359903](https://github.com/vuejs/vitepress/commit/53599039a01af6d8e17a6a6e9cea5c222cc5948c))\n- resolve pages after setting global vitepress config ([56ba65e](https://github.com/vuejs/vitepress/commit/56ba65e1301454df88f9a3856fa1a70dc052d314)), closes [#4803](https://github.com/vuejs/vitepress/issues/4803)\n\n### Features\n\n- **router:** add `replace` option to `useRouter` for history management ([#4788](https://github.com/vuejs/vitepress/issues/4788)) ([23541b4](https://github.com/vuejs/vitepress/commit/23541b4f83726cdac09ffcaf9141bba871cda690)), closes [#4787](https://github.com/vuejs/vitepress/issues/4787)\n- consistent glob options across content, data, and path loaders ([#4808](https://github.com/vuejs/vitepress/issues/4808)) ([7619521](https://github.com/vuejs/vitepress/commit/76195212596cd54095240246b7e78075ac3cbc27)), closes [#4807](https://github.com/vuejs/vitepress/issues/4807)\n- bump to vite 7 ([2ecd607](https://github.com/vuejs/vitepress/commit/2ecd607af15222eeddf0b888a72d0f913f5a3cd2))\n\n### Performance Improvements\n\n- render pages in contentLoader asynchronously ([36148a0](https://github.com/vuejs/vitepress/commit/36148a0bcf3a73d1fe3f0c5f33337b679f700053))\n\n### BREAKING CHANGES\n\n- Only `cwd`, `ignore`, `dot` and `debug` are supported in `globOptions` of `createContentLoader`. If you want to pass other options, you still can but you might need to suppress type errors.\n- Uses vite 7. See [vite migration guide](https://vite.dev/guide/migration.html) for more info. For most of the users no change is required. VitePress should work same as earlier, except for maybe some type mismatches if you're using third-party plugins. You can suppress them using `@ts-expect-error` or `as any` and report the issues at respective repositories.\n\n## [2.0.0-alpha.6](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.5...v2.0.0-alpha.6) (2025-06-12)\n\n### Bug Fixes\n\n- allow AdditionalConfigLoader to return void ([906a44a](https://github.com/vuejs/vitepress/commit/906a44a3ad488a46804757326af95cfb8cac6b75))\n- **build:** avoiding creating separate chunks for vite public assets ([21f24b9](https://github.com/vuejs/vitepress/commit/21f24b9994ea4807ac7e0be38408e9aaa3abe8a9))\n- **build:** emit lean chunks after vite has done processing ([26cb685](https://github.com/vuejs/vitepress/commit/26cb685adf54f07fe3e9fd7bfd49a0ff79956923)), closes [#4737](https://github.com/vuejs/vitepress/issues/4737)\n- **client:** properly skip removed lines when copying code blocks ([c128baf](https://github.com/vuejs/vitepress/commit/c128baf0c41d5113c1b876f691e0185201b1f500))\n- disable appearance scripts in zero-js mode ([e7f9d05](https://github.com/vuejs/vitepress/commit/e7f9d05c3e2ef4f4c1db3b2c17e586f0fc26a6f6)), closes [#4766](https://github.com/vuejs/vitepress/issues/4766)\n- don't preload dynamic imports ([801648a](https://github.com/vuejs/vitepress/commit/801648a4c9d91e7f96302932ac9247d5bdd64ef7)), closes [#4770](https://github.com/vuejs/vitepress/issues/4770)\n- gather additional config files even if root .vitepress/config is not present ([26f178c](https://github.com/vuejs/vitepress/commit/26f178cfaa330a017bb69b1ec6bd482d63a100a9))\n- set `preserveEntrySignatures` for rolldown-vite ([#4784](https://github.com/vuejs/vitepress/issues/4784)) ([4351bc0](https://github.com/vuejs/vitepress/commit/4351bc0b831277401e08b350d7d7c0ab9ea0c9ed))\n- skip fields not supported by rolldown for rolldown-vite ([#4747](https://github.com/vuejs/vitepress/issues/4747)) ([4e3fce4](https://github.com/vuejs/vitepress/commit/4e3fce40c9bab261f3c5e31833475c3e2c6ba0cf))\n- **theme/regression:** code blocks not aligned properly in rtl layouts ([a643347](https://github.com/vuejs/vitepress/commit/a64334753079a5b874a482508d9ee255d2a0ea38))\n- **theme:** hide native search input cancel button ([#4723](https://github.com/vuejs/vitepress/issues/4723)) ([2c4944f](https://github.com/vuejs/vitepress/commit/2c4944f06ccf46fcf58fb18a1819fd167c9533cc))\n- **theme:** prevent error in handleSearchHotKey method ([#4782](https://github.com/vuejs/vitepress/issues/4782)) ([21fcecc](https://github.com/vuejs/vitepress/commit/21fcecce0581d0c461bc15e03429f61ff444a655))\n- use v-pre for mathjax instead of isCustomElement ([c9b8928](https://github.com/vuejs/vitepress/commit/c9b89282f3573998cfc4103bbddbd73d2529cb66))\n\n### Features\n\n- use `oxc-minify` instead of `transformWithEsbuild` when rolldown-vite is used ([#4748](https://github.com/vuejs/vitepress/issues/4748)) ([7c1dc48](https://github.com/vuejs/vitepress/commit/7c1dc48b2fd08e128f7bbe26690fb6534dfb4b95))\n\n## [2.0.0-alpha.5](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.4...v2.0.0-alpha.5) (2025-04-21)\n\n### Bug Fixes\n\n- don't remove shiki styles from `pre` and remove unnecessary transformers (#4652) ([db58af5](https://github.com/vuejs/vitepress/commit/db58af5c66e563e7663084057a9853d8f2da984c)), closes [#4652](https://github.com/vuejs/vitepress/issues/4652)\n- normalize url fragments in internal links to correctly resolve to anchors ([#4628](https://github.com/vuejs/vitepress/issues/4628)) ([e25d080](https://github.com/vuejs/vitepress/commit/e25d0805505db2f1116e99d38a488d5cb39ed426)), closes [#4605](https://github.com/vuejs/vitepress/issues/4605)\n- **theme-default:** ensure proper sizing of SVG hero images ([#4639](https://github.com/vuejs/vitepress/issues/4639)) ([7d94481](https://github.com/vuejs/vitepress/commit/7d9448192079e59493aa5c1e86cdf6d6deae8e36))\n\n### Features\n\n- add `isHome` frontmatter option (#4673) ([544cd81](https://github.com/vuejs/vitepress/commit/544cd8125985b9e3af7fee68ea9592d159799e01)), closes [#4673](https://github.com/vuejs/vitepress/issues/4673)\n- add `custom-block-title-default` class when default title is used for containers ([#4643](https://github.com/vuejs/vitepress/issues/4643)) ([63079bf](https://github.com/vuejs/vitepress/commit/63079bff03b15861d174199f7361a2aff84380e0))\n- add `dir=ltr` by default on code block pre elements instead of relying on css ([19faa16](https://github.com/vuejs/vitepress/commit/19faa16169b44f52bedf1401b4a97b2a8ffdeacb))\n- **default-theme:** make VPButton slottable ([#4689](https://github.com/vuejs/vitepress/issues/4689)) ([0b70397](https://github.com/vuejs/vitepress/commit/0b7039719782e85119ad22be5c89ef3d233ffaae))\n- support distributed config files ([#4660](https://github.com/vuejs/vitepress/issues/4660)) ([c5e2e4d](https://github.com/vuejs/vitepress/commit/c5e2e4db818c06f3c1b458753f22fb6ec1609628))\n- **theme:** make \"Take me home\" button's link customizable ([#4658](https://github.com/vuejs/vitepress/issues/4658)) ([0267dca](https://github.com/vuejs/vitepress/commit/0267dcafa20beea24ef359d24bb1fa99e1ffda49))\n\n### Performance Improvements\n\n- call `module.enableCompileCache()` ([70de34c](https://github.com/vuejs/vitepress/commit/70de34c0387d9668ada3ea9a795f9ebee3535f5b))\n- hoist expensive operations in useLayout ([e5ab067](https://github.com/vuejs/vitepress/commit/e5ab0676a9a8dc607e213eb691439b2e4ee472b7))\n\n### BREAKING CHANGES\n\n- `useLocalNav` and `useSidebar` are removed in favor of `useLayout`. To migrate, just do find and replace. Sidebar controls are no longer exported, but we didn't find any usage on GitHub. If there is demand, we can export respective composables later. `DefaultTheme.DocSidebar` and `DefaultTheme.DocLocalNav` types are also removed.\n- `vp-adaptive-theme` class is no longer added to code blocks when there is single theme. Theme authors supporting single code theme can use `.shiki:not(.shiki-themes)` as selector. Alternatively, it might be better to use the bg/fg variables set on the `.shiki` block to keep things generic.\n- `vp-code` class is no longer added to code blocks. Use `.shiki` or `pre.shiki` or `[class*='language-'] pre` instead. People not customizing their themes are not affected.\n\n## [2.0.0-alpha.4](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.3...v2.0.0-alpha.4) (2025-03-09)\n\n### Bug Fixes\n\n- **build/regression:** langAlias not working ([06ae2bf](https://github.com/vuejs/vitepress/commit/06ae2bf3a4ee02351530b0bd055e577ca6509d62)), closes [#4581](https://github.com/vuejs/vitepress/issues/4581)\n- don't hardcode `tabindex` attr in table renderer ([#4082](https://github.com/vuejs/vitepress/issues/4082)) ([aadc517](https://github.com/vuejs/vitepress/commit/aadc517c69fb239bdda99173bbc123ace567484b))\n- hmr not working for watched files in path loaders ([e271695](https://github.com/vuejs/vitepress/commit/e271695d716247455ca620948f814e6c8ca0e3c4)), closes [#4525](https://github.com/vuejs/vitepress/issues/4525)\n- ignore non-text content in permalink generation and fix types of markdown.config ([a8a1800](https://github.com/vuejs/vitepress/commit/a8a1800ae578be88027aa4ec7561ada4d055b888))\n- prevent reload on first server start in fresh installations ([d8a884e](https://github.com/vuejs/vitepress/commit/d8a884ed0f754523765058a70149cdbaf6942341))\n- properly merge classes in custom containers ([#4128](https://github.com/vuejs/vitepress/issues/4128)) ([8aad617](https://github.com/vuejs/vitepress/commit/8aad617446c03d39a65a0b21e9fce43bc484af1e))\n- rebuild dynamic routes cache on server restart ([9f54714](https://github.com/vuejs/vitepress/commit/9f54714e7db69fd4902f1917f927456c71b5a292)), closes [#4525](https://github.com/vuejs/vitepress/issues/4525)\n\n### Features\n\n- allow matching region end in snippets without tag ([#4287](https://github.com/vuejs/vitepress/issues/4287)) ([1a2f81d](https://github.com/vuejs/vitepress/commit/1a2f81de4d6549dd1adf86ae131d1a861158bd2d))\n- improve region regexes for snippet plugin ([1a6684c](https://github.com/vuejs/vitepress/commit/1a6684cf1054d326bc1dd6eeb9fb78b150ac2b2a))\n- support using header anchors in markdown file inclusion ([#4608](https://github.com/vuejs/vitepress/issues/4608)) ([b99d512](https://github.com/vuejs/vitepress/commit/b99d5123c9b2afdc7461089e03476c34d7816faf)), closes [#4375](https://github.com/vuejs/vitepress/issues/4375) [#4382](https://github.com/vuejs/vitepress/issues/4382)\n\n## [2.0.0-alpha.3](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.2...v2.0.0-alpha.3) (2025-02-24)\n\n### Bug Fixes\n\n- **build:** `--minify` not working as documented ([9b5c037](https://github.com/vuejs/vitepress/commit/9b5c0377cd3474447c84b2901801287f3caf3d82)), closes [#4523](https://github.com/vuejs/vitepress/issues/4523)\n- **build:** deterministic code group ids ([#4565](https://github.com/vuejs/vitepress/issues/4565)) ([b930b8d](https://github.com/vuejs/vitepress/commit/b930b8d5310f1691d8d9f009f45b70122e4ce800))\n- **markdown:** include content of all tokens in heading ids ([68dff2a](https://github.com/vuejs/vitepress/commit/68dff2af8547ae70f6622ac826affd76f2f6378e)), closes [#4561](https://github.com/vuejs/vitepress/issues/4561)\n- **client:** set correct oldURL and newURL for hashchange ([#4573](https://github.com/vuejs/vitepress/issues/4573)) ([d1f2afd](https://github.com/vuejs/vitepress/commit/d1f2afdf0fbb022f12cc12295723b3b7c7ef5cb1))\n- **theme:** allow interactions behind scroll shadow ([#4537](https://github.com/vuejs/vitepress/issues/4537)) ([091d584](https://github.com/vuejs/vitepress/commit/091d5840ae15b64e04e8c07fbc0263a2749571bd))\n- **theme:** code block contrast ratio ([#4487](https://github.com/vuejs/vitepress/issues/4487)) ([5dccaee](https://github.com/vuejs/vitepress/commit/5dccaeef055beb109919f8990032975a0d630384))\n- **build:** fix flaky embedded languages highlighting ([#4566](https://github.com/vuejs/vitepress/issues/4566)) ([1969cf4](https://github.com/vuejs/vitepress/commit/1969cf4f3b93ad105595e4e2f8b030b04eb1c975))\n\n### Features\n\n- **cli:** support custom `srcDir` ([#4270](https://github.com/vuejs/vitepress/issues/4270)) ([518c094](https://github.com/vuejs/vitepress/commit/518c0945f159aae679ef710bb48ae3ab3891cc9f))\n- **cli:** support custom npm scripts prefix ([#4271](https://github.com/vuejs/vitepress/issues/4271)) ([e5a0ee8](https://github.com/vuejs/vitepress/commit/e5a0ee8161752a77c5bb9546245a940cb5f28fb8))\n- **build:** dynamic routes plugin overhaul ([#4525](https://github.com/vuejs/vitepress/issues/4525)) ([a62ea6a](https://github.com/vuejs/vitepress/commit/a62ea6a832a33b756642b24ad5d38c248e08b554))\n- **build:** update to shiki v3 ([#4571](https://github.com/vuejs/vitepress/issues/4571)) ([52c2aa1](https://github.com/vuejs/vitepress/commit/52c2aa178d4b3fa98b863cf28f0ccf6d2aabcd93))\n- **build:** use `markdown-it-async`, remove `synckit` ([#4507](https://github.com/vuejs/vitepress/issues/4507)) ([8062235](https://github.com/vuejs/vitepress/commit/80622356f1d648577ee47ee3a44b04bb015ee462))\n\n### BREAKING CHANGES\n\n- markdown-it-async is used instead of markdown-it. If you're using custom content renderer for local search, you'll need to do `await md.renderAsync` instead of `md.render`.\n- Internals are modified a bit to better support vite 6 and handle HMR more correctly. For most users this won't need any change on their side.\n- shiki is upgraded to v3. There shouldn't be any breaking change but if you see any issue, please report it.\n\n## [2.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2025-01-23)\n\n### Bug Fixes\n\n- fix docsearch navigation and rendering ([e035027](https://github.com/vuejs/vitepress/commit/e0350275b39258a61ee867840ce1c6f5b2cecf2a))\n- **types:** support preload built-in shiki languages as string ([#4513](https://github.com/vuejs/vitepress/issues/4513)) ([4f77b4f](https://github.com/vuejs/vitepress/commit/4f77b4fdfdbe945e482348a57731bff5fb4672fc))\n\n### Features\n\n- allow `markdown.config` and `markdown.preConfig` to accept async function ([#4512](https://github.com/vuejs/vitepress/issues/4512)) ([b88ae8d](https://github.com/vuejs/vitepress/commit/b88ae8d4a11a20104b2007c2631eb7aeb123d965))\n- support same page navigation in `router.go` and expose decoded hash and query from the `route` object ([#4511](https://github.com/vuejs/vitepress/issues/4511)) ([23d3281](https://github.com/vuejs/vitepress/commit/23d3281ed6f1111ab15708ca1fd86202674f8ef7))\n\n## [2.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v1.6.2...v2.0.0-alpha.1) (2025-01-22)\n\n### Features\n\n- upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf))\n\n## [1.6.3](https://github.com/vuejs/vitepress/compare/v1.6.2...v1.6.3) (2025-01-22)\n\n### Bug Fixes\n\n- docsearch not rendering properly ([3e4120e](https://github.com/vuejs/vitepress/commit/3e4120e94805156bf63587fd633162433dbaf260))\n\n## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22)\n\n### Bug Fixes\n\n- fix static content removal for lean chunks due to Vue 3.5 changes ([#4508](https://github.com/vuejs/vitepress/issues/4508)) ([8214cae](https://github.com/vuejs/vitepress/commit/8214cae21bb16842d8870d5867e974146c51fd61))\n\n## [1.6.1](https://github.com/vuejs/vitepress/compare/v1.6.0...v1.6.1) (2025-01-20)\n\n### Bug Fixes\n\n- **build:** escape `$` in replace pattern in dynamic routes plugin ([e812916](https://github.com/vuejs/vitepress/commit/e8129167c76104d59d31a77b16dff3458e6af5eb)), closes [#4499](https://github.com/vuejs/vitepress/issues/4499)\n- **theme/regression:** broken hero heading at certain viewports ([37dbe89](https://github.com/vuejs/vitepress/commit/37dbe895d4cf813e6eb1289f24c637945eec0d1f))\n\n# [1.6.0](https://github.com/vuejs/vitepress/compare/v1.5.0...v1.6.0) (2025-01-20)\n\n### Bug Fixes\n\n- **build:** out of order css in prod builds ([241d17d](https://github.com/vuejs/vitepress/commit/241d17d9839f06b17c3898b1a8ba0f9fa12da0d1)), closes [#4098](https://github.com/vuejs/vitepress/issues/4098)\n- **build:** properly strip vpi-social css declaration in debug mode ([c61182a](https://github.com/vuejs/vitepress/commit/c61182ab278350699b5d50461788478a340790aa))\n- **build:** respect `vite.clearScreen` in build ([8ea776a](https://github.com/vuejs/vitepress/commit/8ea776addc2c3bcabf3c707a9a81d6e0080a8fcb)), closes [#4468](https://github.com/vuejs/vitepress/issues/4468)\n- **build:** specify mode for iconify ([8a5e8ea](https://github.com/vuejs/vitepress/commit/8a5e8ea4f5b7cba0a6c909d8949f0c20426104a6))\n- **theme:** apply `externalLinkIcon` option on `VPHome` ([#4492](https://github.com/vuejs/vitepress/issues/4492)) ([fe48943](https://github.com/vuejs/vitepress/commit/fe48943640895d859811b81f86d78c3e510dbe54))\n- **theme:** don't show external link icon for images ([096bba1](https://github.com/vuejs/vitepress/commit/096bba19fb61c4b2f8f527046b4b0fe2e91c6bd6))\n- **theme:** ignore footnote-ref for outline ([1832617](https://github.com/vuejs/vitepress/commit/183261753b04c2c96ddb8c10e520c748c6d3e613)), closes [#4402](https://github.com/vuejs/vitepress/issues/4402)\n- **theme:** includes text to h1 tag for hero page ([#4472](https://github.com/vuejs/vitepress/issues/4472)) ([bd896c6](https://github.com/vuejs/vitepress/commit/bd896c638f8046f6546b5b32e8f98f3707aa8d05)), closes [#4453](https://github.com/vuejs/vitepress/issues/4453)\n\n### Features\n\n- **build:** export normalize function from shared chunk ([616f63f](https://github.com/vuejs/vitepress/commit/616f63f5f08a57347f2800e2d147d5bcd1cd072d)), closes [#4401](https://github.com/vuejs/vitepress/issues/4401)\n- **theme:** allow customizing skip to content label ([ff254dc](https://github.com/vuejs/vitepress/commit/ff254dcbe6f2bcc89c34d2d2f4050229dc094400)), closes [#4288](https://github.com/vuejs/vitepress/issues/4288)\n- **theme:** export VPNavBarSearch ([23522ab](https://github.com/vuejs/vitepress/commit/23522ab83ff33802d382fa066578dd87eb06789d)), closes [#4476](https://github.com/vuejs/vitepress/issues/4476)\n- **theme:** export VPFeatures ([#4356](https://github.com/vuejs/vitepress/issues/4356)) ([6442e17](https://github.com/vuejs/vitepress/commit/6442e174838aec9668325bb1199419908e7dd728))\n\n### Miscellaneous\n\n- **build:** shiki transformers now use v3 [matching algorithm](https://shiki.style/packages/transformers#matching-algorithm) ([373f9b9](https://github.com/vuejs/vitepress/commit/373f9b933ee44f33a15ebdcfcb6db6dfac52f739))\n\n# [1.5.0](https://github.com/vuejs/vitepress/compare/v1.4.5...v1.5.0) (2024-11-04)\n\n### Features\n\n- on-demand social icons ([#4339](https://github.com/vuejs/vitepress/issues/4339)) ([05f2f0d](https://github.com/vuejs/vitepress/commit/05f2f0d26153ace74b6c023184224d4fada137c2)), closes [#4256](https://github.com/vuejs/vitepress/issues/4256) [#4135](https://github.com/vuejs/vitepress/issues/4135) [#4076](https://github.com/vuejs/vitepress/issues/4076) [#3809](https://github.com/vuejs/vitepress/issues/3809) [#3750](https://github.com/vuejs/vitepress/issues/3750) [#1214](https://github.com/vuejs/vitepress/issues/1214) [#2768](https://github.com/vuejs/vitepress/issues/2768) [#2861](https://github.com/vuejs/vitepress/issues/2861)\n\n## [1.4.5](https://github.com/vuejs/vitepress/compare/v1.4.4...v1.4.5) (2024-11-03)\n\n### Bug Fixes\n\n- lang lazy load not working with twoslash ([fc92a77](https://github.com/vuejs/vitepress/commit/fc92a77a5d871b5252bcb82639f5c3551d5c70bb)), closes [#4334](https://github.com/vuejs/vitepress/issues/4334)\n- typo in missing language check ([dcb8450](https://github.com/vuejs/vitepress/commit/dcb8450f1166d7731c26a0eb5ec6d931bc283172))\n\n## [1.4.3](https://github.com/vuejs/vitepress/compare/v1.4.2...v1.4.3) (2024-10-31)\n\n### Performance Improvements\n\n- lazy load shiki languages ([#4326](https://github.com/vuejs/vitepress/issues/4326)) ([8299778](https://github.com/vuejs/vitepress/commit/829977876a21da4f0af5d27593a2d81eb9af0c33))\n\n## [1.4.2](https://github.com/vuejs/vitepress/compare/v1.4.1...v1.4.2) (2024-10-29)\n\n### Bug Fixes\n\n- cache markdown-it instance and properly dispose shiki on config reload ([#4321](https://github.com/vuejs/vitepress/issues/4321)) ([45968cd](https://github.com/vuejs/vitepress/commit/45968cdc509e04f8e191d28ba7d8d97b08fc578e)) ([acfe97f](https://github.com/vuejs/vitepress/commit/acfe97f60872d251c75c5985ca9841f84392850d))\n- **regression:** hmr not working with markdown includes due to wrong cache key ([615aed5](https://github.com/vuejs/vitepress/commit/615aed5df700ad98f82a74fbc785d290d1c5a018)), closes [#4289](https://github.com/vuejs/vitepress/issues/4289) [#4303](https://github.com/vuejs/vitepress/issues/4303)\n- remove explicit chinese fonts ([#4286](https://github.com/vuejs/vitepress/issues/4286)) ([668e9f7](https://github.com/vuejs/vitepress/commit/668e9f7050f236d571fe2fc2f41e5548d974b503)) ([b893550](https://github.com/vuejs/vitepress/commit/b8935502fbb590449e7d094bdde9c9ae1ac67d0c)), closes [#4286](https://github.com/vuejs/vitepress/issues/4286)\n- **theme/a11y:** don't select search result unless mouse is actually moved ([e638d85](https://github.com/vuejs/vitepress/commit/e638d855cfc8e4e0c9b95c284548ae31233139f5)), closes [#4297](https://github.com/vuejs/vitepress/issues/4297)\n- **theme:** add types for `VPLink`, `VPSocialLink` and `VPSocialLinks` exports ([#4284](https://github.com/vuejs/vitepress/issues/4284)) ([fcae4d5](https://github.com/vuejs/vitepress/commit/fcae4d5554df2130b9a7e5ad8e0cc83eccf88bec))\n- **theme:** don't escape html in `siteTitle` ([#4308](https://github.com/vuejs/vitepress/issues/4308)) ([bd690d6](https://github.com/vuejs/vitepress/commit/bd690d6a9b895f15d5906d245b404f02cfce7489))\n\n## [1.4.1](https://github.com/vuejs/vitepress/compare/v1.4.0...v1.4.1) (2024-10-13)\n\n### Bug Fixes\n\n- broken rewrites on windows ([#4268](https://github.com/vuejs/vitepress/issues/4268)) ([b46d6d3](https://github.com/vuejs/vitepress/commit/b46d6d3a204f5ce347647bfd1ab8073bf313afd6))\n- **client:** use `usePreferredDark` with `appearance: \"force-auto\"` ([#4263](https://github.com/vuejs/vitepress/issues/4263)) ([3e8fc40](https://github.com/vuejs/vitepress/commit/3e8fc40c3621da1ef35645d376dab7765b35bb40))\n- **client:** wrong script async check ([461a5b0](https://github.com/vuejs/vitepress/commit/461a5b001d29f95169f60fe28bc610e3f6e8fd66))\n- **theme:** bind missing no icon prop in the menu link component [#4260](https://github.com/vuejs/vitepress/issues/4260) ([b96712c](https://github.com/vuejs/vitepress/commit/b96712c0744f9ac7ebd65cf4087b2e9fd0d6762b))\n- **theme:** improve local search input a11y ([#4066](https://github.com/vuejs/vitepress/issues/4066)) ([92b92ae](https://github.com/vuejs/vitepress/commit/92b92aefcab9fbb28b51da70ee8ab21724098277))\n\n### Features\n\n- **experimental:** support passing function for rewrites ([#4274](https://github.com/vuejs/vitepress/issues/4274)) ([8436472](https://github.com/vuejs/vitepress/commit/8436472c7874cb16caf9432660b395ca9ba68f9d))\n\n# [1.4.0](https://github.com/vuejs/vitepress/compare/v1.3.4...v1.4.0) (2024-10-07)\n\n### Bug Fixes\n\n- `vueRE` conflicting with `lineNoRE` ([#4247](https://github.com/vuejs/vitepress/issues/4247)) ([2ac64b8](https://github.com/vuejs/vitepress/commit/2ac64b8d4180f2a7c54fda57df7f3a0a52488d62))\n- hmr not updating page data in rewritten paths and file path is wrong in mdit for dynamic routes ([c46e4b7](https://github.com/vuejs/vitepress/commit/c46e4b784ddb9ce3bd1cfcc3de1d1d676535cb5b)), closes [#4172](https://github.com/vuejs/vitepress/issues/4172)\n- remove font synthesis in webfont mode, google fonts now support italic axis in inter ([1628918](https://github.com/vuejs/vitepress/commit/1628918f30b5602b83c51a2a8f4ec5e773cf7445))\n- **theme:** change the order of CSS rules of `VPFlyout` ([#4225](https://github.com/vuejs/vitepress/issues/4225)) ([68150a6](https://github.com/vuejs/vitepress/commit/68150a6f3349c1741ed5683e3010d9ecea02f3a8)), closes [#4224](https://github.com/vuejs/vitepress/issues/4224)\n- **theme:** respect custom tag prop in VPButton component ([#4185](https://github.com/vuejs/vitepress/issues/4185)) ([9c5d348](https://github.com/vuejs/vitepress/commit/9c5d348c034eb6773562c93cad699d287051aa7b))\n\n### Features\n\n- add `data-title` attribute for code group label tag ([#4152](https://github.com/vuejs/vitepress/issues/4152)) ([bc7271d](https://github.com/vuejs/vitepress/commit/bc7271d258047feb8a39c97ebc5e2a16bf899bb5))\n- allow ignoring certain headers and their subtrees completely in outline ([3e11b6a](https://github.com/vuejs/vitepress/commit/3e11b6abf5fbe80c2bc733f590ab57c7b2cc06f2)), closes [#4171](https://github.com/vuejs/vitepress/issues/4171)\n- **client:** add `onAfterPageLoad` hook in router ([#4126](https://github.com/vuejs/vitepress/issues/4126)) ([315c220](https://github.com/vuejs/vitepress/commit/315c22004993f6f1cbdbb59178e46745d8e505a6))\n- support adding extra attributes to snippet imports (useful for twoslash) ([#4100](https://github.com/vuejs/vitepress/issues/4100)) ([e8f7dd1](https://github.com/vuejs/vitepress/commit/e8f7dd16f6139fdfd129b86caff4b6613dd1e887))\n- **theme:** expose theme default VPLink & VPSocialLink(s) component ([#4178](https://github.com/vuejs/vitepress/issues/4178)) ([615e33b](https://github.com/vuejs/vitepress/commit/615e33bb24d5005574af971ffcf1f41d751a855c))\n- trigger `onContentUpdated` on frontmatter-only changes too ([0db269a](https://github.com/vuejs/vitepress/commit/0db269a4c5d90ecf69f0219982cdf8f335e787ce))\n\n## [1.3.4](https://github.com/vuejs/vitepress/compare/v1.3.3...v1.3.4) (2024-08-24)\n\n### Bug Fixes\n\n- check if `_importGlobMap` (vite internal) exists before using it ([612d66f](https://github.com/vuejs/vitepress/commit/612d66fbb5162d9905cfb10919ca1761ce8c4680))\n\n## [1.3.3](https://github.com/vuejs/vitepress/compare/v1.3.2...v1.3.3) (2024-08-17)\n\n### Miscellaneous\n\n- bump deps ([a20db24](https://github.com/vuejs/vitepress/commit/a20db247822438ac4e0e76bc4a2b4ee2f5d94940))\n\n## [1.3.2](https://github.com/vuejs/vitepress/compare/v1.3.1...v1.3.2) (2024-08-05)\n\n### Bug Fixes\n\n- multiple cache busting imports causing useData to fail ([2b3e486](https://github.com/vuejs/vitepress/commit/2b3e486ab913ff77707410b9cee3ba6d256ccc95)), closes [#3820](https://github.com/vuejs/vitepress/issues/3820), reverts [#3398](https://github.com/vuejs/vitepress/issues/3398), reopens [#3363](https://github.com/vuejs/vitepress/issues/3363)\n- **theme:** excerpt style in LocalSearchBox ([#4050](https://github.com/vuejs/vitepress/issues/4050)) ([2bc0d39](https://github.com/vuejs/vitepress/commit/2bc0d39d5089841986f0988fc9cfe15533d3a0c6))\n\n## [1.3.1](https://github.com/vuejs/vitepress/compare/v1.3.0...v1.3.1) (2024-07-14)\n\n### Bug Fixes\n\n- don't reopen browser on restart when `vite.server.open` is specified ([6263db1](https://github.com/vuejs/vitepress/commit/6263db170a658ea887ef4b2bfe4b5239a820e0d9)), closes [#4040](https://github.com/vuejs/vitepress/issues/4040)\n- **theme/regression:** typo in component props resulting in nested titles not showing in navbar ([01d0d45](https://github.com/vuejs/vitepress/commit/01d0d45292602cbb7de492f0c953ddb239842116)), closes [#4042](https://github.com/vuejs/vitepress/issues/4042)\n\n# [1.3.0](https://github.com/vuejs/vitepress/compare/v1.2.3...v1.3.0) (2024-07-07)\n\n### Bug Fixes\n\n- **build:** don't normalize links containing target or download property ([e24899a](https://github.com/vuejs/vitepress/commit/e24899a073d066486e5f7ae0c47ba6d901d5ae51)), closes [#3947](https://github.com/vuejs/vitepress/issues/3947)\n- **build:** respect frontmatter.lastUpdated for pageData.lastUpdated and sitemap generation ([7fcf462](https://github.com/vuejs/vitepress/commit/7fcf462eb8c2be6e72b4426a8211fcd6961e4967)), closes [#3931](https://github.com/vuejs/vitepress/issues/3931)\n- **build:** sort pageToHashMap to ensure stable assets ([e302328](https://github.com/vuejs/vitepress/commit/e302328a4ce3242cbfb7112e856840b7346aa16a)), closes [#4016](https://github.com/vuejs/vitepress/issues/4016)\n- **client:** do nothing on anchor elements with empty href ([6461f5d](https://github.com/vuejs/vitepress/commit/6461f5d42b3bfed1d7959e1167fc77f61d08f314)), closes [#3950](https://github.com/vuejs/vitepress/issues/3950)\n- don't do git log on non-existent file ([387acf7](https://github.com/vuejs/vitepress/commit/387acf71aa351e23ca3402713020a3571ad17155)), closes [#4008](https://github.com/vuejs/vitepress/issues/4008)\n- don't reopen browser on restart ([d837e82](https://github.com/vuejs/vitepress/commit/d837e82bc8bde63df737be2a1290a2e70c8a0bf3)), closes [#4001](https://github.com/vuejs/vitepress/issues/4001)\n- properly handle svg anchor elements ([b785bd6](https://github.com/vuejs/vitepress/commit/b785bd6ab3b5dd909aa955dc9e03b08e66b76294))\n- **theme:** add styles for h4 too ([b54d7b0](https://github.com/vuejs/vitepress/commit/b54d7b0d7cd1257bcadd25f9b69cba21d0a3dff6))\n- **theme:** deep watch sidebar groups and force render on match change ([97f9469](https://github.com/vuejs/vitepress/commit/97f9469b6d4eb7ba9de9a1111986581d1f704ec3)), closes [#3613](https://github.com/vuejs/vitepress/issues/3613)\n- **theme:** dim color for all text like elements inside blockquotes ([5d3ed87](https://github.com/vuejs/vitepress/commit/5d3ed87f8530134fa709681ebadb2f3cfc68680e)), closes [#3929](https://github.com/vuejs/vitepress/issues/3929)\n- **theme:** force update title attribute on hydration ([d348da7](https://github.com/vuejs/vitepress/commit/d348da770c2a68993d1a40d1c0223e42a681057a)), closes [#4004](https://github.com/vuejs/vitepress/issues/4004)\n- **theme:** show filled nav bar when nav screen is open ([0fc70e2](https://github.com/vuejs/vitepress/commit/0fc70e2d0c29c92a1dceba035295a3fac84ffc00))\n\n### Features\n\n- allow using components in navigation bar ([#4000](https://github.com/vuejs/vitepress/issues/4000)) ([fa87d81](https://github.com/vuejs/vitepress/commit/fa87d8150d8185fa8a22cd6b6e762632b83f8231))\n- **cli/init:** allow passing target dir as command argument ([#3948](https://github.com/vuejs/vitepress/issues/3948)) ([99053ba](https://github.com/vuejs/vitepress/commit/99053baea7eb6aa62a11a2cfd4b1e6e60311dd63))\n- **markdown:** support including specific regions from markdown files ([#3978](https://github.com/vuejs/vitepress/issues/3978)) ([143b1e9](https://github.com/vuejs/vitepress/commit/143b1e91f3696507d33666ec5847e7b64a771bcf))\n- support `force-auto` as an option for appearance ([1e8bb48](https://github.com/vuejs/vitepress/commit/1e8bb48bc2891ea388bf0b9edd2f5b612bb1e85d)), closes [#3946](https://github.com/vuejs/vitepress/issues/3946)\n- **theme:** export VPHomeContent ([#3960](https://github.com/vuejs/vitepress/issues/3960)) ([8aa6ccb](https://github.com/vuejs/vitepress/commit/8aa6ccbe32655f76c390d15568f69f83d079385d)), closes [#3954](https://github.com/vuejs/vitepress/issues/3954)\n\n## [1.2.3](https://github.com/vuejs/vitepress/compare/v1.2.2...v1.2.3) (2024-06-04)\n\n### Bug Fixes\n\n- **theme,a11y:** handle overflow on long mathematical equation and make tables focusable ([#3932](https://github.com/vuejs/vitepress/issues/3932)) (closes [#3914](https://github.com/vuejs/vitepress/issues/3914)) ([afc611d](https://github.com/vuejs/vitepress/commit/afc611d399d2780550ae04caa0e73e1c0c69a680))\n- **types:** wrong types generated for markdown-it > mdurl ([48ca76c](https://github.com/vuejs/vitepress/commit/48ca76c523d9b979a678d52447f5ce324799e47f)), closes [#3935](https://github.com/vuejs/vitepress/issues/3935)\n\n## [1.2.2](https://github.com/vuejs/vitepress/compare/v1.2.1...v1.2.2) (2024-05-21)\n\n### Bug Fixes\n\n- dont escape ampersand twice in title ([7ea3572](https://github.com/vuejs/vitepress/commit/7ea357256c855ae0a9a142c14bbd5e7d344ef865))\n\n## [1.2.1](https://github.com/vuejs/vitepress/compare/v1.2.0...v1.2.1) (2024-05-21)\n\n### Bug Fixes\n\n- **a11y:** make code blocks accessible with keyboard ([#3902](https://github.com/vuejs/vitepress/issues/3902)) ([cb308b9](https://github.com/vuejs/vitepress/commit/cb308b9295e1e661c2c72fa4229b5c7d83278d49))\n- escape title properly in build ([49b1233](https://github.com/vuejs/vitepress/commit/49b1233378436054c07a6ef646d0029096124021))\n- **theme:** remove unnecessary navigation role on nav element ([af4717d](https://github.com/vuejs/vitepress/commit/af4717d6820233a011200d44abba53d0f66bfad3))\n\n# [1.2.0](https://github.com/vuejs/vitepress/compare/v1.1.4...v1.2.0) (2024-05-18)\n\n### Bug Fixes\n\n- **build:** show file info on error ([f0debd2](https://github.com/vuejs/vitepress/commit/f0debd20f48ab7eb58cfd142147531509d6c0209))\n- **dev:** match dev and prod routing behavior ([#3837](https://github.com/vuejs/vitepress/issues/3837)) ([b360ac8](https://github.com/vuejs/vitepress/commit/b360ac88df3bfd60e3498cc19066c0c90261ee4f))\n- **markdown:** entities and escapes not working properly ([#3882](https://github.com/vuejs/vitepress/issues/3882)) ([d5dbd70](https://github.com/vuejs/vitepress/commit/d5dbd704ceb215ebf3ce9b23deec6e6c90634f0a))\n- render 404 page completely on client to infer locale from browser path ([#3858](https://github.com/vuejs/vitepress/issues/3858)) ([728cb15](https://github.com/vuejs/vitepress/commit/728cb15677f4f84b33bed6bb2f70f47600ea1057))\n- **style:** prefer YaHei over DengXian ([f0a37b4](https://github.com/vuejs/vitepress/commit/f0a37b4b8445ec914700df054c0897721382e5b1))\n- **theme/regression:** custom font not applying in Chinese docs because of specificity ([fa2f38a](https://github.com/vuejs/vitepress/commit/fa2f38a0c3bd121dcb7e07420566087c19b10f96)), closes [#3864](https://github.com/vuejs/vitepress/issues/3864)\n- **theme:** external link icon not visible for target \\_blank links ([d08eeed](https://github.com/vuejs/vitepress/commit/d08eeed89726572f7ea341df59864cc72716751c)), closes [#3327](https://github.com/vuejs/vitepress/issues/3327)\n- **theme:** fix invalid vp-offset in ssr ([9794877](https://github.com/vuejs/vitepress/commit/9794877347140c7b4955d735cd8867c260a5089d))\n\n### Features\n\n- **build/i18n:** support customizing copy code button's tooltip text ([#3854](https://github.com/vuejs/vitepress/issues/3854)) ([ed6ada7](https://github.com/vuejs/vitepress/commit/ed6ada7a688c466920f3e0ef33b7176b8eb01eee))\n- **build:** add localeIndex to md.env ([#3862](https://github.com/vuejs/vitepress/issues/3862)) ([0cbb469](https://github.com/vuejs/vitepress/commit/0cbb469842d74381ad56d44b7975f34c405b78f8))\n\n## [1.1.4](https://github.com/vuejs/vitepress/compare/v1.1.3...v1.1.4) (2024-04-27)\n\n### Bug Fixes\n\n- **dev:** multiple server instances being created when editing config too quickly ([#3835](https://github.com/vuejs/vitepress/issues/3835)) ([729a890](https://github.com/vuejs/vitepress/commit/729a890669c363895cfac39ece046926cad36d01))\n- **theme/a11y:** add unique name to footer prev / next navigation landmark ([e60c101](https://github.com/vuejs/vitepress/commit/e60c101e50fa56d4cd54d434c5628cc7e2231318))\n- **theme/a11y:** remove duplicate assistive text from outline nav ([#3803](https://github.com/vuejs/vitepress/issues/3803)) ([733d986](https://github.com/vuejs/vitepress/commit/733d986a84f614484b04235546dc4cda0769e833))\n- **theme/i18n:** 404 page not showing localized text ([#3833](https://github.com/vuejs/vitepress/issues/3833)) ([cc11b8e](https://github.com/vuejs/vitepress/commit/cc11b8e41ec481320b03902bdc307d479a8ba838))\n- **theme:** disable keypress effect on search button ([ccc37bb](https://github.com/vuejs/vitepress/commit/ccc37bb80e4147b9ab91b0f5d7dfae9d51533460))\n- **theme:** don't use Chinese quotes on non-Chinese documents ([#3834](https://github.com/vuejs/vitepress/issues/3834)) ([75115f4](https://github.com/vuejs/vitepress/commit/75115f4f8223d67dab2dc82fadaf2941aabf6330))\n- **theme:** leaking event listener when going back/forward on Safari on iOS ([#3658](https://github.com/vuejs/vitepress/issues/3658)) ([#3671](https://github.com/vuejs/vitepress/issues/3671)) ([1a72181](https://github.com/vuejs/vitepress/commit/1a72181c06d78e5e6f293e3f6abdb15caa4d2f53))\n\n## [1.1.3](https://github.com/vuejs/vitepress/compare/v1.1.1...v1.1.3) (2024-04-18)\n\n### Bug Fixes\n\n- **build/regression:** markdown backslash escapes not working ([d02d1e9](https://github.com/vuejs/vitepress/commit/d02d1e923aacdb1e8061a3f76af30e8a13518277)), closes [#3808](https://github.com/vuejs/vitepress/issues/3808)\n\n## [1.1.1](https://github.com/vuejs/vitepress/compare/v1.1.0...v1.1.1) (2024-04-18)\n\n### Bug Fixes\n\n- **client:** don't reload page on hash change ([#3777](https://github.com/vuejs/vitepress/issues/3777)) ([74b725a](https://github.com/vuejs/vitepress/commit/74b725a224438ef776fed25ee82274429d94ac83))\n- let vue compiler handle entity decoding ([f86ac56](https://github.com/vuejs/vitepress/commit/f86ac56b78da76f3061e6537b897bb13c1ed802d))\n- hot updating config file suppresses error logs ([#3592](https://github.com/vuejs/vitepress/issues/3592)) ([cd5adf3](https://github.com/vuejs/vitepress/commit/cd5adf3011d677263c93ce6f8066aaa7870b1dfc))\n\n# [1.1.0](https://github.com/vuejs/vitepress/compare/v1.0.2...v1.1.0) (2024-04-09)\n\n### Bug Fixes\n\n- **client:** hashchange should only be triggered for same page navigations ([#3768](https://github.com/vuejs/vitepress/issues/3768)) ([2a9fc2a](https://github.com/vuejs/vitepress/commit/2a9fc2a26b829bb3f28067ac6f4a41bc1e8b7a1e))\n- **client:** emit correct `Event` instance in hashchange event\n- **theme:** remove small layout shift on `On this page` button ([#3767](https://github.com/vuejs/vitepress/issues/3767)) ([5f28e74](https://github.com/vuejs/vitepress/commit/5f28e74abfc984cdc7e0d9d9f7b7e15cb2b46923))\n\n### Features\n\n- **client:** add `hash` property to `useData()`\n- **theme:** update Inter to version 4 ([#3693](https://github.com/vuejs/vitepress/issues/3693)) ([#3694](https://github.com/vuejs/vitepress/issues/3694)) ([ffafa31](https://github.com/vuejs/vitepress/commit/ffafa31b9204f996f4b819684214fa631c224575))\n\n## [1.0.2](https://github.com/vuejs/vitepress/compare/v1.0.1...v1.0.2) (2024-04-01)\n\n### Bug Fixes\n\n- **theme:** text containing html not showing properly in mobile nav menu ([3c8b4c7](https://github.com/vuejs/vitepress/commit/3c8b4c706051592dd2cca0ae57e293254cbb51ce))\n\n## [1.0.1](https://github.com/vuejs/vitepress/compare/v1.0.0...v1.0.1) (2024-03-22)\n\n### Bug Fixes\n\n- **build:** vendor vue-demi to avoid resolution issues with yarn berry ([#3680](https://github.com/vuejs/vitepress/issues/3680)) ([5d3cb96](https://github.com/vuejs/vitepress/commit/5d3cb96ac364413aa9eb494bc91744bd8f4a2c79))\n\n# [1.0.0](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.45...v1.0.0) (2024-03-21)\n\n### Bug Fixes\n\n- **build:** resolve pattern relative to srcDir instead of root in createContentLoader ([#3638](https://github.com/vuejs/vitepress/issues/3638)) ([59183e9](https://github.com/vuejs/vitepress/commit/59183e9cef112a004c8a8e2b365478af657858b0))\n- **localSearch:** remove empty titles that may appear in search results ([#3665](https://github.com/vuejs/vitepress/issues/3665)) ([f7aef3c](https://github.com/vuejs/vitepress/commit/f7aef3ca23dae39e226c85d7bb2579dbf7c758f3))\n- **theme:** fixed sidebar expand caret showing when no children are present ([#3657](https://github.com/vuejs/vitepress/issues/3657)) ([e13f932](https://github.com/vuejs/vitepress/commit/e13f93292ce1a2b1d5ba161fddfe947a1824a2b0))\n- **theme:** ignore inner-page items in next/prev link ([#3663](https://github.com/vuejs/vitepress/issues/3663)) ([b50a8a1](https://github.com/vuejs/vitepress/commit/b50a8a132577693817a15ab43fc4cc22670a8a65))\n- **theme:** local nav separator not visible on pages having no outline ([1909041](https://github.com/vuejs/vitepress/commit/190904171500ad22998c8666080fd58c867a59b5))\n\n### Features\n\n- **theme:** allow selectively disabling external link icon on navbar items ([#3607](https://github.com/vuejs/vitepress/issues/3607)) ([5f6297c](https://github.com/vuejs/vitepress/commit/5f6297cb3df98926154235f31570e75820d4ea16))\n\n# [1.0.0-rc.45](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.44...v1.0.0-rc.45) (2024-03-06)\n\n### Bug Fixes\n\n- **router:** hashchange not emitted in certain cases ([#3637](https://github.com/vuejs/vitepress/issues/3637)) ([f6bd99e...6c0125b](https://github.com/vuejs/vitepress/compare/f6bd99eb1311238e1114301a767634b139327916...6c0125b65513531870f00ebef1ae11096027875a))\n\n### Features\n\n- set `__VITEPRESS__` for easy detection by plugins and other tools ([#3634](https://github.com/vuejs/vitepress/issues/3634)) ([f6bd99e](https://github.com/vuejs/vitepress/commit/f6bd99eb1311238e1114301a767634b139327916))\n\n# [1.0.0-rc.44](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.43...v1.0.0-rc.44) (2024-2-19)\n\n### Reverts\n\n- types for internal components ([e703429](https://github.com/vuejs/vitepress/commit/e7034294731493a198cdd4789198f1c94f21b181))\n\n# [1.0.0-rc.43](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.42...v1.0.0-rc.43) (2024-2-17)\n\n### Bug Fixes\n\n- handle process.env being undefined while process is not ([b63e0a0](https://github.com/vuejs/vitepress/commit/b63e0a0c57f886f49aa7e073ff623c918164bd0b)), closes [#3579](https://github.com/vuejs/vitepress/issues/3579)\n- make local search work in combination with vue-i18n ([#3559](https://github.com/vuejs/vitepress/issues/3559)) ([6624bb7](https://github.com/vuejs/vitepress/commit/6624bb748610079b88e2dcef7ea1810833a54a85))\n- **theme:** adjust mathjax svg styles ([#3567](https://github.com/vuejs/vitepress/issues/3567)) ([2051100](https://github.com/vuejs/vitepress/commit/20511006dba516ca8c06ed1dd3516547af668a0e))\n\n### Features\n\n- **theme:** auto style markdown content in home page ([#3561](https://github.com/vuejs/vitepress/issues/3561)) ([0903027](https://github.com/vuejs/vitepress/commit/09030272b4a5c8f723b7e11303265f24b7481575))\n\n### Performance Improvements\n\n- **theme:** move svg icons to css ([#3537](https://github.com/vuejs/vitepress/issues/3537)) ([636cca0](https://github.com/vuejs/vitepress/commit/636cca042dfbca006af2d702ddec0a2ff601cb46))\n\n### BREAKING CHANGES\n\n- The default theme now styles the markdown content in the home page. If you have custom styles that rely on the markdown content not being styled, you may need to adjust your styles, or add `markdownStyles: false` to the frontmatter of your home page.\n\n# [1.0.0-rc.42](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.41...v1.0.0-rc.42) (2024-2-6)\n\n### Bug Fixes\n\n- **md:** dont break on nesting blockquotes inside gfm alerts ([8f8a6fe](https://github.com/vuejs/vitepress/commit/8f8a6feb053b3f521a2c90e343dffa7f98bb63b3)), closes [#3512](https://github.com/vuejs/vitepress/issues/3512)\n- **theme:** correctly normalize paths ending with \"index\" ([#3544](https://github.com/vuejs/vitepress/issues/3544)) ([c582a8d](https://github.com/vuejs/vitepress/commit/c582a8d5fd82b84d412c7e6c84e74faeb23beac6))\n\n# [1.0.0-rc.41](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.40...v1.0.0-rc.41) (2024-2-1)\n\n### Bug Fixes\n\n- handle CRLF in snippet plugin ([5811b62](https://github.com/vuejs/vitepress/commit/5811b626576ec4569fa0079d921b8e328d87ca91)), closes [#3499](https://github.com/vuejs/vitepress/issues/3499)\n- lazy evaluate known extensions to allow env set in config ([04f794b](https://github.com/vuejs/vitepress/commit/04f794bf55f8191ea9eed62f545b812f346017d8))\n\n### Features\n\n- **home:** add target and rel attribute to home actions ([#3528](https://github.com/vuejs/vitepress/issues/3528)) ([ab39fd8](https://github.com/vuejs/vitepress/commit/ab39fd8592c994fbc6feba5ee369ca1205c50f04))\n- rename shiki packages ([#3506](https://github.com/vuejs/vitepress/issues/3506)) ([b8487d3](https://github.com/vuejs/vitepress/commit/b8487d3a97679f5b2eb225ee1eb85754b66fee30))\n- wrap site title in span ([#3522](https://github.com/vuejs/vitepress/issues/3522)) ([6b1f951](https://github.com/vuejs/vitepress/commit/6b1f951928a3b9e53dcc9697327b5aba4a5905e2))\n- **theme:** add hero slots that are inside container ([#3524](https://github.com/vuejs/vitepres/issues/3524)) ([28870e6](https://github.com/vuejs/vitepress/commit/28870e68faf0ddaa418ffe0d4371316f6b0bcd02))\n\n### BREAKING CHANGES\n\n- vitepress now uses shiki instead of shikiji. If you’re on the latest version and using shikiji specific features, you just need to change imports. The shikijiSetup hook is renamed to shikiSetup.\n\n# [1.0.0-rc.40](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.39...v1.0.0-rc.40) (2024-1-22)\n\n### Bug Fixes\n\n- **client:** handle head orphans added in initial load ([#3474](https://github.com/vuejs/vitepress/issues/3474)) ([5e2d853](https://github.com/vuejs/vitepress/commit/5e2d853e1a315216dce5fc98ee2efd15c724a25d))\n- **theme:** avoid selecting summary on toggling details ([77a318c](https://github.com/vuejs/vitepress/commit/77a318c2a348d341dd3ea1e1650fcf8ad3abfcd7))\n- **theme:** hover color for code links inside custom containers ([#3467](https://github.com/vuejs/vitepress/issues/3467)) ([d529ed4](https://github.com/vuejs/vitepress/commit/d529ed49756841f055024c559d09875501bc6d76))\n- **type:** fix missed `VPBadge` type in `theme.d.ts` ([#3470](https://github.com/vuejs/vitepress/issues/3470)) ([fcf828c](https://github.com/vuejs/vitepress/commit/fcf828c2a71892dad5af8d21e405f4d1e2cc280c))\n\n### Features\n\n- support GitHub-flavored alerts ([#3482](https://github.com/vuejs/vitepress/issues/3482)) ([ac87d19](https://github.com/vuejs/vitepress/commit/ac87d19ca1bbc966e5fe1cca5f433f5ea4b11be3))\n- support specifying custom extensions to escape routing ([#3466](https://github.com/vuejs/vitepress/issues/3466)) ([c22f5d9](https://github.com/vuejs/vitepress/commit/c22f5d983f3e5d5c4f0ed0683a93ece564487c13))\n- **theme:** add npm icon ([#3483](https://github.com/vuejs/vitepress/issues/3483)) ([c882fa1](https://github.com/vuejs/vitepress/commit/c882fa1469a7bd0d6e28196e7a841adf48e803f1))\n\n# [1.0.0-rc.39](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.38...v1.0.0-rc.39) (2024-01-16)\n\n### Bug Fixes\n\n- **theme:** misaligned outline indicator ([#3458](https://github.com/vuejs/vitepress/issues/3458)) ([0ce5ece](https://github.com/vuejs/vitepress/commit/0ce5ece35687bdad7a65d61432419cfe3961a329))\n- **theme:** enter key behavior conflict with IME in search box ([#3454](https://github.com/vuejs/vitepress/issues/3454)) ([cd8ee6f](https://github.com/vuejs/vitepress/commit/cd8ee6fb32d8135e78c5827a36b79efad509042c))\n- **theme:** use`--vp-c-tip-` CSS variable for badge/block colors with type`tip` ([#3434](https://github.com/vuejs/vitepress/issues/3434)) ([78abf47](https://github.com/vuejs/vitepress/commit/78abf47b8b563d66db9d481a98bbdefac95cc84c))\n\n### Features\n\n- **theme:** export VPBadge ([#3431](https://github.com/vuejs/vitepress/issues/3431)) ([18981c1](https://github.com/vuejs/vitepress/commit/18981c1d1c74a4f4ca379a88b00c02ba5eace6db))\n\n# [1.0.0-rc.36](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.35...v1.0.0-rc.36) (2024-1-8)\n\n### Bug Fixes\n\n- avoid pushing to history when clicking on the current link ([#3405](https://github.com/vuejs/vitepress/issues/3405)) ([d279e63](https://github.com/vuejs/vitepress/commit/d279e63cb4d417420cdc3fb3e6e03c96b777289f))\n- **theme/regression:** external link icon not working ([c236570](https://github.com/vuejs/vitepress/commit/c236570f2806fe76bbc6a69568cf64ed5a3fc2ce)), closes [#3424](https://github.com/vuejs/vitepress/issues/3424)\n- **theme/regression:** inter getting bundled even importing without-fonts entry ([#3412](https://github.com/vuejs/vitepress/issues/3412)) ([b03fb83](https://github.com/vuejs/vitepress/commit/b03fb83a4e67d92a865d90908ccbde3dd0f97373))\n\n# [1.0.0-rc.35](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.34...v1.0.0-rc.35) (2024-1-3)\n\n### Bug Fixes\n\n- **client:** add computed dir and lang to html root ([c2b4c66](https://github.com/vuejs/vitepress/commit/c2b4c66e79fde7479f5f43841e1921a5c220c9a5)), closes [#3353](https://github.com//github.com/vuejs/vitepress/pull/3353/issues/issuecomment-1874753809)\n- fill all empty code lines ([563020b](https://github.com/vuejs/vitepress/commit/563020ba61abda254af9a124ddafd12de644cd4e)), closes [#3305](https://github.com/vuejs/vitepress/issues/3305)\n- fix theme chunking logic causing out-of-order styles ([#3403](https://github.com/vuejs/vitepress/issues/3403)) ([a6cd891](https://github.com/vuejs/vitepress/commit/a6cd891d95454b3130aaf08f499659d2585acc63))\n- invalidate module cache for subsequent builds ([#3398](https://github.com/vuejs/vitepress/issues/3398)) ([27f60e0](https://github.com/vuejs/vitepress/commit/27f60e0b7784603c6fb300bd8dce64515eb98962))\n\n### Features\n\n- allow passing options to emoji plugin ([09e48db](https://github.com/vuejs/vitepress/commit/09e48db355f530c7a138437004659b61239f4b75)), closes [#3174](https://github.com/vuejs/vitepress/issues/3174)\n- **theme:** allow specifying rel and target in logoLink ([6c89943](https://github.com/vuejs/vitepress/commit/6c899437c15b126b488e73c99cdaad77fc7e5611)), closes [#3264](https://github.com/vuejs/vitepress/issues/3264) [#3271](https://github.com/vuejs/vitepress/issues/3271)\n\n### Performance Improvements\n\n- **localSearch:** add concurrency pooling, cleanup logic, improve performance ([#3374](https://github.com/vuejs/vitepress/issues/3374)) ([ac5881e](https://github.com/vuejs/vitepress/commit/ac5881eeac3f042a8fbf034edb99e5f2b45eaa2a))\n\n# [1.0.0-rc.34](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.33...v1.0.0-rc.34) (2023-12-30)\n\n### Bug Fixes\n\n- **build:** clear cache after build ([9568fea](https://github.com/vuejs/vitepress/commit/9568fea8fc50e625c8ef27c588eca3dbe5a44e81)), closes [#3363](https://github.com/vuejs/vitepress/issues/3363)\n- **default-theme:** remove use of reactify for search i18n ([8687b86](https://github.com/vuejs/vitepress/commit/8687b86e1e00ae39ff9c8173aef04eb8a9cda0a8))\n- print errors when importing an invalid dynamic route ([#3201](https://github.com/vuejs/vitepress/issues/3201)) ([6d89a08](https://github.com/vuejs/vitepress/commit/6d89a08cb76674f4d92f54218f8af5624bcf4c47))\n- remove double title from home pages ([9f1f04e](https://github.com/vuejs/vitepress/commit/9f1f04e00a9722ec7369941c40d3d8ad86f61d35)), closes [#3375](https://github.com/vuejs/vitepress/issues/3375)\n- **theme/i18n:** support customizing dark mode switch titles ([#3311](https://github.com/vuejs/vitepress/issues/3311)) ([50c9758](https://github.com/vuejs/vitepress/commit/50c9758d3fa1b60aad5399a0db890644ac44a522))\n\n### Features\n\n- support custom image lazy loading ([#3346](https://github.com/vuejs/vitepress/issues/3346)) ([55be3f1](https://github.com/vuejs/vitepress/commit/55be3f14d79eb578c9aa2e3bc7a90205c910005d))\n- support dir in frontmatter ([#3353](https://github.com/vuejs/vitepress/issues/3353)) ([203446d](https://github.com/vuejs/vitepress/commit/203446d69193483a46e1082bba5fbad0e35966fb))\n- **theme/i18n:** allow customizing sponsor link's text ([#3276](https://github.com/vuejs/vitepress/issues/3276)) ([9c20e3b](https://github.com/vuejs/vitepress/commit/9c20e3b5f80e4197c14c20fa751ec3c8c8219e8e))\n- **theme:** allow using VPBadge classes in sidebar ([#3391](https://github.com/vuejs/vitepress/issues/3391)) ([50a774e](https://github.com/vuejs/vitepress/commit/50a774ea7c70bb200e12c176d6691ab7144a73f9))\n- **theme:** new design for local nav and global header ([#3359](https://github.com/vuejs/vitepress/issues/3359)) ([d10bf42](https://github.com/vuejs/vitepress/commit/d10bf42c2632f1aacb905bc01b36274e9004cbd9))\n\n# [1.0.0-rc.33](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.32...v1.0.0-rc.33) (2023-12-26)\n\n### Features\n\n- allow explicitly mark code element as `.vp-copy-ignore` ([#3360](https://github.com/vuejs/vitepress/issues/3360)) ([93122ee](https://github.com/vuejs/vitepress/commit/93122eee20cb6586026c1ffac04d9787861cc2f3))\n- **build:** enable VUE_PROD_HYDRATION_MISMATCH_DETAILS when DEBUG is truthy ([f4d4280](https://github.com/vuejs/vitepress/commit/f4d4280d7d1728a966bb04968a9bac10470c3d06)), closes [#422](https://github.com/vuejs/vitepress/issues/422)\n\n### Performance Improvements\n\n- implement concurrent promise pooling for render task ([#3366](https://github.com/vuejs/vitepress/issues/3366))\n\n# [1.0.0-rc.32](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.31...v1.0.0-rc.32) (2023-12-16)\n\n### Features\n\n- allow ignoring node in header ([#3331](https://github.com/vuejs/vitepress/issues/3331)) ([e4bf1e4](https://github.com/vuejs/vitepress/commit/e4bf1e48e6a1592d583b218425c1fa7497955dc5))\n- expose `shikijiSetup` hook ([#3344](https://github.com/vuejs/vitepress/issues/3344)) ([d12e23d](https://github.com/vuejs/vitepress/commit/d12e23ddf69480418078ff39846c99ecf2e1eb1b))\n- update shikiji, support twoslash ([#3339](https://github.com/vuejs/vitepress/issues/3339)) ([8800195](https://github.com/vuejs/vitepress/commit/880019545795fd075be89d94794bfbd05af461b5))\n\n# [1.0.0-rc.31](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.30...v1.0.0-rc.31) (2023-11-25)\n\n### Bug Fixes\n\n- **build:** make assets go through vite pipeline during dev too ([#3258](https://github.com/vuejs/vitepress/issues/3258)) ([c3d7f22](https://github.com/vuejs/vitepress/commit/c3d7f22bd313b09e6965ac3125ea662ce283ed2d))\n- **theme:** use VPLink for links in VPDocFooter ([#3248](https://github.com/vuejs/vitepress/issues/3248)) ([479a320](https://github.com/vuejs/vitepress/commit/479a320731313b8e7e0bad3f8383ae6bc05ed8e2))\n\n# [1.0.0-rc.30](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.29...v1.0.0-rc.30) (2023-11-23)\n\n### Bug Fixes\n\n- **client:** no onAfterRouteChanged called after popstate ([#3227](https://github.com/vuejs/vitepress/issues/3227)) ([60fc8fd](https://github.com/vuejs/vitepress/commit/60fc8fd24460eede1dc73768ad0aa53616da746f)), closes [#3226](https://github.com/vuejs/vitepress/issues/3226)\n- **theme:** remove double padding from sidebar ([ef6d8d1](https://github.com/vuejs/vitepress/commit/ef6d8d1e4295c6ff967c17b5b9c20c04843da5a0)), closes [#3228](https://github.com/vuejs/vitepress/issues/3228)\n\n### Features\n\n- migrate to shikiji ([#3237](https://github.com/vuejs/vitepress/pull/3237)) ([75f18e4](https://github.com/vuejs/vitepress/commit/75f18e47334933b642d14b8b69b372cb1ebd4244))\n\n### BREAKING CHANGES\n\n- VitePress now uses shikiji instead of shiki for syntax highlighting. If you're using features like adding extra languages or custom aliases, please refer [shikiji docs](https://github.com/antfu/shikiji) for migration guide or comment on [#3237](https://github.com/vuejs/vitepress/pull/3237) if you need help.\n\n# [1.0.0-rc.29](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.28...v1.0.0-rc.29) (2023-11-19)\n\n### Bug Fixes\n\n- **client:** regression - router not working without .html present ([d63cb86](https://github.com/vuejs/vitepress/commit/d63cb867b14ba49c8333ad0d69d33874e2ece6c6)), closes [#3225](https://github.com/vuejs/vitepress/issues/3225)\n\n# [1.0.0-rc.28](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.27...v1.0.0-rc.28) (2023-11-18)\n\n### Bug Fixes\n\n- **ally:** clear up confusion with the title of theme switch ([#3215](https://github.com/vuejs/vitepress/issues/3215)) ([6761036](https://github.com/vuejs/vitepress/commit/67610363bcb354d33327e6b5c3c2d916ed025ffc))\n- **build:** support nested assetsDir ([02161d0](https://github.com/vuejs/vitepress/commit/02161d0f797cfa36d715119e8c7618770b1a6761))\n- wrong recognition of non-html extension leads to route error ([#3218](https://github.com/vuejs/vitepress/issues/3218)) ([c4abc95](https://github.com/vuejs/vitepress/commit/c4abc950af7061611e3b5eff93e767706bd12396))\n\n### Features\n\n- **build:** html head meta generator ([#3219](https://github.com/vuejs/vitepress/issues/3219)) ([672e494](https://github.com/vuejs/vitepress/commit/672e4946ac3c24f3fc79469534e66cfaf6f23e67))\n- **client:** allow disabling link auto-prefetching ([#3220](https://github.com/vuejs/vitepress/issues/3220)) ([563dc89](https://github.com/vuejs/vitepress/commit/563dc899757e58d2261bcb31081283eb395fab0b))\n\n# [1.0.0-rc.27](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.26...v1.0.0-rc.27) (2023-11-17)\n\n### Bug Fixes\n\n- CSS missing after build ([#3217](https://github.com/vuejs/vitepress/issues/3217)) ([da73b58](https://github.com/vuejs/vitepress/commit/da73b58c795a65a09d028e0ca6acefa1170d3d5b)), closes [#3216](https://github.com/vuejs/vitepress/issues/3216)\n\n# [1.0.0-rc.26](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.25...v1.0.0-rc.26) (2023-11-16)\n\n### Bug Fixes\n\n- \"VPNavScreenMenuGroup\" component HTML not supported ([#3148](https://github.com/vuejs/vitepress/issues/3148)) ([237ad85](https://github.com/vuejs/vitepress/commit/237ad859a982f3fa55f7bba0f98ca94707108618))\n- **build:** remove frontmatter in md file inclusion ([dbbffa2](https://github.com/vuejs/vitepress/commit/dbbffa2487cd1f9899916baa166591248fb24334)), closes [#3195](https://github.com/vuejs/vitepress/issues/3195)\n- style links in footer ([#3178](https://github.com/vuejs/vitepress/issues/3178)) ([a482611](https://github.com/vuejs/vitepress/commit/a482611d17197a0b7afc403891cd95f344e7a55f))\n\n### Features\n\n- switch to vite 5 and bump deps ([#3200](https://github.com/vuejs/vitepress/issues/3200)) ([d2238ee](https://github.com/vuejs/vitepress/commit/d2238eedb7c0c81b2d9f425e6f70f7019ad6a482))\n\n### BREAKING CHANGES\n\n- VitePress now runs on Vite 5. Please refer https://vitejs.dev/guide/migration for breaking changes and migration guide if you're relying on some Vite-specific things.\n\n# [1.0.0-rc.25](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.24...v1.0.0-rc.25) (2023-11-05)\n\n### Bug Fixes\n\n- double-slash format url should be external link ([#3165](https://github.com/vuejs/vitepress/issues/3165)) ([7dbeac6](https://github.com/vuejs/vitepress/commit/7dbeac6df0dfc0da74dffc79998a85a3afa86874))\n- missing export types in localSearch ([#3157](https://github.com/vuejs/vitepress/issues/3157)) ([0761062](https://github.com/vuejs/vitepress/commit/0761062790b441eccd0d57d51903271f30e713af))\n- **theme:** table row background-color in custom containers ([#3179](https://github.com/vuejs/vitepress/issues/3179)) ([beecec1](https://github.com/vuejs/vitepress/commit/beecec16a8d62c18f46522d461db353c97199415))\n- **theme:** theme switch is not hidden on force-dark ([#3155](https://github.com/vuejs/vitepress/issues/3155)) ([2276c1d](https://github.com/vuejs/vitepress/commit/2276c1d4dac547bb09015fcd0df73825b32c5fad))\n\n### Features\n\n- export `mergeConfig()` ([#3143](https://github.com/vuejs/vitepress/issues/3143)) ([a850786](https://github.com/vuejs/vitepress/commit/a850786a566606fda20cc4ed71b79e975307b52a))\n\n### Performance Improvements\n\n- reduce duplicate rendering in localSearch ([#3170](https://github.com/vuejs/vitepress/issues/3170)) ([878f437](https://github.com/vuejs/vitepress/commit/878f4378cdee3c41f7643d9c7693bb607344d0c2))\n\n# [1.0.0-rc.24](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.23...v1.0.0-rc.24) (2023-10-24)\n\n### Bug Fixes\n\n- lock plugin-vue version ([aa75fd6](https://github.com/vuejs/vitepress/commit/aa75fd62643d51be647f6e5937c97b7c47bf9739))\n- **styles:** large blur radius is causing color issues with safari ([a31e143](https://github.com/vuejs/vitepress/commit/a31e143afac597034a8d77f516961b0d2857ac8d))\n\n### Features\n\n- **template:** add types for theme config ([#3122](https://github.com/vuejs/vitepress/issues/3122)) ([56b3ce5](https://github.com/vuejs/vitepress/commit/56b3ce5032b1d3bcfd66a1a397d87172a6f113d7))\n\n# [1.0.0-rc.23](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.22...v1.0.0-rc.23) (2023-10-22)\n\n### Bug Fixes\n\n- don't normalize non-html/non-http links ([#3114](https://github.com/vuejs/vitepress/issues/3114)) ([da3d781](https://github.com/vuejs/vitepress/commit/da3d7812a143e3aa360845b89f573d4e1ec637dd))\n- **mpa:** properly emit assets in mpa mode ([#3115](https://github.com/vuejs/vitepress/issues/3115)) ([6cf1de5](https://github.com/vuejs/vitepress/commit/6cf1de5e9e15d4507054744b665ac15d5f9a05f1))\n- **theme/search:** prevent reactivity loss with i18n ([#3121](https://github.com/vuejs/vitepress/issues/3121)) ([50d61fa](https://github.com/vuejs/vitepress/commit/50d61faefacc3885efe99fe5477a3b815354a0c4))\n\n# [1.0.0-rc.22](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.21...v1.0.0-rc.22) (2023-10-15)\n\n### Bug Fixes\n\n- fixes a regression related with nanoid v5 ([#3090](https://github.com/vuejs/vitepress/issues/3090))\n\n# [1.0.0-rc.21](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.20...v1.0.0-rc.21) (2023-10-12)\n\n### Bug Fixes\n\n- **build:** handle .mjs/.mts files as data / path loaders ([#3058](https://github.com/vuejs/vitepress/issues/3058)) ([7991180](https://github.com/vuejs/vitepress/commit/7991180080366f9eb0d43fe95d25b53cf7af652c))\n- **client:** only update head if needed ([#3017](https://github.com/vuejs/vitepress/issues/3017)) ([f2fc3dc](https://github.com/vuejs/vitepress/commit/f2fc3dc51b8019c18d5ab70a6b55b8333c91045a))\n- **theme:** search's configuration about buttonAriaLabel doesn't work ([#3070](https://github.com/vuejs/vitepress/issues/3070)) ([c08bd46](https://github.com/vuejs/vitepress/commit/c08bd46aa757e7a0bc28b2318fb38037d583b27d))\n\n### Features\n\n- **md:** allow customizing container titles globally ([#3044](https://github.com/vuejs/vitepress/issues/3044)) ([bdb0800](https://github.com/vuejs/vitepress/commit/bdb080093f95ec43d013ea2ad537e567bdbb5a44))\n\n# [1.0.0-rc.20](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.15...v1.0.0-rc.20) (2023-09-24)\n\n### Bug Fixes\n\n- **build:** consistent route.path across dev and ssr ([#2997](https://github.com/vuejs/vitepress/issues/2997)) ([0d56855](https://github.com/vuejs/vitepress/commit/0d56855b54a97d4350485ee76c07a040fdc5738c))\n- **build:** don't show missing lang warnings with text specifiers in fences ([aa40cec](https://github.com/vuejs/vitepress/commit/aa40cecd48942506ffb063863c9b054e66f1d79e))\n- handle references in container titles ([7fbfe71](https://github.com/vuejs/vitepress/commit/7fbfe71b6cab2f091ba3d0c47a401fdc612b88b6)), closes [#3004](https://github.com/vuejs/vitepress/issues/3004)\n- **hmr:** handle hmr in imported code snippets ([#3005](https://github.com/vuejs/vitepress/issues/3005)) ([e84f313](https://github.com/vuejs/vitepress/commit/e84f31371e9e5219d46ae58151667d24e12b77bb))\n- snippet hmr not working with rewrites ([a275049](https://github.com/vuejs/vitepress/commit/a2750492be7869ed48a5bde1ffbc177093356758))\n- selectively pass env for container titles ([1a9c32d](https://github.com/vuejs/vitepress/commit/1a9c32df12388386877c50daf9fc7924888eac07)), closes [#3007](https://github.com/vuejs/vitepress/issues/3007)\n- **types:** add RegExp to markdown's allowed attributes ([#3008](https://github.com/vuejs/vitepress/issues/3008)) ([bc96b2b](https://github.com/vuejs/vitepress/commit/bc96b2bb5bc5361e55c46f270e3759c513db65d3))\n\n# [1.0.0-rc.15](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.14...v1.0.0-rc.15) (2023-09-20)\n\n### Bug Fixes\n\n- **build:** allow using symlinks with code snippets ([f186901](https://github.com/vuejs/vitepress/commit/f186901a5157c904b3593089d72f2bad3530e7a3)), closes [#1617](https://github.com/vuejs/vitepress/issues/1617)\n- **build:** handle importing code snippets not having an extension ([#2978](https://github.com/vuejs/vitepress/issues/2978)) ([e99aaad](https://github.com/vuejs/vitepress/commit/e99aaad9cf8ab3661e609cd2cf6ac7da57cb7eb5))\n- **build:** indentation being lost in code blocks ([5bb6bb0](https://github.com/vuejs/vitepress/commit/5bb6bb0a147ad43ca2d7069aad50fb9c6c2c11d6)), closes [#2988](https://github.com/vuejs/vitepress/issues/2988)\n- **compat:** reset setRawMode on process exit ([#2994](https://github.com/vuejs/vitepress/issues/2994)) ([70fe47c](https://github.com/vuejs/vitepress/commit/70fe47c1dd69d39a40c83e919324d2b71f19bdaa))\n\n### Features\n\n- allow passing fast glob options to `createContentLoader` ([4f9a60b](https://github.com/vuejs/vitepress/commit/4f9a60b0cfa2fa841465f6e8cc5f77ed3e023817)), closes [#2985](https://github.com/vuejs/vitepress/issues/2985)\n\n# [1.0.0-rc.14](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.13...v1.0.0-rc.14) (2023-09-16)\n\n### Bug Fixes\n\n- **client:** router in invalid state after 404 ([#2972](https://github.com/vuejs/vitepress/issues/2972)) ([28ef0ea](https://github.com/vuejs/vitepress/commit/28ef0ea6f60ab33e9cf34ecef10e1515d84f7168))\n- **client:** scripts loading out of order when added through head ([#2970](https://github.com/vuejs/vitepress/issues/2970)) ([98679c9](https://github.com/vuejs/vitepress/commit/98679c9e82fcd3bbe3829640d0386cbd730e61ba))\n- customizing the starting line number even if globally set ([#2941](https://github.com/vuejs/vitepress/issues/2941)) ([0cd87b1](https://github.com/vuejs/vitepress/commit/0cd87b1bafa6158ded0bf741553816f3d9b43a89))\n- make algolia search work with indices that don't return absolute urls ([#2956](https://github.com/vuejs/vitepress/issues/2956)) ([2a34c6b](https://github.com/vuejs/vitepress/commit/2a34c6b3076bf418b3abbbca984fcb033743a611)), closes [#336](https://github.com/vuejs/vitepress/issues/336) [#805](https://github.com/vuejs/vitepress/issues/805)\n- **theme:** remove extra padding from top when navbar is hidden ([#2575](https://github.com/vuejs/vitepress/issues/2575)) ([fd46dc9](https://github.com/vuejs/vitepress/commit/fd46dc9b8f8951b3196e4208d958d1ca0e1dc6e8))\n\n### Features\n\n- mathjax support ([#2977](https://github.com/vuejs/vitepress/issues/2977)) ([7271a95](https://github.com/vuejs/vitepress/commit/7271a959480261d60c01146d2e520d0f662e0380))\n- **theme:** allow forcing dark mode ([#2974](https://github.com/vuejs/vitepress/issues/2974)) ([1fb5d22](https://github.com/vuejs/vitepress/commit/1fb5d228a269e913163246e988806056b3f1b9d9))\n- **theme:** allow forcing site locale in last updated format ([#2973](https://github.com/vuejs/vitepress/issues/2973)) ([a18e5e4](https://github.com/vuejs/vitepress/commit/a18e5e48a442b09487cda8ab14e3b103ce270641))\n\n# [1.0.0-rc.13](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.12...v1.0.0-rc.13) (2023-09-13)\n\n### Bug Fixes\n\n- **theme:** allow wrapping feature icons ([a1e1267](https://github.com/vuejs/vitepress/commit/a1e1267549e198b35455d055536cd0c6d1ad79ce)), closes [#2923](https://github.com/vuejs/vitepress/issues/2923)\n- **theme:** local search enter key with the search result ([#2937](https://github.com/vuejs/vitepress/issues/2937)) ([00ef2f1](https://github.com/vuejs/vitepress/commit/00ef2f1db0369f50b3b634508e798b19b9525b34))\n\n### Features\n\n- **theme:** add search insights boolean to algolia search ([#2940](https://github.com/vuejs/vitepress/issues/2940)) ([32aa2a7](https://github.com/vuejs/vitepress/commit/32aa2a7d179049e5a1ed809018c32418bf69e8d5))\n\n### Reverts\n\n- Revert \"feat(theme): use inert to avoid traverse menus and content with keyboard\" (#2953) ([54891df](https://github.com/vuejs/vitepress/commit/54891df6149f4d0a871b16edf5f9a8a6fec639f9)), closes [#2953](https://github.com/vuejs/vitepress/issues/2953) [#2932](https://github.com/vuejs/vitepress/issues/2932)\n\n# [1.0.0-rc.12](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.11...v1.0.0-rc.12) (2023-09-10)\n\n### Bug Fixes\n\n- **theme:** prevent closing local search box on key enter ([#2933](https://github.com/vuejs/vitepress/issues/2933)) ([e544b41](https://github.com/vuejs/vitepress/commit/e544b411d91eba54154243b0af4cea3226c192c4))\n- **theme:** use brand color on search highlight ([dfc0fbf](https://github.com/vuejs/vitepress/commit/dfc0fbfcb4f255461bd90aef23a3dda1422b8335)), closes [#2902](https://github.com/vuejs/vitepress/issues/2902)\n\n### Features\n\n- highlight nav by default when one of the items is matched ([#2893](https://github.com/vuejs/vitepress/issues/2893)) ([b1fbece](https://github.com/vuejs/vitepress/commit/b1fbece047ca503f2c59553f9e37a0aac4be52c9))\n- process md includes before building local search index ([#2906](https://github.com/vuejs/vitepress/issues/2906)) ([c6ff5c7](https://github.com/vuejs/vitepress/commit/c6ff5c76867dc59d5548cb33fd8447e23712bef5))\n- support for customizing the starting line number in a code block ([#2917](https://github.com/vuejs/vitepress/issues/2917)) ([c0ce7f7](https://github.com/vuejs/vitepress/commit/c0ce7f723e52682d9ca107e4ce4e0e5c82710e02))\n- **theme:** allow setting target in home features ([#2897](https://github.com/vuejs/vitepress/issues/2897)) ([cb49673](https://github.com/vuejs/vitepress/commit/cb4967313e5edcfd4bfc12aa10e75fec7b32e0c8))\n- **theme:** use inert to avoid traverse menus and content with keyboard ([#2932](https://github.com/vuejs/vitepress/issues/2932)) ([070fc0a](https://github.com/vuejs/vitepress/commit/070fc0a56ddb941e26a098ba7207b5d1e91b7b51))\n\n# [1.0.0-rc.11](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.10...v1.0.0-rc.11) (2023-09-10)\n\n### Bug Fixes\n\n- **init:** missing mts extension on windows ([195ebe9](https://github.com/vuejs/vitepress/commit/195ebe9464e2cc9b208e7d6c8bc5fa9f92025fdc)), closes [#2886](https://github.com/vuejs/vitepress/issues/2886)\n- respect attrs on custom containers ([8b76167](https://github.com/vuejs/vitepress/commit/8b76167ccfbe5bf21295db6905451e1c50ca4407))\n- temp workaround for broken navigation from 404 to home ([a18d544](https://github.com/vuejs/vitepress/commit/a18d5447f29f05d75bf0e20ff839e5c3bcdac390)), closes [#2891](https://github.com/vuejs/vitepress/issues/2891)\n- **theme:** dropdown menu partially hidden by the homepage footer when it is too long ([#2904](https://github.com/vuejs/vitepress/issues/2904)) ([a60f079](https://github.com/vuejs/vitepress/commit/a60f079f996cc8ce9aeb189a25187fdbce2217ab))\n- **theme:** improve contrast of search highlight text ([#2887](https://github.com/vuejs/vitepress/issues/2887)) ([20f9770](https://github.com/vuejs/vitepress/commit/20f97702680b47eb9675770df4db94a3e3b94ef1))\n- **theme:** link hover color inside a custom block ([#2876](https://github.com/vuejs/vitepress/issues/2876)) ([39784ca](https://github.com/vuejs/vitepress/commit/39784ca55fdbefa97b7e9f892609ef8bdaeadf50))\n- **theme:** prevent layout shift in search button key ([#2889](https://github.com/vuejs/vitepress/issues/2889)) ([0088434](https://github.com/vuejs/vitepress/commit/0088434895e5df9afea5bb8e81c515a41e824c44))\n- **theme:** search button key misplaced on safari ([18adc07](https://github.com/vuejs/vitepress/commit/18adc07117cbf151b51aa205419496938a322a2e))\n- **types:** NavItem can only have either link or items ([#2880](https://github.com/vuejs/vitepress/issues/2880)) ([12ef12d](https://github.com/vuejs/vitepress/commit/12ef12d6330f61a29102e7a0d537e742ff20367f))\n\n### Features\n\n- detect bun package manager ([#2874](https://github.com/vuejs/vitepress/issues/2874)) ([83270fe](https://github.com/vuejs/vitepress/commit/83270fe65767016a98cd59b6256f1361439cc7c8))\n- skip rendering if env.BUNDLE_ONLY is truthy ([#2890](https://github.com/vuejs/vitepress/issues/2890)) ([d40eb19](https://github.com/vuejs/vitepress/commit/d40eb1903be022c9dfe10136122f5dc5aacb71d3))\n\n# [1.0.0-rc.10](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.9...v1.0.0-rc.10) (2023-08-28)\n\n### Bug Fixes\n\n- pseudo styles being removed with postcssIsolateStyles ([21b4f8c](https://github.com/vuejs/vitepress/commit/21b4f8caad8f0b9a570f00ac2662635062db8566)), closes [#2868](https://github.com/vuejs/vitepress/issues/2868) [#2867](https://github.com/vuejs/vitepress/issues/2867)\n- resolve snippets from original file path - align with include behavior ([8aa032f](https://github.com/vuejs/vitepress/commit/8aa032f60cd52e674a401f79b3cb473ac7d22abb))\n\n### Features\n\n- allow overriding mdit-vue/component options ([4f01f1a](https://github.com/vuejs/vitepress/commit/4f01f1a09c84fced276e1a138a59ed1b9679ce15))\n\n### Reverts\n\n- \"fix: createContentLoader generates invalid url when sets `base`\" ([#2865](https://github.com/vuejs/vitepress/issues/2865)) ([6be5a7e](https://github.com/vuejs/vitepress/commit/6be5a7e830fab2361bde5a4194930b2898733a8b))\n\n# [1.0.0-rc.9](https://github.com/vuejs/vitepress/compare/v1.0.0-rc.4...v1.0.0-rc.9) (2023-08-28)\n\n### Bug Fixes\n\n- **a11y/theme:** disable transitions if user prefers reduced motion ([fc5092f](https://github.com/vuejs/vitepress/commit/fc5092fb651487e69737fff04d3979f00c67dcc6))\n- **build:** respect preserveSymlinks ([#2780](https://github.com/vuejs/vitepress/issues/2780)) ([1bda710](https://github.com/vuejs/vitepress/commit/1bda710702f5569e26b24b44785d938296870884))\n- **cli/init:** print the correct packageManager ([#2787](https://github.com/vuejs/vitepress/issues/2787)) ([b388b0a](https://github.com/vuejs/vitepress/commit/b388b0a8c169e399f8da43368022454b6e8ea489))\n- **cli/init:** terminal message has not enough contrast ([#2786](https://github.com/vuejs/vitepress/issues/2786)) ([4d9d977](https://github.com/vuejs/vitepress/commit/4d9d9775190178d0eaea5b3cea86309ae420bd43))\n- restart server on theme creation/deletion ([#2785](https://github.com/vuejs/vitepress/issues/2785)) ([e0be677](https://github.com/vuejs/vitepress/commit/e0be677554a517e8b02fcaf930828bb052d1c4a4))\n- scroll-to-top in iOS when opens sidebar ([#2803](https://github.com/vuejs/vitepress/issues/2803)) ([3dab9a6](https://github.com/vuejs/vitepress/commit/3dab9a6be1b543cf52c7c61f1e439a7973cd6667))\n- stackblitz not working on firefox ([877f643](https://github.com/vuejs/vitepress/commit/877f643b133b70f01bbf397900829050a399893f)), closes [#2817](https://github.com/vuejs/vitepress/issues/2817)\n- **theme:** docsearch variables not applying properly on ios beta ([436e99a](https://github.com/vuejs/vitepress/commit/436e99a594d42650f69c062fd095eb0502a76b34))\n- **theme:** improve logo svg and add `art` dir ([1f8c58a](https://github.com/vuejs/vitepress/commit/1f8c58aed0bf5a191021913dd7f9a87e9b75f3eb))\n- **theme:** prevent sidebar re-render unless there is actual change ([33962e0](https://github.com/vuejs/vitepress/commit/33962e04ebb2724e12b131f61ff00fe0aaf990f3)), closes [#2796](https://github.com/vuejs/vitepress/issues/2796)\n- **theme:** revert 79 to 179 in yellow-soft ([#2858](https://github.com/vuejs/vitepress/issues/2858)) ([74fcb60](https://github.com/vuejs/vitepress/commit/74fcb60fb4ceb97b9ab0442a26e22a726af2dcc9))\n- **theme:** show only one carbon ad at a time ([5ced0cc](https://github.com/vuejs/vitepress/commit/5ced0cca837ac7fbf1884ab56255b29c69dbec40))\n- **theme:** ssr issues on deno ([e8edd0a](https://github.com/vuejs/vitepress/commit/e8edd0a05f43491656c00db36630f391caf64461))\n\n### Features\n\n- allow customizing markdown renderer used for local search indexing ([#2770](https://github.com/vuejs/vitepress/issues/2770)) ([00dc1e6](https://github.com/vuejs/vitepress/commit/00dc1e6742273fe6fde74e7abbd160bd7724af4d))\n- export postcssIsolateStyles for vp-raw ([3c736c1](https://github.com/vuejs/vitepress/commit/3c736c1c95814d1ca43b4e99bda62b8ccc908cd5))\n- **theme:** allow overriding code copied text from css ([#2833](https://github.com/vuejs/vitepress/issues/2833)) ([e8ef1aa](https://github.com/vuejs/vitepress/commit/e8ef1aaabecd7374cdf6cefca6b02ff9d3d3573f))\n- **theme:** allow overriding last updated time in doc footer from frontmatter ([#2848](https://github.com/vuejs/vitepress/issues/2848)) ([9a062a6](https://github.com/vuejs/vitepress/commit/9a062a6dd63db3dc9d951f2973c4ab606594a11f))\n- **theme:** allow providing custom `toggle-appearance` function ([#2844](https://github.com/vuejs/vitepress/issues/2844)) ([a5f2eac](https://github.com/vuejs/vitepress/commit/a5f2eacf225ff1a9a82c10ae492658190f313fb0))\n- **theme:** allow setting rel and target on sidebar links ([e477cdf](https://github.com/vuejs/vitepress/commit/e477cdfd2f62144cd6331f45aaaa865185a64575)), closes [#2851](https://github.com/vuejs/vitepress/issues/2851)\n- **theme:** export VPButton and VPSponsors ([#2767](https://github.com/vuejs/vitepress/issues/2767)) ([6960ec1](https://github.com/vuejs/vitepress/commit/6960ec1cf61e973ffb238af2b77ad7aaf8c83500))\n- **theme:** export VPImage ([#2814](https://github.com/vuejs/vitepress/issues/2814)) ([f242140](https://github.com/vuejs/vitepress/commit/f242140c47e8a15070f689d5a4e54c7d88100f96))\n- **theme:** improve color system ([#2797](https://github.com/vuejs/vitepress/issues/2797)) ([e4f5c51](https://github.com/vuejs/vitepress/commit/e4f5c51bbe25d42fd52a1cd47e83dda4254fdd7e)), closes [#2100](https://github.com/vuejs/vitepress/issues/2100)\n\n### BREAKING CHANGES\n\n- `pathname://` protocol is dropped. Specify `target=\"_self\"` or `target=\"_blank\"` instead. Refer [docs](https://vitepress.dev/guide/routing#linking-to-non-vitepress-pages) to learn more.\n- Shiki's default theme is now changed to `github-light` and `github-dark`. If you want to use the old theme, you can set `markdown.theme` in your config to `'material-theme-palenight'`.\n- Internal logic of `isDark` is changed to use vueuse. It might impact your custom theme. You can customize its behavior using [`appearance`](https://vitepress.dev/reference/site-config#appearance) option.\n- Default theme's color system is updated to make it more easily customizable. Refer the [PR](https://github.com/vuejs/vitepress/pull/2797) for new variables.\n\n# [1.0.0-rc.4](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.7...v1.0.0-rc.4) (2023-08-08)\n\n### Bug Fixes\n\n- `createContentLoader` generates invalid url when `base` is set ([#2714](https://github.com/vuejs/vitepress/issues/2714)) ([0f38eb4](https://github.com/vuejs/vitepress/commit/0f38eb440492f3a486517714976fbfe6dfb30a09))\n- **build:** make outDir from cli work properly ([17378c0](https://github.com/vuejs/vitepress/commit/17378c064f3e6f166ce180f8d7eeced2f1cc4224)), closes [#2716](https://github.com/vuejs/vitepress/issues/2716)\n- **build:** nested rewrites not working properly ([0f421d7](https://github.com/vuejs/vitepress/commit/0f421d72221495b8ef14195db3e3df9297ebc6ff))\n- **client:** handle empty hash in links ([#2738](https://github.com/vuejs/vitepress/issues/2738)) ([c6c983e](https://github.com/vuejs/vitepress/commit/c6c983ed73a019027b452b3eaf0ee4b502d38818))\n- fix sitemap path resolution ([481a5e3](https://github.com/vuejs/vitepress/commit/481a5e3cb55c6fda2c318180cfa0532ed34e4fc5)), closes [#2749](https://github.com/vuejs/vitepress/issues/2749)\n- **theme:** align max-width media queries ([d31051a](https://github.com/vuejs/vitepress/commit/d31051a05106f97924be3cdb3919f24acc232b59))\n- **theme:** allow using h1 headings in outline ([e3f8fc7](https://github.com/vuejs/vitepress/commit/e3f8fc7972f5506cd9def08ad13c62141737318f)), closes [#1529](https://github.com/vuejs/vitepress/issues/1529)\n- **theme:** close dropdown menus after an item is clicked ([#2380](https://github.com/vuejs/vitepress/issues/2380)) ([e54eea3](https://github.com/vuejs/vitepress/commit/e54eea3da0de640e7b343381bddf9a439d638954))\n- **theme:** don't reset scroll position on changing tab in code groups ([039798a](https://github.com/vuejs/vitepress/commit/039798a8c14a8c455e1187c5584c7f518c40f66a)), closes [#2732](https://github.com/vuejs/vitepress/issues/2732) [#2362](https://github.com/vuejs/vitepress/issues/2362)\n- **theme:** dont show transparent navbar other than home ([#2742](https://github.com/vuejs/vitepress/issues/2742)) ([1d6254b](https://github.com/vuejs/vitepress/commit/1d6254b615b48ceef85267045e8fce976a7eafd5))\n- **theme:** hide outline marker on scroll to top ([81e7405](https://github.com/vuejs/vitepress/commit/81e7405e193e832442db9aedb50ed3dc741e92ed))\n- **theme:** outline marker flicks when navigating towards above ([e8ebf1b](https://github.com/vuejs/vitepress/commit/e8ebf1b0483e025b7d3bc3ea6eb3fa02d4acac93)), closes [#2665](https://github.com/vuejs/vitepress/issues/2665) [#2676](https://github.com/vuejs/vitepress/issues/2676)\n- **theme:** override docsearch button bg ([063b0e5](https://github.com/vuejs/vitepress/commit/063b0e520a0b34db934371f56ddba212ceb3ba4c)), closes [#2735](https://github.com/vuejs/vitepress/issues/2735)\n- **theme:** respect feature icon dimensions set from frontmatter ([93823a8](https://github.com/vuejs/vitepress/commit/93823a8566df22c57cb4fbc81fa65c34222ece5e)), closes [#1886](https://github.com/vuejs/vitepress/issues/1886)\n- **theme:** scroll code group tab into view on selection ([1a6efba](https://github.com/vuejs/vitepress/commit/1a6efbae8e13eb6612aacdb8d384554e72e5f562)), closes [#2355](https://github.com/vuejs/vitepress/issues/2355)\n- **theme:** update sidebar active link status on hash change ([#2736](https://github.com/vuejs/vitepress/issues/2736)) ([3840eaa](https://github.com/vuejs/vitepress/commit/3840eaae163cc9307c8d8525ad03c59752443b2b))\n- **regression/theme:** fix sidebar collapsing ([#2753](https://github.com/vuejs/vitepress/issues/2753)) ([9a4ee07](https://github.com/vuejs/vitepress/commit/9a4ee07260191adeb4c3810d95b044439609525c))\n- **cli:** generate mjs file on init if `\"type\": \"module\"` is not present ([23d7511](https://github.com/vuejs/vitepress/commit/23d751165f6def6fa6b3a5d7efd89b993a2780d8))\n- **theme:** language menu undefined text ([#2755](https://github.com/vuejs/vitepress/issues/2755)) ([c9d4655](https://github.com/vuejs/vitepress/commit/c9d465587a3b2188ff9922483a15d7096e6a3e6c))\n\n### Features\n\n- **theme:** final re-brand ([#2727](https://github.com/vuejs/vitepress/pull/2727)) ([c0d838b](https://github.com/vuejs/vitepress/commit/c0d838bda0121fc162d1e6a43324f75290bc1b72))\n- allow html blocks inside code groups ([#2719](https://github.com/vuejs/vitepress/issues/2719)) ([7f0c18e](https://github.com/vuejs/vitepress/commit/7f0c18e01384d48380b64ba629229ec048f85453))\n- **build:** add `markdown.preConfig` option ([ce85726](https://github.com/vuejs/vitepress/commit/ce85726c127d9478274126374df9c37ee8b31167)), closes [#1382](https://github.com/vuejs/vitepress/issues/1382)\n- **build:** allow overriding vite config loading ([#2750](https://github.com/vuejs/vitepress/issues/2750)) ([1bed154](https://github.com/vuejs/vitepress/commit/1bed154612661ac3783558cf82a7e94832ee4ff8))\n- **client:** allow customizing scrollOffset padding ([20b509c](https://github.com/vuejs/vitepress/commit/20b509c6e1d957c73be75da27635b23de42781d4)), closes [#2739](https://github.com/vuejs/vitepress/issues/2739)\n- **client:** allow overriding props on Content ([1179484](https://github.com/vuejs/vitepress/commit/11794844327c65bd6086b1237b0d6568cb32a4cb)), closes [#2712](https://github.com/vuejs/vitepress/issues/2712)\n- i18n with sitemap ([#2708](https://github.com/vuejs/vitepress/issues/2708)) ([7778187](https://github.com/vuejs/vitepress/commit/7778187f2dc31554fa7541da9648235c994d4ae8))\n- **search:** allow enabling detailed view by default ([4af5975](https://github.com/vuejs/vitepress/commit/4af597582cd8ae565e22c912f26f67123babcd61)), closes [#2690](https://github.com/vuejs/vitepress/issues/2690)\n- **theme:** allow adding custom layouts ([f4a5c43](https://github.com/vuejs/vitepress/commit/f4a5c43cb00d70143cefcd9dfd9ba536f120ffda)), closes [#2547](https://github.com/vuejs/vitepress/issues/2547)\n- **theme:** allow customizing default theme's 404 page ([d7e2254](https://github.com/vuejs/vitepress/commit/d7e225473bd072119c3ce76317db2b723be74f81)), closes [#2715](https://github.com/vuejs/vitepress/issues/2715)\n- **theme:** allow customizing prev/next text from config file ([09a4fdc](https://github.com/vuejs/vitepress/commit/09a4fdc9b844a3e1877045afc496282b988f6f6b)), closes [#1373](https://github.com/vuejs/vitepress/issues/1373)\n- **theme:** allow overriding logo link ([2a7422b](https://github.com/vuejs/vitepress/commit/2a7422bbbf91b852e27525d64627e9cff6eff294)), closes [#1683](https://github.com/vuejs/vitepress/issues/1683)\n- **theme:** allow passing html in nav links ([69251b7](https://github.com/vuejs/vitepress/commit/69251b7484d8e4591841c32dd2f5a0179859cf14)), closes [#1652](https://github.com/vuejs/vitepress/issues/1652)\n- **theme:** allow setting base path in sidebar items ([#2734](https://github.com/vuejs/vitepress/issues/2734)) ([52884d9](https://github.com/vuejs/vitepress/commit/52884d9d4b3ad294f4c4fcab637c4e07c80dde3a))\n\n### Reverts\n\n- [#2689](https://github.com/vuejs/vitepress/issues/2689) ([#2722](https://github.com/vuejs/vitepress/issues/2722)) ([a56d608](https://github.com/vuejs/vitepress/commit/a56d608bec427ad51a9edb620d8fb01ebae29550))\n\n### BREAKING CHANGES\n\n- Node v18+ is now required to run VitePress.\n- VitePress now only provides ESM API. Refer [#2703](https://github.com/vuejs/vitepress/issues/2703) for details.\n\n# [1.0.0-beta.7](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2023-07-29)\n\n### Bug Fixes\n\n- **build:** `createContentLoader` generates invalid url when `srcDir` is set ([#2578](https://github.com/vuejs/vitepress/issues/2578)) ([74d9ba2](https://github.com/vuejs/vitepress/commit/74d9ba27b53c6fd09b91b58bba9c1f138a6ee6f1))\n- **build:** duplicate description tags with transformHead ([#2702](https://github.com/vuejs/vitepress/issues/2702)) ([68f25f5](https://github.com/vuejs/vitepress/commit/68f25f5a9cca1d059831184ad8876bb40326d9b6))\n- **build:** use vue dev build when DEBUG is truthy ([#2689](https://github.com/vuejs/vitepress/issues/2689)) ([b61f36d](https://github.com/vuejs/vitepress/commit/b61f36d85326912ca67f552ecbe89aa4ca0b1919))\n- **build:** remove index.html when using createContentLoader ([#2693](https://github.com/vuejs/vitepress/issues/2693)) ([6fc88a5](https://github.com/vuejs/vitepress/commit/6fc88a5cce431fa47330860155191f7b3eccb62e))\n- **search:** add useFocusTrap and mark.js to optimizeDeps ([#2682](https://github.com/vuejs/vitepress/issues/2682)) ([fb048a6](https://github.com/vuejs/vitepress/commit/fb048a6f7289a12a8e67724cee29e55252568489))\n- **theme:** incorrect header anchor icon position with multline headers ([#2694](https://github.com/vuejs/vitepress/issues/2694)) ([77c1b4d](https://github.com/vuejs/vitepress/commit/77c1b4d3cd3c47ffc5268ac24d0f983df443075d))\n- **theme:** code group tab divider not showing full-width ([#2701](https://github.com/vuejs/vitepress/issues/2701)) ([b39b491](https://github.com/vuejs/vitepress/commit/b39b4912af9664d14f5f7c658e64b96de3865f04))\n- **theme:** fix feature component always generating anchor tags ([51f28bf](https://github.com/vuejs/vitepress/commit/51f28bfac96bbb14ea0175c796e0d18fff3b2cc5))\n- **theme:** respect empty rel and target ([#2705](https://github.com/vuejs/vitepress/issues/2705)) ([60dd0a4](https://github.com/vuejs/vitepress/commit/60dd0a474b056ec884f3173a233f1fb951d96870))\n\n### Features\n\n- sitemap generation ([#2691](https://github.com/vuejs/vitepress/issues/2691)) ([5563695](https://github.com/vuejs/vitepress/commit/5563695b1599165fa85ea69f15334e27ab6955bf))\n- **build:** custom excerpt for `createContentLoader` ([#2698](https://github.com/vuejs/vitepress/issues/2698)) ([13f94a6](https://github.com/vuejs/vitepress/commit/13f94a6663d5b4472ce380ee1c27e6124da8fec3))\n- **theme:** rel for feature links ([#2704](https://github.com/vuejs/vitepress/issues/2704)) ([5d18fd8](https://github.com/vuejs/vitepress/commit/5d18fd8978e418ce920aab357b180a58b1af3077))\n- **theme:** support custom page class ([#2696](https://github.com/vuejs/vitepress/issues/2696)) ([2ae90a2](https://github.com/vuejs/vitepress/commit/2ae90a234338ea074b536e5583d81fd565d8e3f3))\n\n### BREAKING CHANGES\n\n- **build:** `createContentLoader` will now resolve globs relative to `srcDir` instead of `root`\n\n# [1.0.0-beta.6](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2023-07-22)\n\n### Bug Fixes\n\n- **build:** cannot handle file name containing single quote ([#2615](https://github.com/vuejs/vitepress/issues/2615)) ([9949f00](https://github.com/vuejs/vitepress/commit/9949f0046114fdbb59062ecc044aa0a735733e2e))\n- **build:** remove `=\"\"` from boolean attributes in head ([#2620](https://github.com/vuejs/vitepress/issues/2620)) ([e02adfe](https://github.com/vuejs/vitepress/commit/e02adfe3eaed9761f71d1d263822c5f94618ee72)), closes [#1131 (comment)](https://github.com/vuejs/vitepress/issues/1131#issuecomment-1574092184) [#2607](https://github.com/vuejs/vitepress/issues/2607)\n- **build:** resolve nested md inclusions properly ([e8074e6](https://github.com/vuejs/vitepress/commit/e8074e60ec5941e7b447f21a289e59e9a91a9e33)), closes [#2584](https://github.com/vuejs/vitepress/issues/2584) [#2586](https://github.com/vuejs/vitepress/issues/2586)\n- **compat:** disable stdin-discarder ([#2640](https://github.com/vuejs/vitepress/issues/2640)) ([08c4bac](https://github.com/vuejs/vitepress/commit/08c4bacac5e1acaa95a9878e71781f65b49f48f4))\n- **hmr:** allow disabling md cache during dev ([#2581](https://github.com/vuejs/vitepress/issues/2581)) ([f60b32f](https://github.com/vuejs/vitepress/commit/f60b32f02f4236ec0c29f450c4fe79d6aabf5995))\n- invalid css ([b199885](https://github.com/vuejs/vitepress/commit/b199885b9bc55082914fa651407989a03e4e3a9f))\n- **lastUpdated:** use author date instead of commit date ([#2618](https://github.com/vuejs/vitepress/issues/2618)) ([47bf5bf](https://github.com/vuejs/vitepress/commit/47bf5bf991e48fd41b83613136396bc607751104))\n- **theme:** code block style is broken inside custom block ([#2664](https://github.com/vuejs/vitepress/issues/2664)) ([8ff431a](https://github.com/vuejs/vitepress/commit/8ff431a6bcce8cca04d9ea23ef92045a728d686a))\n- **theme:** don't show external link icon on social links ([f3a4597](https://github.com/vuejs/vitepress/commit/f3a459708d55b3b98a9d25b090e442beebcdaa92))\n- **theme:** fix doc footer's prev and next's size difference ([#2600](https://github.com/vuejs/vitepress/issues/2600)) ([f52a262](https://github.com/vuejs/vitepress/commit/f52a2629a7f565ff10b263bf7efd8e258c7d4979))\n- **theme:** fix sidebar's caret alignment issue with long text ([#2599](https://github.com/vuejs/vitepress/issues/2599)) ([01120a5](https://github.com/vuejs/vitepress/commit/01120a51d6d13f842678c6a1d418ac7bd3ccceca))\n- **theme:** fix theme without fonts emitting inter ([#2588](https://github.com/vuejs/vitepress/issues/2588)) ([71eb11f](https://github.com/vuejs/vitepress/commit/71eb11f72e60706a546b756dc3fd72d06e2ae4e2))\n- **theme:** invalid html -- article inside span ([d0e7374](https://github.com/vuejs/vitepress/commit/d0e73744412520fbbc36a8d701fa3aaaaa53ab35))\n- **theme:** re-export default ([#2606](https://github.com/vuejs/vitepress/issues/2606)) ([9fdee9c](https://github.com/vuejs/vitepress/commit/9fdee9c2a30eeccb500e6aff165887d79a1686ef))\n- **theme:** respect `--vp-nav-height` in local nav calculations ([#2663](https://github.com/vuejs/vitepress/issues/2663)) ([3912951](https://github.com/vuejs/vitepress/commit/3912951bad6f61950ba9da4f5cd3061218903e7d))\n- **theme:** support missing meta description tag ([#2639](https://github.com/vuejs/vitepress/issues/2639)) ([cfa870f](https://github.com/vuejs/vitepress/commit/cfa870f060934c4738c2f70e7b21ad13b6acdb42))\n- **theme:** two outlines at 1280px ([ceedb68](https://github.com/vuejs/vitepress/commit/ceedb68d3b22e5c5cc72be1777c6a3f7090d0a6a)), closes [#2668](https://github.com/vuejs/vitepress/issues/2668)\n- **type:** `useSidebar()` type error ([#2643](https://github.com/vuejs/vitepress/issues/2643)) ([a07f959](https://github.com/vuejs/vitepress/commit/a07f959d472f1976d26c675066204eca9bc7c651))\n\n### Features\n\n- **build:** add `metaChunk` option to extract metadata to separate chunk ([#2626](https://github.com/vuejs/vitepress/issues/2626)) ([700fad1](https://github.com/vuejs/vitepress/commit/700fad192edef1f5d4681d714d3eaebbd77eab95))\n- **build:** support custom `assetsDir` ([#2497](https://github.com/vuejs/vitepress/issues/2497)) ([64d7c3b](https://github.com/vuejs/vitepress/commit/64d7c3ba54ed2dceabcc1cb65634381d7b42ce47))\n- **build:** support overriding meta viewport tag ([#2642](https://github.com/vuejs/vitepress/issues/2642)) ([94e2966](https://github.com/vuejs/vitepress/commit/94e2966babfe572a62c71907332450b18c6c9509))\n- **search:** allow excluding content from search results ([#2602](https://github.com/vuejs/vitepress/issues/2602)) ([37d5b27](https://github.com/vuejs/vitepress/commit/37d5b273fbfddd41958e5cae4cc874a81dd9298a)), closes [#2344](https://github.com/vuejs/vitepress/issues/2344)\n- **search:** support `minisearch` customization ([#2576](https://github.com/vuejs/vitepress/issues/2576)) ([9fee554](https://github.com/vuejs/vitepress/commit/9fee5542cb4bd0b83ccad5d625cb4eca8f8abb25))\n- **theme:** allow using html text in VPHero ([#2635](https://github.com/vuejs/vitepress/issues/2635)) ([ec7643d](https://github.com/vuejs/vitepress/commit/ec7643dc1397d5b27158bd0865bd517f08e198a5))\n- **theme:** make navbar logo's height customizable by css variable ([#2644](https://github.com/vuejs/vitepress/issues/2644)) ([c2e79aa](https://github.com/vuejs/vitepress/commit/c2e79aa58387281e482f88e4f307a3c36da60f40))\n- **theme:** support footer frontmatter config ([#2574](https://github.com/vuejs/vitepress/issues/2574)) ([e79a13e](https://github.com/vuejs/vitepress/commit/e79a13eb42a0ab37713f09e7fd067cac559ab812))\n\n### Performance Improvements\n\n- fix race conditions with cache ([#2579](https://github.com/vuejs/vitepress/issues/2579)) ([32d65d4](https://github.com/vuejs/vitepress/commit/32d65d40c55b7df1a814820d5117c360f9d449a4))\n\n# [1.0.0-beta.5](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2023-07-03)\n\n### Bug Fixes\n\n- **types:** `Sidebar` was exported multiple times breaking the config ([#2573](https://github.com/vuejs/vitepress/issues/2573)) ([a99dcf9](https://github.com/vuejs/vitepress/commit/a99dcf94436d6cbbd53ef5481a6ec5ffd8d887d2))\n\n# [1.0.0-beta.4](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2023-07-02)\n\n### Bug Fixes\n\n- **build:** add `@vue/devtools-api` to `optimizeDeps.include` ([#2543](https://github.com/vuejs/vitepress/issues/2543)) ([b2a129f](https://github.com/vuejs/vitepress/commit/b2a129f49b8c83e528f594af977b1e901a57313e))\n- **client:** bypass client router for links explicitly specifying target ([#2563](https://github.com/vuejs/vitepress/issues/2563)) ([e95015f](https://github.com/vuejs/vitepress/commit/e95015f598846e318c60929f1ef6466a8cfbb729))\n- **client:** don't throw on using special chars in element ids ([#2560](https://github.com/vuejs/vitepress/issues/2560)) ([6b98113](https://github.com/vuejs/vitepress/commit/6b98113a4295e5db8d3876f176dab7e5a5b33e5c))\n- **client:** scroll not working on clicking an anchor in search box ([#2527](https://github.com/vuejs/vitepress/issues/2527)) ([c30e758](https://github.com/vuejs/vitepress/commit/c30e758585ef512eef68b33918832d4413839e9c))\n- **theme:** unresponsive back button with empty input in search box ([#2566](https://github.com/vuejs/vitepress/issues/2566)) ([fa3780f](https://github.com/vuejs/vitepress/commit/fa3780f8ef99b88e998523570f08a4e7f86dfd1b))\n\n### Features\n\n- **build:** support nested markdown includes ([#2545](https://github.com/vuejs/vitepress/issues/2545)) ([0c4210b](https://github.com/vuejs/vitepress/commit/0c4210bb5ed114fb8597786230cb145790578071))\n- **client:** add onBeforePageLoad hook for router ([#2564](https://github.com/vuejs/vitepress/issues/2564)) ([665f3b0](https://github.com/vuejs/vitepress/commit/665f3b02f828175d4df5c0f79263dfa6e3f601d2))\n- support selecting line range when importing md file ([#2502](https://github.com/vuejs/vitepress/issues/2502)) ([1ef33fe](https://github.com/vuejs/vitepress/commit/1ef33fe1c44875dc86835a698a708b1aa847e16e))\n- **theme:** allow customizing last updated date time format options ([#2332](https://github.com/vuejs/vitepress/issues/2332)) ([24abc7c](https://github.com/vuejs/vitepress/commit/24abc7c6bda66df6e7ed543531f52c87f52f52df))\n- **theme:** allow hiding navbar on specific pages via frontmatter ([#2565](https://github.com/vuejs/vitepress/issues/2565)) ([1e15001](https://github.com/vuejs/vitepress/commit/1e1500141bf6e2619caa7950f019016dc26d147f))\n- **theme:** expose `useSidebar` ([#2496](https://github.com/vuejs/vitepress/issues/2496)) ([c4909e4](https://github.com/vuejs/vitepress/commit/c4909e4298ec706cf1762cb36af03e5fd3637ccc))\n- **theme:** option to show icon for external links ([#2501](https://github.com/vuejs/vitepress/issues/2501)) ([52cfbc3](https://github.com/vuejs/vitepress/commit/52cfbc323615c3e017b656bb551e0d9de02d1e5f))\n\n### BREAKING CHANGES\n\n- **client:** specifying `target=\"_self\"` for internal links will now perform full reload.\n\n# [1.0.0-beta.3](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2023-06-20)\n\n### Bug Fixes\n\n- **build:** disable validation for rewrite compiling ([69b2625](https://github.com/vuejs/vitepress/commit/69b2625623292591207b6b591f6b39019a054a43))\n- **theme:** prevent glitch when algolia chunk is loaded ([#2519](https://github.com/vuejs/vitepress/issues/2519)) ([51661de](https://github.com/vuejs/vitepress/commit/51661def8ff743733d391a61ffb2ab1b66473fd2))\n- use extends in template custom theme ([#2500](https://github.com/vuejs/vitepress/issues/2500)) ([7e39e02](https://github.com/vuejs/vitepress/commit/7e39e02185f5b18da09b01bd4c132a8b50e15b07))\n\n- revert!: sync defineConfig types with vite (#2529) ([cd03db8](https://github.com/vuejs/vitepress/commit/cd03db803d5e6b9f04e242f7843153dded73ccb2)), closes [#2529](https://github.com/vuejs/vitepress/issues/2529)\n\n### Features\n\n- **build:** allow using regex in rewrites ([f831767](https://github.com/vuejs/vitepress/commit/f831767764030c77cc79db4cc860e7d76afc1b6a))\n- **client:** expose dataSymbol ([a547530](https://github.com/vuejs/vitepress/commit/a5475304faad7db037e19a9ffe4d6f48a816e6ed)), closes [#2489](https://github.com/vuejs/vitepress/issues/2489)\n\n### BREAKING CHANGES\n\n- reverts the breaking changes in beta-2. `defineConfig` and `defineConfigWithTheme` no longer accept functions as argument.\n\n# [1.0.0-beta.2](https://github.com/vuejs/vitepress/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2023-06-11)\n\n### Bug Fixes\n\n- **build:** create markdown env for localSearchPlugin ([#2322](https://github.com/vuejs/vitepress/issues/2322)) ([c9a98ac](https://github.com/vuejs/vitepress/commit/c9a98ac6bb854a7a24c08cfc23e84ebc243ba347))\n- **build:** use rimraf to handle temp folder deletion in windows ([#2483](https://github.com/vuejs/vitepress/issues/2483)) ([2f75769](https://github.com/vuejs/vitepress/commit/2f7576998587387ee32173b6de90f338fc7e85d3))\n- **search:** detailed view not working when page contains script setup ([80e734d](https://github.com/vuejs/vitepress/commit/80e734d67763fea449647b7b21dfde0bde1c360b)), closes [#2485](https://github.com/vuejs/vitepress/issues/2485)\n- **theme:** adjust z-index for active code group marker ([#2413](https://github.com/vuejs/vitepress/issues/2413)) ([06c0fc5](https://github.com/vuejs/vitepress/commit/06c0fc5d5cd55e03b4eee14feac67b749e7283ed))\n- **theme:** properly show divider between navs ([#2481](https://github.com/vuejs/vitepress/issues/2481)) ([2bd55ec](https://github.com/vuejs/vitepress/commit/2bd55eca2e7d8384ac50c94b049310dc6173f849))\n- **theme:** use brand color in skip link in dark theme ([#2431](https://github.com/vuejs/vitepress/issues/2431)) ([62d1110](https://github.com/vuejs/vitepress/commit/62d1110848e9b8944d920232bee185d8066194dd))\n- **theme:** use document !== undefined check for browser ([#2417](https://github.com/vuejs/vitepress/issues/2417)) ([c869ea6](https://github.com/vuejs/vitepress/commit/c869ea64ae3c20aef60af1425b02e5797faa8d69))\n- **types:** sync defineConfig types with vite ([b3ded34](https://github.com/vuejs/vitepress/commit/b3ded34d8a9ca7a9a82e9b0cf705a2ed6233e881))\n- **types:** theme-without-fonts types for node ([#2416](https://github.com/vuejs/vitepress/issues/2416)) ([8e87c14](https://github.com/vuejs/vitepress/commit/8e87c14fba6a76d2dec8611f3d56c0c3a84accc0))\n\n### Features\n\n- **build:** support relative path for code snippet ([#1894](https://github.com/vuejs/vitepress/issues/1894)) ([90478b3](https://github.com/vuejs/vitepress/commit/90478b36cd4d161c2118a9e677384982805963b0))\n- **cli:** add shortcut for restarting server ([#2403](https://github.com/vuejs/vitepress/issues/2403)) ([64b06db](https://github.com/vuejs/vitepress/commit/64b06db3ece7c4c2e73dd28c2f349f521afa390a))\n- **theme:** add custom label for social links ([#2466](https://github.com/vuejs/vitepress/issues/2466)) ([c995b9f](https://github.com/vuejs/vitepress/commit/c995b9f61d90aa7671371373c5772ab59b516fc5))\n- **theme:** add semantic markup to local search dialog ([#2325](https://github.com/vuejs/vitepress/issues/2325)) ([4ddb96f](https://github.com/vuejs/vitepress/commit/4ddb96fe508578893ee5a44621b5bac098bd4710))\n- **theme:** allow prev/next links to be disabled globally ([#2317](https://github.com/vuejs/vitepress/issues/2317)) ([29a9647](https://github.com/vuejs/vitepress/commit/29a9647ee92efe8ea9a7c6698d5cacb22bf3e9ce))\n\n### Performance Improvements\n\n- parallelize mpa chunks copy ([#2389](https://github.com/vuejs/vitepress/issues/2389)) ([6d7d195](https://github.com/vuejs/vitepress/commit/6d7d195adcf354b94e2a69c330264a3106ed5955))\n- **search:** use dom apis instead of regex-based section parsing ([#2486](https://github.com/vuejs/vitepress/issues/2486)) ([d62e6f6](https://github.com/vuejs/vitepress/commit/d62e6f6dd68e1ac31654e0da6102915a5a3709f0))\n- **theme/search:** prevent repeated rendering of same page ([#2398](https://github.com/vuejs/vitepress/issues/2398)) ([e7be720](https://github.com/vuejs/vitepress/commit/e7be720ede403598dcec0a520ccc7bacf4e8b276))\n\n### BREAKING CHANGES\n\n- **types:** `defineConfig` and `defineConfigWithTheme` can now accept functions that return the config object. This might break typings in some third-party plugins that rely on the type of these functions.\n\n# [1.0.0-beta.1](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.76...v1.0.0-beta.1) (2023-05-22)\n\n### Bug Fixes\n\n- **config:** set scrollOffset to 0 is not effect ([#2395](https://github.com/vuejs/vitepress/issues/2395)) ([8153f23](https://github.com/vuejs/vitepress/commit/8153f23c901a6200661813e65f0d8eb602ad46da))\n- **theme:** make features section layout consistent ([#2382](https://github.com/vuejs/vitepress/issues/2382)) ([26f21d9](https://github.com/vuejs/vitepress/commit/26f21d95dfbd671477d425e6b8ac5b0172a846ac))\n- **theme:** missing global properties in localSearch ([#2396](https://github.com/vuejs/vitepress/issues/2396)) ([4896811](https://github.com/vuejs/vitepress/commit/489681117f46a803704b6ec80546a5e787e19df2))\n- **theme:** support custom target and rel in navbar links for mobile ([#2400](https://github.com/vuejs/vitepress/issues/2400)) ([f364a5d](https://github.com/vuejs/vitepress/commit/f364a5d1d3c066c9728beb5d07576d6cb4b0640d))\n\n# [1.0.0-alpha.76](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.75...v1.0.0-alpha.76) (2023-05-18)\n\n### Bug Fixes\n\n- **a11y:** mobile and theme switcher ([#2354](https://github.com/vuejs/vitepress/issues/2354)) ([d6c0985](https://github.com/vuejs/vitepress/commit/d6c0985002ee792b1e8e052f71cdd6bd72c315ad))\n- **build:** uniform handling of windows slash in localSearchPlugin ([#2358](https://github.com/vuejs/vitepress/issues/2358)) ([b31933f](https://github.com/vuejs/vitepress/commit/b31933fbdd7aabfe080234407153aefa8f6a3f30))\n- hmr when `base` is set ([#2375](https://github.com/vuejs/vitepress/issues/2375)) ([484ff5d](https://github.com/vuejs/vitepress/commit/484ff5dd4bd2e5c2d5168437895d400a39f2bfa8))\n- **theme:** don't update opacity on hover ([#2326](https://github.com/vuejs/vitepress/issues/2326)) ([35f8b89](https://github.com/vuejs/vitepress/commit/35f8b896372e75e62882df613a49e8945e7bc832))\n\n### Features\n\n- **cli:** add shortcuts ([#2353](https://github.com/vuejs/vitepress/issues/2353)) ([97065ce](https://github.com/vuejs/vitepress/commit/97065cefc22e4772c0295c5ad23a87eea286f46b))\n- **theme:** add focus trap to local search dialog ([#2324](https://github.com/vuejs/vitepress/issues/2324)) ([2f482af](https://github.com/vuejs/vitepress/commit/2f482afaabdb4206b87e2453d0099257693c4653))\n- **theme:** open search box on pressing slash too ([#2328](https://github.com/vuejs/vitepress/issues/2328)) ([c20bd28](https://github.com/vuejs/vitepress/commit/c20bd283319158135e2d850485970dfc5fe82812))\n\n# [1.0.0-alpha.75](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.74...v1.0.0-alpha.75) (2023-04-30)\n\n### Bug Fixes\n\n- **build:** reset regex lastIndex before testing ([188893c](https://github.com/vuejs/vitepress/commit/188893c2c1569e332e8776581cfa40b4c5f1168e))\n- **cli/init:** remove trailing slash from npm scripts ([64ecedc](https://github.com/vuejs/vitepress/commit/64ecedc73f3e7010de85381d946af1c95404820e))\n- **theme:** hide local nav on home page ([f07587a](https://github.com/vuejs/vitepress/commit/f07587af8a51f92a5ec491e5789dd088e28067b5)), closes [#2312](https://github.com/vuejs/vitepress/issues/2312)\n- **theme:** local search get 404 on build when use route rewrites in windows ([#2301](https://github.com/vuejs/vitepress/issues/2301)) ([494c634](https://github.com/vuejs/vitepress/commit/494c634eb1d77963e555a736fa057dcb23700989))\n- **theme:** vitepress data not properly injected in app when use localSearch ([#2299](https://github.com/vuejs/vitepress/issues/2299)) ([69c7646](https://github.com/vuejs/vitepress/commit/69c7646dafe7a774e0717e032f697b008d9cf7aa))\n\n### Features\n\n- add `filePath` to `PageData` ([#2140](https://github.com/vuejs/vitepress/issues/2140)) ([b24acc6](https://github.com/vuejs/vitepress/commit/b24acc6991570aa054a99b8d3977b8b4d0255418))\n- **build:** allow using `@` prefix with `@include` ([#2292](https://github.com/vuejs/vitepress/issues/2292)) ([a3b38d1](https://github.com/vuejs/vitepress/commit/a3b38d18824343fd5b571a7a9a5d2c4ccf29e8e1))\n- preserve user log level ([#2310](https://github.com/vuejs/vitepress/issues/2310)) ([a647cd3](https://github.com/vuejs/vitepress/commit/a647cd384320101f6df31e03960dd2c40808c49c))\n- **theme:** support light shiki themes ([#2319](https://github.com/vuejs/vitepress/issues/2319)) ([d0f0012](https://github.com/vuejs/vitepress/commit/d0f0012aea4cc71fb28f60f2dd649c23aae146b8))\n\n### BREAKING CHANGES\n\n- **theme:** Styling for code blocks might break, especially if you were earlier overriding it for light theme. Those workarounds are no longer required. VitePress will now show code blocks and groups in light mode too if a light shiki theme is specified.\n\n# [1.0.0-alpha.74](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.73...v1.0.0-alpha.74) (2023-04-24)\n\n### Bug Fixes\n\n- **build:** allow data-loaders files in packages to be found (closes [#2272](https://github.com/vuejs/vitepress/issues/2272)) ([84cf457](https://github.com/vuejs/vitepress/commit/84cf45772ed59f5eae747c15fbffc375768007b8))\n- **router:** scroll back to the hash anchor even if it is already selected ([#2265](https://github.com/vuejs/vitepress/issues/2265)) ([f3d3332](https://github.com/vuejs/vitepress/commit/f3d3332fff72d1df6f70c5893bfc90442b1776fb))\n\n### Features\n\n- allow using html in member description ([#2269](https://github.com/vuejs/vitepress/issues/2269)) ([f744364](https://github.com/vuejs/vitepress/commit/f7443643a4510a6c650f1a1bda977c1d55fddf64))\n- **search:** support custom `disableQueryPersistence` in local search ([#2273](https://github.com/vuejs/vitepress/issues/2273)) ([2f0f2d5](https://github.com/vuejs/vitepress/commit/2f0f2d5ac6efcab22bdb452e5c0780e7cd8f1498))\n- **theme:** mobile view show outline button after removing sidebar ([#2274](https://github.com/vuejs/vitepress/issues/2274)) ([25b9111](https://github.com/vuejs/vitepress/commit/25b9111222cbd3de008e18cac6554933d4db993e))\n\n# [1.0.0-alpha.73](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.72...v1.0.0-alpha.73) (2023-04-20)\n\n### Bug Fixes\n\n- **search:** fix highlighting in detailed view ([1f4920c](https://github.com/vuejs/vitepress/commit/1f4920c60dc1be03444781539064be7b3ec9eb08))\n- **search:** local search showDetailedList not working in windows ([#2253](https://github.com/vuejs/vitepress/issues/2253)) ([09be057](https://github.com/vuejs/vitepress/commit/09be057ffb767e55d3a86f1a3664ebd0690f2fc5))\n\n### Features\n\n- outline link add title attribute ([#2261](https://github.com/vuejs/vitepress/issues/2261)) ([1f5798e](https://github.com/vuejs/vitepress/commit/1f5798e43771ae1e13921a39319345c89bb2298a))\n\n# [1.0.0-alpha.72](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.71...v1.0.0-alpha.72) (2023-04-17)\n\n### Bug Fixes\n\n- **search:** don't directly access userConfig ([3e0e9d2](https://github.com/vuejs/vitepress/commit/3e0e9d2b27c02e250c5b350bf83dce9b95e217a8))\n- **search:** ready event is not fired on mac ([e37e5cb](https://github.com/vuejs/vitepress/commit/e37e5cb45a6c3507b906b9955897ce4e84adf500))\n- **theme:** local search showDetailedList not working in windows ([#2248](https://github.com/vuejs/vitepress/issues/2248)) ([8354f8f](https://github.com/vuejs/vitepress/commit/8354f8fb8649d429b2cb525dd6f35127faba7ae6))\n\n# [1.0.0-alpha.71](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.70...v1.0.0-alpha.71) (2023-04-16)\n\n### Bug Fixes\n\n- **search:** esm interop mark.js import ([1b0a249](https://github.com/vuejs/vitepress/commit/1b0a249ad66288ff56675e4db905959ff0079726))\n- **search:** properly group nested headings ([b1c956c](https://github.com/vuejs/vitepress/commit/b1c956ce99505316842c157c76a4ec051eb7610b)), closes [#2238](https://github.com/vuejs/vitepress/issues/2238)\n\n# [1.0.0-alpha.70](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.69...v1.0.0-alpha.70) (2023-04-16)\n\n### Bug Fixes\n\n- **a11y:** increase touch target size of search icons ([4449867](https://github.com/vuejs/vitepress/commit/44498675aca3271596b041881d44e1524d744df6))\n- **search:** avoid body scroll when using local search ([#2236](https://github.com/vuejs/vitepress/issues/2236)) ([144a7d8](https://github.com/vuejs/vitepress/commit/144a7d8e4ee483475b6956090c267213a1e2f8e1))\n- **search:** better highlighting in detailed view ([#2234](https://github.com/vuejs/vitepress/issues/2234)) ([be83524](https://github.com/vuejs/vitepress/commit/be8352441f8b9a8561961c69f3e1794370101de2))\n- **search:** fix keyword highlighting and scrolling in excerpts ([ca8db8a](https://github.com/vuejs/vitepress/commit/ca8db8adca028bb982b819553b85ac19fe946e7e))\n- **search:** remove double base on importing excepts ([185213c](https://github.com/vuejs/vitepress/commit/185213c6ba4416071025fbf3c5ca7fadf311fdbf)), closes [#2230](https://github.com/vuejs/vitepress/issues/2230)\n- **search:** remove extra /index from routes ([9e04b43](https://github.com/vuejs/vitepress/commit/9e04b435671accfcaee795ec8ec2833d8aa358f8))\n- **search:** show escape to close on footer ([6d5b4cd](https://github.com/vuejs/vitepress/commit/6d5b4cd784274786ad57cef378646320ba17faf1))\n\n### Features\n\n- **search:** allow force disabling detailed view ([40f1d1b](https://github.com/vuejs/vitepress/commit/40f1d1b6f6f2f6c43fd0d9bcf4b6bc1174ce4831))\n- **search:** make styling more configurable, align more with the theme ([#2233](https://github.com/vuejs/vitepress/issues/2233)) ([b2077c7](https://github.com/vuejs/vitepress/commit/b2077c70250d5c390d69ce31111a1c44769dbc78))\n\n# [1.0.0-alpha.69](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.68...v1.0.0-alpha.69) (2023-04-15)\n\n### Bug Fixes\n\n- **search:** fix errors on empty titles ([6d363ec](https://github.com/vuejs/vitepress/commit/6d363ec9ffd6b27e1c77e5aab853471c6883c7bd))\n- **theme:** fix color of blockquote in custom containers ([#2173](https://github.com/vuejs/vitepress/issues/2173)) ([712a57f](https://github.com/vuejs/vitepress/commit/712a57fde74daa27f69319861d95f9dec6bc05ad))\n\n# [1.0.0-alpha.68](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.67...v1.0.0-alpha.68) (2023-04-15)\n\n### Bug Fixes\n\n- **theme:** fix top of scrollbar being unusable ([#2224](https://github.com/vuejs/vitepress/issues/2224)) ([7178a22](https://github.com/vuejs/vitepress/commit/7178a22c9d317245e5167abf80f7081fbf87e78a))\n\n# [1.0.0-alpha.67](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.66...v1.0.0-alpha.67) (2023-04-15)\n\n### Bug Fixes\n\n- **search:** avoid double base ([25a1fe9](https://github.com/vuejs/vitepress/commit/25a1fe90bddd021a1ce5e068d8cad455687647bf))\n- **theme:** navbar style ([#2202](https://github.com/vuejs/vitepress/issues/2202)) ([8ee6b90](https://github.com/vuejs/vitepress/commit/8ee6b905f5243a036c2dee7688539ef33e164f09))\n\n### Features\n\n- allow passing props and children/slots to defineClientComponent ([#2198](https://github.com/vuejs/vitepress/issues/2198)) ([4c24960](https://github.com/vuejs/vitepress/commit/4c2496043394d9b14376e74a5bf11ccea5e6e7d7))\n\n# [1.0.0-alpha.66](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.65...v1.0.0-alpha.66) (2023-04-15)\n\n### Bug Fixes\n\n- **search:** properly resolve page link ([609d447](https://github.com/vuejs/vitepress/commit/609d447ab50b2b8fb78a174e7d5aa0ff52411b0e))\n- **theme:** fix meta key not showing on search button ([e295160](https://github.com/vuejs/vitepress/commit/e2951604fd61336df9559ea16972d3ea76a49894))\n\n### Features\n\n- offline search ([#2110](https://github.com/vuejs/vitepress/issues/2110)) ([6c92675](https://github.com/vuejs/vitepress/commit/6c92675e33d3276a02b790a34083a68093b58c7f))\n\n# [1.0.0-alpha.65](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.64...v1.0.0-alpha.65) (2023-04-04)\n\n### Bug Fixes\n\n- **build:** remove extra line at end of code blocks ([#2191](https://github.com/vuejs/vitepress/issues/2191)) ([a681fd1](https://github.com/vuejs/vitepress/commit/a681fd11e32709367d673cf0d9d26e4288f27776))\n\n# [1.0.0-alpha.64](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.63...v1.0.0-alpha.64) (2023-03-29)\n\n### Bug Fixes\n\n- **build:** make `lastUpdated` work with git submodules ([#2149](https://github.com/vuejs/vitepress/issues/2149)) ([4c23003](https://github.com/vuejs/vitepress/commit/4c2300318952bfdaabd766a6f16f26419ee854da))\n- **theme:** fix color of table head row in custom containers ([#2160](https://github.com/vuejs/vitepress/issues/2160)) ([51ecd58](https://github.com/vuejs/vitepress/commit/51ecd580a29d9e2bea73d4d5897154954d750d9f))\n- **theme:** hide outline dropdown scrollbar when it does not overflow ([#2151](https://github.com/vuejs/vitepress/issues/2151)) ([ff26ff1](https://github.com/vuejs/vitepress/commit/ff26ff1e6683def53bfbe6cbd7656740c77f4bcc))\n\n### Features\n\n- **build:** provide `siteConfig` in `transformPageData` context ([#2163](https://github.com/vuejs/vitepress/issues/2163)) ([3714741](https://github.com/vuejs/vitepress/commit/3714741b409f4e5f8df4cc42c7b59b065c8cc6f6))\n- **theme:** add `page-top/bottom` and `doc-top/bottom` slots ([#2139](https://github.com/vuejs/vitepress/issues/2139)) ([53d0099](https://github.com/vuejs/vitepress/commit/53d0099ffa99582f552d7dff5676734c965ceb05))\n- **theme:** allow moving aside to left ([#2138](https://github.com/vuejs/vitepress/issues/2138)) ([9e3cf0f](https://github.com/vuejs/vitepress/commit/9e3cf0fa7d2c2589d129ef931457ab40f513d187))\n\n# [1.0.0-alpha.63](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.62...v1.0.0-alpha.63) (2023-03-26)\n\n### Bug Fixes\n\n- **theme:** allow adding html as feature icons ([e5bc1e1](https://github.com/vuejs/vitepress/commit/e5bc1e10862a765f6790f5f08aa2bd76bb258532))\n- **theme:** remove label background of code-group tabs ([#2136](https://github.com/vuejs/vitepress/issues/2136)) ([eac03f2](https://github.com/vuejs/vitepress/commit/eac03f26e2d3ab47158ac2528210e95460f6c302))\n\n### Features\n\n- more flexible `ignoreDeadLinks` ([#2135](https://github.com/vuejs/vitepress/issues/2135)) ([3235c23](https://github.com/vuejs/vitepress/commit/3235c23313d81f8f95b91779a48db839c02aa952))\n\n# [1.0.0-alpha.62](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.61...v1.0.0-alpha.62) (2023-03-25)\n\n### Bug Fixes\n\n- make md includes work with rewrites ([#1898](https://github.com/vuejs/vitepress/issues/1898)) ([3553f01](https://github.com/vuejs/vitepress/commit/3553f015a9138cb935d57487755d9d5717f79ae3))\n- **theme:** don't show outline when no header is there ([#2117](https://github.com/vuejs/vitepress/issues/2117)) ([42a0ef2](https://github.com/vuejs/vitepress/commit/42a0ef21c17da20c8f22565807578a05a0461df6))\n- **theme:** fix aside position when footer is there ([#2115](https://github.com/vuejs/vitepress/issues/2115)) ([aecdeb9](https://github.com/vuejs/vitepress/commit/aecdeb9b216803f407fe3b48574bf7664262ef01))\n- **theme:** properly align not found icon in algolia ([#2116](https://github.com/vuejs/vitepress/issues/2116)) ([83ce1b8](https://github.com/vuejs/vitepress/commit/83ce1b8c5e95d2e29e733d9312f514d725fe7f0b))\n- **theme:** use locale lang instead of navigator lang for last updated ([#2118](https://github.com/vuejs/vitepress/issues/2118)) ([56a7d9a](https://github.com/vuejs/vitepress/commit/56a7d9aa74bbb1d945c6ca3a3573b5e49ba3ca65))\n\n# [1.0.0-alpha.61](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.60...v1.0.0-alpha.61) (2023-03-20)\n\n### Bug Fixes\n\n- **build:** skip warning for `txt` language ([#2109](https://github.com/vuejs/vitepress/issues/2109)) ([ac953ce](https://github.com/vuejs/vitepress/commit/ac953ce8bdeecb2854257613c849b82d38a91846))\n- decode when query selecting current hash ([1f2f1ff](https://github.com/vuejs/vitepress/commit/1f2f1ff43dbb3c1598810fe04608678426e4fed5)), closes [#2089](https://github.com/vuejs/vitepress/issues/2089)\n- **theme:** prevent code-groups conflict with shiki-twoslash ([#2059](https://github.com/vuejs/vitepress/issues/2059)) ([ee6cda4](https://github.com/vuejs/vitepress/commit/ee6cda42d8631c5f1f6ef47ac1aec0b178a6cbf2))\n\n# [1.0.0-alpha.60](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.59...v1.0.0-alpha.60) (2023-03-15)\n\n### Features\n\n- support multiple selectors for scrollOffset ([86e2a6f](https://github.com/vuejs/vitepress/commit/86e2a6f97287c0999090d5af0e8362f3e48884db))\n- **theme:** add animation to mobile page outline dropdown ([a6b18a8](https://github.com/vuejs/vitepress/commit/a6b18a8b9aba706aa3a567ee7b2564437a0850aa))\n\n# [1.0.0-alpha.59](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.58...v1.0.0-alpha.59) (2023-03-15)\n\n### Bug Fixes\n\n- handle async enhanceApp when extending themes ([52b04f3](https://github.com/vuejs/vitepress/commit/52b04f324cc3a675ed87353d516a6302d282ccfb))\n- **theme:** improve Chinese font handling ([81ae1c7](https://github.com/vuejs/vitepress/commit/81ae1c79cd1c0c9c31f48100f131715efc68efbd)), closes [#2036](https://github.com/vuejs/vitepress/issues/2036)\n- **theme:** move doc-footer-before slot into the footer ([b0160bc](https://github.com/vuejs/vitepress/commit/b0160bc2619b50e3bca2bf1bba60d68708a39145)), closes [#2082](https://github.com/vuejs/vitepress/issues/2082)\n\n### Features\n\n- defineClientComponent helper ([2ad668c](https://github.com/vuejs/vitepress/commit/2ad668cd54174b37a8c68b389a5e31e0aae60828))\n\n# [1.0.0-alpha.58](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.57...v1.0.0-alpha.58) (2023-03-14)\n\n### Bug Fixes\n\n- fix optional component imports from default theme ([7b0f289](https://github.com/vuejs/vitepress/commit/7b0f28915fc15e155fbb27d5153e25d004bdc294))\n\n# [1.0.0-alpha.57](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.56...v1.0.0-alpha.57) (2023-03-14)\n\n### Bug Fixes\n\n- **types:** allow void return in transformHead hook ([32dfaf5](https://github.com/vuejs/vitepress/commit/32dfaf5adc9db5e87995c67a7060169cbf835b09))\n\n### Features\n\n- expose page and assets on build hooks TransformContext ([468c049](https://github.com/vuejs/vitepress/commit/468c049ccd7648144761def11c88ebf70c0d4226))\n- **theme:** a11y improvements ([3b6a6d1](https://github.com/vuejs/vitepress/commit/3b6a6d1abdc42437d9e659ef598db1d93695db21))\n- **theme:** aria-label for social links ([6ca34c4](https://github.com/vuejs/vitepress/commit/6ca34c4236c076fb40fb0b4fb01c1f9783e2210c))\n- **theme:** page outline for mobile ([7182c42](https://github.com/vuejs/vitepress/commit/7182c4231f3c435f1471dfecacdce99d48270978))\n- **theme:** support extending default theme without importing fonts ([da1691d](https://github.com/vuejs/vitepress/commit/da1691d77e371892cbe566ba45ca24f1fa03dc7c))\n- **theme:** use more accessible header anchors [#2040](https://github.com/vuejs/vitepress/pull/2040)\n\n### Performance Improvements\n\n- **theme:** preload font ([24735db](https://github.com/vuejs/vitepress/commit/24735dbcde15be41bc2697a4ea44001a1a583511))\n\n### BREAKING CHANGES\n\n- `markdown.headers` is now disabled by default. This means `PageData` will no longer include extracted headers by default unless this option is explicitly enabled. This is because the default theme now extracts page headers at runtime, so the data is no longer needed by default.\n\n# [1.0.0-alpha.56](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.55...v1.0.0-alpha.56) (2023-03-13)\n\n### Bug Fixes\n\n- do not include head tags in inlined site data ([2f26693](https://github.com/vuejs/vitepress/commit/2f26693a1d78f24d5a62a9b988c457e7c299fc5c))\n\n# [1.0.0-alpha.55](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.54...v1.0.0-alpha.55) (2023-03-13)\n\n### Bug Fixes\n\n- fix scroll to hash on new tab during dev ([9aafc88](https://github.com/vuejs/vitepress/commit/9aafc88d5951684b9b583a7a164840a9b87467b0)), closes [#653](https://github.com/vuejs/vitepress/issues/653)\n- gracefully handle config update with syntax error ([470ce3d](https://github.com/vuejs/vitepress/commit/470ce3d3f3272639288cb888dc89d37f041df104)), closes [#2041](https://github.com/vuejs/vitepress/issues/2041)\n\n### Performance Improvements\n\n- inline site data on page ([22ace7b](https://github.com/vuejs/vitepress/commit/22ace7b075276c340d0ae2a1f260d119e82c6470))\n- kickoff main chunk fetch earlier in browsers without modulepreload support ([d64a76e](https://github.com/vuejs/vitepress/commit/d64a76eb366a270c56189096a5e0ae6b8ae23ea7))\n\n# [1.0.0-alpha.54](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.53...v1.0.0-alpha.54) (2023-03-13)\n\n### Bug Fixes\n\n- fix chunking logic that causes breakage ([bed202d](https://github.com/vuejs/vitepress/commit/bed202dbcc8f3954c12aaef993369b29ff47211e)), closes [#2072](https://github.com/vuejs/vitepress/issues/2072) [#2073](https://github.com/vuejs/vitepress/issues/2073) [#2074](https://github.com/vuejs/vitepress/issues/2074) [#2075](https://github.com/vuejs/vitepress/issues/2075)\n\n# [1.0.0-alpha.53](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.52...v1.0.0-alpha.53) (2023-03-13)\n\n### Bug Fixes\n\n- avoid circular dependency between siteData virtual module and useData() ([905f58b](https://github.com/vuejs/vitepress/commit/905f58b2a80cd1dd37b645dddde3d54b02cd60d4)), closes [#2072](https://github.com/vuejs/vitepress/issues/2072) [#2073](https://github.com/vuejs/vitepress/issues/2073) [#2074](https://github.com/vuejs/vitepress/issues/2074)\n\n### Features\n\n- createContentLoader ([d2838e3](https://github.com/vuejs/vitepress/commit/d2838e3755a8ef5861d1a921a336dfebc6156634))\n- **theme:** editLink can accept function ([#2058](https://github.com/vuejs/vitepress/issues/2058)) ([192708d](https://github.com/vuejs/vitepress/commit/192708de678115116f3477293742c155b8f48e5d))\n\n# [1.0.0-alpha.52](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.51...v1.0.0-alpha.52) (2023-03-11)\n\n### Bug Fixes\n\n- fix line higlighting for empty lines ([9708510](https://github.com/vuejs/vitepress/commit/9708510cbd893f02916c95fabad5a8f07d52dbaf))\n- fix rewrites with non ascii chars ([6ce88da](https://github.com/vuejs/vitepress/commit/6ce88da3baa4bc9e6b8dc3254180ed995766c7ec)), closes [#2017](https://github.com/vuejs/vitepress/issues/2017)\n- fix same page hash links with encoded chars ([e05a3f2](https://github.com/vuejs/vitepress/commit/e05a3f2b5aff54ec7e5211c1021c16814eb57e58)), closes [#1749](https://github.com/vuejs/vitepress/issues/1749)\n- properly serialize header in outline ([8ab36d0](https://github.com/vuejs/vitepress/commit/8ab36d05fa4aa8b3707c1f89efc1c820ffaf9669))\n- remove @vue/devtools from force include ([9bd940f](https://github.com/vuejs/vitepress/commit/9bd940f22cae0ec88dc1670a31fb9ebc015e1f92))\n- respect user vue alias ([63f33d2](https://github.com/vuejs/vitepress/commit/63f33d2895d21c08903eb4d625c13d8d3721d861)), closes [#1065](https://github.com/vuejs/vitepress/issues/1065)\n- **theme:** re-support dynamic headers ([657a7d3](https://github.com/vuejs/vitepress/commit/657a7d38df3c9022a7ef6977fd71a6bde6571cfc))\n- trim spaces from outline headers ([9ceff1d](https://github.com/vuejs/vitepress/commit/9ceff1d587f6b61529806c5eb705fc417b685ad9))\n\n### Features\n\n- allow disabling markdown.headers ([868a9ff](https://github.com/vuejs/vitepress/commit/868a9ff81ea445556bc7500dfe4210d253da9ceb))\n\n### Performance Improvements\n\n- improve default theme chunking ([f6cb4c0](https://github.com/vuejs/vitepress/commit/f6cb4c0d44108116c91b28a3fcde820093d94340))\n\n### BREAKING CHANGES\n\n- default theme config option `outlineBadge` has been\n  removed. Badges in headers are now always excluded when generating\n  outline text.\n\n# [1.0.0-alpha.51](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.50...v1.0.0-alpha.51) (2023-03-09)\n\n### Bug Fixes\n\n- **theme:** align number to code line ([#2044](https://github.com/vuejs/vitepress/issues/2044)) ([27e3adf](https://github.com/vuejs/vitepress/commit/27e3adf8ed888f03466fec2e10bc7589b0d010e8))\n- **theme:** remove log in VPContent ([747a04d](https://github.com/vuejs/vitepress/commit/747a04d3416a4014e46e41ebfdc734643268bc29))\n\n### Features\n\n- **theme:** add not-found layout slot ([#2054](https://github.com/vuejs/vitepress/issues/2054)) ([41987b6](https://github.com/vuejs/vitepress/commit/41987b6a880d99e78e48ae3b4a2e6b815e183348))\n\n### Performance Improvements\n\n- **a11y:** add aria-label to language button ([#2025](https://github.com/vuejs/vitepress/issues/2025)) ([322c633](https://github.com/vuejs/vitepress/commit/322c633fd0df15b2dfae62b54479d7cdb3255155))\n\n# [1.0.0-alpha.50](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.49...v1.0.0-alpha.50) (2023-03-07)\n\n### Bug Fixes\n\n- avoid deprecation warning when using --force ([0c0b6cc](https://github.com/vuejs/vitepress/commit/0c0b6cc5a3a06bb0bee14dc854c7c1102a1b6657))\n- ensure HMR works properly for page outline ([1457681](https://github.com/vuejs/vitepress/commit/1457681484c873a7801729f9a9e11872b60b4868)), closes [#1281](https://github.com/vuejs/vitepress/issues/1281)\n- extract all headers by default ([580a8e1](https://github.com/vuejs/vitepress/commit/580a8e1a551089e973745fd224d97aec9d3fa702))\n- respect command line minify and outDir options ([22047f3](https://github.com/vuejs/vitepress/commit/22047f3363af290687cb3077ff617ae550af6e8a))\n- **theme:** make tip box text color darker ([3158115](https://github.com/vuejs/vitepress/commit/3158115afc8f15bee3e35644a33328b02dee6d6d))\n- **theme:** prevent text wrapping in nav dropdown menu ([2a1abbe](https://github.com/vuejs/vitepress/commit/2a1abbe45e10b38f03795357cd52dc4f6cea5dfc))\n\n### Features\n\n- **data-loader:** defineLoader() type helper ([4673bb1](https://github.com/vuejs/vitepress/commit/4673bb187905374896b7a1a3b1a1e5ad3777bdc4))\n- **data-loader:** pass watched files into load() ([e29b6a0](https://github.com/vuejs/vitepress/commit/e29b6a051e89e23945e2acfdfca7057978929715))\n- deprecate Theme.setup ([868a586](https://github.com/vuejs/vitepress/commit/868a58670e747310bba1f0f900a76243c6473da3))\n- export loadEnv from vite ([7609704](https://github.com/vuejs/vitepress/commit/76097048f3570b3f2417ac76ef177ce16afb9116))\n- expose isNotFound on PageData, deperecate Theme.NotFound ([74caccd](https://github.com/vuejs/vitepress/commit/74caccda4342feee3ab980b1a446ef7ec4819e0f))\n- expose params at top level in useData() ([66f94fd](https://github.com/vuejs/vitepress/commit/66f94fd7a0f43882386d32769b6b98014154ffa6))\n- support $params in page components ([a4ac055](https://github.com/vuejs/vitepress/commit/a4ac055dbf42848206683611a8d15e09572441ac))\n- support Theme.extends ([f39b6a9](https://github.com/vuejs/vitepress/commit/f39b6a98d6d2cc9ba405204a4d7a91eadce64a0d))\n- **theme:** add `as` prop to `Content` ([#2011](https://github.com/vuejs/vitepress/issues/2011)) ([254e15b](https://github.com/vuejs/vitepress/commit/254e15beb9b895c081e301eb379cbc2551b3e53c))\n- **theme:** add `home-hero-info` slot ([#1807](https://github.com/vuejs/vitepress/issues/1807)) ([996a5f4](https://github.com/vuejs/vitepress/commit/996a5f47e9064da839aef9e81db22db70fa8d76d))\n- vitepress init command ([#2020](https://github.com/vuejs/vitepress/issues/2020)) ([38bbdad](https://github.com/vuejs/vitepress/commit/38bbdaddb72ec426865d731c2f443e545e5bbbd7)), closes [#1252](https://github.com/vuejs/vitepress/issues/1252)\n\n# [1.0.0-alpha.49](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.48...v1.0.0-alpha.49) (2023-02-28)\n\n### Bug Fixes\n\n- disable fuzzy link recognition by default ([2450710](https://github.com/vuejs/vitepress/commit/24507105b18362210632543b8a72893832b5940a))\n- dyamic routes w/ srcDir + relative imports ([b075ee5](https://github.com/vuejs/vitepress/commit/b075ee5be6785e671b19ded066c22a1d506ec508))\n- hmr on deps change of data loaders ([5913ebc](https://github.com/vuejs/vitepress/commit/5913ebc34f810e84b4ad482aa835e1a4e8beb404))\n- normalize all paths in config ([8e8fcd9](https://github.com/vuejs/vitepress/commit/8e8fcd9caa4194787c5fc81ad10d17cf82638b8f))\n- **theme:** \"copy code\" button not readable on hover state ([#819](https://github.com/vuejs/vitepress/issues/819)) ([#1892](https://github.com/vuejs/vitepress/issues/1892)) ([#1998](https://github.com/vuejs/vitepress/issues/1998)) ([c2de4ca](https://github.com/vuejs/vitepress/commit/c2de4caa345bdeda5252a8fc00cfcdbcc18d5d2d))\n- **theme:** tip custom container has wrong bg color for `<code>` block ([d9a2e6e](https://github.com/vuejs/vitepress/commit/d9a2e6e8978f614d70f347be81b9b3b9df03d7a1))\n- update route configs on file add / delete ([bccce98](https://github.com/vuejs/vitepress/commit/bccce98c62d1ea405c55a6f72bab6f2ce27e2e65))\n\n### Features\n\n- dynamic routes ([24fa862](https://github.com/vuejs/vitepress/commit/24fa862c39d1b5c2ea6da6faf08cfe95e07f5d2f))\n- **theme:** enhance readability of custom containers ([#1824](https://github.com/vuejs/vitepress/issues/1824)) ([#1989](https://github.com/vuejs/vitepress/issues/1989)) ([472b6ec](https://github.com/vuejs/vitepress/commit/472b6ecf5e404bccc751bcf93b868ac30f43f22b))\n\n# [1.0.0-alpha.48](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.47...v1.0.0-alpha.48) (2023-02-26)\n\n### Bug Fixes\n\n- **compat:** remove use of array.at ([fd99590](https://github.com/vuejs/vitepress/commit/fd995906f61e5181ca8e1116dcd93eec65075056))\n- **theme:** add height constraints to hero image ([#1983](https://github.com/vuejs/vitepress/issues/1983)) ([803d5b6](https://github.com/vuejs/vitepress/commit/803d5b6d663b5293c70672ca5526a33f454e4a17))\n- **theme:** allow empty details in home feature ([#1936](https://github.com/vuejs/vitepress/issues/1936)) ([#1963](https://github.com/vuejs/vitepress/issues/1963)) ([b56351c](https://github.com/vuejs/vitepress/commit/b56351c7785b7a3a3413dcf24d7ac63c1f40fd2b))\n- **theme:** show external link icon in navbar ([#1881](https://github.com/vuejs/vitepress/issues/1881)) ([8e6e8d9](https://github.com/vuejs/vitepress/commit/8e6e8d9af534e124cb16552686b460e19d0f894f)), closes [#1948](https://github.com/vuejs/vitepress/issues/1948)\n- **theme:** show external link icon on same line ([#1880](https://github.com/vuejs/vitepress/issues/1880)) ([6218b10](https://github.com/vuejs/vitepress/commit/6218b108bc78aed0ec1afd3d1cf4182e611eed90))\n\n### Features\n\n- **build:** add support for custom languages ([#1837](https://github.com/vuejs/vitepress/issues/1837)) ([5a6d384](https://github.com/vuejs/vitepress/commit/5a6d3849527ee1dfd9f4299f5350cfa7641effb7))\n- **theme:** make prev/next links changeable ([#1972](https://github.com/vuejs/vitepress/issues/1972)) ([b8a5e8e](https://github.com/vuejs/vitepress/commit/b8a5e8e5b24b025c9a5e4850b72296f726ae71e5))\n- **theme:** support custom target and rel in navbar links ([#1993](https://github.com/vuejs/vitepress/issues/1993)) ([e2d4edf](https://github.com/vuejs/vitepress/commit/e2d4edf45b5ec890c088d3b0517b21a7b3eab9df))\n\n# [1.0.0-alpha.47](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.46...v1.0.0-alpha.47) (2023-02-20)\n\n### Bug Fixes\n\n- **build:** show error stack in logs ([#1960](https://github.com/vuejs/vitepress/issues/1960)) ([c4d8d72](https://github.com/vuejs/vitepress/commit/c4d8d7225c2d8dd75f1640730e8d1425097e3aa3))\n- custom titles of code snippets inside code groups ([#1834](https://github.com/vuejs/vitepress/issues/1834)) ([bcb8cbf](https://github.com/vuejs/vitepress/commit/bcb8cbf3c839dc17c1eaee7e39edb3ecca236a27))\n- **types:** augment vite user config ([#1946](https://github.com/vuejs/vitepress/issues/1946)) ([5c9b75e](https://github.com/vuejs/vitepress/commit/5c9b75e325c27f63373c969e16035a9df5292cc9))\n\n### Reverts\n\n- \"docs: add linkage for `code-groups` in `getting-started`\" ([#1943](https://github.com/vuejs/vitepress/issues/1943)) ([ed90724](https://github.com/vuejs/vitepress/commit/ed90724022359358de582a3c00e86f381d57eeba)), closes [#1906](https://github.com/vuejs/vitepress/issues/1906)\n\n# [1.0.0-alpha.46](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.45...v1.0.0-alpha.46) (2023-02-12)\n\n### Bug Fixes\n\n- **build:** prepend base to all internal non-relative links ([#1908](https://github.com/vuejs/vitepress/issues/1908)) ([dcf2941](https://github.com/vuejs/vitepress/commit/dcf29419f24bfb0fe99e424771be931bf77b9961))\n- **theme-default:** avoid preconnect without algolia ([#1902](https://github.com/vuejs/vitepress/issues/1902)) ([616fe5b](https://github.com/vuejs/vitepress/commit/616fe5b636050caa338cabede3794e658baa0ed6))\n- **theme-default:** remove duplicate judgments in `preconnect()` ([#1903](https://github.com/vuejs/vitepress/issues/1903)) ([48c9b11](https://github.com/vuejs/vitepress/commit/48c9b113161823133276198ebeb15131b83a7a75))\n- **theme:** make features support line wrapping ([#1913](https://github.com/vuejs/vitepress/issues/1913)) ([ea43076](https://github.com/vuejs/vitepress/commit/ea430760f507e3ba381c4ab01ec89a2111f35e8c))\n\n### Features\n\n- **build:** use vite logger ([#1899](https://github.com/vuejs/vitepress/issues/1899)) ([a00bb62](https://github.com/vuejs/vitepress/commit/a00bb621439b2571b3d33da6aa67c74ecd13d3c6))\n- **shiki:** support `ansi` code highlight ([#1878](https://github.com/vuejs/vitepress/issues/1878)) ([f974381](https://github.com/vuejs/vitepress/commit/f9743816a55503c387b9c71793a92eb38817650d))\n- **theme:** support disabling aside globally ([#1925](https://github.com/vuejs/vitepress/issues/1925)) ([dd0c4c6](https://github.com/vuejs/vitepress/commit/dd0c4c698c26d3e249d353c3baff568a8f406e8f))\n\n### BREAKING CHANGES\n\n- **build:** `base` is now prepended to all internal (non-relative) links, including any reference to a file present in the public directory. If you want the earlier behavior for such links, use absolute links.\n\n# [1.0.0-alpha.45](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.44...v1.0.0-alpha.45) (2023-01-31)\n\n### Bug Fixes\n\n- safari use `window.requestIdleCallback` ([#1871](https://github.com/vuejs/vitepress/issues/1871)) ([507b193](https://github.com/vuejs/vitepress/commit/507b193ef0e09afe667fccbf6de256cbc86de53f))\n\n# [1.0.0-alpha.44](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.43...v1.0.0-alpha.44) (2023-01-31)\n\n### Bug Fixes\n\n- take `<a>` in SVG into account ([#1850](https://github.com/vuejs/vitepress/issues/1850)) ([010b3e5](https://github.com/vuejs/vitepress/commit/010b3e5ad99f5e61fd01e27d0c3144896a8f3d86))\n- **theme:** infer collapsible from collapsed ([#1865](https://github.com/vuejs/vitepress/issues/1865)) ([dea6cfa](https://github.com/vuejs/vitepress/commit/dea6cfa9cbccf4c6433295e80571acee9b260f71))\n\n### Features\n\n- **theme:** preconnect algolia when idle ([#1851](https://github.com/vuejs/vitepress/issues/1851)) ([1f77577](https://github.com/vuejs/vitepress/commit/1f775774da7ef51ae8e690bbd86f94c739611a65))\n\n### BREAKING CHANGES\n\n- **theme:** `collapsible` is dropped from sidebar, use `collapsed` instead\n\n# [1.0.0-alpha.43](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.42...v1.0.0-alpha.43) (2023-01-29)\n\n### Bug Fixes\n\n- **build:** hmr with rewrites when base is set ([a05956f](https://github.com/vuejs/vitepress/commit/a05956f38a5295cf038ecfc762c044dbc1cdf040))\n\n# [1.0.0-alpha.42](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.41...v1.0.0-alpha.42) (2023-01-29)\n\n### Bug Fixes\n\n- **build:** consider base when checking actual pathname ([#1858](https://github.com/vuejs/vitepress/issues/1858)) ([cf8ad1a](https://github.com/vuejs/vitepress/commit/cf8ad1a29133cc373a1a70720d36e02b38ba6898))\n\n# [1.0.0-alpha.41](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.40...v1.0.0-alpha.41) (2023-01-28)\n\n### Bug Fixes\n\n- check document instead of window to detect browser ([#1833](https://github.com/vuejs/vitepress/issues/1833)) ([0f145cb](https://github.com/vuejs/vitepress/commit/0f145cb3c6568760199a9c8eee785aecaf0e0494))\n- **router:** avoid duplicate history entries ([#1827](https://github.com/vuejs/vitepress/issues/1827)) ([1553dbc](https://github.com/vuejs/vitepress/commit/1553dbce8eac9ed4a65312d4590d6b0f9261135c))\n- **theme:** don't show border on navbar when sidebar is there ([#1845](https://github.com/vuejs/vitepress/issues/1845)) ([3db532e](https://github.com/vuejs/vitepress/commit/3db532ed0999c9bddfd6bc90f6b627ae1b9178af))\n\n### Features\n\n- **build:** allow ignoring only localhost dead links ([#1821](https://github.com/vuejs/vitepress/issues/1821)) ([fe52fa3](https://github.com/vuejs/vitepress/commit/fe52fa34201dcfa87ac4886fe285331f0ef89ba8))\n- **build:** expose vitepress site config to vite plugins ([#1822](https://github.com/vuejs/vitepress/issues/1822)) ([05430e4](https://github.com/vuejs/vitepress/commit/05430e45c90562b62796caba28c633070934d85f))\n- **build:** support rewrites ([#1798](https://github.com/vuejs/vitepress/issues/1798)) ([00abac6](https://github.com/vuejs/vitepress/commit/00abac611664e12710e5152d0259390b22c0e8ca))\n- stable `cleanUrls` ([#1852](https://github.com/vuejs/vitepress/issues/1852)) ([5ae4fbd](https://github.com/vuejs/vitepress/commit/5ae4fbde3843236e180e63e2cd2b7021efa0fad4))\n- **theme:** allow removing badge text from outline ([#1825](https://github.com/vuejs/vitepress/issues/1825)) ([5d2fc3f](https://github.com/vuejs/vitepress/commit/5d2fc3f9228c9b26dec26264d0951d0f43b3d90d))\n- **theme:** enable multi level sidebar nesting ([#1360](https://github.com/vuejs/vitepress/issues/1360)) ([#1835](https://github.com/vuejs/vitepress/issues/1835)) ([c35a1f0](https://github.com/vuejs/vitepress/commit/c35a1f0faee3702c0494fb22043ce058e7a2954c)), closes [#1361](https://github.com/vuejs/vitepress/issues/1361) [#1680](https://github.com/vuejs/vitepress/issues/1680)\n\n# [1.0.0-alpha.40](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.39...v1.0.0-alpha.40) (2023-01-20)\n\n### Bug Fixes\n\n- **theme:** nav bg not being applied on some viewport ([39294e0](https://github.com/vuejs/vitepress/commit/39294e0a4ec53b245da4344187de842d0044dac8))\n\n# [1.0.0-alpha.39](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.38...v1.0.0-alpha.39) (2023-01-20)\n\n### Bug Fixes\n\n- **theme:** adjust the position of the curtain to avoid block sidebar ([#1816](https://github.com/vuejs/vitepress/issues/1816)) ([48f0b01](https://github.com/vuejs/vitepress/commit/48f0b015694c17767180eb2f75e9eb12c3f2a358))\n- **theme:** sidebar scrollbar is cropped by nav bar ([bd36224](https://github.com/vuejs/vitepress/commit/bd36224b45ee832765afcf4a57c211d362e4e6af))\n\n# [1.0.0-alpha.38](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.37...v1.0.0-alpha.38) (2023-01-17)\n\n### Bug Fixes\n\n- **theme:** spacing between aside sponsors and ads section is missing ([5c2eb1b](https://github.com/vuejs/vitepress/commit/5c2eb1b3b0988ae98639543e60a740d6b40a17a5))\n\n# [1.0.0-alpha.37](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.36...v1.0.0-alpha.37) (2023-01-17)\n\n### Bug Fixes\n\n- **build:** don't warn on blank lang in fences ([99ad162](https://github.com/vuejs/vitepress/commit/99ad162fb7b11ac80c787131714c9c8bf66fa8c7))\n- **theme:** prevent vertical scrollbar on code group tabs ([#1793](https://github.com/vuejs/vitepress/issues/1793)) ([#1805](https://github.com/vuejs/vitepress/issues/1805)) ([4314b57](https://github.com/vuejs/vitepress/commit/4314b5795918ceaa798dee550b79ff2e8a686b26))\n\n### Features\n\n- add i18n feature ([#1339](https://github.com/vuejs/vitepress/issues/1339)) ([8de2f44](https://github.com/vuejs/vitepress/commit/8de2f4499d9364d85e6070ce4b94651a1902b101)), closes [#291](https://github.com/vuejs/vitepress/issues/291) [#628](https://github.com/vuejs/vitepress/issues/628) [#631](https://github.com/vuejs/vitepress/issues/631) [#902](https://github.com/vuejs/vitepress/issues/902) [#955](https://github.com/vuejs/vitepress/issues/955) [#1253](https://github.com/vuejs/vitepress/issues/1253) [#1381](https://github.com/vuejs/vitepress/issues/1381)\n- support for teleports to body ([#1642](https://github.com/vuejs/vitepress/issues/1642)) ([09c2c52](https://github.com/vuejs/vitepress/commit/09c2c52d6c027f6e30fac33c2d11246a4a530c24))\n- **build:** don't hard fail on unknown languages in fences ([#1750](https://github.com/vuejs/vitepress/issues/1750)) ([1ae0596](https://github.com/vuejs/vitepress/commit/1ae05969396ef1651af56c66696ed77f8c4e7e85))\n- **theme:** refine overall styles ([#1049](https://github.com/vuejs/vitepress/issues/1049)) ([#1790](https://github.com/vuejs/vitepress/issues/1790)) ([471f00a](https://github.com/vuejs/vitepress/commit/471f00a68d1e3d8d925ab996f462adaf4f1261a0))\n\n# [1.0.0-alpha.36](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.35...v1.0.0-alpha.36) (2023-01-11)\n\n### Bug Fixes\n\n- **build:** handle cleanUrls without trailing slash ([#1772](https://github.com/vuejs/vitepress/issues/1772)) ([2a80fbd](https://github.com/vuejs/vitepress/commit/2a80fbd14ae124eddb05deca71ebffa50de4c2ce))\n- **theme:** `activeMatch` support regexp ([#1754](https://github.com/vuejs/vitepress/issues/1754)) ([0913e0f](https://github.com/vuejs/vitepress/commit/0913e0fe69167c796b0c3c22706b26f4840c6493)), closes [#1771](https://github.com/vuejs/vitepress/issues/1771)\n- **theme:** add cursor for summary of custom block details ([#1774](https://github.com/vuejs/vitepress/issues/1774)) ([167a474](https://github.com/vuejs/vitepress/commit/167a474cb8121d758c2aa863016dffbe8d0a1e55))\n- **theme:** wrap long words in `li` ([#1782](https://github.com/vuejs/vitepress/issues/1782)) ([48a42c1](https://github.com/vuejs/vitepress/commit/48a42c19b17417fea384bb0a7004d140b16d9c23)), closes [#1783](https://github.com/vuejs/vitepress/issues/1783) [#1405](https://github.com/vuejs/vitepress/issues/1405)\n\n### Features\n\n- allow `enhanceApp` to return a `Promise` ([#1760](https://github.com/vuejs/vitepress/issues/1760)) ([01ac579](https://github.com/vuejs/vitepress/commit/01ac57918767f44a0757414316e67072399ffb6d))\n- **build:** support interpolation inside code blocks ([#1759](https://github.com/vuejs/vitepress/issues/1759)) ([3b7ff8d](https://github.com/vuejs/vitepress/commit/3b7ff8d66e9eda3aab1fb126984efc63132bd22d))\n\n# [1.0.0-alpha.35](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.34...v1.0.0-alpha.35) (2023-01-03)\n\n### Bug Fixes\n\n- **theme:** adjust styles for copied button ([#1751](https://github.com/vuejs/vitepress/issues/1751)) ([565ae71](https://github.com/vuejs/vitepress/commit/565ae711b9b90ad2fe820cdbaa04a9d41506ac53))\n- **theme:** adjust styles for diff indicator in code blocks ([#1755](https://github.com/vuejs/vitepress/issues/1755)) ([a642ea2](https://github.com/vuejs/vitepress/commit/a642ea2526f5638243283bd37ef9ba0af350d407))\n- **theme:** prevent layout shift on carbon ads ([f6c5e1f](https://github.com/vuejs/vitepress/commit/f6c5e1f098d1fd4d4f6325a21adbb088c32a0740))\n- **theme:** refresh ads per page navigation ([#1734](https://github.com/vuejs/vitepress/issues/1734)) ([8db20fe](https://github.com/vuejs/vitepress/commit/8db20fe02240bb1d3c02da738740f2433edb1e8b))\n\n# [1.0.0-alpha.34](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.33...v1.0.0-alpha.34) (2023-01-01)\n\n### Bug Fixes\n\n- **build:** dedent of a single-line region ([#1687](https://github.com/vuejs/vitepress/issues/1687)) ([7de7fff](https://github.com/vuejs/vitepress/commit/7de7fff4178251a6173ac67b52de50176830f539))\n- **build:** handle `-` in title of code blocks with line highlighting ([#1743](https://github.com/vuejs/vitepress/issues/1743)) ([ce9467e](https://github.com/vuejs/vitepress/commit/ce9467e389a2776f3230cb31e596cf9e575cc0df))\n- handle cleanUrls with subfolders when using a trailing slash ([#1575](https://github.com/vuejs/vitepress/issues/1575)) ([195d867](https://github.com/vuejs/vitepress/commit/195d867ee9bb51a4c112534b34bda7bcd0c2c3f5))\n\n### Features\n\n- **build:** allow specifying default language for syntax highlighter ([#1296](https://github.com/vuejs/vitepress/issues/1296)) ([f40df31](https://github.com/vuejs/vitepress/commit/f40df319475dba9f3fe1e13ff8d8dc4c0950bf5f))\n- **build:** fence-level config for line-numbers ([#1733](https://github.com/vuejs/vitepress/issues/1733)) ([c048076](https://github.com/vuejs/vitepress/commit/c048076370b081acc69c04754bf5deba2b8f5cd5))\n- **theme:** add `home-hero-image` slot ([#1528](https://github.com/vuejs/vitepress/issues/1528)) ([e72998b](https://github.com/vuejs/vitepress/commit/e72998b68bfcc301d15553033a8b90dee0db65cf))\n- **theme:** add mastodon icon ([#1736](https://github.com/vuejs/vitepress/issues/1736)) ([7a73784](https://github.com/vuejs/vitepress/commit/7a737845e5d81a09151320d373a787d2e5f881af))\n- **theme:** allow adding images as icons in features section ([#1738](https://github.com/vuejs/vitepress/issues/1738)) ([9df598f](https://github.com/vuejs/vitepress/commit/9df598f36e30fdc9d1c7440bf98b45783126c39f))\n\n### Performance Improvements\n\n- **a11y:** make menu traversable only when it is open ([#1491](https://github.com/vuejs/vitepress/issues/1491)) ([257f9e6](https://github.com/vuejs/vitepress/commit/257f9e68e947a603f9c3ef0df4be7b2afa79fbe7))\n- preload css to improve loading speed ([bf1315a](https://github.com/vuejs/vitepress/commit/bf1315ace670df0128682838736371e5381b3f42))\n\n# [1.0.0-alpha.33](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.32...v1.0.0-alpha.33) (2022-12-21)\n\n### Bug Fixes\n\n- **theme:** remove experimental fonts ([#1710](https://github.com/vuejs/vitepress/issues/1710)) ([1ebde66](https://github.com/vuejs/vitepress/commit/1ebde6623ef7f279a77b5a2ddc61e50e322481d1))\n\n### Features\n\n- **build:** provide a `pathname://` protocol to escape SPA ([#1719](https://github.com/vuejs/vitepress/issues/1719)) ([ae21a3a](https://github.com/vuejs/vitepress/commit/ae21a3a622844af476f8311b1d7eba7ae3d5af36))\n- **theme:** headings anchor should not be selectable ([#1701](https://github.com/vuejs/vitepress/issues/1701)) ([505a4f8](https://github.com/vuejs/vitepress/commit/505a4f8eee254844be98d224d7f0b943a33959e7))\n\n# [1.0.0-alpha.32](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.31...v1.0.0-alpha.32) (2022-12-16)\n\n### Bug Fixes\n\n- **build:** fix code groups for line numbers mode ([#1700](https://github.com/vuejs/vitepress/issues/1700)) ([135b797](https://github.com/vuejs/vitepress/commit/135b797cfb572659726d9dfbe11ca6045dee9fa3))\n\n### Features\n\n- add code-group feature ([#728](https://github.com/vuejs/vitepress/issues/728)) ([#1560](https://github.com/vuejs/vitepress/issues/1560)) ([a684b67](https://github.com/vuejs/vitepress/commit/a684b67ec084fdc3b3a300ffbdd21e19fdcf7b1e)), closes [#1242](https://github.com/vuejs/vitepress/issues/1242)\n- **build:** support `cacheDir` ([#1355](https://github.com/vuejs/vitepress/issues/1355)) ([f899764](https://github.com/vuejs/vitepress/commit/f899764bad8bfdf4fef91e23901d4af3cda91bcc))\n\n# [1.0.0-alpha.31](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.30...v1.0.0-alpha.31) (2022-12-10)\n\n### Features\n\n- **build:** switch to rollup 3 and vite 4 ([#1591](https://github.com/vuejs/vitepress/issues/1591)) ([ae33896](https://github.com/vuejs/vitepress/commit/ae33896a322b6b4cc944d44398ddba6e60b5d1c7))\n\n### Performance Improvements\n\n- **a11y:** add aria-hidden to line numbers wrapper ([#1675](https://github.com/vuejs/vitepress/issues/1675)) ([4c5a892](https://github.com/vuejs/vitepress/commit/4c5a892d7787440faebf061daaaff908680dcd99))\n\n# [1.0.0-alpha.30](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.29...v1.0.0-alpha.30) (2022-12-05)\n\n### Bug Fixes\n\n- **build:** allow importing files having numbers in extension ([#1618](https://github.com/vuejs/vitepress/issues/1618)) ([0565c38](https://github.com/vuejs/vitepress/commit/0565c38fc172cefb9a068882e215ac09dca6636d))\n- **build:** allow serving files in dev from workspace root ([#1647](https://github.com/vuejs/vitepress/issues/1647)) ([dc59662](https://github.com/vuejs/vitepress/commit/dc596621cf5ad11585597423b0a98266949c932a))\n- **theme:** default to vertical align top on badges inside headings ([#1584](https://github.com/vuejs/vitepress/issues/1584)) ([8a488de](https://github.com/vuejs/vitepress/commit/8a488deac111fbc43b8739c8959b8ae60cbedc80))\n- **theme:** ignore removed diff lines while copying code ([f4d5417](https://github.com/vuejs/vitepress/commit/f4d54179306c0ecbc08e4275081e3e169d304e09))\n- **theme:** move background colors to theme-default style ([#1347](https://github.com/vuejs/vitepress/issues/1347)) ([4f0194f](https://github.com/vuejs/vitepress/commit/4f0194f1dceec8c7aff70c490b5e757aca560e8a))\n\n### Features\n\n- **build:** add preview as an alias for serve in cli ([#1651](https://github.com/vuejs/vitepress/issues/1651)) ([4ba33da](https://github.com/vuejs/vitepress/commit/4ba33dac60b8b091627eb3e9c2347da0aa5efb82))\n\n# [1.0.0-alpha.29](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.28...v1.0.0-alpha.29) (2022-11-15)\n\n### Bug Fixes\n\n- **build:** explicitly specify asset and entry file names ([#1607](https://github.com/vuejs/vitepress/issues/1607)) ([8601e15](https://github.com/vuejs/vitepress/commit/8601e1596b45e6684b71964d002133fb32d51b9f))\n- **theme:** typo in attribute name ([#1597](https://github.com/vuejs/vitepress/issues/1597)) ([cc91d55](https://github.com/vuejs/vitepress/commit/cc91d555b5bfcbde35f2ba33aedcd79a5cef713b))\n\n# [1.0.0-alpha.28](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.27...v1.0.0-alpha.28) (2022-11-08)\n\n### Bug Fixes\n\n- **theme:** use faux italics only with web fonts ([#1581](https://github.com/vuejs/vitepress/issues/1581)) ([124158e](https://github.com/vuejs/vitepress/commit/124158e3a9793fc466b96b51cf7330b8aa3e055b))\n\n### Features\n\n- **theme:** sidebar nav slots ([#1582](https://github.com/vuejs/vitepress/issues/1582)) ([d410d4d](https://github.com/vuejs/vitepress/commit/d410d4dd9f1140b68d140642c1bceaf5419ff304))\n- **theme:** use v-html in VPDocFooter ([#1580](https://github.com/vuejs/vitepress/issues/1580)) ([9d10b1d](https://github.com/vuejs/vitepress/commit/9d10b1d5a1ec8d30689ddad5f2d63d22342cf707))\n\n# [1.0.0-alpha.27](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.26...v1.0.0-alpha.27) (2022-11-03)\n\n### Bug Fixes\n\n- **build:** use addClass from shiki-processor ([#1557](https://github.com/vuejs/vitepress/issues/1557)) ([4b0b1ef](https://github.com/vuejs/vitepress/commit/4b0b1ef35f38461514f3e97e0a509029a70d3086)), closes [#1555](https://github.com/vuejs/vitepress/issues/1555)\n- **build:** use default slugify from mdit-vue ([#1554](https://github.com/vuejs/vitepress/issues/1554)) ([8cd1f7c](https://github.com/vuejs/vitepress/commit/8cd1f7c4aadb7a911158ac628233b3878a60786a))\n- prevent overlay getting hidden behind navbar ([#1547](https://github.com/vuejs/vitepress/issues/1547)) ([87d6c08](https://github.com/vuejs/vitepress/commit/87d6c085d6ccf084d5435216741e3af408c9897a))\n- remove shell code copy trailing newline ([#1561](https://github.com/vuejs/vitepress/issues/1561)) ([f36cd0d](https://github.com/vuejs/vitepress/commit/f36cd0d62625c3221533b9e1f83a58b2cd4429a2))\n- **theme:** use stored preference to be the value of `userPreference` ([#1543](https://github.com/vuejs/vitepress/issues/1543)) ([a7abf73](https://github.com/vuejs/vitepress/commit/a7abf73e432caa6b06b868e7c8c01c6f31b6cc54))\n\n### Features\n\n- **theme:** add built-in global component `Badge` ([#1239](https://github.com/vuejs/vitepress/issues/1239)) ([ac8619f](https://github.com/vuejs/vitepress/commit/ac8619f841862b8629ea0416ba2f188faceebc70))\n- **theme:** add link feature in homepage features ([#984](https://github.com/vuejs/vitepress/issues/984)) ([#1404](https://github.com/vuejs/vitepress/issues/1404)) ([84b4abc](https://github.com/vuejs/vitepress/commit/84b4abc5fa29b353d52162508a31f55a4ea755e5)), closes [#1070](https://github.com/vuejs/vitepress/issues/1070)\n- **theme:** sort multiple sidebars ([#1552](https://github.com/vuejs/vitepress/issues/1552)) ([db1c343](https://github.com/vuejs/vitepress/commit/db1c343dfb7011825b18253b4b8a47b5d8f6f817))\n\n### Reverts\n\n- **#1530:** explicitly exit process after build to prevent hangup ([#1572](https://github.com/vuejs/vitepress/issues/1572)) ([01719fa](https://github.com/vuejs/vitepress/commit/01719fa58e245291e640d5b0bc51cac5a4a3085c)), closes [#1530](https://github.com/vuejs/vitepress/issues/1530)\n\n# [1.0.0-alpha.26](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.25...v1.0.0-alpha.26) (2022-10-27)\n\n### Bug Fixes\n\n- properly apply dark/light classes in code blocks ([#1546](https://github.com/vuejs/vitepress/issues/1546)) ([178895f](https://github.com/vuejs/vitepress/commit/178895f067e0f38e1c76d3efe64a75612cd4ad3a))\n\n# [1.0.0-alpha.25](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.24...v1.0.0-alpha.25) (2022-10-25)\n\n### Bug Fixes\n\n- **banner:** prevent hidden local nav on scroll ([63449ca](https://github.com/vuejs/vitepress/commit/63449caf4cb2c7e8449e4f8aee1d8f504fa949df))\n\n# [1.0.0-alpha.24](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.23...v1.0.0-alpha.24) (2022-10-25)\n\n### Bug Fixes\n\n- **banner:** broken layout on smaller viewports ([#1536](https://github.com/vuejs/vitepress/issues/1536)) ([028cc2c](https://github.com/vuejs/vitepress/commit/028cc2c76e540c595e55a399606701490afd4beb))\n\n# [1.0.0-alpha.23](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.22...v1.0.0-alpha.23) (2022-10-25)\n\n### Bug Fixes\n\n- **build:** explicitly exit process after build to prevent hangup ([#1530](https://github.com/vuejs/vitepress/issues/1530)) ([09fcc46](https://github.com/vuejs/vitepress/commit/09fcc460794d515c48c38ccb47a936d58a2582b3))\n\n### Features\n\n- **build:** add `useWebFonts` option ([#1531](https://github.com/vuejs/vitepress/issues/1531)) ([c9f04e0](https://github.com/vuejs/vitepress/commit/c9f04e045922a6f1e11136bd1ccc824c2e9928f1))\n- support focus, colored diffs, error highlights in code blocks ([#1534](https://github.com/vuejs/vitepress/issues/1534)) ([04ab0eb](https://github.com/vuejs/vitepress/commit/04ab0eb6dcacb065e865332580088891bc2df893))\n- **theme:** add --vp-layout-top-height to adjust banner ([#1521](https://github.com/vuejs/vitepress/issues/1521)) ([a29a4a6](https://github.com/vuejs/vitepress/commit/a29a4a62c682b54ec88c609cb480ddb68b3f4699))\n\n# [1.0.0-alpha.22](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.21...v1.0.0-alpha.22) (2022-10-22)\n\n### Bug Fixes\n\n- **types:** change ComponentOptions to DefineComponent ([#1499](https://github.com/vuejs/vitepress/issues/1499)) ([5711660](https://github.com/vuejs/vitepress/commit/57116607b83f79e62f399cd6430b0d80524861a3))\n\n### Features\n\n- expose isDark ([#1525](https://github.com/vuejs/vitepress/issues/1525)) ([d327811](https://github.com/vuejs/vitepress/commit/d327811fd5b333a73d77730b6b0b347e3d052ebc))\n- **theme:** allow defining dark as the default theme ([#1498](https://github.com/vuejs/vitepress/issues/1498)) ([d404753](https://github.com/vuejs/vitepress/commit/d404753005bf4cc3bb645553ac473d08c6473180))\n- **theme:** support html strings for SidebarGroup headings, SidebarItem text ([#1489](https://github.com/vuejs/vitepress/issues/1489)) ([946c579](https://github.com/vuejs/vitepress/commit/946c579f2b8957839b8e0ef3474bded5ad06de1a))\n- transformPageData hook ([#1492](https://github.com/vuejs/vitepress/issues/1492)) ([afeb06f](https://github.com/vuejs/vitepress/commit/afeb06f17cbd439e3e0151f9571107754fe98b57))\n\n# [1.0.0-alpha.21](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.20...v1.0.0-alpha.21) (2022-10-14)\n\n### Bug Fixes\n\n- **build:** better align server and client side filename sanitization ([3fd20fe](https://github.com/vuejs/vitepress/commit/3fd20fedb81c88c188cff22b4c03ccc2ad416d2c))\n- **theme:** match switch background transition with page transition ([#1479](https://github.com/vuejs/vitepress/issues/1479)) ([962065a](https://github.com/vuejs/vitepress/commit/962065a46ee1ef34eccbffbde9e65d7f174f8ab1))\n- **theme:** prevent body scrolling when sidebar has opened on small screens ([#1391](https://github.com/vuejs/vitepress/issues/1391)) ([3daabdc](https://github.com/vuejs/vitepress/commit/3daabdc480c0cc10a12a83a08a734f8719d092c5))\n\n### Features\n\n- **theme:** allow specifying common alt for logo ([#1451](https://github.com/vuejs/vitepress/issues/1451)) ([55688a8](https://github.com/vuejs/vitepress/commit/55688a87e3baa38d0e0a37a6eba0039484416875))\n\n# [1.0.0-alpha.20](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.19...v1.0.0-alpha.20) (2022-10-12)\n\n### Bug Fixes\n\n- **a11y:** add title to copy code button ([#1437](https://github.com/vuejs/vitepress/issues/1437)) ([f79bb78](https://github.com/vuejs/vitepress/commit/f79bb78bf7f472d9bc376a3ec393f731bfe9e7ce))\n- **router:** don't intercept download links ([#1452](https://github.com/vuejs/vitepress/issues/1452)) ([54cf6ce](https://github.com/vuejs/vitepress/commit/54cf6ce51fcf8ce91c0706332e0b51ddcc2b519d))\n- **theme:** disable transitions on theme toggle ([#1447](https://github.com/vuejs/vitepress/issues/1447)) ([067e1a9](https://github.com/vuejs/vitepress/commit/067e1a97434f88835dbfedcf18e2f98d8bfacad9))\n- **theme:** make text prop of VPHero optional ([#1445](https://github.com/vuejs/vitepress/issues/1445)) ([95e4f2a](https://github.com/vuejs/vitepress/commit/95e4f2acc9614360fbfe37450028d2067e5993b8))\n\n### Reverts\n\n- \"fix(build): remove leading underscore from chunks\" ([#1471](https://github.com/vuejs/vitepress/issues/1471)) ([18f0fb4](https://github.com/vuejs/vitepress/commit/18f0fb4e3989192ba95a397476371a945bf84542))\n\n# [1.0.0-alpha.19](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.18...v1.0.0-alpha.19) (2022-10-02)\n\n### Bug Fixes\n\n- **build:** ignore tsconfig target in dev ([#1428](https://github.com/vuejs/vitepress/issues/1428)) ([a13bc86](https://github.com/vuejs/vitepress/commit/a13bc866d0af911256e0629136f4b48e88c44df1))\n\n# [1.0.0-alpha.18](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.17...v1.0.0-alpha.18) (2022-10-01)\n\n### Bug Fixes\n\n- **theme:** break long words on overflow ([#1405](https://github.com/vuejs/vitepress/issues/1405)) ([2114d13](https://github.com/vuejs/vitepress/commit/2114d1326a9d3b952ca8a150f1c27c89169629cc))\n\n# [1.0.0-alpha.17](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.16...v1.0.0-alpha.17) (2022-09-27)\n\n### Bug Fixes\n\n- **theme:** add cursor for collapsible sidebar title ([#1397](https://github.com/vuejs/vitepress/issues/1397)) ([ed37b9a](https://github.com/vuejs/vitepress/commit/ed37b9a0e04f85f941131ec9e2ca8b145d89a535))\n- **theme:** remove extra space before docsearch key ([#1396](https://github.com/vuejs/vitepress/issues/1396)) ([6cb79bb](https://github.com/vuejs/vitepress/commit/6cb79bbe6a26f2e8dbd4b07b3fb5b6377f06958d))\n\n### Reverts\n\n- [#1064](https://github.com/vuejs/vitepress/issues/1064) ([9d70ca5](https://github.com/vuejs/vitepress/commit/9d70ca56f147a2ec30d12b03353ea7e4b0850df0))\n\n# [1.0.0-alpha.16](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.15...v1.0.0-alpha.16) (2022-09-24)\n\n### Bug Fixes\n\n- **build:** line numbers mode when language specifier has symbol ([#1353](https://github.com/vuejs/vitepress/issues/1353)) ([9c04a10](https://github.com/vuejs/vitepress/commit/9c04a10c4d9fbfc591dc2386b4780a6728f6364a))\n- **build:** remove leading underscore from chunks ([#1394](https://github.com/vuejs/vitepress/issues/1394)) ([66cd164](https://github.com/vuejs/vitepress/commit/66cd1640d16170e0c2d9eb4565ad1ebe81f940e1))\n- **compat:** use default export of dns module ([#1388](https://github.com/vuejs/vitepress/issues/1388)) ([fa6fa56](https://github.com/vuejs/vitepress/commit/fa6fa56af9de78856017f935922e4f2f9376be62))\n- **theme:** always add alt attribute to images ([#1348](https://github.com/vuejs/vitepress/issues/1348)) ([a621c69](https://github.com/vuejs/vitepress/commit/a621c6910c0083adc26dd4b7aaa7d532544cc7fa))\n\n### Features\n\n- **build:** allow using `transformIndexHtml` ([#1380](https://github.com/vuejs/vitepress/issues/1380)) ([ce8d139](https://github.com/vuejs/vitepress/commit/ce8d139a8e70e4d0a8d06711c50119990b041078))\n\n# [1.0.0-alpha.15](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.14...v1.0.0-alpha.15) (2022-09-15)\n\n### Bug Fixes\n\n- **build:** properly resolve node_modules ([#1337](https://github.com/vuejs/vitepress/issues/1337)) ([0672a69](https://github.com/vuejs/vitepress/commit/0672a696a427731851e1ed79fe689c4a2a46fedf))\n- **theme:** hide extra navbar when no content ([#1338](https://github.com/vuejs/vitepress/issues/1338)) ([4482c50](https://github.com/vuejs/vitepress/commit/4482c5019d89129791fe066f011648500d105f41))\n- **theme:** remove trailing `#` from outline ([#1344](https://github.com/vuejs/vitepress/issues/1344)) ([f1cf1e8](https://github.com/vuejs/vitepress/commit/f1cf1e800f0e99fe726bdfa7767180473faaf2c2))\n\n# [1.0.0-alpha.14](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.13...v1.0.0-alpha.14) (2022-09-14)\n\n### Bug Fixes\n\n- prevent jumping on clicking docsearch action buttons ([#1140](https://github.com/vuejs/vitepress/issues/1140)) ([86413e6](https://github.com/vuejs/vitepress/commit/86413e6739a834f8490c2004a62a27d1f5a59d00))\n- **theme:** break long words ([#1064](https://github.com/vuejs/vitepress/issues/1064)) ([9c739fd](https://github.com/vuejs/vitepress/commit/9c739fd37d15bbf16e8214e20a4bca1c763c4510))\n- **theme:** don't nest sidebar links ([#1279](https://github.com/vuejs/vitepress/issues/1279)) ([f840dbc](https://github.com/vuejs/vitepress/commit/f840dbc58f972492ed4afa9b6b222c4f7d89ade1))\n- **theme:** keep display copied hint when click multiple times ([#1262](https://github.com/vuejs/vitepress/issues/1262)) ([bb11d0f](https://github.com/vuejs/vitepress/commit/bb11d0f17852a3f2a35339f765acffca526a9ee8))\n- **theme:** show progress bar after delay ([#1278](https://github.com/vuejs/vitepress/issues/1278)) ([496bd34](https://github.com/vuejs/vitepress/commit/496bd34ff4143dcef9532f4298ca670bfa34e399))\n- **theme:** use pointer cursor only on enabled buttons ([#1300](https://github.com/vuejs/vitepress/issues/1300)) ([d7eac98](https://github.com/vuejs/vitepress/commit/d7eac980e15510de18dbf1fd675a6c1def5f6697))\n- **theme:** use pointer-events auto instead of all ([#1290](https://github.com/vuejs/vitepress/issues/1290)) ([6fac5b2](https://github.com/vuejs/vitepress/commit/6fac5b2964e77462edc963811ee1714e337fa53e))\n- **types:** allow non async `transformHtml` and `buildEnd` ([#1270](https://github.com/vuejs/vitepress/issues/1270)) ([ee37eaa](https://github.com/vuejs/vitepress/commit/ee37eaa27191faad03c04d60fb3ca8ffbb887fbe))\n\n### Features\n\n- add `transformHead` hook ([#1323](https://github.com/vuejs/vitepress/issues/1323)) ([6b16dad](https://github.com/vuejs/vitepress/commit/6b16dad22f944cb173dbf67ef04be5cb0d09279f))\n- add `vp-raw` container ([#1104](https://github.com/vuejs/vitepress/issues/1104)) ([9a6e1ea](https://github.com/vuejs/vitepress/commit/9a6e1ea401c4a44205f96c4786c44061582f675c))\n- bundle type definitions of dev-deps ([#1257](https://github.com/vuejs/vitepress/issues/1257)) ([12591a9](https://github.com/vuejs/vitepress/commit/12591a9487ff7647162051f4b28956f0c1403efb))\n- **theme:** add page load progress bar ([#1264](https://github.com/vuejs/vitepress/issues/1264)) ([ecf5515](https://github.com/vuejs/vitepress/commit/ecf5515bd453eca20946339a56be9180f6dca2c1))\n- **theme:** allow disabling whole layout ([#1268](https://github.com/vuejs/vitepress/issues/1268)) ([8f63033](https://github.com/vuejs/vitepress/commit/8f630339ba95cbaded97f0fcff9323755dd16bcc))\n- **theme:** support dynamic headers and nesting in outline ([#1281](https://github.com/vuejs/vitepress/issues/1281)) ([288aa48](https://github.com/vuejs/vitepress/commit/288aa48b92bc1d4dd74d064148a3b03373cdf1c3))\n\n### Performance Improvements\n\n- **a11y:** add aria-checked attribute to switch ([#644](https://github.com/vuejs/vitepress/issues/644)) ([eb9026d](https://github.com/vuejs/vitepress/commit/eb9026d83ca17c59893e7063e0c64b0bf1b99765))\n- render pages asynchronously ([#1320](https://github.com/vuejs/vitepress/issues/1320)) ([8e4ff4d](https://github.com/vuejs/vitepress/commit/8e4ff4de901d846ac99d37ebf212b12e9687ed5e))\n\n### Reverts\n\n- **#1264:** add page load progress bar ([#1311](https://github.com/vuejs/vitepress/issues/1311)) ([5378a49](https://github.com/vuejs/vitepress/commit/5378a49613ceef591d2cacecbc175921658b22b1)), closes [#1264](https://github.com/vuejs/vitepress/issues/1264)\n\n# [1.0.0-alpha.13](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.12...v1.0.0-alpha.13) (2022-08-30)\n\n### Features\n\n- use global delegation for copy code interaction ([b5bd73f](https://github.com/vuejs/vitepress/commit/b5bd73f6300e458d419d3a7816272d3c7244a4d3))\n\n# [1.0.0-alpha.12](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.11...v1.0.0-alpha.12) (2022-08-26)\n\n# [1.0.0-alpha.11](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.10...v1.0.0-alpha.11) (2022-08-26)\n\n### Features\n\n- support markdown sfc options ([#1238](https://github.com/vuejs/vitepress/issues/1238)) ([d700a66](https://github.com/vuejs/vitepress/commit/d700a66e65c9c457e44c9272362be36a2002eaf7))\n\n# [1.0.0-alpha.10](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.9...v1.0.0-alpha.10) (2022-08-22)\n\n### Bug Fixes\n\n- avoid circular deps when extending default theme + importing feature components ([5fb7948](https://github.com/vuejs/vitepress/commit/5fb794864b20c59729686aa7e19f0e5659c6534f)), closes [#1210](https://github.com/vuejs/vitepress/issues/1210)\n\n### Features\n\n- **build:** support markdown frontmatter options ([#1218](https://github.com/vuejs/vitepress/issues/1218)) ([bfb0220](https://github.com/vuejs/vitepress/commit/bfb02209896075483b7c9a8c1ca3d36de0a0b731))\n\n# [1.0.0-alpha.9](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.8...v1.0.0-alpha.9) (2022-08-20)\n\n### Bug Fixes\n\n- **theme:** fix typo in carbon ads components ([#1192](https://github.com/vuejs/vitepress/issues/1192)) ([e0932ce](https://github.com/vuejs/vitepress/commit/e0932ce5f49535fb28c6b6e4d17b888dd09187dc))\n- **theme:** show footer message/copyright only if present ([#1191](https://github.com/vuejs/vitepress/issues/1191)) ([da2f8d2](https://github.com/vuejs/vitepress/commit/da2f8d28a6993b099a97b01ab2ff94104e84190c))\n- **theme:** show outline even without sidebar ([#1189](https://github.com/vuejs/vitepress/issues/1189)) ([3714ea3](https://github.com/vuejs/vitepress/commit/3714ea34635e69aa96de3da5f3cbc5b6198fdbc2))\n- **types:** explicitly re-export to resolve ambiguities ([#1193](https://github.com/vuejs/vitepress/issues/1193)) ([eacc18c](https://github.com/vuejs/vitepress/commit/eacc18c993cefa2922c13826c1d0498a9eafc4d1))\n- use junctions in Windows ([#1217](https://github.com/vuejs/vitepress/issues/1217)) ([0e14211](https://github.com/vuejs/vitepress/commit/0e14211b609c4694c7654ce381998ce751230480))\n\n### Features\n\n- **theme:** extend titleTemplate by replacing the title ([#1200](https://github.com/vuejs/vitepress/issues/1200)) ([c7def73](https://github.com/vuejs/vitepress/commit/c7def730c3d9266e7573b91e16e00dd2f3f3350b))\n\n# [1.0.0-alpha.8](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.7...v1.0.0-alpha.8) (2022-08-17)\n\n### Bug Fixes\n\n- fix client build entry ([04c4d0f](https://github.com/vuejs/vitepress/commit/04c4d0f01b6cb67fe842d9a88f8810f6959eb3ca))\n\n# [1.0.0-alpha.7](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.6...v1.0.0-alpha.7) (2022-08-17)\n\n### Bug Fixes\n\n- fix static data file support in vite 3 ([19ec22c](https://github.com/vuejs/vitepress/commit/19ec22cb4055e903b28ee70d606163b49009ef59))\n\n# [1.0.0-alpha.6](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.5...v1.0.0-alpha.6) (2022-08-17)\n\n### Breaking Changes\n\n- `/@theme` import alias has been removed. Use `@theme` instead.\n\n### Bug Fixes\n\n- **theme:** remove extra padding in code blocks with line numbers ([f6d6c62](https://github.com/vuejs/vitepress/commit/f6d6c6211708d54fb60b89583fe1665aedd9c22f))\n- **theme:** restore styles for code blocks ([#1170](https://github.com/vuejs/vitepress/issues/1170)) ([2c89afb](https://github.com/vuejs/vitepress/commit/2c89afb7ddfeb04f947f95f9ecf636a384492ba8))\n- **theme:** set pointer events all on VPNavScreen ([#1182](https://github.com/vuejs/vitepress/issues/1182)) ([b36656a](https://github.com/vuejs/vitepress/commit/b36656a925b30ce5c85a78d6ae3b686917895822))\n\n### Features\n\n- **build:** switch to vite 3, support clean urls and esm mode ([#856](https://github.com/vuejs/vitepress/issues/856)) ([0048e2b](https://github.com/vuejs/vitepress/commit/0048e2bf1e7ef0bf0a4b66bcdd49f9dc84074b2d))\n\n# [1.0.0-alpha.5](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.4...v1.0.0-alpha.5) (2022-08-16)\n\n### Bug Fixes\n\n- **build:** cache key should consider file path ([#948](https://github.com/vuejs/vitepress/issues/948)) ([1daeaa1](https://github.com/vuejs/vitepress/commit/1daeaa16a038cfa927a24bb970ad62c524aed6cf))\n- **build:** handle vite constants replacement ([#419](https://github.com/vuejs/vitepress/issues/419)) ([#888](https://github.com/vuejs/vitepress/issues/888)) ([9d9db62](https://github.com/vuejs/vitepress/commit/9d9db6227dff40734bf7129abb69f26412424486))\n- **build:** recreate server on config change ([#1132](https://github.com/vuejs/vitepress/issues/1132)) ([93fe820](https://github.com/vuejs/vitepress/commit/93fe8207e7993d62a167af752a8da3c30388f642))\n- **build:** show workaround on encountering dead links ([#822](https://github.com/vuejs/vitepress/issues/822)) ([#868](https://github.com/vuejs/vitepress/issues/868)) ([29d44e7](https://github.com/vuejs/vitepress/commit/29d44e7a2201d43227758745e1e3a14858224736))\n- **build:** strip custom anchor with capital letters in outline ([#1005](https://github.com/vuejs/vitepress/issues/1005)) ([f6d5697](https://github.com/vuejs/vitepress/commit/f6d5697ed7f247e8673614f4e0ff7232e808ef1e))\n- **build:** update language regex for line number class ([#1108](https://github.com/vuejs/vitepress/issues/1108)) ([708c361](https://github.com/vuejs/vitepress/commit/708c36183a925e06c13b9b04ed03af073c315978))\n- can't detect that the page has scrolled to the bottom ([#956](https://github.com/vuejs/vitepress/issues/956)) ([#970](https://github.com/vuejs/vitepress/issues/970)) ([98e45af](https://github.com/vuejs/vitepress/commit/98e45af127a11bfff3577fe5675788e5479f9d79))\n- de-duplicate head tags while merging ([#975](https://github.com/vuejs/vitepress/issues/975)) ([#976](https://github.com/vuejs/vitepress/issues/976)) ([f7e9cfe](https://github.com/vuejs/vitepress/commit/f7e9cfeb3a06ec93726870dd17116a019959d980))\n- decode href before using as query selector ([#951](https://github.com/vuejs/vitepress/issues/951)) ([22006e8](https://github.com/vuejs/vitepress/commit/22006e8d6e3ed45841979d684eb6a4ef999bd707))\n- decode image src so that rollup can process it ([#933](https://github.com/vuejs/vitepress/issues/933)) ([bb41a9f](https://github.com/vuejs/vitepress/commit/bb41a9fed771a5bdfc73b1bbe5200d11c3630367))\n- don't add base to external urls while preloading ([#1045](https://github.com/vuejs/vitepress/issues/1045)) ([7295033](https://github.com/vuejs/vitepress/commit/72950337bc31fd2f8879d6a2f219018a18b29727))\n- don't change url hash while scrolling ([#991](https://github.com/vuejs/vitepress/issues/991)) ([0826944](https://github.com/vuejs/vitepress/commit/082694470a15e50c5d000936572856a574409ea5))\n- layout inconsistencies and remove sidebar from 404 page ([#964](https://github.com/vuejs/vitepress/issues/964)) ([0257ea8](https://github.com/vuejs/vitepress/commit/0257ea88dca09ced9c1dc6e53ba5f133c468df19))\n- line highlighting in custom code block ([#959](https://github.com/vuejs/vitepress/issues/959)) ([#969](https://github.com/vuejs/vitepress/issues/969)) ([7a9e4d9](https://github.com/vuejs/vitepress/commit/7a9e4d9ee02cc677f1b84cc5f2c1f8f385c3a65c))\n- normalize link in VPButton ([#919](https://github.com/vuejs/vitepress/issues/919)) ([bed68f1](https://github.com/vuejs/vitepress/commit/bed68f134186e4fd3c0bca4c6a5871a79e4cd224))\n- only check for duplicate meta tags ([#977](https://github.com/vuejs/vitepress/issues/977)) ([1ef7a18](https://github.com/vuejs/vitepress/commit/1ef7a1857c2a8e2abc7c1859cd54504c144eab3b)), closes [/github.com/vuejs/vitepress/issues/975#issuecomment-1183507200](https://github.com//github.com/vuejs/vitepress/issues/975/issues/issuecomment-1183507200)\n- regression caused by [#887](https://github.com/vuejs/vitepress/issues/887) ([30249dc](https://github.com/vuejs/vitepress/commit/30249dc2c3d933dadf6e22e64728a6ffd3647f8e))\n- remove duplicate router logic ([#1087](https://github.com/vuejs/vitepress/issues/1087)) ([63584c2](https://github.com/vuejs/vitepress/commit/63584c2812d2c5172356ef2615ac608684d52681))\n- remove explicit noopener from external links ([#871](https://github.com/vuejs/vitepress/issues/871)) ([e4c60ab](https://github.com/vuejs/vitepress/commit/e4c60ab3c834fe7f730cd7b0d64dd23c6d04dbed))\n- support urls with query during dev ([35b7361](https://github.com/vuejs/vitepress/commit/35b7361ca2c689f0fb464ab9cbab8bb02e4884d5))\n- **theme:** change sponsor link class name to bypass adblock ([#866](https://github.com/vuejs/vitepress/issues/866)) ([#867](https://github.com/vuejs/vitepress/issues/867)) ([e33955e](https://github.com/vuejs/vitepress/commit/e33955e7696af2de2d9ed53d53a06aa5de17f3ce))\n- **theme:** close menu on route change ([#887](https://github.com/vuejs/vitepress/issues/887)) ([fcd7642](https://github.com/vuejs/vitepress/commit/fcd7642924331e81e85ee75a1224a04d1882531c))\n- **theme:** don't let navbar obstruct clicks to top part of scrollbar ([#1168](https://github.com/vuejs/vitepress/issues/1168)) ([44953dc](https://github.com/vuejs/vitepress/commit/44953dcd1e0224bae95666c87e368b9d3fdf17ae))\n- **theme:** fix custom NotFound component rendering ([#1163](https://github.com/vuejs/vitepress/issues/1163)) ([4a6eda4](https://github.com/vuejs/vitepress/commit/4a6eda48704ad34e003d144594bbc56c1b448c6d))\n- **theme:** hide doc footer if empty ([#1126](https://github.com/vuejs/vitepress/issues/1126)) ([70da5f2](https://github.com/vuejs/vitepress/commit/70da5f275bc44ce4e6ed97af40cf30d6971ee378))\n- **theme:** make last updated time reactive ([#879](https://github.com/vuejs/vitepress/issues/879)) ([25a835f](https://github.com/vuejs/vitepress/commit/25a835f0f437a2181f67dbcefa17546dbcb833de))\n- **theme:** navbar menu may exceed the screen ([#988](https://github.com/vuejs/vitepress/issues/988)) ([#989](https://github.com/vuejs/vitepress/issues/989)) ([8a46413](https://github.com/vuejs/vitepress/commit/8a46413d6fa6ff671f780b60c7bc6380d84dc25d))\n- **theme:** prevent docsearch button key from changing ([#986](https://github.com/vuejs/vitepress/issues/986)) ([d65667b](https://github.com/vuejs/vitepress/commit/d65667b8d49a11fccee6bc0cd06a75333a65f22c))\n- **theme:** tweak styles of nav title ([#962](https://github.com/vuejs/vitepress/issues/962)) ([#968](https://github.com/vuejs/vitepress/issues/968)) ([d91f3b1](https://github.com/vuejs/vitepress/commit/d91f3b1b7d46db8009bb459079794b0626488033))\n- **theme:** typo in color name ([#1020](https://github.com/vuejs/vitepress/issues/1020)) ([4b38736](https://github.com/vuejs/vitepress/commit/4b38736adf2853276f573a1980a213a17cf2c740))\n- treat all URI schemes as external ([#945](https://github.com/vuejs/vitepress/issues/945)) ([#946](https://github.com/vuejs/vitepress/issues/946)) ([1e9a7ac](https://github.com/vuejs/vitepress/commit/1e9a7ac6c478c57d7336e2d7b0392f23659080d3))\n- **types:** add client and theme to `exports` field ([#914](https://github.com/vuejs/vitepress/issues/914)) ([1cc087d](https://github.com/vuejs/vitepress/commit/1cc087deeee5f6c8289259bb7a2695ed75f287c3))\n- **types:** fix broken syntax in `theme.d.ts` ([#1101](https://github.com/vuejs/vitepress/issues/1101)) ([70b3060](https://github.com/vuejs/vitepress/commit/70b3060be963ed7a0d2041446d67ac970d6f35e3))\n- use `router.go` if search string is not same ([#1109](https://github.com/vuejs/vitepress/issues/1109)) ([5597165](https://github.com/vuejs/vitepress/commit/55971659a5c4b25cb07968ca4e162abc11fe2e80))\n\n### Features\n\n- allow adding custom social icons as inline svg ([#738](https://github.com/vuejs/vitepress/issues/738)) ([#953](https://github.com/vuejs/vitepress/issues/953)) ([74e4950](https://github.com/vuejs/vitepress/commit/74e4950c1b83f2e0c8659477c7b2763fa150b349))\n- allow html in footer ([#1034](https://github.com/vuejs/vitepress/issues/1034)) ([ad9af83](https://github.com/vuejs/vitepress/commit/ad9af83278d702a76f674f847b383370b3921256))\n- allow using custom syntax highlighting themes ([#992](https://github.com/vuejs/vitepress/issues/992)) ([d5ed66c](https://github.com/vuejs/vitepress/commit/d5ed66c6d21ec3b5e17469771057132c53220bea))\n- **build:** allow ignoring dead links ([#586](https://github.com/vuejs/vitepress/issues/586)) ([#793](https://github.com/vuejs/vitepress/issues/793)) ([19b0758](https://github.com/vuejs/vitepress/commit/19b0758a04e9fb7863b3a961024dfe1137fbe928))\n- **build:** allow using custom highlighter ([#754](https://github.com/vuejs/vitepress/issues/754)) ([#857](https://github.com/vuejs/vitepress/issues/857)) ([ddf876d](https://github.com/vuejs/vitepress/commit/ddf876d8e90e812a198bb417a5dc60cd443a8273))\n- **build:** handle change of config file dependencies ([#1009](https://github.com/vuejs/vitepress/issues/1009)) ([8e6665b](https://github.com/vuejs/vitepress/commit/8e6665bd8de66a8249fca92fbb1b9a4f6d76a041))\n- **build:** improve code blocks and snippets ([#875](https://github.com/vuejs/vitepress/issues/875)) ([f789932](https://github.com/vuejs/vitepress/commit/f789932ffc79723a90b3b19a59d6f277d9edaaa9)), closes [#861](https://github.com/vuejs/vitepress/issues/861) [#471](https://github.com/vuejs/vitepress/issues/471) [#884](https://github.com/vuejs/vitepress/issues/884)\n- **build:** support code highlight in uppercase ([#1082](https://github.com/vuejs/vitepress/issues/1082)) ([867f305](https://github.com/vuejs/vitepress/commit/867f30588687c4f9228c1511bee672074e54c802)), closes [#772](https://github.com/vuejs/vitepress/issues/772)\n- provide `transformHtml` hook ([#1022](https://github.com/vuejs/vitepress/issues/1022)) ([2b4b800](https://github.com/vuejs/vitepress/commit/2b4b80061818f1c471aafb23c0572172ef842138))\n- provide build end hook ([#709](https://github.com/vuejs/vitepress/issues/709)) ([e0b730a](https://github.com/vuejs/vitepress/commit/e0b730aa8ee9bec1fe16245c4c1a1a91f62bed42))\n- **theme:** add `doc-footer-before` slot ([#1050](https://github.com/vuejs/vitepress/issues/1050)) ([#1052](https://github.com/vuejs/vitepress/issues/1052)) ([60c515c](https://github.com/vuejs/vitepress/commit/60c515c1255085d73845d2b2cc315823ee18e7b8))\n- **theme:** add navigation slots ([#739](https://github.com/vuejs/vitepress/issues/739)) ([#741](https://github.com/vuejs/vitepress/issues/741)) ([0f0453c](https://github.com/vuejs/vitepress/commit/0f0453c6750c5af9c1ae65abb994813eecf9af27))\n- **theme:** add option to customize search button text ([#713](https://github.com/vuejs/vitepress/issues/713)) ([#747](https://github.com/vuejs/vitepress/issues/747)) ([00fe809](https://github.com/vuejs/vitepress/commit/00fe8092d9e097d2dd24c06787fcb740310bdda7))\n- **theme:** auto open collapsed sidebar on entering ([#1094](https://github.com/vuejs/vitepress/issues/1094)) ([f4f1a6c](https://github.com/vuejs/vitepress/commit/f4f1a6ccd62ea52c03b2c342c649f0f06f466126))\n- **theme:** custom prev/next labels and text ([#897](https://github.com/vuejs/vitepress/issues/897)) ([836a246](https://github.com/vuejs/vitepress/commit/836a24683a19eefbc98d6c448c26e3696a679e7c))\n- **theme:** support hiding aside component from frontmatter ([#980](https://github.com/vuejs/vitepress/issues/980)) ([69ef299](https://github.com/vuejs/vitepress/commit/69ef2998c37453ab9c0147e87dd9a6efb41a24a3))\n- **theme:** support multi-level sidebar ([#851](https://github.com/vuejs/vitepress/issues/851)) ([d1a2c76](https://github.com/vuejs/vitepress/commit/d1a2c76f33ab55ad8d43357b57c9ae3de55e9d0c))\n\n### Performance Improvements\n\n- **a11y:** change copy code span to button ([#1056](https://github.com/vuejs/vitepress/issues/1056)) ([fb9cee9](https://github.com/vuejs/vitepress/commit/fb9cee95b95bf5989599deb1c4fbb1a448d67952))\n\n### Reverts\n\n- vuejs/vitepress[#889](https://github.com/vuejs/vitepress/issues/889) ([#896](https://github.com/vuejs/vitepress/issues/896)) ([e1339fd](https://github.com/vuejs/vitepress/commit/e1339fdc4fc9736fc31d69393ca4289a1f245013))\n\n## [1.0.0-alpha.4](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.3...v1.0.0-alpha.4) (2022-06-22)\n\n### Bug Fixes\n\n- **theme:** home image style is broken in big view port ([2bd960d](https://github.com/vuejs/vitepress/commit/2bd960d5f5a84df614035a4fb941331fdf9d84f2))\n\n## [1.0.0-alpha.3](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.2...v1.0.0-alpha.3) (2022-06-22)\n\n### Bug Fixes\n\n- **theme:** italic fonts are missing ([#759](https://github.com/vuejs/vitepress/issues/759)) ([#777](https://github.com/vuejs/vitepress/issues/777)) ([fa00c83](https://github.com/vuejs/vitepress/commit/fa00c83af4aa5fa619cf2e3da8d5aab77984ba7c))\n- **theme:** copy code in non-secure contexts ([#792](https://github.com/vuejs/vitepress/issues/792)) ([2935ed2](https://github.com/vuejs/vitepress/commit/2935ed22954010fa0d48d0625e5f2b0136991e0b))\n- **theme:** copy code button has wrong tag closing syntax ([#816](https://github.com/vuejs/vitepress/issues/816)) ([75ca9e4](https://github.com/vuejs/vitepress/commit/75ca9e4302c65e3bcc9518f7df928318380f6cf6))\n- **theme:** edit link gets hidden when a page don't have siblings ([#751](https://github.com/vuejs/vitepress/issues/751)) ([9bc4330](https://github.com/vuejs/vitepress/commit/9bc43306a1fe7bfd54b738642fd1737917a3af41))\n- **theme:** nav close icon not working correctly ([#744](https://github.com/vuejs/vitepress/issues/744)) ([75c9d80](https://github.com/vuejs/vitepress/commit/75c9d809d21c0484c0ae8ce691d598cf229c9525))\n- **theme:** sidebar is shown on home layout ([#825](https://github.com/vuejs/vitepress/issues/825)) ([#829](https://github.com/vuejs/vitepress/issues/829)) ([42cbd31](https://github.com/vuejs/vitepress/commit/42cbd31327b789ff9525919afb39b3092f1d445b))\n- **theme:** sidebar collapsed option not working on layout change ([#809](https://github.com/vuejs/vitepress/issues/809)) ([#811](https://github.com/vuejs/vitepress/issues/811)) ([7737699](https://github.com/vuejs/vitepress/commit/773769926b74cabfbb3577d6c6e654fe976c0b76))\n- **theme:** `DefaultTheme` type causes error in some cases ([#804](https://github.com/vuejs/vitepress/issues/804)) ([107724a](https://github.com/vuejs/vitepress/commit/107724ac6f24e5272964d3bdbff54169fa4d91ae))\n\n### Features\n\n- **build:** allow setting `base` from command line ([2952638](https://github.com/vuejs/vitepress/commit/295263807df5a0cdff3b04d5131a3cebc76ec491))\n- **theme:** add active status to nav menu group ([#820](https://github.com/vuejs/vitepress/issues/820)) ([fdb5720](https://github.com/vuejs/vitepress/commit/fdb5720acda9f8f2dd1e4f33d0810a6e9ca9e7de))\n- **theme:** add global layout slots ([#760](https://github.com/vuejs/vitepress/issues/760)) ([#812](https://github.com/vuejs/vitepress/issues/812)) ([1f1e298](https://github.com/vuejs/vitepress/commit/1f1e298864f7b8af9672b55251958ba766678e0b))\n- **theme:** support themeable images for logo and hero ([#745](https://github.com/vuejs/vitepress/issues/745)) ([42813ce](https://github.com/vuejs/vitepress/commit/42813ce936d9fb141241969651cb0e3a02345442))\n- **theme:** add team page feature ([#828](https://github.com/vuejs/vitepress/issues/828)) ([7cfe0f0](https://github.com/vuejs/vitepress/commit/7cfe0f05ab013904c66c48d8529d2ba4747869cb))\n\n## [1.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2022-06-14)\n\n### Bug Fixes\n\n- use h1 for title in hero instead of p ([#776](https://github.com/vuejs/vitepress/issues/776)) ([919d230](https://github.com/vuejs/vitepress/commit/919d23079b636c188ea2049039461b88e0c02fc2))\n- add background color in navbar to avoid contrast issues ([#695](https://github.com/vuejs/vitepress/issues/695)) ([305bcc0](https://github.com/vuejs/vitepress/commit/305bcc02e68f8f9aea0000e6950e78455cf572f5))\n- add default value for base in `createMarkdownRenderer` ([#555](https://github.com/vuejs/vitepress/issues/555)) ([#556](https://github.com/vuejs/vitepress/issues/556)) ([78a2e84](https://github.com/vuejs/vitepress/commit/78a2e84e7bb7acfda50e686bbd404961babb91e8))\n- allow lang='ts' on scripts in markdown ([#693](https://github.com/vuejs/vitepress/issues/693)) ([#701](https://github.com/vuejs/vitepress/issues/701)) ([59df105](https://github.com/vuejs/vitepress/commit/59df10590b958bbc39cc2e8c81a2209eda9d431b))\n- better nav item types ([#714](https://github.com/vuejs/vitepress/issues/714)) ([263607b](https://github.com/vuejs/vitepress/commit/263607b279cbfd3db80bbe0ea66000560d24993a))\n- double base in sidebar links ([#756](https://github.com/vuejs/vitepress/issues/756)) ([aa65cb5](https://github.com/vuejs/vitepress/commit/aa65cb58f508bb8e79c20b6370bdfe1b7e470abf))\n- use `pre-wrap` for text and tagline ([#746](https://github.com/vuejs/vitepress/issues/746)) ([94704c9](https://github.com/vuejs/vitepress/commit/94704c95637f1cc844d526d4743818d38d1cbae0))\n- nav nested items type error ([#710](https://github.com/vuejs/vitepress/issues/710)) ([#711](https://github.com/vuejs/vitepress/issues/711)) ([e5bf15a](https://github.com/vuejs/vitepress/commit/e5bf15a21ee777b4e56ad86ec5ebb5b0e161b721))\n- page layout breaks when page name matches the css class name ([#696](https://github.com/vuejs/vitepress/issues/696)) ([#699](https://github.com/vuejs/vitepress/issues/699)) ([9c0ed93](https://github.com/vuejs/vitepress/commit/9c0ed9397f35827a261d45c789d23ce7faa7ecee))\n- remove title bg transition to avoid flush on sidebar on/off ([1942418](https://github.com/vuejs/vitepress/commit/1942418f9570feb81d8066a2413d70b0f36fb8ce))\n- sidebar right blur notch ([#712](https://github.com/vuejs/vitepress/issues/712)) ([64c3654](https://github.com/vuejs/vitepress/commit/64c3654b4ba82c16fefdf396106f3077d066c67b))\n- typo ([#708](https://github.com/vuejs/vitepress/issues/708)) ([#716](https://github.com/vuejs/vitepress/issues/716)) ([1fe5153](https://github.com/vuejs/vitepress/commit/1fe5153f47465efed05e087119c93d50da6e92a3))\n- title in containers not working with markdown content ([#765](https://github.com/vuejs/vitepress/issues/765)) ([#768](https://github.com/vuejs/vitepress/issues/768)) ([c5c3c64](https://github.com/vuejs/vitepress/commit/c5c3c64851b240279a304198fd97e3dc8b5f2fd0))\n- use base in links ([#717](https://github.com/vuejs/vitepress/issues/717)) ([#718](https://github.com/vuejs/vitepress/issues/718)) ([8e50154](https://github.com/vuejs/vitepress/commit/8e5015462c8f42c5404525ac8de33af8862c204d))\n- use h2 for feature headers ([#774](https://github.com/vuejs/vitepress/issues/774)) ([b1ff725](https://github.com/vuejs/vitepress/commit/b1ff72561182c91b4912ebef44204a53ee3aca5e))\n\n### Features\n\n- add `lastUpdated` option to frontmatter ([b31fbf3](https://github.com/vuejs/vitepress/commit/b31fbf3621bbd7f627a1b80c581b7a8444bc6b0d))\n- add doc before and after slot ([#762](https://github.com/vuejs/vitepress/issues/762)) ([#786](https://github.com/vuejs/vitepress/issues/786)) ([9c2a36f](https://github.com/vuejs/vitepress/commit/9c2a36f5428bd98eafb6e2e9bc63f5e532b596b7))\n- allow custom edit links ([#698](https://github.com/vuejs/vitepress/issues/698)) ([535e176](https://github.com/vuejs/vitepress/commit/535e176b9a230f692f58a79813a12d2ffbe90be3)), closes [#694](https://github.com/vuejs/vitepress/issues/694) [#697](https://github.com/vuejs/vitepress/issues/697)\n- allow custom outline title ([#689](https://github.com/vuejs/vitepress/issues/689)) ([#690](https://github.com/vuejs/vitepress/issues/690)) ([a8a1623](https://github.com/vuejs/vitepress/commit/a8a16237cd8e3e4bb180fbd523a4668a4555b732))\n- allow external links in sidebar ([#205](https://github.com/vuejs/vitepress/issues/205)) ([#686](https://github.com/vuejs/vitepress/issues/686)) ([ce17f50](https://github.com/vuejs/vitepress/commit/ce17f5035cbbd1e07373ce0f44913f25269bd80b))\n- support custom content in home layout ([#702](https://github.com/vuejs/vitepress/issues/702)) ([92659a2](https://github.com/vuejs/vitepress/commit/92659a2e9dde13e35fadf2d2dca157d648bc9013))\n- emit 404.html on build ([#729](https://github.com/vuejs/vitepress/issues/729)) ([#740](https://github.com/vuejs/vitepress/issues/740)) ([23276ba](https://github.com/vuejs/vitepress/commit/23276bae050190b6c1d57347424360fe2c3a57be))\n- setup devtools and remove debug component ([#721](https://github.com/vuejs/vitepress/issues/721)) ([421f641](https://github.com/vuejs/vitepress/commit/421f641a76ddc0e8b0f23ab7ad711833fc98c245))\n\n## [1.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v0.22.4...v1.0.0-alpha.1) (2022-06-01)\n\nComplete rewrite on default theme, with bunch of features added. Please refer to the docs for the new feature and changes.\n\n## [0.22.4](https://github.com/vuejs/vitepress/compare/v0.22.3...v0.22.4) (2022-05-06)\n\n### Bug Fixes\n\n- **plugin:** set content-type header for serving index.html ([#616](https://github.com/vuejs/vitepress/issues/616)) ([1656f03](https://github.com/vuejs/vitepress/commit/1656f0365ae7aa07b008d4e367e5b1b382118897))\n- remove 404 from title on initial route ([#590](https://github.com/vuejs/vitepress/issues/590)) ([216e129](https://github.com/vuejs/vitepress/commit/216e12950b312f9f5b8af74cac0ce243693e37ee)), closes [#589](https://github.com/vuejs/vitepress/issues/589)\n\n## [0.22.3](https://github.com/vuejs/vitepress/compare/v0.22.2...v0.22.3) (2022-02-22)\n\n### Bug Fixes\n\n- append base to links ([#502](https://github.com/vuejs/vitepress/issues/502)) ([804954c](https://github.com/vuejs/vitepress/commit/804954cf4d5417b1abcba9854ed5f064348292c5)), closes [#252](https://github.com/vuejs/vitepress/issues/252)\n- avoid minimizing non-javascript inline scripts ([#517](https://github.com/vuejs/vitepress/issues/517)) ([779b789](https://github.com/vuejs/vitepress/commit/779b78902fc7b1f9e7806751c0ca1e229a2161ce)), closes [#538](https://github.com/vuejs/vitepress/issues/538) [#540](https://github.com/vuejs/vitepress/issues/540)\n- **client router:** tolerant invalid hash selector typo ([#506](https://github.com/vuejs/vitepress/issues/506)) ([ffe0c40](https://github.com/vuejs/vitepress/commit/ffe0c40ebc42d7769b5378775cdffcab52d3cf11))\n- don't add .html to urls of non-html files ([#515](https://github.com/vuejs/vitepress/issues/515)) ([34d1542](https://github.com/vuejs/vitepress/commit/34d1542f466e2eed28b1be7153d1c3461d84528f)), closes [#265](https://github.com/vuejs/vitepress/issues/265)\n- normalize relative img src ([#514](https://github.com/vuejs/vitepress/issues/514)) ([9270477](https://github.com/vuejs/vitepress/commit/9270477fa59545978dc2732ac0a8091bed39625f)), closes [#450](https://github.com/vuejs/vitepress/issues/450)\n- require at least node v14 ([#546](https://github.com/vuejs/vitepress/issues/546)) ([7cf7011](https://github.com/vuejs/vitepress/commit/7cf70111a5a00579d46453b682ef33169c7846c5))\n- reset page data on 404 ([#497](https://github.com/vuejs/vitepress/issues/497)) ([28eaa3b](https://github.com/vuejs/vitepress/commit/28eaa3b04ab71674330151d2a9b79d52c382e71e))\n\n## [0.22.2](https://github.com/vuejs/vitepress/compare/v0.22.1...v0.22.2) (2022-02-14)\n\n### Features\n\n- improve default chunk strategy + page hash stability ([1ef69e2](https://github.com/vuejs/vitepress/commit/1ef69e212f91e43431b4fe4bdba17ca4f29a7b49))\n\n## [0.22.1](https://github.com/vuejs/vitepress/compare/v0.22.0...v0.22.1) (2022-02-14)\n\n### Features\n\n- automatically update hash map + retry on failed page fetch ([2324948](https://github.com/vuejs/vitepress/commit/23249483d60da1952c64a1f764873652b587c2dc))\n- use git-based lastUpdated data ([d32d8d4](https://github.com/vuejs/vitepress/commit/d32d8d441917dcb480a6735da78c2d6fc3e589c0))\n\n  Note: lastUpdated data is now disabled by default due to the performance overhead of retrieving the git information. This also means each page's metadata object no longer contains the `lastUpdated` property by default - it will only be present if the new `lastUpdated: true` config option is enabled.\n\n# [0.22.0](https://github.com/vuejs/vitepress/compare/v0.21.6...v0.22.0) (2022-02-11)\n\n- Upgrade to Vite 2.8\n\n## [0.21.6](https://github.com/vuejs/vitepress/compare/v0.21.5...v0.21.6) (2022-01-19)\n\n### Perf\n\n- Avoid wrapping siteData as readonly proxy in production builds\n\n## [0.21.5](https://github.com/vuejs/vitepress/compare/v0.21.4...v0.21.5) (2022-01-16)\n\n### Bug Fixes\n\n- allow overriding title if home is true ([#493](https://github.com/vuejs/vitepress/issues/493)) ([88d57a9](https://github.com/vuejs/vitepress/commit/88d57a93ef2689a8f5344b7f38b26db5ea86759b))\n- **types:** fix vitepress/theme type ([eabf6d2](https://github.com/vuejs/vitepress/commit/eabf6d2aa69d2a5452042bbb59edbbbc95aece87)), closes [#489](https://github.com/vuejs/vitepress/issues/489) [#438](https://github.com/vuejs/vitepress/issues/438) [#494](https://github.com/vuejs/vitepress/issues/494) [#442](https://github.com/vuejs/vitepress/issues/442)\n\n### Features\n\n- scrollOffset option ([b66785d](https://github.com/vuejs/vitepress/commit/b66785d68a86c118a7a036f3de8b3e504390f1da))\n\n## [0.21.4](https://github.com/vuejs/vitepress/compare/v0.21.3...v0.21.4) (2022-01-07)\n\n### Bug Fixes\n\n- set \\_\\_data in md.render ([dfbc932](https://github.com/vuejs/vitepress/commit/dfbc932fac50d39b047b211cedca0dcce05aebc8))\n\n## [0.21.3](https://github.com/vuejs/vitepress/compare/v0.21.2...v0.21.3) (2022-01-06)\n\n### Bug Fixes\n\n- prioritize vue installed in user project root ([9b3243b](https://github.com/vuejs/vitepress/commit/9b3243b75752209943af5b247f5d38e641d4ff6d))\n\n## [0.21.2](https://github.com/vuejs/vitepress/compare/v0.21.1...v0.21.2) (2022-01-06)\n\n## [0.21.1](https://github.com/vuejs/vitepress/compare/v0.21.0...v0.21.1) (2022-01-06)\n\n### Performance Improvements\n\n- do not include head config in client bundle for production ([6f3a96f](https://github.com/vuejs/vitepress/commit/6f3a96f06daec4baad4420b54137a7afb1512e7f))\n\n# [0.21.0](https://github.com/vuejs/vitepress/compare/v0.20.10...v0.21.0) (2022-01-06)\n\n### Bug Fixes\n\n- Chinese file link build failed ([#425](https://github.com/vuejs/vitepress/issues/425)) ([ae029ae](https://github.com/vuejs/vitepress/commit/ae029ae9e17fa6df1d2f89043f1891271e9c5b9b)), closes [#424](https://github.com/vuejs/vitepress/issues/424)\n- initial render of 404 pages ([#418](https://github.com/vuejs/vitepress/issues/418)) ([a3bf52f](https://github.com/vuejs/vitepress/commit/a3bf52fed53e82b9756c844f6bdd576662d2e726))\n- remove `.` for mjs in `supportedConfigExtensions` ([#447](https://github.com/vuejs/vitepress/issues/447)) ([fb6a4ad](https://github.com/vuejs/vitepress/commit/fb6a4ad3e008af9ce4393fb3ca37645f4efba951))\n- **serve:** respect base config in serve mode ([#470](https://github.com/vuejs/vitepress/issues/470)) ([08a0b12](https://github.com/vuejs/vitepress/commit/08a0b129928cef44e613ff410d769a7ac7bf5fa3)), closes [#416](https://github.com/vuejs/vitepress/issues/416)\n- set tempDir outside package root ([#439](https://github.com/vuejs/vitepress/issues/439)) ([bd35451](https://github.com/vuejs/vitepress/commit/bd35451ed42d7b5c47e2b49a7e659807cd7d7a0c)), closes [#435](https://github.com/vuejs/vitepress/issues/435)\n- use algolia search lang ([#459](https://github.com/vuejs/vitepress/issues/459)) ([444562c](https://github.com/vuejs/vitepress/commit/444562c3a763bab7a9c0ebfca5eec635e142a61f))\n\n### Features\n\n- add details custom container ([#455](https://github.com/vuejs/vitepress/issues/455)) ([a8f147f](https://github.com/vuejs/vitepress/commit/a8f147f153efdd17989a02eb620c3ae9ab0d13dd))\n- catch localhost links as dead links ([7387649](https://github.com/vuejs/vitepress/commit/7387649ff7c621402e49e26493b4eed25006fb4b))\n- expose `__path` and `__relativePath` on md instance for md plugins ([4cec660](https://github.com/vuejs/vitepress/commit/4cec660401d8d01830e5a11b9c66bc0ac5a935db))\n- improve typescript support for config file, add `defineConfigWithTheme` ([#465](https://github.com/vuejs/vitepress/issues/465)) ([ba41bb9](https://github.com/vuejs/vitepress/commit/ba41bb90551c01b9f84de2d2d3bc1920ce2ebe93))\n- properly remove `{#custom-anchor}` syntax in headers ([6120da2](https://github.com/vuejs/vitepress/commit/6120da25a87f6bec3918be804e95f2b3c8afb6c8))\n- user configurable `outDir` ([#448](https://github.com/vuejs/vitepress/issues/448)) ([5b04bb9](https://github.com/vuejs/vitepress/commit/5b04bb9eb5ced720414f4b0d729fde36432dd451))\n\n## [0.20.10](https://github.com/vuejs/vitepress/compare/v0.20.9...v0.20.10) (2021-12-25)\n\n### Features\n\n- minify head inline scripts ([e61db62](https://github.com/vuejs/vitepress/commit/e61db62a1c49cb5f368a152221bfa60737dbbc6a))\n\n## [0.20.9](https://github.com/vuejs/vitepress/compare/v0.20.8...v0.20.9) (2021-12-15)\n\n### Features\n\n- shouldPreload hook ([e721d60](https://github.com/vuejs/vitepress/commit/e721d605851be4e27f4948d96d5c3bab6d23ead2))\n- support array of patterns in data loaders ([f5308d7](https://github.com/vuejs/vitepress/commit/f5308d746f3089ef6818b0139fe249827a47628b))\n\n## [0.20.8](https://github.com/vuejs/vitepress/compare/v0.20.7...v0.20.8) (2021-12-14)\n\n## [0.20.7](https://github.com/vuejs/vitepress/compare/v0.20.6...v0.20.7) (2021-12-14)\n\n### Features\n\n- **types:** re-export vite client type ([4caa7b2](https://github.com/vuejs/vitepress/commit/4caa7b231753ddedb83365a37b8c259ae461bd37))\n\n## [0.20.6](https://github.com/vuejs/vitepress/compare/v0.20.4...v0.20.6) (2021-12-14)\n\n### Features\n\n- support static data loaders ([26fe81c](https://github.com/vuejs/vitepress/commit/26fe81c88618d7df5d623d041ac3df96e7d7ee7b))\n\n## [0.20.5](https://github.com/vuejs/vitepress/compare/v0.20.4...v0.20.5) (2021-12-12)\n\n- Bump vue & vite versions\n\n## [0.20.4](https://github.com/vuejs/vitepress/compare/v0.20.3...v0.20.4) (2021-12-07)\n\n### Bug Fixes\n\n- **build:** fix typing files ([ae11dc0](https://github.com/vuejs/vitepress/commit/ae11dc0b59ac90375079f1ebf0efacf1b1e58e8d))\n\n## [0.20.3](https://github.com/vuejs/vitepress/compare/v0.20.2...v0.20.3) (2021-12-07)\n\n### Features\n\n- expose createMarkdownRenderer ([d54c7d8](https://github.com/vuejs/vitepress/commit/d54c7d8c56973dac138bfe96ff16dfab162ef64b))\n\n## [0.20.2](https://github.com/vuejs/vitepress/compare/v0.20.1...v0.20.2) (2021-12-06)\n\n### Bug Fixes\n\n- handle potential string quote mismatch in generated code ([dfa7c05](https://github.com/vuejs/vitepress/commit/dfa7c0525f010994437acb060867d9ca1572867d))\n- improve createStaticVNode match for rollup codegen compat ([abb1b57](https://github.com/vuejs/vitepress/commit/abb1b578cdedf184ae386ce455e60a23672adfcb))\n- lazy require @vitejs/plugin-vue to respect NODE_ENV ([a051e66](https://github.com/vuejs/vitepress/commit/a051e66f1ae211174cf470d4430427dc0189194b))\n- static string strip regex for mulitiline static strings ([bc486aa](https://github.com/vuejs/vitepress/commit/bc486aae563fd77f38da44d9ae3ea28c021f6df0))\n\n### Features\n\n- upgrade docsearch version ([#441](https://github.com/vuejs/vitepress/issues/441)) ([1b245e2](https://github.com/vuejs/vitepress/commit/1b245e22d8a00ea7c01c052ac1ea3d8d94aaeefb))\n\n## [0.20.1](https://github.com/vuejs/vitepress/compare/v0.20.0...v0.20.1) (2021-11-05)\n\n### Bug Fixes\n\n- **hmr:** avoid relying on revertd vite hmr behavior ([4114674](https://github.com/vuejs/vitepress/commit/4114674c69f917ff2e611ec30eb72d224f175f62))\n\n# [0.20.0](https://github.com/vuejs/vitepress/compare/v0.19.2...v0.20.0) (2021-10-07)\n\n### Bug Fixes\n\n- fix code line hightlighting ([4c042b6](https://github.com/vuejs/vitepress/commit/4c042b61e7beb70d0a0b77cc9a00d725c7863089)), closes [#408](https://github.com/vuejs/vitepress/issues/408)\n- invalid active props when `base` option is added ([#342](https://github.com/vuejs/vitepress/issues/342)) ([383d8ff](https://github.com/vuejs/vitepress/commit/383d8ffbba5283774e0f1e39302a29efc0db7e79))\n- make config hmr work in window ([#364](https://github.com/vuejs/vitepress/issues/364)) ([58663bb](https://github.com/vuejs/vitepress/commit/58663bbd02aa3da0efd939bd27de2ee5c0ab14d8))\n- print urls again ([df69b76](https://github.com/vuejs/vitepress/commit/df69b76427ab2c770010cd79e1076a1c414fb3bc))\n- support vite plugins provided via `config.vite` ([#394](https://github.com/vuejs/vitepress/issues/394)) ([4b76617](https://github.com/vuejs/vitepress/commit/4b7661762143b033e82fad526e256f7bc54df9af))\n- **theme-default/algolia:** avoid creating multiple algolia searches ([#292](https://github.com/vuejs/vitepress/issues/292)) ([389e863](https://github.com/vuejs/vitepress/commit/389e863b4d5e69c856d1e647d4d4c1807bd94c5d))\n- **theme:** fix algolia search filter ([5fd7db2](https://github.com/vuejs/vitepress/commit/5fd7db2b7fcd947d77c97b1e9bdaf83845c1321d))\n- tolerant invalid hash ([#399](https://github.com/vuejs/vitepress/issues/399)) ([efc5e1b](https://github.com/vuejs/vitepress/commit/efc5e1b2566eedc47a9420accae3dfba1a594ba4))\n\n### Features\n\n- support ts/esm config file + defineConfig() helper ([d3b1521](https://github.com/vuejs/vitepress/commit/d3b1521ebef831e0d0307b3b12e4fc1f6ce4721a)), closes [#339](https://github.com/vuejs/vitepress/issues/339) [#376](https://github.com/vuejs/vitepress/issues/376)\n- **theme-default:** home slot for customizing the entire homepage easily ([#314](https://github.com/vuejs/vitepress/issues/314)) ([07bf145](https://github.com/vuejs/vitepress/commit/07bf1451909ad615565e01d719e8a350ea07e69e))\n\n## [0.19.2](https://github.com/vuejs/vitepress/compare/v0.19.1...v0.19.2) (2021-09-28)\n\n### Bug Fixes\n\n- encode urls that conflict w/ vite built-in replacements ([3940625](https://github.com/vuejs/vitepress/commit/3940625121455b7ad6e5ea8ebb3e1cf2faf9c7fc))\n\n## [0.19.1](https://github.com/vuejs/vitepress/compare/v0.19.0...v0.19.1) (2021-09-21)\n\n- Fix build\n\n# [0.19.0](https://github.com/vuejs/vitepress/compare/v0.18.1...v0.19.0) (2021-09-21)\n\n### Features\n\n- upgrade vue, simplify deps ([9030486](https://github.com/vuejs/vitepress/commit/9030486409f10a59115d874b9365f71348ed76c2))\n- use `markdown-it-attrs` for markdown-it plugins ([#393](https://github.com/vuejs/vitepress/issues/393)) ([610e9b7](https://github.com/vuejs/vitepress/commit/610e9b7111462d3aace878017fa4d359cd2ae7ea))\n\n## [0.18.1](https://github.com/vuejs/vitepress/compare/v0.18.0...v0.18.1) (2021-09-16)\n\n### Bug Fixes\n\n- ensure stable pages entry order across builds ([929bcf5](https://github.com/vuejs/vitepress/commit/929bcf50ee634d9fe73adbe2aae5f7038b048e5a))\n\n# [0.18.0](https://github.com/vuejs/vitepress/compare/v0.17.3...v0.18.0) (2021-09-14)\n\n### Features\n\n- map mode + remove deprecated options ([b94b163](https://github.com/vuejs/vitepress/commit/b94b163a3a931fe03e69547391d6ac22eb41b789))\n- support `<script client>` in mpa mode ([e0b6997](https://github.com/vuejs/vitepress/commit/e0b69973f840bfa281fae209da1f1c674c1301a8))\n\n## [0.17.3](https://github.com/vuejs/vitepress/compare/v0.17.2...v0.17.3) (2021-09-09)\n\n### Bug Fixes\n\n- emit prevented hashchange event ([4fb387d](https://github.com/vuejs/vitepress/commit/4fb387d94ea9d7ae28a871929cbbc57e931b8d7a))\n\n## [0.17.2](https://github.com/vuejs/vitepress/compare/v0.17.1...v0.17.2) (2021-09-08)\n\n### Bug Fixes\n\n- improve fs allow ([2e9264f](https://github.com/vuejs/vitepress/commit/2e9264f03259354e7739e2a56a7c1306fb167843))\n\n### Features\n\n- support config.extends ([f749b27](https://github.com/vuejs/vitepress/commit/f749b272d4603a3b8eaf251b0feebe2d33da3983))\n\n## [0.17.1](https://github.com/vuejs/vitepress/compare/v0.17.0...v0.17.1) (2021-09-08)\n\n### Bug Fixes\n\n- avoid using spread for client code ([03abee7](https://github.com/vuejs/vitepress/commit/03abee7f7c0fac95806f31ff5761b9e912a1f232))\n- **default-theme:** use description as tagline by default ([b94c827](https://github.com/vuejs/vitepress/commit/b94c82710a7b230a918790ac0b6aa1d2f5afc1c3))\n- handle case when there is no themeConfig ([034c737](https://github.com/vuejs/vitepress/commit/034c7375ad2de4b42c0ac861c2dd18183511771d))\n\n### Performance Improvements\n\n- minor optimizations ([96bcdda](https://github.com/vuejs/vitepress/commit/96bcddabedac9af4e1c817ed651bb4ce692c75e7))\n\n# [0.17.0](https://github.com/vuejs/vitepress/compare/v0.16.1...v0.17.0) (2021-08-31)\n\n### Bug Fixes\n\n- allow vite server access to theme and local files ([9b9fdc7](https://github.com/vuejs/vitepress/commit/9b9fdc710a6cedb3e278805eb07bed669ca2075e))\n- **code:** code block highlight bug in ul ([#352](https://github.com/vuejs/vitepress/issues/352)) ([9245226](https://github.com/vuejs/vitepress/commit/9245226b16f6113c722e5e8c7b876bea1cf1c255))\n- **css:** remove 720px breakpoint in home layout ([#347](https://github.com/vuejs/vitepress/issues/347)) ([0c1a1f2](https://github.com/vuejs/vitepress/commit/0c1a1f2ef43cd7d995f3e9d43f19be8b3f961cb1))\n- **i18n:** fix locales reading, add site.langs ([#353](https://github.com/vuejs/vitepress/issues/353)) ([bc78adb](https://github.com/vuejs/vitepress/commit/bc78adb468bce8ce2d4e2543423adacc9351cf51)), closes [/vuepress.vuejs.org/guide/i18n.html#site-level-i18](https://github.com//vuepress.vuejs.org/guide/i18n.html/issues/site-level-i18) [/v2.vuepress.vuejs.org/guide/i18n.html#site-i18](https://github.com//v2.vuepress.vuejs.org/guide/i18n.html/issues/site-i18)\n- include emoji text in nav link to match toc ([#284](https://github.com/vuejs/vitepress/issues/284)) ([80ff360](https://github.com/vuejs/vitepress/commit/80ff36066ef6a4ed4a18548993bc5d8d9a6dab58))\n- use useData() instead of $site ([#365](https://github.com/vuejs/vitepress/issues/365)) ([1e64773](https://github.com/vuejs/vitepress/commit/1e6477393308a5d8bd03a614cecf9573466f6e6c))\n\n### Features\n\n- support function config ([e74c5f0](https://github.com/vuejs/vitepress/commit/e74c5f06d1d5890fad6dd728df9bf85dcfda87d1))\n- support partial include directive ([7b3a9e5](https://github.com/vuejs/vitepress/commit/7b3a9e59b44e9e354692eed6c1ca453be9cb7a86))\n- upgrade markdown-it-anchor ([#350](https://github.com/vuejs/vitepress/issues/350)) ([26b5aa9](https://github.com/vuejs/vitepress/commit/26b5aa931f1935bd67dcd1d511461ff5fa8a00ec))\n\n### BREAKING CHANGES\n\n- the `markdown.anchor` option is updated. Refer to\n  valeriangalliat/markdown-it-anchor#permalinks for\n  instructions to upgrade your existing `markdown.anchor.permalink`\n  option. **This doesn't affect you if you weren't changing the header\n  permalinks behavior**.\n\n## [0.16.1](https://github.com/vuejs/vitepress/compare/v0.16.0...v0.16.1) (2021-08-11)\n\n### Features\n\n- info custom container ([4925fb5](https://github.com/vuejs/vitepress/commit/4925fb5c29c59b7e17d050ab4346f71afc0463cd))\n\n# [0.16.0](https://github.com/vuejs/vitepress/compare/v0.15.6...v0.16.0) (2021-08-10)\n\nThis version uses Vue 3.2.0.\n\n### Bug Fixes\n\n- override target and rel links attribute in config ([#332](https://github.com/vuejs/vitepress/issues/332)) ([9d98dbb](https://github.com/vuejs/vitepress/commit/9d98dbbe60d477a78d6dc0e80d16fdddedcd4ed5))\n- **edit-link:** let frontmatter overwrite global editLink ([#340](https://github.com/vuejs/vitepress/issues/340)) ([cfbba80](https://github.com/vuejs/vitepress/commit/cfbba80a0a6e33bcb2ca3d4450fb9624dcd6d140))\n\n## [0.15.6](https://github.com/vuejs/vitepress/compare/v0.15.5...v0.15.6) (2021-07-02)\n\n### Bug Fixes\n\n- automatically escape vite user defined variables in markdown ([3cec536](https://github.com/vuejs/vitepress/commit/3cec536c1f3d5d027ee16cd0629f84461e565096))\n- skip external URLs in `withBase` ([#328](https://github.com/vuejs/vitepress/issues/328)) ([53bb961](https://github.com/vuejs/vitepress/commit/53bb961a925cbafe53730450c5b069e255b54e03))\n\n## [0.15.5](https://github.com/vuejs/vitepress/compare/v0.15.4...v0.15.5) (2021-06-23)\n\n### Bug Fixes\n\n- **nav:** display nav if locales are present ([#321](https://github.com/vuejs/vitepress/issues/321)) ([e76e6ec](https://github.com/vuejs/vitepress/commit/e76e6ecd54f8a202a9d5051afd72553080f898c9))\n- **search:** correctly detect multilang ([c046905](https://github.com/vuejs/vitepress/commit/c046905b032a765352ff6bb9944f72db76c5cf45)), closes [#316](https://github.com/vuejs/vitepress/issues/316)\n\n### Performance Improvements\n\n- only update necessary head tags in prod ([e6bb5a4](https://github.com/vuejs/vitepress/commit/e6bb5a4806bb16f1ace26f27f43b5ed83885bf1a))\n\n## [0.15.4](https://github.com/vuejs/vitepress/compare/v0.15.3...v0.15.4) (2021-06-19)\n\n### Bug Fixes\n\n- avoid scroll behavior reliance on .nav-bar class ([9b35dfc](https://github.com/vuejs/vitepress/commit/9b35dfcde4c00e6f10b2631103f95e97cbf4af9e))\n\n## [0.15.3](https://github.com/vuejs/vitepress/compare/v0.15.2...v0.15.3) (2021-06-15)\n\n### Bug Fixes\n\n- avoid error when theme does not have .nav-bar class ([a9d5800](https://github.com/vuejs/vitepress/commit/a9d580069fff90298b197808379cd0c4b756d463))\n- avoid resetting head tags on hmr/page switch ([f52f20e](https://github.com/vuejs/vitepress/commit/f52f20e02f6908411ad9cddb341583456a3c2a8c))\n- watch config file when using srcDir ([348f19a](https://github.com/vuejs/vitepress/commit/348f19a537930b1d4c7272e05e91edcb72219f34))\n\n## [0.15.2](https://github.com/vuejs/vitepress/compare/v0.15.1...v0.15.2) (2021-06-15)\n\n### Bug Fixes\n\n- force optimize vue to avoid duplication when linked ([eefba39](https://github.com/vuejs/vitepress/commit/eefba398b0e5a4b5afb47ce6e06b0c39a6be55d2))\n\n## [0.15.1](https://github.com/vuejs/vitepress/compare/v0.15.0...v0.15.1) (2021-06-14)\n\n### Features\n\n- support passing vite config in vitepress config file via `vite` option ([3737b10](https://github.com/vuejs/vitepress/commit/3737b1055dc1145dc70b10994564c6d83affd15d))\n- support srcDir config option ([aaf4910](https://github.com/vuejs/vitepress/commit/aaf4910d938f4449fdab576ffd0ae853b5aace24))\n\n### Performance Improvements\n\n- avoid double resolve user config on startup ([5733fc6](https://github.com/vuejs/vitepress/commit/5733fc625ea33ab1b07ddfd4f8412e15473d8cca))\n\n### BREAKING CHANGES\n\n- Some config options have changed.\n  - `vueOptions` renamed to `vue`\n  - `alias` option has been removed. Use `vite.resovle.alias` instead.\n\n# [0.15.0](https://github.com/vuejs/vitepress/compare/v0.14.1...v0.15.0) (2021-06-14)\n\n### Bug Fixes\n\n- fix frontmatter sidebarDepth for headers ([424a4ca](https://github.com/vuejs/vitepress/commit/424a4ca379f028e3542e2e9598cb5beacaf50067))\n- fix vue code block type indication ([76fa173](https://github.com/vuejs/vitepress/commit/76fa1733fff4e3aa4356df08272e4811db996dab))\n\n### Features\n\n- more efficient `useData()` method that exposes all data ([0661063](https://github.com/vuejs/vitepress/commit/0661063d29c0e1dce108cac608be0ff754d2d4c1))\n\n### BREAKING CHANGES\n\n- The following methods are removed.\n  - `useSiteData`\n  - `useSiteDataByRoute`\n  - `usePageData`\n  - `useFrontmatter`\n\n  Instead, use the new `useData()` method:\n\n  ```js\n  // before\n  import { useSiteDataByRoute, usePageData } from 'vitepress'\n  const site = useSiteDataByRoute()\n  const page = usePageData()\n  const theme = computed(() => site.value.themeConfig)\n\n  // after\n  import { useData } from 'vitepress'\n  const { site, page, theme } = useData()\n  ```\n\n  All destructured values are computed refs injected from app root\n  so they are created only once globally.\n\n- All global mixin properties (e.g. `$site`) except `$frontmatter` are removed. Always use `useData()` to retrieve VitePress data in Vue components.\n\n## [0.14.1](https://github.com/vuejs/vitepress/compare/v0.14.0...v0.14.1) (2021-06-08)\n\n### Bug Fixes\n\n- functional templates with vue v3.1 ([#312](https://github.com/vuejs/vitepress/issues/312)) ([8988aad](https://github.com/vuejs/vitepress/commit/8988aadbcbd781a81df0a8d1a4a6964d324c58a3))\n\n# [0.14.0](https://github.com/vuejs/vitepress/compare/v0.13.2...v0.14.0) (2021-05-27)\n\n### Bug Fixes\n\n- chinese filenames can't build ([#217](https://github.com/vuejs/vitepress/issues/217)) ([#262](https://github.com/vuejs/vitepress/issues/262)) ([b940397](https://github.com/vuejs/vitepress/commit/b940397cd0e5135e7433bac6fc99da8553915053))\n- **theme:** set search box min-width for >=751px ([#286](https://github.com/vuejs/vitepress/issues/286)) ([9589a5d](https://github.com/vuejs/vitepress/commit/9589a5d0e6458da07054a84d2df6ef99a5ad1dbd))\n- detect public folder for dead link ([#290](https://github.com/vuejs/vitepress/issues/290)) ([3aa185f](https://github.com/vuejs/vitepress/commit/3aa185fa9f9dd49e32cfd60f96a30da8616e419e))\n- remove unnecessary 'vite/dynamic-import-polyfill' ([6b4a4aa](https://github.com/vuejs/vitepress/commit/6b4a4aa7a6cd2f2e044a5cc54c5bf72a50f9df67))\n\n### Features\n\n- Vite version bumped to `^2.3.4`\n- exclude option ([#281](https://github.com/vuejs/vitepress/issues/281)) ([71a5e1c](https://github.com/vuejs/vitepress/commit/71a5e1c2a2b552ced8a994dc60201c4be89b4ac9))\n- Render titles for social sharing and improve home page sharing ([#263](https://github.com/vuejs/vitepress/issues/263)) ([e651f97](https://github.com/vuejs/vitepress/commit/e651f977d6b9f50fef25f6d736f8d4880c997305))\n\n## [0.13.2](https://github.com/vuejs/vitepress/compare/v0.13.1...v0.13.2) (2021-04-26)\n\n### Bug Fixes\n\n- **search:** silence warning for prop ([0716ffa](https://github.com/vuejs/vitepress/commit/0716ffade743c65c240d616329c1a6bc3e83c4bd))\n\n## [0.13.1](https://github.com/vuejs/vitepress/compare/v0.13.0...v0.13.1) (2021-04-26)\n\n### Bug Fixes\n\n- **locales:** use correct lang ([#283](https://github.com/vuejs/vitepress/issues/283)) ([de89c1e](https://github.com/vuejs/vitepress/commit/de89c1e5ebf09557532eec93269b7143f454f9d1))\n\n# [0.13.0](https://github.com/vuejs/vitepress/compare/v0.12.2...v0.13.0) (2021-04-08)\n\n### Bug Fixes\n\n- build fails without css chunks ([#209](https://github.com/vuejs/vitepress/issues/209)) ([#239](https://github.com/vuejs/vitepress/issues/239)) ([fa469fd](https://github.com/vuejs/vitepress/commit/fa469fd2750ac74417238de7547cd8e7cd939cb0))\n- **css:** reuse css vars ([#256](https://github.com/vuejs/vitepress/issues/256)) ([8d91524](https://github.com/vuejs/vitepress/commit/8d915245c6740874abad0e11f374703aa07afec3))\n- **docs:** global-component link ([#271](https://github.com/vuejs/vitepress/issues/271)) ([a43933c](https://github.com/vuejs/vitepress/commit/a43933c8ab4474c905005a337da3620621878a1c))\n- **locales:** use correct lang ([#276](https://github.com/vuejs/vitepress/issues/276)) ([f505db9](https://github.com/vuejs/vitepress/commit/f505db945af3ca4e4ce0a06b5aa2a4d32d47bac7))\n- **navbar:** use css var for background-color ([#264](https://github.com/vuejs/vitepress/issues/264)) ([f385bc4](https://github.com/vuejs/vitepress/commit/f385bc467306c075871485e6a9bfe773fc9054a1))\n- badge for language-javascript ([#245](https://github.com/vuejs/vitepress/issues/245)) ([f8b4aa5](https://github.com/vuejs/vitepress/commit/f8b4aa5baa7f2fba843427f2f4f3985222c3c78d))\n\n### Features\n\n- detect dead links ([74f5ada](https://github.com/vuejs/vitepress/commit/74f5adafcde8a597939fbb37422aa68187b6dad4))\n- import code snippet with region ([#237](https://github.com/vuejs/vitepress/issues/237)) ([#238](https://github.com/vuejs/vitepress/issues/238)) ([d1a62e1](https://github.com/vuejs/vitepress/commit/d1a62e1c6630b289777b78eea359acd49174148d))\n\n## [0.12.2](https://github.com/vuejs/vitepress/compare/v0.12.1...v0.12.2) (2021-02-15)\n\n### Bug Fixes\n\n- **theme-default:** avoid ad image distortion on mobile ([4a40e1f](https://github.com/vuejs/vitepress/commit/4a40e1faf477c4e779b78f55ac1604eeb52b2499))\n\n## [0.12.1](https://github.com/vuejs/vitepress/compare/v0.12.0...v0.12.1) (2021-02-15)\n\n### Bug Fixes\n\n- `@` alias for import code snippet being always `undefined` ([#204](https://github.com/vuejs/vitepress/issues/204)) ([2aa8ab2](https://github.com/vuejs/vitepress/commit/2aa8ab26e2fcf87ced27999c0be67798d5b4bb88))\n- `base` option not generating correct multi sidebar ([#231](https://github.com/vuejs/vitepress/issues/231)) ([#234](https://github.com/vuejs/vitepress/issues/234)) ([a613df4](https://github.com/vuejs/vitepress/commit/a613df46e8cd7709dd2ad0f411ff52aa431850b6))\n- ads display causing layout break in mobile view ([#230](https://github.com/vuejs/vitepress/issues/230)) ([7ceaf34](https://github.com/vuejs/vitepress/commit/7ceaf344d20f8a51c0452eed264e07b47d104043))\n- home action link not being reactive ([#195](https://github.com/vuejs/vitepress/issues/195)) ([#212](https://github.com/vuejs/vitepress/issues/212)) ([5678dc3](https://github.com/vuejs/vitepress/commit/5678dc3a255c90309d5d7d9b609f3dc7ec7f9d00))\n- nav home title not having locale based link ([#195](https://github.com/vuejs/vitepress/issues/195)) ([#233](https://github.com/vuejs/vitepress/issues/233)) ([6538c8e](https://github.com/vuejs/vitepress/commit/6538c8e70aac60823fd2374e36cb502420184b44))\n\n# [0.12.0](https://github.com/vuejs/vitepress/compare/v0.11.5...v0.12.0) (2021-02-09)\n\n### Bug Fixes\n\n- `base` option not working on dev mode ([#223](https://github.com/vuejs/vitepress/issues/223)) ([0b5b306](https://github.com/vuejs/vitepress/commit/0b5b306f85ada7e670345d31cb52931d0e46f784))\n- frontmatter description duplication ([#194](https://github.com/vuejs/vitepress/issues/194)) ([#170](https://github.com/vuejs/vitepress/issues/170)) ([338e845](https://github.com/vuejs/vitepress/commit/338e8453d8c5f3955923d98bafcbb92261a8f045))\n- sidebar 'auto' not working ([#178](https://github.com/vuejs/vitepress/issues/178)) ([#224](https://github.com/vuejs/vitepress/issues/224)) ([5deaf6a](https://github.com/vuejs/vitepress/commit/5deaf6a2cdeb1622ae5afc1c8e522d57ff39e4e1))\n- render document with standards mode in dev ([#207](https://github.com/vuejs/vitepress/issues/207)) ([8a0db65](https://github.com/vuejs/vitepress/commit/8a0db65a8a8939e4505b004b884e9395e25e983b))\n- utf-8 character not working on safari in dev mode ([#228](https://github.com/vuejs/vitepress/issues/228)) ([b82d8f2](https://github.com/vuejs/vitepress/commit/b82d8f2ecee31d6ffdc6f74b0bad4fe2c74d40de))\n- use brand color in algolia search box ([2330023](https://github.com/vuejs/vitepress/commit/2330023d99741ea18fd606a7601ab19815333f7c))\n\n### Features\n\n- add vue options config (expose @vitejs/plugin-vue) ([#215](https://github.com/vuejs/vitepress/issues/215)) ([5b34c6a](https://github.com/vuejs/vitepress/commit/5b34c6a94ad7d2eecf667844c60504e776f15afc))\n\n### BREAKING CHANGES\n\n- If sidebar option is `undefined` it will be treated as `auto`, where previsouly it looked like it was treated as `false`. It was always treated as `auto`, but due to [this bug](https://github.com/vuejs/vitepress/issues/178), the sidebar was hidden, therefore it looked like it was treated as `false`.\n\n## [0.11.5](https://github.com/vuejs/vitepress/compare/v0.11.4...v0.11.5) (2021-01-29)\n\n### Bug Fixes\n\n- avoid layout shift due to ads ([#176](https://github.com/vuejs/vitepress/issues/176)) ([78b026c](https://github.com/vuejs/vitepress/commit/78b026cb7aa5b40a7dd98a1337646b38b1fc5367))\n- support symbolic links in building docs dist ([#184](https://github.com/vuejs/vitepress/issues/184)) ([#185](https://github.com/vuejs/vitepress/issues/185)) ([5190604](https://github.com/vuejs/vitepress/commit/51906043d318b2485ea8fc3aff4b4644c95dd3f4))\n- update base option usage ([8cfdd19](https://github.com/vuejs/vitepress/commit/8cfdd1912dda9153daa7cb4db8e5c9f0cab4d654))\n\n### Features\n\n- $lang and $localePath globals ([#166](https://github.com/vuejs/vitepress/issues/166)) ([#167](https://github.com/vuejs/vitepress/issues/167)) ([481c451](https://github.com/vuejs/vitepress/commit/481c4513d78450951add6177824b7996b89ae034))\n\n## [0.11.4](https://github.com/vuejs/vitepress/compare/v0.11.3...v0.11.4) (2021-01-19)\n\n- Latest Vite beta.32 compat (internal changes).\n\n## [0.11.3](https://github.com/vuejs/vitepress/compare/v0.11.2...v0.11.3) (2021-01-13)\n\n### Bug Fixes\n\n- ignore non-html links in router and prefetch ([3e6e61b](https://github.com/vuejs/vitepress/commit/3e6e61bcea8d4a34079428fcce3ecd25af1ae4f7))\n\n## [0.11.2](https://github.com/vuejs/vitepress/compare/v0.11.1...v0.11.2) (2021-01-12)\n\n### Bug Fixes\n\n- aria label id ([a0f463a](https://github.com/vuejs/vitepress/commit/a0f463af8fd828d24d9a01c3d808d85af8a71c9f))\n\n### Performance Improvements\n\n- generate preload directives for dynamicImport chunks too ([b9fc0cb](https://github.com/vuejs/vitepress/commit/b9fc0cb78d43949b417376498939daa892a33334))\n\n## [0.11.1](https://github.com/vuejs/vitepress/compare/v0.11.0...v0.11.1) (2021-01-12)\n\n### Features\n\n- render content on home page ([ca631c7](https://github.com/vuejs/vitepress/commit/ca631c7f516ad6c643d252dd81e03e29fb3b9e05))\n\n# [0.11.0](https://github.com/vuejs/vitepress/compare/v0.10.8...v0.11.0) (2021-01-12)\n\n### Code Refactoring\n\n- move default theme to 'vitepress/theme' ([a79e1e1](https://github.com/vuejs/vitepress/commit/a79e1e1916a71271728e6fe7c2b734fc2f209518))\n\n### Features\n\n- support customData in config ([4072dc5](https://github.com/vuejs/vitepress/commit/4072dc5f7ede381709fce49e9a29d6af4f7ab81a))\n\n### BREAKING CHANGES\n\n- the default theme is now exposed via 'vitepress/theme',\n  instead of a named export from 'vitepress'. This change fixes the case where\n  when a completely custom theme is used, importing anything from 'vitepress'\n  also imports the entire default theme.\n\n## [0.10.8](https://github.com/vuejs/vitepress/compare/v0.10.7...v0.10.8) (2021-01-11)\n\n### Bug Fixes\n\n- resolve page hash case-insenstively, close [#202](https://github.com/vuejs/vitepress/issues/202) ([#203](https://github.com/vuejs/vitepress/issues/203)) ([bac1ce2](https://github.com/vuejs/vitepress/commit/bac1ce2d01469ff7586437f43b0d665b1c5eb278))\n\n## [0.10.7](https://github.com/vuejs/vitepress/compare/v0.10.6...v0.10.7) (2021-01-05)\n\n### Features\n\nBump to Vite 2.0.0-beta.8\n\n### Bug Fixes\n\n- scrollbar when using line highlight ([#200](https://github.com/vuejs/vitepress/issues/200)) ([b6ba8a9](https://github.com/vuejs/vitepress/commit/b6ba8a943cc0488410a438c6c2f277c1c33a90bf))\n\n## [0.10.6](https://github.com/vuejs/vitepress/compare/v0.10.5...v0.10.6) (2021-01-04)\n\n### Bug Fixes\n\n- bump vite and fix win32 path resolving ([#198](https://github.com/vuejs/vitepress/issues/198)) ([da2c4f6](https://github.com/vuejs/vitepress/commit/da2c4f694e6dd2d11ff061b8eb7cae2354ae930d))\n\n## [0.10.5](https://github.com/vuejs/vitepress/compare/v0.10.4...v0.10.5) (2021-01-02)\n\n### Bug Fixes\n\n- vite 2.0.0-beta.2 compat ([991a443](https://github.com/vuejs/vitepress/commit/991a443c70c6173aa0100fcccf57f3565e9e38d9))\n\n## [0.10.4](https://github.com/vuejs/vitepress/compare/v0.10.3...v0.10.4) (2021-01-01)\n\n### Bug Fixes\n\n- ensure the same vue dep in all cases ([d6b8568](https://github.com/vuejs/vitepress/commit/d6b8568c52d51d66423a32293879f8bb57756954))\n- respect root during build ([055e3fd](https://github.com/vuejs/vitepress/commit/055e3fd043b6ec425f1b0a0cf529bc1ff66acda5))\n\n## [0.10.3](https://github.com/vuejs/vitepress/compare/v0.10.2...v0.10.3) (2021-01-01)\n\n### Bug Fixes\n\n- always define theme globals ([8769b4b](https://github.com/vuejs/vitepress/commit/8769b4b49f398c5244354fbb93fcbecdb9b9c638))\n- avoid unexpected vite define replacements in markdown content ([a41928e](https://github.com/vuejs/vitepress/commit/a41928ef83eaf9dcb68be26b1e1f8a3edadfb74a))\n- loosen navLink active matching ([8a2ff33](https://github.com/vuejs/vitepress/commit/8a2ff33bf8043b5b0ec21826d7962d7e6337e394))\n\n### Features\n\n- **theme-default:** nav.item.activeMatch ([e262ef6](https://github.com/vuejs/vitepress/commit/e262ef63d89b2bc90c7e42bfc302ba6c602fab16))\n- add altAction for home ([9a17ddf](https://github.com/vuejs/vitepress/commit/9a17ddfdfb3cf7afd70d28d697245a298de090e1))\n\n## [0.10.2](https://github.com/vuejs/vitepress/compare/v0.10.1...v0.10.2) (2020-12-31)\n\n### Bug Fixes\n\n- adjust multi sidebar matching logic ([7e4b16e](https://github.com/vuejs/vitepress/commit/7e4b16ee524efc87c150a3d57a3215aac76b3669))\n\n## [0.10.1](https://github.com/vuejs/vitepress/compare/v0.10.0...v0.10.1) (2020-12-30)\n\n### Bug Fixes\n\n- disable css code split ([04dc058](https://github.com/vuejs/vitepress/commit/04dc058cd9977b47eb29c6d2d043e33d92802af8))\n- minify ([e3d7fc0](https://github.com/vuejs/vitepress/commit/e3d7fc035376d6d73e350be661925058c84828a8))\n\n### Features\n\n- production ready serve ([2d77eaf](https://github.com/vuejs/vitepress/commit/2d77eafe3b05e9fe76031af9a6c5386c4c6586ac))\n\n### Performance Improvements\n\n- avoid including optional features in build when not used ([c878e6d](https://github.com/vuejs/vitepress/commit/c878e6d3b56ecbd71bd75ff4360446d6dacbd70b))\n\n# [0.10.0](https://github.com/vuejs/vitepress/compare/v0.9.2...v0.10.0) (2020-12-30)\n\n- Upgrade to Vite 2.0\n\n### Bug Fixes\n\n- port fixes to parseHeader utils from vuepress ([#172](https://github.com/vuejs/vitepress/issues/172)) ([dd312ce](https://github.com/vuejs/vitepress/commit/dd312ce86bf9daf4b169e025d4215c05e2ad63c5))\n- revert datetime handling ([a1daf2b](https://github.com/vuejs/vitepress/commit/a1daf2b8a012a8a248b3a832d80d6933778087d0))\n- style pollution on custom theme ([#190](https://github.com/vuejs/vitepress/issues/190)) ([46e99ba](https://github.com/vuejs/vitepress/commit/46e99babc2d1a0e456d47081c2e7beb961bcd1d5))\n- temporarily disable slot usage causing hydration mismatch ([0239159](https://github.com/vuejs/vitepress/commit/02391593bcdd21b621a60aaa0ea2c8cf2ef450d8))\n- **md:** avoid normalising markdown \"mailto:\" links ([#173](https://github.com/vuejs/vitepress/issues/173)) ([18d18d2](https://github.com/vuejs/vitepress/commit/18d18d2eb15a569113ca68ccbb9ba52dfd46c80a))\n\n## [0.9.2](https://github.com/vuejs/vitepress/compare/v0.9.1...v0.9.2) (2020-12-10)\n\nFix build files\n\n## [0.9.1](https://github.com/vuejs/vitepress/compare/v0.9.0...v0.9.1) (2020-12-05)\n\n### Bug Fixes\n\n- **theme:** the actionLink miss withBase ([#168](https://github.com/vuejs/vitepress/issues/168)) ([#169](https://github.com/vuejs/vitepress/issues/169)) ([ffaca73](https://github.com/vuejs/vitepress/commit/ffaca73992675cef789fe8e13dd8132ae14bbd53))\n- align $title with vuepress ([#158](https://github.com/vuejs/vitepress/issues/158)) ([#163](https://github.com/vuejs/vitepress/issues/163)) ([30740d3](https://github.com/vuejs/vitepress/commit/30740d3516e3f7cce0e083faa90a732d9916f9af))\n- fix h2 anchor hover ([9bd79e8](https://github.com/vuejs/vitepress/commit/9bd79e8de1827251796d1647b5d258818a94f3b3)), closes [#174](https://github.com/vuejs/vitepress/issues/174)\n- fix inline code not inheriting the parent font size ([f5a570f](https://github.com/vuejs/vitepress/commit/f5a570f640c539d96cfa2104613521a70cf2f199))\n- fix link prefetch ([ade6ddd](https://github.com/vuejs/vitepress/commit/ade6dddbb5ea72cc7569fcfc46f5e6a362af58ce))\n- hydration mismatch when home page having action link ([a7686b7](https://github.com/vuejs/vitepress/commit/a7686b7691a3e3d7d10226fd4f7971929701965a))\n- make home page look better ([#154](https://github.com/vuejs/vitepress/issues/154)) ([a084cd3](https://github.com/vuejs/vitepress/commit/a084cd3f782f2aaf78a6542b0c86f67676580a73))\n- prevLinks and nextLinks config type ([#165](https://github.com/vuejs/vitepress/issues/165)) ([1b6981a](https://github.com/vuejs/vitepress/commit/1b6981a9157588bc4e29e591ba8a0d9ca5c9c9e8))\n- siteData passed to enhanceApp being siteDataByRoute ([#159](https://github.com/vuejs/vitepress/issues/159)) ([01d2837](https://github.com/vuejs/vitepress/commit/01d2837474caef19daaf0be4b3c283dbe85a09da))\n\n### Features\n\n- built-in ClientOnly component ([8809d2d](https://github.com/vuejs/vitepress/commit/8809d2dbfc6818ba1618fa43368a45130d940890))\n- **default-theme:** support customLayout: true in frontmatter ([f32771f](https://github.com/vuejs/vitepress/commit/f32771fe8646701410ba4b231a2b0ce38230ab64))\n- add `$withBase` global app function ([15e18df](https://github.com/vuejs/vitepress/commit/15e18df01e6e5ca8af605365896fee0024244b37))\n- add Algolia DocSearch ([#40](https://github.com/vuejs/vitepress/issues/40)) ([#153](https://github.com/vuejs/vitepress/issues/153)) ([5bb4730](https://github.com/vuejs/vitepress/commit/5bb4730f7f48153ae006d7878431d0b58b0fffee))\n- add native support for carbon ads ([#86](https://github.com/vuejs/vitepress/issues/86)) ([9d6b8ca](https://github.com/vuejs/vitepress/commit/9d6b8cadcc6cd59bde6b9b20037f9038190672ce))\n- support customizing default theme via slots ([b8e892e](https://github.com/vuejs/vitepress/commit/b8e892e94a2fd2cedf7b25651548a08a758ccbdb))\n- add more global and computed properties (#152) ([c6bdcfb](https://github.com/vuejs/vitepress/commit/c6bdcfbf4f14916f20a7192b44941d33d4bee51e)), closes [#152](https://github.com/vuejs/vitepress/issues/152)\n\n# [0.9.0](https://github.com/vuejs/vitepress/compare/v0.8.1...v0.9.0) (2020-11-24)\n\n### Bug Fixes\n\n- avoid 300ms click delay on touch devices ([621ca3e](https://github.com/vuejs/vitepress/commit/621ca3e26f65e13e504724aef76aba3f3361ce81))\n- fix nested list having too much margin ([b0cf2be](https://github.com/vuejs/vitepress/commit/b0cf2be5614505731a3b6dcebeab949c3639c2b2))\n- fix sidebar active status not working as expected ([#140](https://github.com/vuejs/vitepress/issues/140)) ([#149](https://github.com/vuejs/vitepress/issues/149)) ([0b181e7](https://github.com/vuejs/vitepress/commit/0b181e7582ea4be7dca51ec399c697e32b7116f3))\n- make code block look prettier ([#146](https://github.com/vuejs/vitepress/issues/146)) ([242fcc1](https://github.com/vuejs/vitepress/commit/242fcc1098f606f13e7d8e123c081e73a3d89366))\n- some color in code block not working as expected ([#143](https://github.com/vuejs/vitepress/issues/143)) ([da09266](https://github.com/vuejs/vitepress/commit/da09266f5eede3796bb150ccd9d6a173e90354a4))\n\n### Features\n\n- add \"last updated\" feature ([40d204b](https://github.com/vuejs/vitepress/commit/40d204b2f68b90bd2c5e9940cd128c4c16cd5274))\n\n## [0.8.1](https://github.com/vuejs/vitepress/compare/v0.8.0...v0.8.1) (2020-11-20)\n\n### Bug Fixes\n\n- fix \"next and prev link\" not working when `link` has extention ([6dcf6b3](https://github.com/vuejs/vitepress/commit/6dcf6b3796bb3d6e703fddd79c6b0c0a7adfd567))\n- fix \"next and prev links\" not working when the `base` option is set ([#139](https://github.com/vuejs/vitepress/issues/139)) ([018a9b4](https://github.com/vuejs/vitepress/commit/018a9b46d924d0d08f7ff67f18a813348c84ab0a))\n\n# [0.8.0](https://github.com/vuejs/vitepress/compare/v0.7.4...v0.8.0) (2020-11-20)\n\n### Bug Fixes\n\n- exit process with non-zero code on error ([fb09f8e](https://github.com/vuejs/vitepress/commit/fb09f8e638c06aec32494f731554fb1b989daaf0))\n- fix edit link and prev and next links display ([#97](https://github.com/vuejs/vitepress/issues/97)) ([c3b7172](https://github.com/vuejs/vitepress/commit/c3b71729513592112e233165782e60c9c5b425c4))\n- fix next and prev links not working ([#130](https://github.com/vuejs/vitepress/issues/130)) ([fdd498b](https://github.com/vuejs/vitepress/commit/fdd498be70cc09a4331dadd17c4a5339318f21bf))\n- display header-anchor links when using keyboard navigation ([ddc3640](https://github.com/vuejs/vitepress/commit/ddc3640ce66f606894b31e1b7ebeacaaf7b0f1b5))\n- show top part of scrollbar in sidebar ([#129](https://github.com/vuejs/vitepress/issues/129)) ([1ba209a](https://github.com/vuejs/vitepress/commit/1ba209a4d2b606bee1abb7ec1d383467d98cf198))\n\n### Features\n\n- add ability to configure markdown options ([#127](https://github.com/vuejs/vitepress/issues/127)) ([#128](https://github.com/vuejs/vitepress/issues/128)) ([463a03a](https://github.com/vuejs/vitepress/commit/463a03a9815ce8fc9f55293dda07bc211ef4f62b))\n- add serve command ([#136](https://github.com/vuejs/vitepress/issues/136)) ([67868bd](https://github.com/vuejs/vitepress/commit/67868bd9281077a4ce708e666bf61a7824afb8b2))\n- better build command output ([e435eec](https://github.com/vuejs/vitepress/commit/e435eec94a841ab0e1c14d59bb13608d5ad6a011))\n\n## [0.7.4](https://github.com/vuejs/vitepress/compare/v0.7.3...v0.7.4) (2020-11-11)\n\n### Bug Fixes\n\n- **css:** fix padding on mobile ([9c7293b](https://github.com/vuejs/vitepress/commit/9c7293b6cbdbcabb4257793e1b1f3fea2388c31e)), closes [#121](https://github.com/vuejs/vitepress/issues/121)\n\n## [0.7.3](https://github.com/vuejs/vitepress/compare/v0.7.2...v0.7.3) (2020-11-06)\n\n### Bug Fixes\n\n- Fix sidebar page switch layout shifting\n- Fix production hydration mismatch\n\n## [0.7.2](https://github.com/vuejs/vitepress/compare/v0.7.1...v0.7.2) (2020-11-02)\n\n### Bug Fixes\n\n- adapt to vite fix of ssr build asset paths ([6b3fbe3](https://github.com/vuejs/vitepress/commit/6b3fbe31a31adad2a836c45905bde86332e4f1f6))\n\n### Features\n\n- add home page feature ([#108](https://github.com/vuejs/vitepress/issues/108)) ([3a0af0b](https://github.com/vuejs/vitepress/commit/3a0af0b6141ed739aa4a2d72f43d0fa63739c695))\n\n## [0.7.1](https://github.com/vuejs/vitepress/compare/v0.7.0...v0.7.1) (2020-10-30)\n\n### Bug Fixes\n\n- compat with latest vite + handle no export default script tags in md ([b10da2f](https://github.com/vuejs/vitepress/commit/b10da2f47b456a10e62f16e2cd08d6983da041c0))\n- fix switch language error ([#103](https://github.com/vuejs/vitepress/issues/103), [#106](https://github.com/vuejs/vitepress/issues/106)) ([#104](https://github.com/vuejs/vitepress/issues/104)) ([d354d1e](https://github.com/vuejs/vitepress/commit/d354d1ef2211cc8734a7228d56f27b014af7a4f9))\n\n# [0.7.0](https://github.com/vuejs/vitepress/compare/v0.6.0...v0.7.0) (2020-10-19)\n\n### Bug Fixes\n\n- **css:** theme specific ([6891092](https://github.com/vuejs/vitepress/commit/6891092b90d5a405a718b08b30c7be5260adef47))\n- **router:** remove fakeHost when fixing url extenions ([2eb3135](https://github.com/vuejs/vitepress/commit/2eb31358bf4790a08f43c102691df75023382ce5))\n\n### Features\n\n- **client:** add slot for a searchbar ([68d9b18](https://github.com/vuejs/vitepress/commit/68d9b18f391b9ad1dd8d800296a6117119e397b5))\n- **i18n:** add nav dropdown language selector feature ([#91](https://github.com/vuejs/vitepress/issues/91)) ([294836c](https://github.com/vuejs/vitepress/commit/294836ce40afcb9e3af8146575d06bf386bfe1a1))\n- **sidebar:** close when navigating ([2094d53](https://github.com/vuejs/vitepress/commit/2094d534dbe9f84d308fbf130dabbf6155a33005))\n- add doctype html ([02f2e10](https://github.com/vuejs/vitepress/commit/02f2e10f89881d99bf3c016477da788c25ef207f))\n- add some space between 2 code blocks ([5daa8d2](https://github.com/vuejs/vitepress/commit/5daa8d2c38d3c8352b340ad1f5fd4a67d1fdb09b))\n\n# [0.6.0](https://github.com/vuejs/vitepress/compare/v0.5.0...v0.6.0) (2020-09-17)\n\n### Bug Fixes\n\n- **client:** use relative import ([725a04c](https://github.com/vuejs/vitepress/commit/725a04cdf02f208c85de01e4f1e74168511b95aa))\n- **links:** keep relative hash links as is ([a90d971](https://github.com/vuejs/vitepress/commit/a90d971b40d775e2bac19bcfd17cbeafbc878d34))\n- **router:** allow open new tab with ctrl + click ([#69](https://github.com/vuejs/vitepress/issues/69)) ([092ee77](https://github.com/vuejs/vitepress/commit/092ee772dafa78a66c2e35524bd921eb0aa31b16))\n- **sidebar:** no margin on mobile ([#89](https://github.com/vuejs/vitepress/issues/89)) ([218c729](https://github.com/vuejs/vitepress/commit/218c72915489e25e1d6ca7b09979c45abf64a3a3))\n- sidebar not working correctly when path starts with slash ([610cc17](https://github.com/vuejs/vitepress/commit/610cc17af0624d82d0eb3ed652f0b5fa1c2402f0))\n- **sidebar:** fix sidebar when you open a nested link ([#73](https://github.com/vuejs/vitepress/issues/73)) ([d2b6d39](https://github.com/vuejs/vitepress/commit/d2b6d39228a03ad122ab09420dab2cba2c2b4167))\n\n### Features\n\n- add blockquote styling ([8c1aada](https://github.com/vuejs/vitepress/commit/8c1aada6288609c2f01c14f353359a14d1264244))\n- add charset and viewport meta tags ([#77](https://github.com/vuejs/vitepress/issues/77)) ([2e8e1f5](https://github.com/vuejs/vitepress/commit/2e8e1f57cc7618c4cbc198153dde3927b076b08c))\n- add git repo link and edit links ([#55](https://github.com/vuejs/vitepress/issues/55)) ([0ea34cb](https://github.com/vuejs/vitepress/commit/0ea34cbb1de0db8a2ff34bb858c2904c89369ccd))\n- add prev/next links ([#56](https://github.com/vuejs/vitepress/issues/56)) ([f52b1d5](https://github.com/vuejs/vitepress/commit/f52b1d576b024443f737604d2220a0edb1571355))\n- add responsive sidebar support ([#75](https://github.com/vuejs/vitepress/issues/75)) ([39dbd78](https://github.com/vuejs/vitepress/commit/39dbd7806e96e18e60de87311ae7b162ebb61c3c))\n- add table css from vuepress ([#88](https://github.com/vuejs/vitepress/issues/88)) ([8435e36](https://github.com/vuejs/vitepress/commit/8435e36374e2d5c96bbab781f378602e2372f5d4))\n- close the sidebar when clicking outside of the sidebar ([#78](https://github.com/vuejs/vitepress/issues/78)) ([e93ee09](https://github.com/vuejs/vitepress/commit/e93ee094ea5696d692323546738d0643ed82f154))\n- navlinks in sidebar ([#80](https://github.com/vuejs/vitepress/issues/80)) ([a20bcf3](https://github.com/vuejs/vitepress/commit/a20bcf3cd7c4d8e243d6547f099b9fdc702ee350))\n- overwrite prev/next link ([#61](https://github.com/vuejs/vitepress/issues/61)) ([1b96f63](https://github.com/vuejs/vitepress/commit/1b96f631b83585591a1436b8a7dadf52fad61c25))\n- support config alias ([#59](https://github.com/vuejs/vitepress/issues/59)) ([63a3691](https://github.com/vuejs/vitepress/commit/63a36919601df678a0f8225627d66dff67c81c3a))\n- top and bottom slots for sidebar and page ([#90](https://github.com/vuejs/vitepress/issues/90)) ([1106013](https://github.com/vuejs/vitepress/commit/11060136c4bf2ec1d39e0d0d6951b9093e3edc06))\n- **sidebar:** use base when creating link ([#74](https://github.com/vuejs/vitepress/issues/74)) ([79bc9fb](https://github.com/vuejs/vitepress/commit/79bc9fb15a9560932228f22e7bd152272d577da6))\n\n# [0.5.0](https://github.com/vuejs/vitepress/compare/v0.4.1...v0.5.0) (2020-07-21)\n\n### Bug Fixes\n\n- decode hash before selecting ([e782c4c](https://github.com/vuejs/vitepress/commit/e782c4cb86dbb8ff294d0670e171692651618a0e))\n- fix navbar withBase ([e9ab56b](https://github.com/vuejs/vitepress/commit/e9ab56b0dbe859c0a147e2a2755bfcf2c0b92904))\n- typings field in package.json ([#48](https://github.com/vuejs/vitepress/issues/48)) ([692a490](https://github.com/vuejs/vitepress/commit/692a490986ab81eb5be5bc7fdce0434ce84aa620))\n\n### Features\n\n- add external link support for nav items ([#46](https://github.com/vuejs/vitepress/issues/46)) ([44e91bb](https://github.com/vuejs/vitepress/commit/44e91bb98631c843f9accad1cffd24fbc6337fe0))\n- add multi sidebar support ([#38](https://github.com/vuejs/vitepress/issues/38)) ([#49](https://github.com/vuejs/vitepress/issues/49)) ([050fa4c](https://github.com/vuejs/vitepress/commit/050fa4cf245f9f33d25684f8bcf218a6b5d6dedb))\n- i18n support ([#50](https://github.com/vuejs/vitepress/issues/50)) ([7802cb5](https://github.com/vuejs/vitepress/commit/7802cb55c2a82cc1878fc1ebc4dc2fcf1f2f1ff0))\n- nav dropdown ([#51](https://github.com/vuejs/vitepress/issues/51)) ([5780461](https://github.com/vuejs/vitepress/commit/578046145ff4ef445f7a7704016ab791a4ef330f))\n\n## [0.4.1](https://github.com/vuejs/vitepress/compare/v0.4.0...v0.4.1) (2020-07-02)\n\n### Bug Fixes\n\n- avoid error when requesting non-existing md file ([e77ea63](https://github.com/vuejs/vitepress/commit/e77ea6323720f19d7401cb1a9fa94d1963f29e15))\n- resolve relative path on windows ([#27](https://github.com/vuejs/vitepress/issues/27)) ([9116c9c](https://github.com/vuejs/vitepress/commit/9116c9c3e06071f34b523cb488d9e5d963808a3c))\n- use resolve instead of join ([#33](https://github.com/vuejs/vitepress/issues/33)) ([6f10ed6](https://github.com/vuejs/vitepress/commit/6f10ed6c63b7486f678fdd7eedc888925feb473c))\n\n### Features\n\n- add array sidebar support ([#35](https://github.com/vuejs/vitepress/issues/35)) ([4a8388e](https://github.com/vuejs/vitepress/commit/4a8388e113f978f6afc6936a86b06effc42a8304))\n\n# [0.4.0](https://github.com/vuejs/vitepress/compare/v0.3.1...v0.4.0) (2020-06-19)\n\n## [0.3.1](https://github.com/vuejs/vitepress/compare/v0.3.0...v0.3.1) (2020-06-05)\n\n### Bug Fixes\n\n- avoid using **DEV** + throttle active header link ([a63b0cf](https://github.com/vuejs/vitepress/commit/a63b0cf69a4d1f8b1b7e44f76c6283f28d437b59))\n\n# [0.3.0](https://github.com/vuejs/vitepress/compare/v0.2.0...v0.3.0) (2020-06-02)\n\n### Bug Fixes\n\n- lazy load @vue/server-render for production build ([382e1b6](https://github.com/vuejs/vitepress/commit/382e1b6514035f69dc9e505fad38a781cd35166e))\n\n### Features\n\n- active sidebar links ([d2ea963](https://github.com/vuejs/vitepress/commit/d2ea9637eeafc1c1510d038f1f749e650a086a32))\n\n# [0.2.0](https://github.com/vuejs/vitepress/compare/v0.1.1...v0.2.0) (2020-05-22)\n\n### Bug Fixes\n\n- avoid unnecessary prefetches ([0a81525](https://github.com/vuejs/vitepress/commit/0a815255b9f226ec5ac032d6db5b151caa9c58fb))\n- handle links that embed other elements ([#2](https://github.com/vuejs/vitepress/issues/2)) ([4cbfc60](https://github.com/vuejs/vitepress/commit/4cbfc60a58f7b7ef0d82c6a2b1a48b67ace3d924))\n\n### Features\n\n- copy public dir ([ddc9d51](https://github.com/vuejs/vitepress/commit/ddc9d519c60423e2432c1f3c0ab5b2ccbabd34a6))\n- lean builds ([b61e239](https://github.com/vuejs/vitepress/commit/b61e2398fc40be98cd8372834fa3b1e5277c8e1f))\n- prefetch in viewport inbound page chunks ([da4852a](https://github.com/vuejs/vitepress/commit/da4852a61bd73a8b46c4971c330f95761237c733))\n- use hashed page file names ([a873564](https://github.com/vuejs/vitepress/commit/a8735646e8aae04d7091decc8c4fd54025ceb181))\n- use modulepreload links ([0025af1](https://github.com/vuejs/vitepress/commit/0025af12f4ec8e021ea1b7b9d48b0b4025924d83))\n\n### Performance Improvements\n\n- inject script tags for page common chunk imports ([57d900d](https://github.com/vuejs/vitepress/commit/57d900d4b357f15f3dec28e822bd5fd8d100d589))\n\n## 0.1.1 (2020-04-30)\n\n- fix dependency versions\n\n# 0.1.0 (2020-04-30)\n\n### Features\n\n- add markdown processing ([5c47bbb](https://github.com/vuejs/vitepress/commit/5c47bbb4638d7f78ae38fe02732f5b639654c134))\n- spa navigation ([21d3cd8](https://github.com/vuejs/vitepress/commit/21d3cd8cbe4102293d2903c3d060764d86a8f785))\n- update head tags during dev ([bdbbdd5](https://github.com/vuejs/vitepress/commit/bdbbdd556fe7e3906a5997291ff692cf2b78d632))\n- update title & description during dev ([0b9bf27](https://github.com/vuejs/vitepress/commit/0b9bf273ef4f31bf448f7813c50e474b4035b7dc))\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019-present, Yuxi (Evan) You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# VitePress 📝💨\n\n[![test](https://github.com/vuejs/vitepress/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/vuejs/vitepress/actions/workflows/test.yml)\n[![npm](https://img.shields.io/npm/v/vitepress/next)](https://www.npmjs.com/package/vitepress/v/next)\n[![nightly releases](https://img.shields.io/badge/nightly-releases-orange)](https://nightly.akryum.dev/vuejs/vitepress)\n[![chat](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://chat.vuejs.org)\n\n---\n\nVitePress is a Vue-powered static site generator and a spiritual successor to [VuePress](https://vuepress.vuejs.org), built on top of [Vite](https://github.com/vitejs/vite).\n\n## Documentation\n\nTo check out docs, visit [vitepress.dev](https://vitepress.dev).\n\n## Changelog\n\nDetailed changes for each release are documented in the [CHANGELOG](https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md).\n\n## Contribution\n\nPlease make sure to read the [Contributing Guide](https://github.com/vuejs/vitepress/blob/main/.github/contributing.md) before making a pull request.\n\n## License\n\n[MIT](https://github.com/vuejs/vitepress/blob/main/LICENSE)\n\nCopyright (c) 2019-present, Yuxi (Evan) You\n\n## Special Thanks\n\nThis project would not be possible without the support of these amazing companies and tools.\n\n|                                                                                                                                             |                                              |                                                                                                                                                                                                        |\n| ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| <a href=\"https://voidzero.dev\" target=\"_blank\"><img alt=\"VoidZero's logo\" src=\"https://github.com/voidzero-dev.png\" width=\"80\" /></a>         | **[VoidZero](https://voidzero.dev)**         | The company behind Vite, Vitest, Rolldown, and Oxc. VoidZero has been a long-time sponsor of VitePress. VitePress itself is built on top of this ecosystem of high-performance JavaScript tooling.     |\n| <a href=\"https://stackblitz.com\" target=\"_blank\"><img alt=\"StackBlitz's logo\" src=\"https://github.com/stackblitz.png\" width=\"80\" /></a>       | **[StackBlitz](https://stackblitz.com)**     | Creators of WebContainers and a browser-based development platform. Their technology powers the VitePress playground and provides instant preview releases for our pull requests and commits.          |\n| <a href=\"https://algolia.com\" target=\"_blank\"><img alt=\"Algolia's logo\" src=\"https://github.com/algolia.png\" width=\"80\" /></a>                | **[Algolia](https://algolia.com)**           | An AI-powered search platform that provides fast, scalable search. Algolia powers DocSearch for VitePress. Their team has been a long-time partner in building and maintaining our search integration. |\n| <a href=\"https://browserstack.com\" target=\"_blank\"><img alt=\"BrowserStack's logo\" src=\"https://github.com/browserstack.png\" width=\"80\" /></a> | **[BrowserStack](https://browserstack.com)** | A cloud-based testing platform for websites and mobile apps. BrowserStack provides the cross-browser and real-device infrastructure used to ensure VitePress works consistently across all browsers.   |\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/config.ts",
    "content": "import { defineConfig, type DefaultTheme } from 'vitepress'\n\nconst nav: DefaultTheme.Config['nav'] = [\n  {\n    text: 'Home',\n    link: '/'\n  },\n  {\n    text: 'API Reference',\n    items: [\n      {\n        text: 'Example',\n        link: '/home.html'\n      },\n      {\n        component: 'ApiPreference',\n        props: {\n          options: ['JavaScript', 'TypeScript', 'Flow'],\n          defaultOption: 'TypeScript'\n        }\n      },\n      {\n        component: 'ApiPreference',\n        props: {\n          options: ['Options', 'Composition'],\n          defaultOption: 'Composition'\n        }\n      }\n    ]\n  },\n  {\n    component: 'NavVersion',\n    props: {\n      versions: [\n        {\n          text: 'v1.x',\n          link: '/'\n        },\n        {\n          text: 'v0.x',\n          link: '/v0.x/'\n        }\n      ]\n    }\n  },\n  {\n    text: 'Nested',\n    items: [\n      {\n        text: 'Level 1 - 1',\n        items: [\n          {\n            text: 'Level 2 - 1',\n            link: '/nested/level1-1/level2-1'\n          }\n        ]\n      },\n      {\n        text: 'Level 1 - 2',\n        items: [\n          {\n            text: 'Level 2 - 2',\n            link: '/nested/level1-2/level2-2'\n          }\n        ]\n      }\n    ]\n  }\n]\n\nconst sidebar: DefaultTheme.Config['sidebar'] = {\n  '/': [\n    {\n      text: 'Frontmatter',\n      collapsed: false,\n      items: [\n        {\n          text: 'Multiple Levels Outline',\n          link: '/frontmatter/multiple-levels-outline'\n        }\n      ]\n    },\n    {\n      text: '& &#60;Text Literals &> <code>code</code>',\n      items: [\n        {\n          text: '& &#60;Test Page &> <code>code</code>',\n          link: '/text-literals/'\n        }\n      ]\n    },\n    {\n      text: 'Data Loading',\n      items: [\n        {\n          text: 'Test Page',\n          link: '/data-loading/data'\n        }\n      ]\n    },\n    {\n      text: 'Multi Sidebar Test',\n      items: [\n        {\n          text: 'Test Page',\n          link: '/multi-sidebar/'\n        }\n      ]\n    },\n    {\n      text: 'Dynamic Routes',\n      items: [\n        {\n          text: 'Foo',\n          link: '/dynamic-routes/foo'\n        },\n        {\n          text: 'Bar',\n          link: '/dynamic-routes/bar'\n        }\n      ]\n    },\n    {\n      text: 'Markdown Extensions',\n      items: [\n        {\n          text: 'Test Page',\n          link: '/markdown-extensions/'\n        },\n        {\n          text: 'Foo',\n          link: '/markdown-extensions/foo'\n        }\n      ]\n    }\n  ],\n  '/multi-sidebar/': [\n    {\n      text: 'Multi Sidebar',\n      items: [\n        {\n          text: 'Test Page',\n          link: '/multi-sidebar/'\n        },\n        {\n          text: 'Back',\n          link: '/'\n        }\n      ]\n    }\n  ]\n}\n\nexport default defineConfig({\n  title: 'Example',\n  description: 'An example app using VitePress.',\n  markdown: {\n    image: {\n      lazyLoading: true\n    }\n  },\n  themeConfig: {\n    nav,\n    sidebar,\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('local-search/excluded')) return ''\n          return html\n        }\n      }\n    }\n  },\n  vite: {\n    server: {\n      watch: {\n        usePolling: true,\n        interval: 100\n      }\n    }\n  }\n})\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/theme/components/ApiPreference.vue",
    "content": "<script setup lang=\"ts\">\nimport { useLocalStorage } from '@vueuse/core'\n\nconst props = defineProps<{\n  options: string[]\n  defaultOption: string\n  screenMenu?: boolean\n}>()\n\n// reactivity isn't needed for props here\n\nconst key = removeSpaces(`api-preference-${props.options.join('-')}`)\nconst name = key + (props.screenMenu ? '-screen-menu' : '')\n\nconst selected = useLocalStorage(key, () => props.defaultOption)\n\nconst optionsWithKeys = props.options.map((option) => ({\n  key: name + '-' + removeSpaces(option),\n  value: option\n}))\n\nfunction removeSpaces(str: string) {\n  return str.replace(/\\s/g, '_')\n}\n</script>\n\n<template>\n  <div class=\"VPApiPreference\" :class=\"{ 'screen-menu': screenMenu }\">\n    <template v-for=\"option in optionsWithKeys\" :key=\"option\">\n      <input\n        type=\"radio\"\n        :id=\"option.key\"\n        :name\n        :value=\"option.value\"\n        v-model=\"selected\"\n      />\n      <label :for=\"option.key\">{{ option.value }}</label>\n    </template>\n  </div>\n</template>\n\n<style scoped>\n.VPApiPreference {\n  display: flex;\n  margin: 12px 0;\n  border: 1px solid var(--vp-c-border);\n  border-radius: 6px;\n  font-size: 14px;\n  color: var(--vp-c-text-1);\n}\n\n.VPApiPreference:first-child {\n  margin-top: 0;\n}\n\n.VPApiPreference:last-child {\n  margin-bottom: 0;\n}\n\n.VPApiPreference.screen-menu {\n  margin: 12px 0 0 12px;\n}\n\n.VPApiPreference input[type='radio'] {\n  pointer-events: none;\n  position: fixed;\n  opacity: 0;\n}\n\n.VPApiPreference label {\n  flex: 1;\n  margin: 2px;\n  padding: 4px 12px;\n  cursor: pointer;\n  border-radius: 4px;\n  text-align: center;\n}\n\n.VPApiPreference input[type='radio']:checked + label {\n  background-color: var(--vp-c-default-soft);\n  color: var(--vp-c-brand-1);\n}\n</style>\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/theme/components/CustomLayout.vue",
    "content": "<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport HomeHeroCopy from './HomeHeroCopy.vue'\n\nconst INSTALL_COMMAND = 'npx vitepress init'\n</script>\n\n<template>\n  <DefaultTheme.Layout>\n    <template #home-hero-actions-before-actions>\n      <HomeHeroCopy :command=\"INSTALL_COMMAND\" />\n    </template>\n  </DefaultTheme.Layout>\n</template>\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/theme/components/HomeHeroCopy.vue",
    "content": "<script setup lang=\"ts\">\n  import { ref } from 'vue'\n\n  const props = defineProps<{\n    command: string\n  }>()\n\n  const copied = ref(false)\n\n  async function copy () {\n    try {\n      await navigator.clipboard.writeText(props.command)\n      copied.value = true\n      setTimeout(() => {\n        copied.value = false\n      }, 2000)\n    } catch (error) {\n      console.error('Failed to copy', error)\n    }\n  }\n</script>\n\n<template>\n  <div\n    class=\"hero-copy-btn\"\n    :class=\"{ copied }\"\n    role=\"button\"\n    tabindex=\"0\"\n    @click=\"copy\"\n    @keydown.enter=\"copy\"\n    @keydown.space.prevent=\"copy\"\n  >\n    <div class=\"content\">\n      <span class=\"prompt\">$</span>\n      <span class=\"command\">{{ command }}</span>\n    </div>\n    <div class=\"icon-wrapper\">\n      <transition mode=\"out-in\" name=\"fade\">\n        <svg\n          v-if=\"!copied\"\n          class=\"lucide lucide-copy\"\n          fill=\"none\"\n          height=\"18\"\n          stroke=\"currentColor\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n          stroke-width=\"2\"\n          viewBox=\"0 0 24 24\"\n          width=\"18\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n        >\n          <rect\n            height=\"14\"\n            rx=\"2\"\n            ry=\"2\"\n            width=\"14\"\n            x=\"8\"\n            y=\"8\"\n          />\n          <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n        </svg>\n        <svg\n          v-else\n          class=\"lucide lucide-check\"\n          fill=\"none\"\n          height=\"18\"\n          stroke=\"currentColor\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n          stroke-width=\"2\"\n          viewBox=\"0 0 24 24\"\n          width=\"18\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n        >\n          <path d=\"M20 6 9 17l-5-5\" />\n        </svg>\n      </transition>\n    </div>\n    <transition name=\"slide-up\">\n      <div v-if=\"copied\" class=\"tooltip\">Copied!</div>\n    </transition>\n  </div>\n</template>\n\n<style scoped>\n.hero-copy-btn {\n  margin-bottom: 32px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n  background: var(--vp-c-bg-soft);\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 8px;\n  padding: 0 16px;\n  height: 48px;\n  cursor: pointer;\n  transition: all 0.25s ease;\n  position: relative;\n  user-select: none;\n  max-width: calc(100vw - 2 * 24px);\n  width: 100%;\n}\n\n.hero-copy-btn:hover {\n  border-color: var(--vp-c-brand-1);\n  background: var(--vp-c-bg-mute);\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n  transform: translateY(-1px);\n}\n\n.hero-copy-btn:active {\n  transform: translateY(0);\n}\n\n.hero-copy-btn.copied {\n  border-color: var(--vp-c-green-1);\n  background: var(--vp-c-green-dimm-1);\n}\n\n.content {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  font-family: var(--vp-font-family-mono);\n  font-size: 14px;\n  color: var(--vp-c-text-2);\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  flex: 1;\n}\n\n.prompt {\n  color: var(--vp-c-text-3);\n  user-select: none;\n  font-weight: 600;\n}\n\n.command {\n  color: var(--vp-c-text-1);\n  font-weight: 500;\n}\n\n.icon-wrapper {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: var(--vp-c-text-3);\n  transition: color 0.2s;\n  flex-shrink: 0;\n}\n\n.hero-copy-btn:hover .icon-wrapper {\n  color: var(--vp-c-text-1);\n}\n\n.hero-copy-btn.copied .icon-wrapper {\n  color: var(--vp-c-green-1);\n}\n\n.tooltip {\n  position: absolute;\n  top: -36px;\n  right: 0;\n  background: var(--vp-c-text-1);\n  color: var(--vp-c-bg);\n  padding: 6px 10px;\n  border-radius: 6px;\n  font-size: 12px;\n  font-weight: 600;\n  pointer-events: none;\n  box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n  z-index: 10;\n}\n\n/* Tooltip arrow */\n.tooltip::after {\n  content: '';\n  position: absolute;\n  bottom: -4px;\n  right: 12px;\n  width: 8px;\n  height: 8px;\n  background: var(--vp-c-text-1);\n  transform: rotate(45deg);\n}\n\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n  opacity: 0;\n  transform: scale(0.8);\n}\n\n.slide-up-enter-active,\n.slide-up-leave-active {\n  transition: all 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);\n}\n\n.slide-up-enter-from,\n.slide-up-leave-to {\n  opacity: 0;\n  transform: translateY(10px);\n}\n</style>\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/theme/components/NavVersion.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useRoute } from 'vitepress'\nimport VPNavBarMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavBarMenuGroup.vue'\nimport VPNavScreenMenuGroup from 'vitepress/dist/client/theme-default/components/VPNavScreenMenuGroup.vue'\n\nconst props = defineProps<{\n  versions: { text: string; link: string }[]\n  screenMenu?: boolean\n}>()\n\nconst route = useRoute()\n\nconst sortedVersions = computed(() => {\n  return [...props.versions].sort(\n    (a, b) => b.link.split('/').length - a.link.split('/').length\n  )\n})\n\nconst currentVersion = computed(() => {\n  return (\n    sortedVersions.value.find((version) => route.path.startsWith(version.link))\n      ?.text || 'Versions'\n  )\n})\n</script>\n\n<template>\n  <VPNavBarMenuGroup\n    v-if=\"!screenMenu\"\n    :item=\"{ text: currentVersion, items: versions }\"\n    class=\"VPNavVersion\"\n  />\n  <VPNavScreenMenuGroup\n    v-else\n    :text=\"currentVersion\"\n    :items=\"versions\"\n    class=\"VPNavVersion\"\n  />\n</template>\n\n<style scoped>\n.VPNavVersion :deep(button .text) {\n  color: var(--vp-c-text-1) !important;\n}\n\n.VPNavVersion:hover :deep(button .text) {\n  color: var(--vp-c-text-2) !important;\n}\n</style>\n"
  },
  {
    "path": "__tests__/e2e/.vitepress/theme/index.ts",
    "content": "import type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport CustomLayout from './components/CustomLayout.vue'\nimport ApiPreference from './components/ApiPreference.vue'\nimport NavVersion from './components/NavVersion.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout: CustomLayout,\n  enhanceApp({ app }) {\n    app.component('ApiPreference', ApiPreference)\n    app.component('NavVersion', NavVersion)\n  }\n} satisfies Theme\n"
  },
  {
    "path": "__tests__/e2e/__snapshots__/home.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`render correct content > main content 1`] = `\n[\n  \"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\",\n  \"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\",\n  \"Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\",\n  \"The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from \"de Finibus Bonorum et Malorum\" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.\",\n  \"It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).\",\n  \"There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.\",\n]\n`;\n"
  },
  {
    "path": "__tests__/e2e/data-loading/basic.data.mts",
    "content": "import fs from 'node:fs'\nimport { defineLoader } from 'vitepress'\n\ntype Data = Record<string, boolean>[]\nexport declare const data: Data\n\nexport default defineLoader({\n  watch: ['./data/*'],\n  async load(files: string[]): Promise<Data> {\n    const data: Data = []\n    for (const file of files.sort().filter((file) => file.endsWith('.json'))) {\n      data.push(JSON.parse(fs.readFileSync(file, 'utf-8')))\n    }\n    return data\n  }\n})\n"
  },
  {
    "path": "__tests__/e2e/data-loading/content/bar.md",
    "content": "---\ntitle: bar\n---\n\nHello\n\n---\n\nworld\n"
  },
  {
    "path": "__tests__/e2e/data-loading/content/foo.md",
    "content": "---\ntitle: foo\n---\n\nHello\n\n---\n\nworld\n"
  },
  {
    "path": "__tests__/e2e/data-loading/contentLoader.data.ts",
    "content": "import { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('data-loading/content/*.md', {\n  includeSrc: true,\n  excerpt: true,\n  render: true,\n  transform(data) {\n    return data.map((item) => ({\n      ...item,\n      transformed: true\n    }))\n  }\n})\n"
  },
  {
    "path": "__tests__/e2e/data-loading/data/a.json",
    "content": "{\n  \"a\": true\n}\n"
  },
  {
    "path": "__tests__/e2e/data-loading/data/b.json",
    "content": "{\n  \"b\": true\n}\n"
  },
  {
    "path": "__tests__/e2e/data-loading/data.md",
    "content": "# Static Data\n\n<script setup lang=\"ts\">\nimport { data } from './basic.data.mjs'\nimport { data as contentData } from './contentLoader.data.js'\n</script>\n\n<pre id=\"basic\">{{ data }}</pre>\n\n<pre id=\"content\">{{ contentData }}</pre>\n"
  },
  {
    "path": "__tests__/e2e/data-loading/data.test.ts",
    "content": "import fs from 'node:fs/promises'\nimport { fileURLToPath } from 'node:url'\n\ndescribe('static data file support in vite 3', () => {\n  beforeAll(async () => {\n    await goto('/data-loading/data')\n  })\n\n  test('render correct content', async () => {\n    expect(await page.textContent('pre#basic')).toMatchInlineSnapshot(`\n      \"[\n        {\n          \"a\": true\n        },\n        {\n          \"b\": true\n        }\n      ]\"\n    `)\n    expect(await page.textContent('pre#content')).toMatchInlineSnapshot(`\n      \"[\n        {\n          \"src\": \"---\\\\ntitle: bar\\\\n---\\\\n\\\\nHello\\\\n\\\\n---\\\\n\\\\nworld\\\\n\",\n          \"html\": \"<p>Hello</p>\\\\n<hr>\\\\n<p>world</p>\\\\n\",\n          \"frontmatter\": {\n            \"title\": \"bar\"\n          },\n          \"excerpt\": \"<p>Hello</p>\\\\n\",\n          \"url\": \"/data-loading/content/bar.html\",\n          \"transformed\": true\n        },\n        {\n          \"src\": \"---\\\\ntitle: foo\\\\n---\\\\n\\\\nHello\\\\n\\\\n---\\\\n\\\\nworld\\\\n\",\n          \"html\": \"<p>Hello</p>\\\\n<hr>\\\\n<p>world</p>\\\\n\",\n          \"frontmatter\": {\n            \"title\": \"foo\"\n          },\n          \"excerpt\": \"<p>Hello</p>\\\\n\",\n          \"url\": \"/data-loading/content/foo.html\",\n          \"transformed\": true\n        }\n      ]\"\n    `)\n  })\n\n  test.runIf(!process.env.VITE_TEST_BUILD)('hmr works', async () => {\n    const a = fileURLToPath(new URL('./data/a.json', import.meta.url))\n    const b = fileURLToPath(new URL('./data/b.json', import.meta.url))\n\n    try {\n      await fs.writeFile(a, JSON.stringify({ a: false }, null, 2) + '\\n')\n      await page.waitForFunction(\n        () =>\n          document.querySelector('pre#basic')?.textContent ===\n          JSON.stringify([{ a: false }, { b: true }], null, 2)\n      )\n    } finally {\n      await fs.writeFile(a, JSON.stringify({ a: true }, null, 2) + '\\n')\n    }\n\n    let err = true\n\n    try {\n      await fs.unlink(b)\n      await page.waitForFunction(\n        () =>\n          document.querySelector('pre#basic')?.textContent ===\n          JSON.stringify([{ a: true }], null, 2)\n      )\n      err = false\n    } finally {\n      if (err) {\n        await fs.writeFile(b, JSON.stringify({ b: true }, null, 2) + '\\n')\n      }\n    }\n\n    try {\n      await fs.writeFile(b, JSON.stringify({ b: false }, null, 2) + '\\n')\n      await page.waitForFunction(\n        () =>\n          document.querySelector('pre#basic')?.textContent ===\n          JSON.stringify([{ a: true }, { b: false }], null, 2)\n      )\n    } finally {\n      await fs.writeFile(b, JSON.stringify({ b: true }, null, 2) + '\\n')\n    }\n  })\n\n  /*\n    MODIFY a.json with { a: false }\n    this should trigger a hmr update and the content should be updated to [{ a: false }, { b: true }]\n    reset a.json\n\n    DELETE b.json\n    this should trigger a hmr update and the content should be updated to [{ a: true }]\n    reset b.json if failed\n\n    CREATE b.json with { b: false }\n    this should trigger a hmr update and the content should be updated to [{ a: true }, { b: false }]\n    reset b.json\n  */\n})\n"
  },
  {
    "path": "__tests__/e2e/dynamic-routes/[id].md",
    "content": "<!-- @content -->\n\n<pre class=\"params\">{{ $params }}</pre>\n"
  },
  {
    "path": "__tests__/e2e/dynamic-routes/[id].paths.ts",
    "content": "import { defineRoutes } from 'vitepress'\nimport paths from './paths'\n\nexport default defineRoutes({\n  async paths(watchedFiles: string[]) {\n    // console.log('watchedFiles', watchedFiles)\n    return paths\n  },\n  watch: ['../data-loading/**/*.json'],\n  async transformPageData(pageData) {\n    // console.log('transformPageData', pageData.filePath)\n    pageData.title += ' - transformed'\n  }\n})\n"
  },
  {
    "path": "__tests__/e2e/dynamic-routes/dynamic-routes.test.ts",
    "content": "describe('dynamic routes', () => {\n  test('render correct content', async () => {\n    await goto('/dynamic-routes/foo')\n    expect(await page.textContent('h1')).toMatch('Foo')\n    expect(await page.textContent('pre.params')).toMatch('\"id\": \"foo\"')\n\n    await goto('/dynamic-routes/bar')\n    expect(await page.textContent('h1')).toMatch('Bar')\n    expect(await page.textContent('pre.params')).toMatch('\"id\": \"bar\"')\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/dynamic-routes/paths.ts",
    "content": "export default [\n  { params: { id: 'foo' }, content: `# Foo` },\n  { params: { id: 'bar' }, content: `# Bar` }\n]\n"
  },
  {
    "path": "__tests__/e2e/frontmatter/multiple-levels-outline.md",
    "content": "---\ntitle: Multiple Levels Outline\neditLink: true\noutline: deep\n---\n\n# h1 - 1\n\nLorem ipsum\n\n## h2 - 1\n\nLorem ipsum\n\n### h3 - 1\n\nLorem ipsum\n\n#### h4 - 1\n\nLorem ipsum\n\n### h3 - 2\n\nLorem ipsum\n\n#### h4 - 2\n\nLorem ipsum\n\n## h2 - 2\n\nLorem ipsum\n\n### h3 - 3\n\nLorem ipsum\n\n#### h4 - 3\n\nLorem ipsum\n"
  },
  {
    "path": "__tests__/e2e/frontmatter/multiple-levels-outline.test.ts",
    "content": "describe('outline', () => {\n  beforeAll(async () => {\n    await goto('/frontmatter/multiple-levels-outline')\n  })\n\n  test('set outline to deep', async () => {\n    const outlineLinksLocator = page.locator('.VPDocAsideOutline .outline-link')\n\n    const outlineLinksContent = await outlineLinksLocator.allTextContents()\n    expect(outlineLinksContent).toEqual([\n      'h2 - 1',\n      'h3 - 1',\n      'h4 - 1',\n      'h3 - 2',\n      'h4 - 2',\n      'h2 - 2',\n      'h3 - 3',\n      'h4 - 3'\n    ])\n\n    const linkHrefs = await outlineLinksLocator.evaluateAll((element) =>\n      element.map((element) => element.getAttribute('href'))\n    )\n\n    expect(linkHrefs).toEqual([\n      '#h2-1',\n      '#h3-1',\n      '#h4-1',\n      '#h3-2',\n      '#h4-2',\n      '#h2-2',\n      '#h3-3',\n      '#h4-3'\n    ])\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/home.md",
    "content": "# Lorem Ipsum\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n## What is Lorem Ipsum?\n\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n\n## Where does it come from?\n\nContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.\n\nThe standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from \"de Finibus Bonorum et Malorum\" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.\n\n## Why do we use it?\n\nIt is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).\n\n## Where can I get some?\n\nThere are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.\n"
  },
  {
    "path": "__tests__/e2e/home.test.ts",
    "content": "describe('render correct content', async () => {\n  beforeAll(async () => {\n    await goto('/home')\n  })\n\n  test('main content', async () => {\n    const h1Locator = page.locator('.VPContent h1')\n    const h2Locator = page.locator('.VPContent h2')\n    const pLocator = page.locator('.VPContent p')\n\n    const [h1Contents, h2Contents, pContents] = await Promise.all([\n      h1Locator.allTextContents(),\n      h2Locator.allTextContents(),\n      pLocator.allTextContents()\n    ])\n\n    expect(h1Contents).toEqual(['Lorem Ipsum \\u200b'])\n    expect(h2Contents.map((s) => s.trim())).toEqual([\n      'What is Lorem Ipsum? \\u200b',\n      'Where does it come from? \\u200b',\n      'Why do we use it? \\u200b',\n      'Where can I get some? \\u200b'\n    ])\n    expect(pContents).toMatchSnapshot()\n  })\n\n  test('outline', async () => {\n    const outlineLinksLocator = page.locator(\n      '.VPDocAsideOutline .root .outline-link'\n    )\n\n    const outlineLinksCount = await outlineLinksLocator.count()\n    expect(outlineLinksCount).toEqual(4)\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/index.md",
    "content": "---\nlayout: home\n\ntitle: VitePress\n\nhero:\n  name: VitePress\n  text: Vite & Vue Powered Static Site Generator\n  image:\n    src: /vitepress-logo.svg\n    alt: VitePress\n\n  actions:\n    - theme: brand\n      text: Examples\n      link: /home\n\nfeatures:\n  - title: Emoji\n    details: Emoji on features section\n    icon: ⚡️\n  - title: SVG\n    details: SVG on features section\n    icon:\n      src: /vitepress.svg\n      alt: VitePress Logo\n  - title: PNG\n    details: PNG on features section\n    icon:\n      src: /vitepress.png\n      width: 48\n      height: 48\n      alt: VitePress Logo\n  - title: Dark/Light SVG\n    details: Dark/Light SVG on features section\n    icon:\n      dark: /pwa_dark.svg\n      light: /pwa_light.svg\n      alt: Vite PWA Logo\n---\n"
  },
  {
    "path": "__tests__/e2e/local-search/excluded.md",
    "content": "# Local search config excluded"
  },
  {
    "path": "__tests__/e2e/local-search/frontmatter-excluded.md",
    "content": "---\nsearch: false\n---\n\n# Local search frontmatter excluded"
  },
  {
    "path": "__tests__/e2e/local-search/index.md",
    "content": "# Local search included"
  },
  {
    "path": "__tests__/e2e/local-search/local-search.test.ts",
    "content": "describe('local search', () => {\n  beforeEach(async () => {\n    await goto('/')\n  })\n\n  test('exclude content from search results', async () => {\n    await page.locator('.VPNavBarSearchButton').click()\n\n    const input = await page.waitForSelector('input#localsearch-input')\n    await input.type('local')\n\n    await page.waitForSelector('ul#localsearch-list', { state: 'visible' })\n\n    const searchResults = page.locator('#localsearch-list')\n    expect(await searchResults.locator('li[role=option]').count()).toBe(1)\n\n    expect(\n      await searchResults.filter({ hasText: 'Local search included' }).count()\n    ).toBe(1)\n\n    expect(\n      await searchResults.filter({ hasText: 'Local search excluded' }).count()\n    ).toBe(0)\n\n    expect(\n      await searchResults\n        .filter({ hasText: 'Local search frontmatter excluded' })\n        .count()\n    ).toBe(0)\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/bar.md",
    "content": "# Bar\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/foo.md",
    "content": "# Foo\n\nThis is before region\n\n<!-- #region snippet -->\n## Region\n\nThis is a region\n<!-- #endregion snippet -->\n\nThis is after region\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/header-include.md",
    "content": "# header 1\n\nheader 1 content\n\n## header 1.1\n\nheader 1.1 content\n\n### header 1.1.1\n\nheader 1.1.1 content\n\n### header 1.1.2\n\nheader 1.1.2 content\n\n## header 1.2\n\nheader 1.2 content\n\n### header 1.2.1\n\nheader 1.2.1 content\n\n### header 1.2.2\n\nheader 1.2.2 content\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/index.md",
    "content": "# Markdown Extensions\n\n## Links\n\n### Internal Links\n\n- [home](/)\n- [markdown-extensions](/markdown-extensions/)\n- [heading](./#internal-links)\n- [omit extension](./foo)\n- [.md extension](./foo.md)\n- [.html extension](./foo.html)\n\n### External Links\n\n[VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## GitHub-Style Tables\n\n| Tables        |      Are      |   Cool |\n| ------------- | :-----------: | -----: |\n| col 3 is      | right-aligned | \\$1600 |\n| col 2 is      |   centered    |   \\$12 |\n| zebra stripes |   are neat    |    \\$1 |\n\n## Emoji\n\n- :tada:\n- :100:\n\n## Table of Contents\n\n[[toc]]\n\n## Custom Containers\n\n### Default Title\n\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n\n### Custom Title\n\n::: danger STOP\nDanger zone, do not proceed\n:::\n\n::: details Click me to view the code\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n\n## Line Highlighting in Code Blocks\n\n### Single Line\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n\n### Multiple single lines, ranges\n\n```js{1,4,6-8}\nexport default {\n  data () {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\n### Comment Highlight\n\n```js\nexport default { // [!code focus]\n  data() { // [!code hl]\n    return {\n      msg: 'Removed' // [!code --]\n      msg: 'Added' // [!code ++]\n      msg: 'Error', // [!code error]\n      msg: 'Warning' // [!code warning]\n    }\n  }\n}\n```\n\n## Line Numbers\n\n```ts:line-numbers\nconst line1 = 'This is line 1'\nconst line2 = 'This is line 2'\n```\n\n## Import Code Snippets\n\n### Basic Code Snippet\n\n<<< @/markdown-extensions/foo.md\n\n### Specify Region\n\n<<< @/markdown-extensions/foo.md#snippet\n\n### With Other Features\n\n<<< @/markdown-extensions/foo.md#snippet{1 ts:line-numbers} [snippet with region]\n\n## Code Groups\n\n### Basic Code Group\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\n### With Other Features\n\n::: code-group\n\n<<< @/markdown-extensions/foo.md\n\n<<< @/markdown-extensions/foo.md#snippet{1 ts:line-numbers} [snippet with region]\n\n:::\n\n## Markdown File Inclusion\n\n<!--@include: ./foo.md-->\n\n## Markdown At File Inclusion\n\n<!--@include: @/markdown-extensions/bar.md-->\n\n## Markdown Nested File Inclusion\n\n<!--@include: ./nested-include.md-->\n\n## Markdown File Inclusion with Range\n\n<!--@include: ./foo.md{6,8}-->\n\n## Markdown File Inclusion with Range without Start\n\n<!--@include: ./foo.md{,8}-->\n\n## Markdown File Inclusion with Range without End\n\n<!--@include: ./foo.md{6,}-->\n\n## Markdown At File Region Snippet\n\n<!--@include: ./region-include.md#snippet-->\n\n## Markdown At File Range Region Snippet\n\n<!--@include: ./region-include.md#range-region{3,4}-->\n\n## Markdown At File Range Region Snippet without start\n\n<!--@include: ./region-include.md#range-region{,2}-->\n\n## Markdown At File Range Region Snippet without end\n\n<!--@include: ./region-include.md#range-region{5,}-->\n\n## Markdown File Inclusion with Header\n\n<!--@include: ./header-include.md#header-1-1-->\n\n## Image Lazy Loading\n\n![vitepress logo](/vitepress.png)\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/markdown-extensions.test.ts",
    "content": "import type { Locator } from 'playwright-chromium'\n\nconst getClassList = async (locator: Locator) => {\n  const className = await locator.getAttribute('class')\n  return className?.split(' ').filter(Boolean) ?? []\n}\n\nconst trim = (str?: string | null) => str?.replace(/\\u200B/g, '').trim()\n\nbeforeEach(async () => {\n  await goto('/markdown-extensions/')\n})\n\ndescribe('Links', () => {\n  test('render internal link', async () => {\n    const targetMap = Object.entries({\n      home: '/',\n      'markdown-extensions': '/markdown-extensions/',\n      heading: './#internal-links',\n      'omit extension': './foo.html',\n      '.md extension': './foo.html',\n      '.html extension': './foo.html'\n    })\n\n    const items = page.locator('#internal-links +ul a')\n    const count = await items.count()\n    expect(count).toBe(6)\n\n    for (let i = 0; i < count; i++) {\n      const [text, href] = targetMap[i]\n      expect(await items.nth(i).textContent()).toBe(text)\n      expect(await items.nth(i).getAttribute('href')).toBe(href)\n    }\n  })\n\n  test('external link get target=\"_blank\" and rel=\"noreferrer\"', async () => {\n    const link = page.locator('#external-links + p a')\n    expect(await link.getAttribute('target')).toBe('_blank')\n    expect(await link.getAttribute('rel')).toBe('noreferrer')\n  })\n})\n\ndescribe('GitHub-Style Tables', () => {\n  test('render table', async () => {\n    const table = page.locator('#github-style-tables + table')\n    expect(table).toBeTruthy()\n  })\n})\n\ndescribe('Emoji', () => {\n  test('render emoji', async () => {\n    const emojis = ['🎉', '💯']\n\n    const items = page.locator('#emoji + ul li')\n    const count = await items.count()\n    expect(count).toBe(2)\n\n    for (let i = 0; i < count; i++) {\n      expect(await items.nth(i).textContent()).toBe(emojis[i])\n    }\n  })\n})\n\ndescribe('Table of Contents', () => {\n  test('render toc', async () => {\n    const items = page.locator('#table-of-contents + nav ul li')\n    expect(\n      await items.evaluateAll((elements) =>\n        elements.map((el) => el.childNodes[0].textContent)\n      )\n    ).toMatchInlineSnapshot(`\n      [\n        \"Links\",\n        \"Internal Links\",\n        \"External Links\",\n        \"GitHub-Style Tables\",\n        \"Emoji\",\n        \"Table of Contents\",\n        \"Custom Containers\",\n        \"Default Title\",\n        \"Custom Title\",\n        \"Line Highlighting in Code Blocks\",\n        \"Single Line\",\n        \"Multiple single lines, ranges\",\n        \"Comment Highlight\",\n        \"Line Numbers\",\n        \"Import Code Snippets\",\n        \"Basic Code Snippet\",\n        \"Specify Region\",\n        \"With Other Features\",\n        \"Code Groups\",\n        \"Basic Code Group\",\n        \"With Other Features\",\n        \"Markdown File Inclusion\",\n        \"Region\",\n        \"Markdown At File Inclusion\",\n        \"Markdown Nested File Inclusion\",\n        \"Region\",\n        \"After Foo\",\n        \"Sub sub\",\n        \"Sub sub sub\",\n        \"Markdown File Inclusion with Range\",\n        \"Region\",\n        \"Markdown File Inclusion with Range without Start\",\n        \"Region\",\n        \"Markdown File Inclusion with Range without End\",\n        \"Region\",\n        \"Markdown At File Region Snippet\",\n        \"Region Snippet\",\n        \"Markdown At File Range Region Snippet\",\n        \"Range Region Line 2\",\n        \"Markdown At File Range Region Snippet without start\",\n        \"Range Region Line 1\",\n        \"Markdown At File Range Region Snippet without end\",\n        \"Range Region Line 3\",\n        \"Markdown File Inclusion with Header\",\n        \"header 1.1.1\",\n        \"header 1.1.2\",\n        \"Image Lazy Loading\",\n      ]\n    `)\n  })\n})\n\ndescribe('Custom Containers', () => {\n  enum CustomBlocks {\n    Info = 'INFO',\n    Tip = 'TIP',\n    Warning = 'WARNING',\n    Danger = 'DANGER',\n    Details = 'Details'\n  }\n\n  const classnameMap = {\n    [CustomBlocks.Info]: 'info',\n    [CustomBlocks.Tip]: 'tip',\n    [CustomBlocks.Warning]: 'warning',\n    [CustomBlocks.Danger]: 'danger',\n    [CustomBlocks.Details]: 'details'\n  }\n\n  const getTitleText = (locator: Locator, type: CustomBlocks) => {\n    if (type === CustomBlocks.Details) {\n      return locator.locator('summary').textContent()\n    } else {\n      return locator.locator('.custom-block-title').textContent()\n    }\n  }\n\n  test('default title', async () => {\n    const blocks = page.locator('#default-title ~ .custom-block')\n    for (const [index, type] of Object.values(CustomBlocks).entries()) {\n      const block = blocks.nth(index)\n      const classList = await getClassList(block)\n      expect(classList).contain(classnameMap[type as CustomBlocks])\n      expect(await getTitleText(block, type)).toBe(type)\n    }\n  })\n\n  test('custom Title', async () => {\n    const blocks = page.locator('#custom-title ~ .custom-block')\n    expect(await getTitleText(blocks.nth(0), CustomBlocks.Danger)).toBe('STOP')\n    expect(await getTitleText(blocks.nth(1), CustomBlocks.Details)).toBe(\n      'Click me to view the code'\n    )\n  })\n})\n\ndescribe('Line Highlighting in Code Blocks', () => {\n  test('single line', async () => {\n    const classList = await getClassList(\n      page.locator('#single-line + div code > span').nth(3)\n    )\n    expect(classList).toContain('highlighted')\n  })\n\n  test('multiple single lines, ranges', async () => {\n    const lines = page.locator(\n      '#multiple-single-lines-ranges + div code > span'\n    )\n\n    for (const num of [1, 4, 6, 7, 8]) {\n      expect(await getClassList(lines.nth(num - 1))).toContain('highlighted')\n    }\n  })\n\n  test('comment highlight', async () => {\n    const lines = page.locator('#comment-highlight + div code > span')\n    expect(await getClassList(lines.nth(0))).toContain('has-focus')\n\n    expect(await getClassList(lines.nth(1))).toContain('highlighted')\n\n    expect(await getClassList(lines.nth(3))).toContain('diff')\n    expect(await getClassList(lines.nth(3))).toContain('remove')\n\n    expect(await getClassList(lines.nth(4))).toContain('diff')\n    expect(await getClassList(lines.nth(4))).toContain('add')\n\n    expect(await getClassList(lines.nth(5))).toContain('highlighted')\n    expect(await getClassList(lines.nth(5))).toContain('error')\n\n    expect(await getClassList(lines.nth(6))).toContain('highlighted')\n    expect(await getClassList(lines.nth(6))).toContain('warning')\n  })\n})\n\ndescribe('Line Numbers', () => {\n  test('render line numbers', async () => {\n    const div = page.locator('#line-numbers + div')\n    expect(await getClassList(div)).toContain('line-numbers-mode')\n    const lines = div.locator('.line-numbers-wrapper > span')\n    expect(await lines.count()).toBe(2)\n  })\n})\n\ndescribe('Import Code Snippets', () => {\n  test('basic', async () => {\n    const lines = page.locator('#basic-code-snippet + div code > span')\n    expect(await lines.count()).toBe(11)\n  })\n\n  test('specify region', async () => {\n    const lines = page.locator('#specify-region + div code > span')\n    expect(await lines.count()).toBe(3)\n  })\n\n  test('with other features', async () => {\n    const div = page.locator('#with-other-features + div')\n    expect(await getClassList(div)).toContain('line-numbers-mode')\n    const lines = div.locator('code > span')\n    expect(await lines.count()).toBe(3)\n    expect(await getClassList(lines.nth(0))).toContain('highlighted')\n  })\n})\n\ndescribe('Code Groups', () => {\n  test('basic', async () => {\n    const div = page.locator('#basic-code-group + div')\n\n    // tabs\n    const labels = div.locator('.tabs > label')\n    const labelNames = ['config.js', 'config.ts']\n    const count = await labels.count()\n    expect(count).toBe(2)\n    for (let i = 0; i < count; i++) {\n      const text = await labels.nth(i).textContent()\n      expect(text).toBe(labelNames[i])\n    }\n\n    // blocks\n    const blocks = div.locator('.blocks > div')\n    expect(await getClassList(blocks.nth(0))).toContain('active')\n    await labels.nth(1).click()\n    expect(await getClassList(blocks.nth(1))).toContain('active')\n  })\n\n  test('with other features', async () => {\n    const div = page.locator('#with-other-features-1 + div')\n\n    // tabs\n    const labels = div.locator('.tabs > label')\n    const labelNames = ['foo.md', 'snippet with region']\n    const count = await labels.count()\n    expect(count).toBe(2)\n    for (let i = 0; i < count; i++) {\n      const text = await labels.nth(i).textContent()\n      expect(text).toBe(labelNames[i])\n    }\n\n    // blocks\n    const blocks = div.locator('.blocks > div')\n    expect(await blocks.nth(0).locator('code > span').count()).toBe(11)\n    expect(await getClassList(blocks.nth(1))).toContain('line-numbers-mode')\n    expect(await getClassList(blocks.nth(1))).toContain('language-ts')\n    expect(await blocks.nth(1).locator('code > span').count()).toBe(3)\n    expect(\n      await getClassList(blocks.nth(1).locator('code > span').nth(0))\n    ).toContain('highlighted')\n  })\n})\n\ndescribe('Markdown File Inclusion', () => {\n  test('render markdown', async () => {\n    const h1 = page.locator('#markdown-file-inclusion + h1')\n    expect(await h1.getAttribute('id')).toBe('foo')\n  })\n\n  test('render markdown using @', async () => {\n    const h1 = page.locator('#markdown-at-file-inclusion + h1')\n    expect(await h1.getAttribute('id')).toBe('bar')\n  })\n\n  test('render markdown using nested inclusion', async () => {\n    const h1 = page.locator('#markdown-nested-file-inclusion + h1')\n    expect(await h1.getAttribute('id')).toBe('foo-1')\n  })\n\n  test('render markdown using nested inclusion inside sub folder', async () => {\n    const h1 = page.locator('#after-foo + h1')\n    expect(await h1.getAttribute('id')).toBe('inside-sub-folder')\n    const h2 = page.locator('#after-foo + h1 + h2')\n    expect(await h2.getAttribute('id')).toBe('sub-sub')\n    const h3 = page.locator('#after-foo + h1 + h2 + h3')\n    expect(await h3.getAttribute('id')).toBe('sub-sub-sub')\n  })\n\n  test('support selecting range', async () => {\n    const h2 = page.locator('#markdown-file-inclusion-with-range + h2')\n    expect(trim(await h2.textContent())).toBe('Region')\n\n    const p = page.locator('#markdown-file-inclusion-with-range + h2 + p')\n    expect(trim(await p.textContent())).toBe('This is a region')\n  })\n\n  test('support selecting range without specifying start', async () => {\n    const p = page.locator(\n      '#markdown-file-inclusion-with-range-without-start ~ p'\n    )\n    expect(trim(await p.nth(0).textContent())).toBe('This is before region')\n    expect(trim(await p.nth(1).textContent())).toBe('This is a region')\n  })\n\n  test('support selecting range without specifying end', async () => {\n    const p = page.locator(\n      '#markdown-file-inclusion-with-range-without-end ~ p'\n    )\n    expect(trim(await p.nth(0).textContent())).toBe('This is a region')\n    expect(trim(await p.nth(1).textContent())).toBe('This is after region')\n  })\n\n  test('support markdown region snippet', async () => {\n    const h2 = page.locator('#markdown-at-file-region-snippet + h2')\n    expect(await h2.getAttribute('id')).toBe('region-snippet')\n\n    const line = page.locator('#markdown-at-file-range-region-snippet + h2')\n    expect(await line.getAttribute('id')).toBe('range-region-line-2')\n\n    const lineWithoutStart = page.locator(\n      '#markdown-at-file-range-region-snippet-without-start + h2'\n    )\n    expect(await lineWithoutStart.getAttribute('id')).toBe(\n      'range-region-line-1'\n    )\n\n    const lineWithoutEnd = page.locator(\n      '#markdown-at-file-range-region-snippet-without-end + h2'\n    )\n    expect(await lineWithoutEnd.getAttribute('id')).toBe('range-region-line-3')\n  })\n\n  test('ignore frontmatter if range is not specified', async () => {\n    const p = page.locator('.vp-doc')\n    expect(await p.textContent()).not.toContain('title')\n  })\n})\n\ndescribe('Image Lazy Loading', () => {\n  test('render loading=\"lazy\" in the <img> tag', async () => {\n    const img = page.locator('#image-lazy-loading + p img')\n    expect(await img.getAttribute('loading')).toBe('lazy')\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/nested-include.md",
    "content": "---\ntitle: Nested Include\n---\n\n<!--@include: ./foo.md-->\n\n### After Foo\n\n<!--@include: ./subfolder/inside-subfolder.md-->\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/region-include.md",
    "content": "\n<!-- #region range-region -->\n\n## Range Region Line 1\n\n## Range Region Line 2\n\n## Range Region Line 3\n<!-- #endregion range-region -->\n\n<!-- #region snippet -->\n## Region Snippet\n<!-- #endregion snippet -->\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/subfolder/inside-subfolder.md",
    "content": "# Inside sub folder\n\n<!--@include: ./subsub/subsub.md-->\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/subfolder/subsub/subsub.md",
    "content": "## Sub sub\n\n<!--@include: ./subsubsub/subsubsub.md-->\n"
  },
  {
    "path": "__tests__/e2e/markdown-extensions/subfolder/subsub/subsubsub/subsubsub.md",
    "content": "### Sub sub sub\n"
  },
  {
    "path": "__tests__/e2e/multi-sidebar/index.md",
    "content": "# Multi Sidebar\n"
  },
  {
    "path": "__tests__/e2e/multi-sidebar/index.test.ts",
    "content": "describe('test multi sidebar sort root', () => {\n  beforeAll(async () => {\n    await goto('/frontmatter/multiple-levels-outline')\n  })\n\n  test('using / sidebar', async () => {\n    const sidebarLocator = page.locator(\n      '.VPSidebarItem.level-0 > .item > .text'\n    )\n\n    const sidebarContent = await sidebarLocator.allTextContents()\n    expect(sidebarContent).toEqual([\n      'Frontmatter',\n      '& <Text Literals &> code',\n      'Data Loading',\n      'Multi Sidebar Test',\n      'Dynamic Routes',\n      'Markdown Extensions'\n    ])\n  })\n})\n\ndescribe('test multi sidebar sort order', () => {\n  beforeAll(async () => {\n    await goto('/multi-sidebar/')\n  })\n\n  test('using /multi-sidebar/ sidebar', async () => {\n    const sidebarLocator = page.locator(\n      '.VPSidebarItem.level-0 > .item > .text'\n    )\n\n    const sidebarContent = await sidebarLocator.allTextContents()\n    expect(sidebarContent).toEqual(['Multi Sidebar'])\n  })\n})\n"
  },
  {
    "path": "__tests__/e2e/package.json",
    "content": "{\n  \"name\": \"tests-e2e\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"test\": \"vitest run\",\n    \"watch\": \"DEBUG=1 vitest\",\n    \"site:dev\": \"vitepress\",\n    \"site:build\": \"vitepress build\",\n    \"site:preview\": \"vitepress preview\"\n  },\n  \"devDependencies\": {\n    \"vitepress\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "__tests__/e2e/shims.ts",
    "content": "import { type Page } from 'playwright-chromium'\n\ndeclare global {\n  var page: Page\n  var goto: (path: string) => Promise<void>\n}\n"
  },
  {
    "path": "__tests__/e2e/text-literals/index.md",
    "content": "# Text Literals\n"
  },
  {
    "path": "__tests__/e2e/vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config'\n\nconst timeout = 60_000\n\nexport default defineConfig({\n  test: {\n    setupFiles: ['vitestSetup.ts'],\n    globalSetup: ['vitestGlobalSetup.ts'],\n    testTimeout: timeout,\n    hookTimeout: timeout,\n    teardownTimeout: timeout,\n    globals: true\n  }\n})\n"
  },
  {
    "path": "__tests__/e2e/vitestGlobalSetup.ts",
    "content": "import getPort from 'get-port'\nimport type { Server } from 'node:net'\nimport { chromium, type BrowserServer } from 'playwright-chromium'\nimport type { ViteDevServer } from 'vite'\nimport { build, createServer, serve } from 'vitepress'\n\nlet browserServer: BrowserServer\nlet server: ViteDevServer | Server\n\nconst root = '.'\n\nexport async function setup() {\n  browserServer = await chromium.launchServer({\n    headless: !process.env.DEBUG,\n    args: process.env.CI\n      ? ['--no-sandbox', '--disable-setuid-sandbox']\n      : undefined\n  })\n  process.env['WS_ENDPOINT'] = browserServer.wsEndpoint()\n  const port = await getPort()\n  process.env['PORT'] = port.toString()\n\n  if (process.env['VITE_TEST_BUILD']) {\n    await build(root)\n    server = (await serve({ root, port })).server\n  } else {\n    server = await createServer(root, { port })\n    await server!.listen()\n  }\n}\n\nexport async function teardown() {\n  await browserServer.close()\n  if ('ws' in server) {\n    await server.close()\n  } else {\n    await new Promise<void>((resolve, reject) => {\n      server.close((error) => (error ? reject(error) : resolve()))\n    })\n  }\n}\n"
  },
  {
    "path": "__tests__/e2e/vitestSetup.ts",
    "content": "import { chromium, type Browser } from 'playwright-chromium'\n\nlet browser: Browser\n\nbeforeAll(async () => {\n  browser = await chromium.connect(process.env['WS_ENDPOINT']!)\n  globalThis.page = await browser.newPage()\n  globalThis.goto = async (path: string) => {\n    await page.goto(`http://localhost:${process.env['PORT']}${path}`)\n    await page.waitForSelector('#app .Layout')\n  }\n})\n\nafterAll(async () => {\n  await page.close()\n  await browser.close()\n  // @ts-ignore\n  delete globalThis.page\n  // @ts-ignore\n  delete globalThis.goto\n})\n"
  },
  {
    "path": "__tests__/init/init.test.ts",
    "content": "import fs from 'fs-extra'\nimport getPort from 'get-port'\nimport { nanoid } from 'nanoid'\nimport path from 'node:path'\nimport { fileURLToPath, URL } from 'node:url'\nimport { chromium } from 'playwright-chromium'\nimport { createServer, scaffold, ScaffoldThemeType } from 'vitepress'\n\nconst tempDir = fileURLToPath(new URL('./.temp', import.meta.url))\nconst getTempRoot = () => path.join(tempDir, nanoid())\n\nconst browser = await chromium.launch({\n  headless: !process.env.DEBUG,\n  args: process.env.CI\n    ? ['--no-sandbox', '--disable-setuid-sandbox']\n    : undefined\n})\n\nconst page = await browser.newPage()\n\nconst themes = [\n  ScaffoldThemeType.Default,\n  ScaffoldThemeType.DefaultCustom,\n  ScaffoldThemeType.Custom\n]\nconst usingTs = [false, true]\nconst variations = themes.flatMap((theme) =>\n  usingTs.map(\n    (useTs) => [`${theme}${useTs ? ' + ts' : ''}`, { theme, useTs }] as const\n  )\n)\n\nafterAll(async () => {\n  await page.close()\n  await browser.close()\n  await fs.remove(tempDir)\n})\n\ntest.each(variations)('init %s', async (_, { theme, useTs }) => {\n  const root = getTempRoot()\n  await fs.remove(root)\n  scaffold({ root, theme, useTs, injectNpmScripts: false })\n\n  const port = await getPort()\n  const server = await createServer(root, { port })\n  await server.listen()\n\n  async function goto(path: string) {\n    await page.goto(`http://localhost:${port}${path}`)\n    await page.waitForSelector('#app div')\n  }\n\n  try {\n    await goto('/')\n    expect(await page.textContent('h1')).toMatch('My Awesome Project')\n\n    await page.click('a[href=\"/markdown-examples.html\"]')\n    await page.waitForFunction('document.querySelector(\"pre code\")')\n    expect(await page.textContent('h1')).toMatch('Markdown Extension Examples')\n\n    await goto('/')\n    expect(await page.textContent('h1')).toMatch('My Awesome Project')\n\n    await page.click('a[href=\"/api-examples.html\"]')\n    await page.waitForFunction('document.querySelector(\"pre code\")')\n    expect(await page.textContent('h1')).toMatch('Runtime API Examples')\n\n    // teardown\n  } finally {\n    await server.close()\n  }\n})\n"
  },
  {
    "path": "__tests__/init/package.json",
    "content": "{\n  \"name\": \"tests-init\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"test\": \"vitest run\",\n    \"watch\": \"DEBUG=1 vitest\"\n  },\n  \"devDependencies\": {\n    \"vitepress\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "__tests__/init/vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config'\n\nconst timeout = 60_000\n\nexport default defineConfig({\n  test: {\n    testTimeout: timeout,\n    hookTimeout: timeout,\n    teardownTimeout: timeout,\n    globals: true\n  }\n})\n"
  },
  {
    "path": "__tests__/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"isolatedModules\": false,\n    \"baseUrl\": \".\",\n    \"types\": [\"node\", \"vitest/globals\"],\n    \"paths\": {\n      \"client/*\": [\"../src/client/*\"],\n      \"node/*\": [\"../src/node/*\"],\n      \"shared/*\": [\"../src/shared/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "__tests__/unit/client/theme-default/composables/outline.test.ts",
    "content": "import { resolveHeaders } from 'client/theme-default/composables/outline'\n\nconst element = {\n  classList: {\n    contains: () => false\n  }\n} as unknown as HTMLHeadElement\n\ndescribe('client/theme-default/composables/outline', () => {\n  describe('resolveHeader', () => {\n    test('levels range', () => {\n      expect(\n        resolveHeaders(\n          [\n            {\n              level: 2,\n              title: 'h2 - 1',\n              link: '#h2-1',\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 1',\n              link: '#h3-1',\n              element\n            }\n          ],\n          [2, 3]\n        )\n      ).toEqual([\n        {\n          level: 2,\n          title: 'h2 - 1',\n          link: '#h2-1',\n          children: [\n            {\n              level: 3,\n              title: 'h3 - 1',\n              link: '#h3-1',\n              children: [],\n              element\n            }\n          ],\n          element\n        }\n      ])\n    })\n\n    test('specific level', () => {\n      expect(\n        resolveHeaders(\n          [\n            {\n              level: 2,\n              title: 'h2 - 1',\n              link: '#h2-1',\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 1',\n              link: '#h3-1',\n              element\n            }\n          ],\n          2\n        )\n      ).toEqual([\n        {\n          level: 2,\n          title: 'h2 - 1',\n          link: '#h2-1',\n          children: [],\n          element\n        }\n      ])\n    })\n\n    test('complex deep', () => {\n      expect(\n        resolveHeaders(\n          [\n            {\n              level: 2,\n              title: 'h2 - 1',\n              link: '#h2-1',\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 1',\n              link: '#h3-1',\n              element\n            },\n            {\n              level: 4,\n              title: 'h4 - 1',\n              link: '#h4-1',\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 2',\n              link: '#h3-2',\n              element\n            },\n            {\n              level: 4,\n              title: 'h4 - 2',\n              link: '#h4-2',\n              element\n            },\n            {\n              level: 2,\n              title: 'h2 - 2',\n              link: '#h2-2',\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 3',\n              link: '#h3-3',\n              element\n            },\n            {\n              level: 4,\n              title: 'h4 - 3',\n              link: '#h4-3',\n              element\n            }\n          ],\n          'deep'\n        )\n      ).toEqual([\n        {\n          level: 2,\n          title: 'h2 - 1',\n          link: '#h2-1',\n          children: [\n            {\n              level: 3,\n              title: 'h3 - 1',\n              link: '#h3-1',\n              children: [\n                {\n                  level: 4,\n                  title: 'h4 - 1',\n                  link: '#h4-1',\n                  children: [],\n                  element\n                }\n              ],\n              element\n            },\n            {\n              level: 3,\n              title: 'h3 - 2',\n              link: '#h3-2',\n              children: [\n                {\n                  level: 4,\n                  title: 'h4 - 2',\n                  link: '#h4-2',\n                  children: [],\n                  element\n                }\n              ],\n              element\n            }\n          ],\n          element\n        },\n        {\n          level: 2,\n          title: 'h2 - 2',\n          link: '#h2-2',\n          children: [\n            {\n              level: 3,\n              title: 'h3 - 3',\n              link: '#h3-3',\n              children: [\n                {\n                  level: 4,\n                  title: 'h4 - 3',\n                  link: '#h4-3',\n                  children: [],\n                  element\n                }\n              ],\n              element\n            }\n          ],\n          element\n        }\n      ])\n    })\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/client/theme-default/support/docsearch.test.ts",
    "content": "import {\n  buildAskAiConfig,\n  hasAskAi,\n  hasKeywordSearch,\n  mergeLangFacetFilters,\n  validateCredentials\n} from 'client/theme-default/support/docsearch'\n\ndescribe('client/theme-default/support/docsearch', () => {\n  describe('mergeLangFacetFilters', () => {\n    test('adds a lang facet filter when none is provided', () => {\n      expect(mergeLangFacetFilters(undefined, 'en')).toEqual(['lang:en'])\n    })\n\n    test('replaces existing lang facet filters', () => {\n      expect(mergeLangFacetFilters('lang:fr', 'en')).toEqual(['lang:en'])\n      expect(mergeLangFacetFilters(['foo', 'lang:fr'], 'en')).toEqual([\n        'foo',\n        'lang:en'\n      ])\n    })\n\n    test('handles nested facet filters (OR conditions)', () => {\n      expect(\n        mergeLangFacetFilters([['tag:foo', 'tag:bar'], 'lang:fr'], 'en')\n      ).toEqual([['tag:foo', 'tag:bar'], 'lang:en'])\n    })\n\n    test('removes empty nested arrays', () => {\n      expect(mergeLangFacetFilters([['lang:fr'], 'other'], 'en')).toEqual([\n        'other',\n        'lang:en'\n      ])\n    })\n\n    test('handles multiple lang filters in nested arrays', () => {\n      expect(\n        mergeLangFacetFilters([['lang:fr', 'tag:foo'], 'bar'], 'en')\n      ).toEqual([['tag:foo'], 'bar', 'lang:en'])\n    })\n  })\n\n  describe('hasKeywordSearch', () => {\n    test('returns true when all credentials are provided', () => {\n      expect(\n        hasKeywordSearch({\n          appId: 'app',\n          apiKey: 'key',\n          indexName: 'index'\n        })\n      ).toBe(true)\n    })\n\n    test('returns false when any credential is missing', () => {\n      expect(\n        hasKeywordSearch({\n          appId: undefined,\n          apiKey: 'key',\n          indexName: 'index'\n        })\n      ).toBe(false)\n      expect(\n        hasKeywordSearch({\n          appId: 'app',\n          apiKey: undefined,\n          indexName: 'index'\n        })\n      ).toBe(false)\n      expect(\n        hasKeywordSearch({\n          appId: 'app',\n          apiKey: 'key',\n          indexName: undefined\n        })\n      ).toBe(false)\n    })\n  })\n\n  describe('hasAskAi', () => {\n    test('returns true for valid string assistantId', () => {\n      expect(hasAskAi('assistant123')).toBe(true)\n    })\n\n    test('returns false for empty string assistantId', () => {\n      expect(hasAskAi('')).toBe(false)\n    })\n\n    test('returns true for object with assistantId', () => {\n      expect(hasAskAi({ assistantId: 'assistant123' } as any)).toBe(true)\n    })\n\n    test('returns false for object without assistantId', () => {\n      expect(hasAskAi({ assistantId: null } as any)).toBe(false)\n      expect(hasAskAi({} as any)).toBe(false)\n    })\n\n    test('returns false for undefined', () => {\n      expect(hasAskAi(undefined)).toBe(false)\n    })\n  })\n\n  describe('validateCredentials', () => {\n    test('validates complete credentials', () => {\n      const result = validateCredentials({\n        appId: 'app',\n        apiKey: 'key',\n        indexName: 'index'\n      })\n      expect(result.valid).toBe(true)\n      expect(result.appId).toBe('app')\n      expect(result.apiKey).toBe('key')\n      expect(result.indexName).toBe('index')\n    })\n\n    test('invalidates incomplete credentials', () => {\n      expect(\n        validateCredentials({\n          appId: undefined,\n          apiKey: 'key',\n          indexName: 'index'\n        }).valid\n      ).toBe(false)\n    })\n  })\n\n  describe('buildAskAiConfig', () => {\n    test('builds config from string assistantId', () => {\n      const result = buildAskAiConfig(\n        'assistant123',\n        {\n          appId: 'app',\n          apiKey: 'key',\n          indexName: 'index'\n        } as any,\n        'en'\n      )\n      expect(result.assistantId).toBe('assistant123')\n      expect(result.appId).toBe('app')\n      expect(result.apiKey).toBe('key')\n      expect(result.indexName).toBe('index')\n    })\n\n    test('builds config from object with overrides', () => {\n      const result = buildAskAiConfig(\n        {\n          assistantId: 'assistant123',\n          appId: 'custom-app',\n          apiKey: 'custom-key',\n          indexName: 'custom-index'\n        } as any,\n        {\n          appId: 'default-app',\n          apiKey: 'default-key',\n          indexName: 'default-index'\n        } as any,\n        'en'\n      )\n      expect(result.assistantId).toBe('assistant123')\n      expect(result.appId).toBe('custom-app')\n      expect(result.apiKey).toBe('custom-key')\n      expect(result.indexName).toBe('custom-index')\n    })\n\n    test('merges facet filters with lang', () => {\n      const result = buildAskAiConfig(\n        {\n          assistantId: 'assistant123',\n          searchParameters: {\n            facetFilters: ['tag:docs']\n          }\n        } as any,\n        {\n          appId: 'app',\n          apiKey: 'key',\n          indexName: 'index'\n        } as any,\n        'en'\n      )\n      expect(result.searchParameters?.facetFilters).toContain('tag:docs')\n      expect(result.searchParameters?.facetFilters).toContain('lang:en')\n    })\n\n    test('always adds lang facet filter to searchParameters', () => {\n      const result = buildAskAiConfig(\n        'assistant123',\n        {\n          appId: 'app',\n          apiKey: 'key',\n          indexName: 'index'\n        } as any,\n        'en'\n      )\n      expect(result.searchParameters?.facetFilters).toEqual(['lang:en'])\n    })\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/client/theme-default/support/sidebar.test.ts",
    "content": "import { getSidebar, hasActiveLink } from 'client/theme-default/support/sidebar'\n\ndescribe('client/theme-default/support/sidebar', () => {\n  describe('getSidebar', () => {\n    const root = [\n      {\n        text: 'A',\n        collapsible: true,\n        items: [{ text: 'A', link: '' }]\n      },\n      {\n        text: 'B',\n        items: [{ text: 'B', link: '' }]\n      }\n    ]\n\n    const another = [\n      {\n        text: 'C',\n        items: [{ text: 'C', link: '' }]\n      }\n    ]\n\n    describe('normal sidebar sort', () => {\n      const normalSidebar = {\n        '/': root,\n        '/multi-sidebar/': another\n      }\n\n      test('gets `/` sidebar', () => {\n        expect(getSidebar(normalSidebar, '/')).toStrictEqual(root)\n      })\n\n      test('gets `/multi-sidebar/` sidebar', () => {\n        expect(getSidebar(normalSidebar, '/multi-sidebar/')).toStrictEqual(\n          another\n        )\n      })\n\n      test('gets `/` sidebar again', () => {\n        expect(getSidebar(normalSidebar, '/some-entry.html')).toStrictEqual(\n          root\n        )\n      })\n    })\n\n    describe('reversed sidebar sort', () => {\n      const reversedSidebar = {\n        '/multi-sidebar/': another,\n        '/': root\n      }\n\n      test('gets `/` sidebar', () => {\n        expect(getSidebar(reversedSidebar, '/')).toStrictEqual(root)\n      })\n\n      test('gets `/multi-sidebar/` sidebar', () => {\n        expect(getSidebar(reversedSidebar, '/multi-sidebar/')).toStrictEqual(\n          another\n        )\n      })\n\n      test('gets `/` sidebar again', () => {\n        expect(getSidebar(reversedSidebar, '/some-entry.html')).toStrictEqual(\n          root\n        )\n      })\n    })\n\n    describe('nested sidebar sort', () => {\n      const nested = [\n        {\n          text: 'D',\n          items: [{ text: 'D', link: '' }]\n        }\n      ]\n\n      const nestedSidebar = {\n        '/': root,\n        '/multi-sidebar/': another,\n        '/multi-sidebar/nested/': nested\n      }\n\n      test('gets `/` sidebar', () => {\n        expect(getSidebar(nestedSidebar, '/')).toStrictEqual(root)\n      })\n\n      test('gets `/multi-sidebar/` sidebar', () => {\n        expect(getSidebar(nestedSidebar, '/multi-sidebar/')).toStrictEqual(\n          another\n        )\n      })\n\n      test('gets `/multi-sidebar/nested/` sidebar', () => {\n        expect(\n          getSidebar(nestedSidebar, '/multi-sidebar/nested/')\n        ).toStrictEqual(nested)\n      })\n\n      test('gets `/` sidebar again', () => {\n        expect(getSidebar(nestedSidebar, '/some-entry.html')).toStrictEqual(\n          root\n        )\n      })\n    })\n  })\n\n  describe('hasActiveLink', () => {\n    test('checks `SidebarItem`', () => {\n      const item = {\n        text: 'Item 001',\n        items: [\n          { text: 'Item 001', link: '/active-1' },\n          { text: 'Item 002', link: '/active-2' }\n        ]\n      }\n\n      expect(hasActiveLink('active-1', item)).toBe(true)\n      expect(hasActiveLink('inactive', item)).toBe(false)\n    })\n\n    test('checks `SidebarItem[]`', () => {\n      const item = [\n        {\n          text: 'Item 001',\n          items: [\n            { text: 'Item 001', link: '/active-1' },\n            { text: 'Item 002', link: '/active-2' }\n          ]\n        },\n        {\n          text: 'Item 002',\n          items: [\n            { text: 'Item 003', link: '/active-3' },\n            { text: 'Item 004', link: '/active-4' }\n          ]\n        }\n      ]\n\n      expect(hasActiveLink('active-1', item)).toBe(true)\n      expect(hasActiveLink('active-3', item)).toBe(true)\n      expect(hasActiveLink('inactive', item)).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/client/theme-default/support/utils.test.ts",
    "content": "import { ensureStartingSlash } from 'client/theme-default/support/utils'\n\ndescribe('client/theme-default/utils', () => {\n  describe('ensureStartingSlash', () => {\n    test('it adds slash to the beginning of the given path', () => {\n      expect(ensureStartingSlash('path')).toBe('/path')\n      expect(ensureStartingSlash('path/nested')).toBe('/path/nested')\n      expect(ensureStartingSlash('/path')).toBe('/path')\n      expect(ensureStartingSlash('/path/nested')).toBe('/path/nested')\n    })\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/node/markdown/plugins/highlight.test.ts",
    "content": "import { highlight } from 'node/markdown/plugins/highlight'\n\ndescribe('node/markdown/plugins/highlight', () => {\n  test('passes color replacements through markdown options', async () => {\n    const [render, dispose] = await highlight(\n      { light: 'github-light', dark: 'github-dark' },\n      {\n        colorReplacements: {\n          'github-light': {\n            '#005cc5': '#000000'\n          }\n        }\n      }\n    )\n\n    try {\n      const html = await render('const a = 1', 'js', '')\n\n      expect(html).toContain('--shiki-light:#000000')\n      expect(html).toContain('--shiki-dark:#79B8FF')\n      expect(html).not.toContain('--shiki-light:#005CC5')\n    } finally {\n      dispose()\n    }\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/node/markdown/plugins/link.test.ts",
    "content": "import { slugify } from '@mdit-vue/shared'\nimport { MarkdownItAsync } from 'markdown-it-async'\nimport { linkPlugin } from 'node/markdown/plugins/link'\n\ndescribe('node/markdown/plugins/link', () => {\n  const md = new MarkdownItAsync()\n  linkPlugin(md, {}, '/', slugify)\n\n  test('preserves text-fragment hashes on markdown links', async () => {\n    const html = await md.renderAsync(\n      '[58-61](/resources/server/user#:~:text=58*,time%20authentication%20token)',\n      { cleanUrls: false }\n    )\n\n    expect(html).toContain(\n      'href=\"/resources/server/user.html#:~:text=58*,time%20authentication%20token\"'\n    )\n  })\n\n  // https://web.dev/articles/text-fragments#mixing_element_and_text_fragments\n  test('preserves mixed element and text-fragment hashes', async () => {\n    const html = await md.renderAsync(\n      '[Section](/guide/getting-started#Hello%20World:~:text=Hello%20World)',\n      { cleanUrls: false }\n    )\n\n    expect(html).toContain(\n      'href=\"/guide/getting-started.html#hello-world:~:text=Hello%20World\"'\n    )\n  })\n\n  test('continues to normalize regular heading hashes', async () => {\n    const html = await md.renderAsync(\n      '[Section](/guide/getting-started#Hello%20World)',\n      { cleanUrls: false }\n    )\n\n    expect(html).toContain('href=\"/guide/getting-started.html#hello-world\"')\n  })\n\n  test('does not break encoding for text-fragments', async () => {\n    const html = await md.renderAsync(\n      '[Section](/foo?title=Cat&oldid=916388819#:~:text=Claws-,Like%20almost,the%20Felidae%2C,-cats)',\n      { cleanUrls: false }\n    )\n\n    expect(html).toContain(\n      'href=\"/foo.html?title=Cat&amp;oldid=916388819#:~:text=Claws-,Like%20almost,the%20Felidae%2C,-cats\"'\n    )\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/node/markdown/plugins/snippet.test.ts",
    "content": "import {\n  dedent,\n  findRegion,\n  rawPathToToken\n} from 'node/markdown/plugins/snippet'\n\nconst removeEmptyKeys = <T extends Record<string, unknown>>(obj: T) => {\n  return Object.fromEntries(\n    Object.entries(obj).filter(([, value]) => value !== '')\n  ) as T\n}\n\n/* prettier-ignore */\nconst rawPathTokenMap: [string, Partial<{ filepath: string, extension: string, title: string, region: string, lines: string, lang: string }>][] = [\n  ['/path/to/file.extension', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['./path/to/file.extension', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['/path to/file.extension', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['./path to/file.extension', { filepath: './path to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['/path.to/file.extension', { filepath: '/path.to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['./path.to/file.extension', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['/path .to/file.extension', { filepath: '/path .to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['./path .to/file.extension', { filepath: './path .to/file.extension', extension: 'extension', title: 'file.extension' }],\n  ['/path/to/file', { filepath: '/path/to/file', title: 'file' }],\n  ['./path/to/file', { filepath: './path/to/file', title: 'file' }],\n  ['/path to/file', { filepath: '/path to/file', title: 'file' }],\n  ['./path to/file', { filepath: './path to/file', title: 'file' }],\n  ['/path.to/file', { filepath: '/path.to/file', title: 'file' }],\n  ['./path.to/file', { filepath: './path.to/file', title: 'file' }],\n  ['/path .to/file', { filepath: '/path .to/file', title: 'file' }],\n  ['./path .to/file', { filepath: './path .to/file', title: 'file' }],\n  ['/path/to/file.extension#region', { filepath: '/path/to/file.extension', extension: 'extension', title: 'file.extension', region: '#region' }],\n  ['./path/to/file.extension {c#}', { filepath: './path/to/file.extension', extension: 'extension', title: 'file.extension', lang: 'c#' }],\n  ['/path to/file.extension {1,2,4-6}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6' }],\n  ['/path to/file.extension {1,2,4-6 c#}', { filepath: '/path to/file.extension', extension: 'extension', title: 'file.extension', lines: '1,2,4-6', lang: 'c#' }],\n  ['/path.to/file.extension [title]', { filepath: '/path.to/file.extension', extension: 'extension', title: 'title' }],\n  ['./path.to/file.extension#region {c#}', { filepath: './path.to/file.extension', extension: 'extension', title: 'file.extension', region: '#region', lang: 'c#' }],\n  ['/path/to/file#region {1,2,4-6}', { filepath: '/path/to/file', title: 'file', region: '#region', lines: '1,2,4-6' }],\n  ['./path/to/file#region {1,2,4-6 c#}', { filepath: './path/to/file', title: 'file', region: '#region', lines: '1,2,4-6', lang: 'c#' }],\n  ['/path to/file {1,2,4-6 c#} [title]', { filepath: '/path to/file', title: 'title', lines: '1,2,4-6', lang: 'c#' }],\n  ['./path to/file#region {1,2,4-6 c#} [title]', { filepath: './path to/file', title: 'title', region: '#region', lines: '1,2,4-6', lang: 'c#' }],\n]\n\ndescribe('node/markdown/plugins/snippet', () => {\n  describe('dedent', () => {\n    test('when 0-level is minimal, do not remove spaces', () => {\n      expect(\n        dedent(\n          [\n            //\n            'fn main() {',\n            '  println!(\"Hello\");',\n            '}'\n          ].join('\\n')\n        )\n      ).toMatchInlineSnapshot(`\n        \"fn main() {\n          println!(\"Hello\");\n        }\"\n      `)\n    })\n\n    test('when 4-level is minimal, remove 4 spaces', () => {\n      expect(\n        dedent(\n          [\n            //\n            '    let a = {',\n            '        value: 42',\n            '    };'\n          ].join('\\n')\n        )\n      ).toMatchInlineSnapshot(`\n        \"let a = {\n            value: 42\n        };\"\n      `)\n    })\n\n    test('when only 1 line is passed, dedent it', () => {\n      expect(dedent('    let a = 42;')).toEqual('let a = 42;')\n    })\n\n    test('handle tabs as well', () => {\n      expect(\n        dedent(\n          [\n            //\n            '\tlet a = {',\n            '\t\tvalue: 42',\n            '\t};'\n          ].join('\\n')\n        )\n      ).toMatchInlineSnapshot(`\n        \"let a = {\n        \tvalue: 42\n        };\"\n      `)\n    })\n  })\n\n  describe('rawPathToToken', () => {\n    test.each(rawPathTokenMap)('%s', (rawPath, token) => {\n      expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token)\n    })\n  })\n\n  describe('findRegion', () => {\n    it('returns null when no region markers are present', () => {\n      const lines = ['function foo() {', '  console.log(\"hello\");', '}']\n      expect(findRegion(lines, 'foo')).toBeNull()\n    })\n\n    it('ignores non-matching region names', () => {\n      const lines = [\n        '// #region regionA',\n        'some code here',\n        '// #endregion regionA'\n      ]\n      expect(findRegion(lines, 'regionC')).toBeNull()\n    })\n\n    it('returns null if a region start marker exists without a matching end marker', () => {\n      const lines = [\n        '// #region missingEnd',\n        'console.log(\"inside region\");',\n        'console.log(\"still inside\");'\n      ]\n      expect(findRegion(lines, 'missingEnd')).toBeNull()\n    })\n\n    it('returns null if an end marker exists without a preceding start marker', () => {\n      const lines = [\n        '// #endregion ghostRegion',\n        'console.log(\"stray end marker\");'\n      ]\n      expect(findRegion(lines, 'ghostRegion')).toBeNull()\n    })\n\n    it('detects C#/JavaScript style region markers with matching tags', () => {\n      const lines = [\n        'Console.WriteLine(\"Before region\");',\n        '#region hello',\n        'Console.WriteLine(\"Hello, World!\");',\n        '#endregion hello',\n        'Console.WriteLine(\"After region\");'\n      ]\n      const result = findRegion(lines, 'hello')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'Console.WriteLine(\"Hello, World!\");'\n        )\n      }\n    })\n\n    it('detects region markers even when the end marker omits the region name', () => {\n      const lines = [\n        'Console.WriteLine(\"Before region\");',\n        '#region hello',\n        'Console.WriteLine(\"Hello, World!\");',\n        '#endregion',\n        'Console.WriteLine(\"After region\");'\n      ]\n      const result = findRegion(lines, 'hello')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'Console.WriteLine(\"Hello, World!\");'\n        )\n      }\n    })\n\n    it('handles indented region markers correctly', () => {\n      const lines = [\n        '  Console.WriteLine(\"Before region\");',\n        '  #region hello',\n        '  Console.WriteLine(\"Hello, World!\");',\n        '  #endregion hello',\n        '  Console.WriteLine(\"After region\");'\n      ]\n      const result = findRegion(lines, 'hello')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          '  Console.WriteLine(\"Hello, World!\");'\n        )\n      }\n    })\n\n    it('detects TypeScript style region markers', () => {\n      const lines = [\n        'let regexp: RegExp[] = [];',\n        '// #region foo',\n        'let start = -1;',\n        '// #endregion foo'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'let start = -1;'\n        )\n      }\n    })\n\n    it('detects CSS style region markers', () => {\n      const lines = [\n        '.body-content {',\n        '/* #region foo */',\n        '  padding-left: 15px;',\n        '/* #endregion foo */',\n        '  padding-right: 15px;',\n        '}'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          '  padding-left: 15px;'\n        )\n      }\n    })\n\n    it('detects HTML style region markers', () => {\n      const lines = [\n        '<div>Some content</div>',\n        '<!-- #region foo -->',\n        '  <h1>Hello world</h1>',\n        '<!-- #endregion foo -->',\n        '<div>Other content</div>'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          '  <h1>Hello world</h1>'\n        )\n      }\n    })\n\n    it('detects Visual Basic style region markers (with case-insensitive \"End\")', () => {\n      const lines = [\n        'Console.WriteLine(\"VB\")',\n        '#Region VBRegion',\n        '  Console.WriteLine(\"Inside region\")',\n        '#End Region VBRegion',\n        'Console.WriteLine(\"Done\")'\n      ]\n      const result = findRegion(lines, 'VBRegion')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          '  Console.WriteLine(\"Inside region\")'\n        )\n      }\n    })\n\n    it('detects Bat style region markers', () => {\n      const lines = ['::#region foo', 'echo off', '::#endregion foo']\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'echo off'\n        )\n      }\n    })\n\n    it('detects C/C++ style region markers using #pragma', () => {\n      const lines = [\n        '#pragma region foo',\n        'int a = 1;',\n        '#pragma endregion foo'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'int a = 1;'\n        )\n      }\n    })\n\n    it('returns the first complete region when multiple regions exist', () => {\n      const lines = [\n        '// #region foo',\n        'first region content',\n        '// #endregion foo',\n        '// #region foo',\n        'second region content',\n        '// #endregion foo'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        expect(lines.slice(result.start, result.end).join('\\n')).toBe(\n          'first region content'\n        )\n      }\n    })\n\n    it('handles nested regions with different names properly', () => {\n      const lines = [\n        '// #region foo',\n        \"console.log('line before nested');\",\n        '// #region bar',\n        \"console.log('nested content');\",\n        '// #endregion bar',\n        '// #endregion foo'\n      ]\n      const result = findRegion(lines, 'foo')\n      expect(result).not.toBeNull()\n      if (result) {\n        const extracted = lines.slice(result.start, result.end).join('\\n')\n        const expected = [\n          \"console.log('line before nested');\",\n          '// #region bar',\n          \"console.log('nested content');\",\n          '// #endregion bar'\n        ].join('\\n')\n        expect(extracted).toBe(expected)\n      }\n    })\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/node/postcss/__snapshots__/isolateStyles.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`node/postcss/isolateStyles > transforms selectors and skips keyframes 1`] = `\n\"\n/* simple classes */\n.example:not(:where(.vp-raw, .vp-raw *)) { color: red; }\n.class-a:not(:where(.vp-raw, .vp-raw *)) { color: coral; }\n.class-b:not(:where(.vp-raw, .vp-raw *)) { color: deepskyblue; }\n\n/* escaped colon in class */\n.baz\\\\:not\\\\(.bar\\\\):not(:where(.vp-raw, .vp-raw *)) { display: block; }\n.disabled\\\\:opacity-50:not(:where(.vp-raw, .vp-raw *)):disabled { opacity: .5; }\n\n/* pseudos (class + element) */\n.button:not(:where(.vp-raw, .vp-raw *)):hover { color: pink; }\n.button:not(:where(.vp-raw, .vp-raw *)):focus:hover { color: hotpink; }\n.item:not(:where(.vp-raw, .vp-raw *))::before { content: '•'; }\n:not(:where(.vp-raw, .vp-raw *))::first-letter { color: pink; }\n:not(:where(.vp-raw, .vp-raw *))::before { content: ''; }\n\n/* universal + :not */\n*:not(:where(.vp-raw, .vp-raw *)) { background-color: red; }\n*:not(:where(.vp-raw, .vp-raw *)):not(.b) { text-transform: uppercase; }\n\n/* combinators */\n.foo:hover .bar:not(:where(.vp-raw, .vp-raw *)) { background: blue; }\nul > li.active:not(:where(.vp-raw, .vp-raw *)) { color: green; }\na + b ~ c:not(:where(.vp-raw, .vp-raw *)) { color: orange; }\n\n/* ids + attribute selectors */\n#wow:not(:where(.vp-raw, .vp-raw *)) { color: yellow; }\n[data-world] .d:not(:where(.vp-raw, .vp-raw *)) { padding: 10px 20px; }\n\n/* :root and chained tags */\n:not(:where(.vp-raw, .vp-raw *)):root { --bs-blue: #0d6efd; }\n:root .a:not(:where(.vp-raw, .vp-raw *)) { --bs-green: #bada55; }\nhtml:not(:where(.vp-raw, .vp-raw *)) { margin: 0; }\nbody:not(:where(.vp-raw, .vp-raw *)) { padding: 0; }\nhtml body div:not(:where(.vp-raw, .vp-raw *)) { color: blue; }\n\n/* grouping with commas */\n.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: red; }\n\n/* multiple repeated groups to ensure stability */\n.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: coral; }\n.a:not(:where(.vp-raw, .vp-raw *)) { animation: glow 1s linear infinite alternate; }\n\n/* nested blocks */\n.foo:not(:where(.vp-raw, .vp-raw *)) {\n  svg:not(:where(.vp-raw, .vp-raw *)) { display: none; }\n  .bar:not(:where(.vp-raw, .vp-raw *)) { display: inline; }\n}\n\n/* standalone pseudos */\n:not(:where(.vp-raw, .vp-raw *)):first-child { color: pink; }\n:not(:where(.vp-raw, .vp-raw *)):hover { color: blue; }\n:not(:where(.vp-raw, .vp-raw *)):active { color: red; }\n\n/* keyframes (should be ignored) */\n@keyframes fade {\n  from { opacity: 0; }\n  to { opacity: 1; }\n}\n@-webkit-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n@-moz-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n@-o-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n\"\n`;\n"
  },
  {
    "path": "__tests__/unit/node/postcss/isolateStyles.test.ts",
    "content": "import { postcssIsolateStyles } from 'node/postcss/isolateStyles'\nimport postcss from 'postcss'\n\nconst INPUT_CSS = `\n/* simple classes */\n.example { color: red; }\n.class-a { color: coral; }\n.class-b { color: deepskyblue; }\n\n/* escaped colon in class */\n.baz\\\\:not\\\\(.bar\\\\) { display: block; }\n.disabled\\\\:opacity-50:disabled { opacity: .5; }\n\n/* pseudos (class + element) */\n.button:hover { color: pink; }\n.button:focus:hover { color: hotpink; }\n.item::before { content: '•'; }\n::first-letter { color: pink; }\n::before { content: ''; }\n\n/* universal + :not */\n* { background-color: red; }\n*:not(.b) { text-transform: uppercase; }\n\n/* combinators */\n.foo:hover .bar { background: blue; }\nul > li.active { color: green; }\na + b ~ c { color: orange; }\n\n/* ids + attribute selectors */\n#wow { color: yellow; }\n[data-world] .d { padding: 10px 20px; }\n\n/* :root and chained tags */\n:root { --bs-blue: #0d6efd; }\n:root .a { --bs-green: #bada55; }\nhtml { margin: 0; }\nbody { padding: 0; }\nhtml body div { color: blue; }\n\n/* grouping with commas */\n.a, .b { color: red; }\n\n/* multiple repeated groups to ensure stability */\n.a, .b { color: coral; }\n.a { animation: glow 1s linear infinite alternate; }\n\n/* nested blocks */\n.foo {\n  svg { display: none; }\n  .bar { display: inline; }\n}\n\n/* standalone pseudos */\n:first-child { color: pink; }\n:hover { color: blue; }\n:active { color: red; }\n\n/* keyframes (should be ignored) */\n@keyframes fade {\n  from { opacity: 0; }\n  to { opacity: 1; }\n}\n@-webkit-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n@-moz-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n@-o-keyframes glow {\n  from { color: coral; }\n  to { color: red; }\n}\n`\n\ndescribe('node/postcss/isolateStyles', () => {\n  test('transforms selectors and skips keyframes', () => {\n    const out = run(INPUT_CSS)\n    expect(out.css).toMatchSnapshot()\n  })\n\n  test('idempotent (running twice produces identical CSS)', () => {\n    const first = run(INPUT_CSS).css\n    const second = run(first).css\n    expect(second).toBe(first)\n  })\n})\n\nfunction run(css: string, from = 'src/styles/vp-doc.css') {\n  return postcss([postcssIsolateStyles()]).process(css, { from })\n}\n"
  },
  {
    "path": "__tests__/unit/node/utils/moduleGraph.test.ts",
    "content": "import { ModuleGraph } from 'node/utils/moduleGraph'\n\ndescribe('node/utils/moduleGraph', () => {\n  let graph: ModuleGraph\n\n  beforeEach(() => {\n    graph = new ModuleGraph()\n  })\n\n  it('should correctly delete a module and its dependents', () => {\n    graph.add('A', ['B', 'C'])\n    graph.add('B', ['D'])\n    graph.add('C', [])\n    graph.add('D', [])\n\n    expect(graph.delete('D')).toEqual(new Set(['D', 'B', 'A']))\n  })\n\n  it('should handle shared dependencies correctly', () => {\n    graph.add('A', ['B', 'C'])\n    graph.add('B', ['D'])\n    graph.add('C', ['D']) // Shared dependency\n    graph.add('D', [])\n\n    expect(graph.delete('D')).toEqual(new Set(['A', 'B', 'C', 'D']))\n  })\n\n  it('merges dependencies correctly', () => {\n    // Add module A with dependency B\n    graph.add('A', ['B'])\n    // Merge new dependency C into module A (B should remain)\n    graph.add('A', ['C'])\n\n    // Deleting B should remove A as well, since A depends on B.\n    expect(graph.delete('B')).toEqual(new Set(['B', 'A']))\n  })\n\n  it('handles cycles gracefully', () => {\n    // Create a cycle: A -> B, B -> C, C -> A.\n    graph.add('A', ['B'])\n    graph.add('B', ['C'])\n    graph.add('C', ['A'])\n\n    // Deleting any module in the cycle should delete all modules in the cycle.\n    expect(graph.delete('A')).toEqual(new Set(['A', 'B', 'C']))\n  })\n\n  it('cleans up dependencies when deletion', () => {\n    // Setup A -> B relationship.\n    graph.add('A', ['B'])\n    graph.add('B', [])\n\n    // Deleting B should remove both B and A from the graph.\n    expect(graph.delete('B')).toEqual(new Set(['B', 'A']))\n\n    // After deletion, add modules again.\n    graph.add('C', [])\n    graph.add('A', ['C']) // Now A depends only on C.\n\n    expect(graph.delete('C')).toEqual(new Set(['C', 'A']))\n  })\n\n  it('handles independent modules', () => {\n    // Modules with no dependencies.\n    graph.add('X', [])\n    graph.add('Y', [])\n\n    // Deletion of one should only remove that module.\n    expect(graph.delete('X')).toEqual(new Set(['X']))\n    expect(graph.delete('Y')).toEqual(new Set(['Y']))\n  })\n})\n"
  },
  {
    "path": "__tests__/unit/shims.ts",
    "content": "export default {}\n"
  },
  {
    "path": "__tests__/unit/vitest.config.ts",
    "content": "import vue from '@vitejs/plugin-vue'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { defineConfig } from 'vitest/config'\n\nconst dir = dirname(fileURLToPath(import.meta.url))\n\nexport default defineConfig({\n  plugins: [vue()],\n  resolve: {\n    alias: [\n      { find: '@siteData', replacement: resolve(dir, './shims.ts') },\n      { find: 'client', replacement: resolve(dir, '../../src/client') },\n      { find: 'node', replacement: resolve(dir, '../../src/node') },\n      { find: 'shared', replacement: resolve(dir, '../../src/shared') },\n      {\n        find: /^vitepress$/,\n        replacement: resolve(dir, '../../src/client/index.js')\n      },\n      {\n        find: /^vitepress\\/theme$/,\n        replacement: resolve(dir, '../../src/client/theme-default/index.js')\n      }\n    ]\n  },\n  test: {\n    globals: true\n  }\n})\n"
  },
  {
    "path": "bin/vitepress.js",
    "content": "#!/usr/bin/env node\n// @ts-check\n\nimport module from 'node:module'\n\n// https://github.com/vitejs/vite/blob/6c8a5a27e645a182f5b03a4ed6aa726eab85993f/packages/vite/bin/vite.js#L48-L63\ntry {\n  module.enableCompileCache?.()\n  setTimeout(() => {\n    try {\n      module.flushCompileCache?.()\n    } catch {}\n  }, 10 * 1000).unref()\n} catch {}\n\nimport('../dist/node/cli.js')\n"
  },
  {
    "path": "client.d.ts",
    "content": "// re-export vite client types. with strict installers like pnpm, user won't\n// be able to reference vite/client in project root.\n/// <reference types=\"vite/client\" />\n\nexport * from './dist/client/index.js'\n\ndeclare global {\n  interface WindowEventMap {\n    'vitepress:codeGroupTabActivate': Event & {\n      /** code block element that was activated */\n      detail: Element\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.postcssrc.json",
    "content": "{\n  \"plugins\": {\n    \"postcss-rtlcss\": {\n      \"ltrPrefix\": \":where([dir=\\\"ltr\\\"])\",\n      \"rtlPrefix\": \":where([dir=\\\"rtl\\\"])\"\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/config.ts",
    "content": "import {\n  defineConfig,\n  resolveSiteDataByRoute,\n  type HeadConfig\n} from 'vitepress'\nimport {\n  groupIconMdPlugin,\n  groupIconVitePlugin,\n  localIconLoader\n} from 'vitepress-plugin-group-icons'\nimport llmstxt from 'vitepress-plugin-llms'\n\nconst prod = !!process.env.NETLIFY\n\nexport default defineConfig({\n  title: 'VitePress',\n\n  rewrites: {\n    'en/:rest*': ':rest*'\n  },\n\n  lastUpdated: true,\n  cleanUrls: true,\n  metaChunk: true,\n\n  markdown: {\n    math: true,\n    codeTransformers: [\n      // We use `[!!code` and `@@include` in demo to prevent transformation,\n      // here we revert it back.\n      {\n        postprocess(code) {\n          return code\n            .replaceAll('[!!code', '[!code')\n            .replaceAll('@@include', '@include')\n        }\n      }\n    ],\n    config(md) {\n      // TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed\n      const fence = md.renderer.rules.fence!\n      md.renderer.rules.fence = function (tokens, idx, options, env, self) {\n        const { localeIndex = 'root' } = env\n        const codeCopyButtonTitle = (() => {\n          switch (localeIndex) {\n            case 'es':\n              return 'Copiar código'\n            case 'fa':\n              return 'کپی کد'\n            case 'ko':\n              return '코드 복사'\n            case 'pt':\n              return 'Copiar código'\n            case 'ru':\n              return 'Скопировать код'\n            case 'zh':\n              return '复制代码'\n            case 'ja':\n              return 'コードをコピー'\n            default:\n              return 'Copy code'\n          }\n        })()\n        return fence(tokens, idx, options, env, self).replace(\n          '<button title=\"Copy Code\" class=\"copy\"></button>',\n          `<button title=\"${codeCopyButtonTitle}\" class=\"copy\"></button>`\n        )\n      }\n      md.use(groupIconMdPlugin)\n    }\n  },\n\n  sitemap: {\n    hostname: 'https://vitepress.dev',\n    transformItems(items) {\n      return items.filter((item) => !item.url.includes('migration'))\n    }\n  },\n\n  head: [\n    [\n      'link',\n      { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }\n    ],\n    [\n      'link',\n      { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }\n    ],\n    ['meta', { name: 'theme-color', content: '#5f67ee' }],\n    ['meta', { property: 'og:type', content: 'website' }],\n    ['meta', { property: 'og:site_name', content: 'VitePress' }],\n    [\n      'meta',\n      {\n        property: 'og:image',\n        content: 'https://vitepress.dev/vitepress-og.jpg'\n      }\n    ],\n    ['meta', { property: 'og:url', content: 'https://vitepress.dev/' }],\n    [\n      'script',\n      {\n        src: 'https://cdn.usefathom.com/script.js',\n        'data-site': 'AZBRSFGG',\n        'data-spa': 'auto',\n        defer: ''\n      }\n    ]\n  ],\n\n  themeConfig: {\n    logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 },\n\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' }\n    ],\n\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '8J64VVRP8K',\n        apiKey: '52f578a92b88ad6abde815aae2b0ad7c',\n        indexName: 'vitepress',\n        askAi: {\n          assistantId: 'YaVSonfX5bS8',\n          sidePanel: true\n        }\n      }\n    },\n\n    carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' }\n  },\n\n  locales: {\n    root: { label: 'English', lang: 'en-US', dir: 'ltr' },\n    zh: { label: '简体中文', lang: 'zh-Hans', dir: 'ltr' },\n    pt: { label: 'Português', lang: 'pt-BR', dir: 'ltr' },\n    ru: { label: 'Русский', lang: 'ru-RU', dir: 'ltr' },\n    es: { label: 'Español', lang: 'es', dir: 'ltr' },\n    ko: { label: '한국어', lang: 'ko-KR', dir: 'ltr' },\n    fa: { label: 'فارسی', lang: 'fa-IR', dir: 'rtl' },\n    ja: { label: '日本語', lang: 'ja', dir: 'ltr' }\n  },\n\n  vite: {\n    plugins: [\n      groupIconVitePlugin({\n        customIcon: {\n          vitepress: localIconLoader(\n            import.meta.url,\n            '../public/vitepress-logo-mini.svg'\n          ),\n          firebase: 'logos:firebase'\n        }\n      }),\n      prod &&\n        llmstxt({\n          workDir: 'en',\n          ignoreFiles: ['index.md']\n        })\n    ],\n    experimental: {\n      enableNativePlugin: true\n    }\n  },\n\n  transformPageData: prod\n    ? (pageData, ctx) => {\n        const site = resolveSiteDataByRoute(\n          ctx.siteConfig.site,\n          pageData.relativePath\n        )\n        const title = `${pageData.title || site.title} | ${pageData.description || site.description}`\n        ;((pageData.frontmatter.head ??= []) as HeadConfig[]).push(\n          ['meta', { property: 'og:locale', content: site.lang }],\n          ['meta', { property: 'og:title', content: title }]\n        )\n      }\n    : undefined\n})\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "import Theme from 'vitepress/theme'\nimport 'virtual:group-icons.css'\nimport './styles.css'\n\nexport default Theme\n"
  },
  {
    "path": "docs/.vitepress/theme/styles.css",
    "content": ":root:where(:lang(fa)) {\n  --vp-font-family-base:\n    'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif,\n    'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n}\n\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(\n    120deg,\n    #bd34fe 30%,\n    #41d1ff\n  );\n  --vp-home-hero-image-background-image: linear-gradient(\n    -45deg,\n    #bd34fe 50%,\n    #47caff 50%\n  );\n  --vp-home-hero-image-filter: blur(44px);\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(68px);\n  }\n}\n\n.VPHero .VPImage {\n  filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, 0.2));\n  padding: 18px;\n}\n\n/* used in reference/default-theme-search */\nimg[src='/search.png'] {\n  width: 100%;\n  aspect-ratio: 1 / 1;\n}\n"
  },
  {
    "path": "docs/components/ComponentInHeader.vue",
    "content": "<template>\n  <span>&#x26A1;</span>\n</template>\n"
  },
  {
    "path": "docs/components/ModalDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nconst showModal = ref(false)\n</script>\n\n<template>\n  <button class=\"modal-button\" @click=\"showModal = true\">Show Modal</button>\n\n  <Teleport to=\"body\">\n    <Transition name=\"modal\">\n      <div v-show=\"showModal\" class=\"modal-mask\">\n        <div class=\"modal-container\">\n          <p>Hello from the modal!</p>\n          <div class=\"model-footer\">\n            <button class=\"modal-button\" @click=\"showModal = false\">\n              Close\n            </button>\n          </div>\n        </div>\n      </div>\n    </Transition>\n  </Teleport>\n</template>\n\n<style scoped>\n.modal-mask {\n  position: fixed;\n  z-index: 200;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n}\n\n.modal-container {\n  width: 300px;\n  margin: auto;\n  padding: 20px 30px;\n  background-color: var(--vp-c-bg);\n  border-radius: 2px;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);\n  transition: all 0.3s ease;\n}\n\n.model-footer {\n  margin-top: 8px;\n  text-align: right;\n}\n\n.modal-button {\n  padding: 4px 8px;\n  border-radius: 4px;\n  border-color: var(--vp-button-alt-border);\n  color: var(--vp-button-alt-text);\n  background-color: var(--vp-button-alt-bg);\n}\n\n.modal-button:hover {\n  border-color: var(--vp-button-alt-hover-border);\n  color: var(--vp-button-alt-hover-text);\n  background-color: var(--vp-button-alt-hover-bg);\n}\n\n.modal-enter-from,\n.modal-leave-to {\n  opacity: 0;\n}\n\n.modal-enter-from .modal-container,\n.modal-leave-to .modal-container {\n  transform: scale(1.1);\n}\n</style>\n"
  },
  {
    "path": "docs/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Vite & Vue powered static site generator.',\n\n  themeConfig: {\n    nav: nav(),\n\n    sidebar: {\n      '/guide/': { base: '/guide/', items: sidebarGuide() },\n      '/reference/': { base: '/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    },\n\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'Guide',\n      link: '/guide/what-is-vitepress',\n      activeMatch: '/guide/'\n    },\n    {\n      text: 'Reference',\n      link: '/reference/site-config',\n      activeMatch: '/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/'\n        },\n        {\n          text: 'Changelog',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'Contributing',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Introduction',\n      collapsed: false,\n      items: [\n        { text: 'What is VitePress?', link: 'what-is-vitepress' },\n        { text: 'Getting Started', link: 'getting-started' },\n        { text: 'Routing', link: 'routing' },\n        { text: 'Deploy', link: 'deploy' }\n      ]\n    },\n    {\n      text: 'Writing',\n      collapsed: false,\n      items: [\n        { text: 'Markdown Extensions', link: 'markdown' },\n        { text: 'Asset Handling', link: 'asset-handling' },\n        { text: 'Frontmatter', link: 'frontmatter' },\n        { text: 'Using Vue in Markdown', link: 'using-vue' },\n        { text: 'Internationalization', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'Customization',\n      collapsed: false,\n      items: [\n        { text: 'Using a Custom Theme', link: 'custom-theme' },\n        {\n          text: 'Extending the Default Theme',\n          link: 'extending-default-theme'\n        },\n        { text: 'Build-Time Data Loading', link: 'data-loading' },\n        { text: 'SSR Compatibility', link: 'ssr-compat' },\n        { text: 'Connecting to a CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: 'Experimental',\n      collapsed: false,\n      items: [\n        { text: 'MPA Mode', link: 'mpa-mode' },\n        { text: 'Sitemap Generation', link: 'sitemap-generation' }\n      ]\n    },\n    { text: 'Config & API Reference', base: '/reference/', link: 'site-config' }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Reference',\n      items: [\n        { text: 'Site Config', link: 'site-config' },\n        { text: 'Frontmatter Config', link: 'frontmatter-config' },\n        { text: 'Runtime API', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: 'Default Theme',\n          base: '/reference/default-theme-',\n          items: [\n            { text: 'Overview', link: 'config' },\n            { text: 'Nav', link: 'nav' },\n            { text: 'Sidebar', link: 'sidebar' },\n            { text: 'Home Page', link: 'home-page' },\n            { text: 'Footer', link: 'footer' },\n            { text: 'Layout', link: 'layout' },\n            { text: 'Badge', link: 'badge' },\n            { text: 'Team Page', link: 'team-page' },\n            { text: 'Prev / Next Links', link: 'prev-next-links' },\n            { text: 'Edit Link', link: 'edit-link' },\n            { text: 'Last Updated Timestamp', link: 'last-updated' },\n            { text: 'Search', link: 'search' },\n            { text: 'Carbon Ads', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/en/guide/asset-handling.md",
    "content": "# Asset Handling\n\n## Referencing Static Assets\n\nAll Markdown files are compiled into Vue components and processed by [Vite](https://vitejs.dev/guide/assets.html). You can, **and should**, reference any assets using relative URLs:\n\n```md\n![An image](./image.png)\n```\n\nYou can reference static assets in your markdown files, your `*.vue` components in the theme, styles and plain `.css` files either using absolute public paths (based on project root) or relative paths (based on your file system). The latter is similar to the behavior you are used to if you have used Vite, Vue CLI, or webpack's `file-loader`.\n\nCommon image, media, and font filetypes are detected and included as assets automatically.\n\n::: tip Linked files are not treated as assets\nPDFs or other documents referenced by links within markdown files are not automatically treated as assets. To make linked files accessible, you must manually place them within the [`public`](#the-public-directory) directory of your project.\n:::\n\nAll referenced assets, including those using absolute paths, will be copied to the output directory with a hashed file name in the production build. Never-referenced assets will not be copied. Image assets smaller than 4kb will be base64 inlined - this can be configured via the [`vite`](../reference/site-config#vite) config option.\n\nAll **static** path references, including absolute paths, should be based on your working directory structure.\n\n## The Public Directory\n\nSometimes you may need to provide static assets that are not directly referenced in any of your Markdown or theme components, or you may want to serve certain files with the original filename. Examples of such files include `robots.txt`, favicons, and PWA icons.\n\nYou can place these files in the `public` directory under the [source directory](./routing#source-directory). For example, if your project root is `./docs` and using default source directory location, then your public directory will be `./docs/public`.\n\nAssets placed in `public` will be copied to the root of the output directory as-is.\n\nNote that you should reference files placed in `public` using root absolute path - for example, `public/icon.png` should always be referenced in source code as `/icon.png`.\n\n## Base URL\n\nIf your site is deployed to a non-root URL, you will need to set the `base` option in `.vitepress/config.js`. For example, if you plan to deploy your site to `https://foo.github.io/bar/`, then `base` should be set to `'/bar/'` (it should always start and end with a slash).\n\nAll your static asset paths are automatically processed to adjust for different `base` config values. For example, if you have an absolute reference to an asset under `public` in your markdown:\n\n```md\n![An image](/image-inside-public.png)\n```\n\nYou do **not** need to update it when you change the `base` config value in this case.\n\nHowever, if you are authoring a theme component that links to assets dynamically, e.g. an image whose `src` is based on a theme config value:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nIn this case it is recommended to wrap the path with the [`withBase` helper](../reference/runtime-api#withbase) provided by VitePress:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/en/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# Connecting to a CMS\n\n## General Workflow\n\nConnecting VitePress to a CMS will largely revolve around [Dynamic Routes](./routing#dynamic-routes). Make sure to understand how it works before proceeding.\n\nSince each CMS will work differently, here we can only provide a generic workflow that you will need to adapt to your specific scenario.\n\n1. If your CMS requires authentication, create an `.env` file to store your API tokens and load it so:\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. Fetch the necessary data from the CMS and format it into proper paths data:\n\n    ```js\n    export default {\n      async paths() {\n        // use respective CMS client library if needed\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // token if necessary\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* title, authors, date etc. */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. Render the content in the page:\n\n    ```md\n    # {{ $params.title }}\n\n    - by {{ $params.author }} on {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## Integration Guides\n\nIf you have written a guide on integrating VitePress with a specific CMS, please use the \"Edit this page\" link below to submit it here!\n"
  },
  {
    "path": "docs/en/guide/custom-theme.md",
    "content": "# Using a Custom Theme\n\n## Theme Resolving\n\nYou can enable a custom theme by creating a `.vitepress/theme/index.js` or `.vitepress/theme/index.ts` file (the \"theme entry file\"):\n\n```\n.\n├─ docs                # project root\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # theme entry\n│  │  └─ config.js     # config file\n│  └─ index.md\n└─ package.json\n```\n\nVitePress will always use the custom theme instead of the default theme when it detects presence of a theme entry file. You can, however, [extend the default theme](./extending-default-theme) to perform advanced customizations on top of it.\n\n## Theme Interface\n\nA VitePress custom theme is defined as an object with the following interface:\n\n```ts\ninterface Theme {\n  /**\n   * Root layout component for every page\n   * @required\n   */\n  Layout: Component\n  /**\n   * Enhance Vue app instance\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * Extend another theme, calling its `enhanceApp` before ours\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // Vue app instance\n  router: Router // VitePress router instance\n  siteData: Ref<SiteData> // Site-level metadata\n}\n```\n\nThe theme entry file should export the theme as its default export:\n\n```js [.vitepress/theme/index.js]\n\n// You can directly import Vue files in the theme entry\n// VitePress is pre-configured with @vitejs/plugin-vue.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nThe default export is the only contract for a custom theme, and only the `Layout` property is required. So technically, a VitePress theme can be as simple as a single Vue component.\n\nInside your layout component, it works just like a normal Vite + Vue 3 application. Do note the theme also needs to be [SSR-compatible](./ssr-compat).\n\n## Building a Layout\n\nThe most basic layout component needs to contain a [`<Content />`](../reference/runtime-api#content) component:\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Custom Layout!</h1>\n\n  <!-- this is where markdown content will be rendered -->\n  <Content />\n</template>\n```\n\nThe above layout simply renders every page's markdown as HTML. The first improvement we can add is to handle 404 errors:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <Content v-else />\n</template>\n```\n\nThe [`useData()`](../reference/runtime-api#usedata) helper provides us with all the runtime data we need to conditionally render different layouts. One of the other data we can access is the current page's frontmatter. We can leverage this to allow the end user to control the layout in each page. For example, the user can indicate the page should use a special home page layout with:\n\n```md\n---\nlayout: home\n---\n```\n\nAnd we can adjust our theme to handle this:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Custom home page!\n  </div>\n  <Content v-else />\n</template>\n```\n\nYou can, of course, split the layout into more components:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> renders <Content /> -->\n</template>\n```\n\nConsult the [Runtime API Reference](../reference/runtime-api) for everything available in theme components. In addition, you can leverage [Build-Time Data Loading](./data-loading) to generate data-driven layout - for example, a page that lists all blog posts in the current project.\n\n## Distributing a Custom Theme\n\nThe easiest way to distribute a custom theme is by providing it as a [template repository on GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).\n\nIf you wish to distribute the theme as an npm package, follow these steps:\n\n1. Export the theme object as the default export in your package entry.\n\n2. If applicable, export your theme config type definition as `ThemeConfig`.\n\n3. If your theme requires adjusting the VitePress config, export that config under a package sub-path (e.g. `my-theme/config`) so the user can extend it.\n\n4. Document the theme config options (both via config file and frontmatter).\n\n5. Provide clear instructions on how to consume your theme (see below).\n\n## Consuming a Custom Theme\n\nTo consume an external theme, import and re-export it from the custom theme entry:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nIf the theme needs to be extended:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nIf the theme requires special VitePress config, you will need to also extend it in your own config:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // extend theme base config (if needed)\n  extends: baseConfig\n}\n```\n\nFinally, if the theme provides types for its theme config:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // Type is `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/en/guide/data-loading.md",
    "content": "# Build-Time Data Loading\n\nVitePress provides a feature called **data loaders** that allows you to load arbitrary data and import it from pages or components. The data loading is executed **only at build time**: the resulting data will be serialized as JSON in the final JavaScript bundle.\n\nData loaders can be used to fetch remote data, or generate metadata based on local files. For example, you can use data loaders to parse all your local API pages and automatically generate an index of all API entries.\n\n## Basic Usage\n\nA data loader file must end with either `.data.js` or `.data.ts`. The file should provide a default export of an object with the `load()` method:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\nThe loader module is evaluated only in Node.js, so you can import Node APIs and npm dependencies as needed.\n\nYou can then import data from this file in `.md` pages and `.vue` components using the `data` named export:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\nOutput:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\nYou'll notice the data loader itself does not export the `data`. It is VitePress calling the `load()` method behind the scenes and implicitly exposing the result via the `data` named export.\n\nThis works even if the loader is async:\n\n```js\nexport default {\n  async load() {\n    // fetch remote data\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## Data from Local Files\n\nWhen you need to generate data based on local files, you should use the `watch` option in the data loader so that changes made to these files can trigger hot updates.\n\nThe `watch` option is also convenient in that you can use [glob patterns](https://github.com/mrmlnc/fast-glob#pattern-syntax) to match multiple files. The patterns can be relative to the loader file itself, and the `load()` function will receive the matched files as absolute paths.\n\nThe following example shows loading CSV files and transforming them into JSON using [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Because this file only executes at build time, you will not be shipping the CSV parser to the client!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles will be an array of absolute paths of the matched files.\n    // generate an array of blog post metadata that can be used to render\n    // a list in the theme layout\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\nWhen building a content focused site, we often need to create an \"archive\" or \"index\" page: a page where we list all available entries in our content collection, for example blog posts or API pages. We **can** implement this directly with the data loader API, but since this is such a common use case, VitePress also provides a `createContentLoader` helper to simplify this:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* options */)\n```\n\nThe helper takes a glob pattern relative to the [source directory](./routing#source-directory), and returns a `{ watch, load }` data loader object that can be used as the default export in a data loader file. It also implements caching based on file modified timestamps to improve dev performance.\n\nNote the loader only works with Markdown files - matched non-Markdown files will be skipped.\n\nThe loaded data will be an array with the type of `ContentData[]`:\n\n```ts\ninterface ContentData {\n  // mapped URL for the page. e.g. /posts/hello.html (does not include base)\n  // manually iterate or use custom `transform` to normalize the paths\n  url: string\n  // frontmatter data of the page\n  frontmatter: Record<string, any>\n\n  // the following are only present if relevant options are enabled\n  // we will discuss them below\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nBy default, only `url` and `frontmatter` are provided. This is because the loaded data will be inlined as JSON in the client bundle, so we need to be cautious about its size. Here's an example using the data to build a minimal blog index page:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>All Blog Posts</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>by {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### Options\n\nThe default data may not suit all needs - you can opt-in to transform the data using options:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // include raw markdown source?\n  render: true,     // include rendered full page HTML?\n  excerpt: true,    // include excerpt?\n  transform(rawData) {\n    // map, sort, or filter the raw data as you wish.\n    // the final result is what will be shipped to the client.\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // raw markdown source\n      page.html    // rendered full page HTML\n      page.excerpt // rendered excerpt HTML (content above first `---`)\n      return {/* ... */}\n    })\n  }\n})\n```\n\nCheck out how it is used in the [Vue.js blog](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).\n\nThe `createContentLoader` API can also be used inside [build hooks](../reference/site-config#build-hooks):\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // generate files based on posts metadata, e.g. RSS feed\n  }\n}\n```\n\n**Types**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * Include src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * Render src to HTML and include in data?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * If `boolean`, whether to parse and include excerpt? (rendered as HTML)\n   *\n   * If `function`, control how the excerpt is extracted from the content.\n   *\n   * If `string`, define a custom separator to be used for extracting the\n   * excerpt. Default separator is `---` if `excerpt` is `true`.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * Transform the data. Note the data will be inlined as JSON in the client\n   * bundle if imported from components or markdown files.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## Typed Data Loaders\n\nWhen using TypeScript, you can type your loader and `data` export like so:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // data type\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // type checked loader options\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## Configuration\n\nTo get the configuration information inside a loader, you can use some code like this:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/en/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# Deploy Your VitePress Site\n\nThe following guides are based on some shared assumptions:\n\n- The VitePress site is inside the `docs` directory of your project.\n- You are using the default build output directory (`.vitepress/dist`).\n- VitePress is installed as a local dependency in your project, and you have set up the following scripts in your `package.json`:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## Build and Test Locally\n\n1. Run this command to build the docs:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. Once built, preview it locally by running:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   The `preview` command will boot up a local static web server that will serve the output directory `.vitepress/dist` at `http://localhost:4173`. You can use this to make sure everything looks good before pushing to production.\n\n3. You can configure the port of the server by passing `--port` as an argument.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   Now the `docs:preview` method will launch the server at `http://localhost:8080`.\n\n## Setting a Public Base Path\n\nBy default, we assume the site is going to be deployed at the root path of a domain (`/`). If your site is going to be served at a sub-path, e.g. `https://mywebsite.com/blog/`, then you need to set the [`base`](../reference/site-config#base) option to `'/blog/'` in the VitePress config.\n\n**Example:** If you're using Github (or GitLab) Pages and deploying to `user.github.io/repo/`, then set your `base` to `/repo/`.\n\n## HTTP Cache Headers\n\nIf you have control over the HTTP headers on your production server, you can configure `cache-control` headers to achieve better performance on repeated visits.\n\nThe production build uses hashed file names for static assets (JavaScript, CSS and other imported assets not in `public`). If you inspect the production preview using your browser devtools' network tab, you will see files like `app.4f283b18.js`.\n\nThis `4f283b18` hash is generated from the content of this file. The same hashed URL is guaranteed to serve the same file content - if the contents change, the URLs change too. This means you can safely use the strongest cache headers for these files. All such files will be placed under `assets/` in the output directory, so you can configure the following header for them:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Example Netlify `_headers` file\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\nNote: the `_headers` file should be placed in the [public directory](./asset-handling#the-public-directory) - in our case, `docs/public/_headers` - so that it is copied verbatim to the output directory.\n\n[Netlify custom headers documentation](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details Example Vercel config in `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nNote: the `vercel.json` file should be placed at the root of your **repository**.\n\n[Vercel documentation on headers config](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## Platform Guides\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\nSet up a new project and change these settings using your dashboard:\n\n- **Build Command:** `npm run docs:build`\n- **Output Directory:** `docs/.vitepress/dist`\n- **Node Version:** `20` (or above)\n\n::: warning\nDon't enable options like _Auto Minify_ for HTML code. It will remove comments from output which have meaning to Vue. You may see hydration mismatch errors if they get removed.\n:::\n\n### GitHub Pages\n\n1. Create a file named `deploy.yml` inside `.github/workflows` directory of your project with some content like this:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Sample workflow for building and deploying a VitePress site to GitHub Pages\n   #\n   name: Deploy VitePress site to Pages\n\n   on:\n     # Runs on pushes targeting the `main` branch. Change this to `master` if you're\n     # using the `master` branch as the default branch.\n     push:\n       branches: [main]\n\n     # Allows you to run this workflow manually from the Actions tab\n     workflow_dispatch:\n\n   # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n   # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Build job\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # Not needed if lastUpdated is not enabled\n         # - uses: pnpm/action-setup@v4 # Uncomment this block if you're using pnpm\n         #   with:\n         #     version: 9 # Not needed if you've set \"packageManager\" in package.json\n         # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # or pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # or pnpm install / yarn install / bun install\n         - name: Build with VitePress\n           run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Deployment job\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   Make sure the `base` option in your VitePress is properly configured. See [Setting a Public Base Path](#setting-a-public-base-path) for more details.\n   :::\n\n2. In your repository's settings under \"Pages\" menu item, select \"GitHub Actions\" in \"Build and deployment > Source\".\n\n3. Push your changes to the `main` branch and wait for the GitHub Actions workflow to complete. You should see your site deployed to `https://<username>.github.io/[repository]/` or `https://<custom-domain>/` depending on your settings. Your site will automatically be deployed on every push to the `main` branch.\n\n### GitLab Pages\n\n1. Set `outDir` in VitePress config to `../public`. Configure `base` option to `'/<repository>/'` if you want to deploy to `https://<username>.gitlab.io/<repository>/`. You don't need `base` if you're deploying to custom domain, user or group pages, or have \"Use unique domain\" setting enabled in GitLab.\n\n2. Create a file named `.gitlab-ci.yml` in the root of your project with the content below. This will build and deploy your site whenever you make changes to your content:\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Uncomment this if you're using small docker images like alpine and have lastUpdated enabled\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n<!-- keep headings sorted alphabetically, leave nginx at the end -->\n\n### Azure\n\n1. Follow the [official documentation](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration).\n\n2. Set these values in your configuration file (and remove the ones you don't require, like `api_location`):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\nYou can deploy your VitePress project with [CloudRay](https://cloudray.io/) by following these [instructions](https://cloudray.io/articles/how-to-deploy-vitepress-site).\n\n### Firebase\n\n1. Create `firebase.json` and `.firebaserc` at the root of your project:\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. After running `npm run docs:build`, run this command to deploy:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. Follow documentation and guide given in [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static).\n\n2. Create a file called `static.json` in the root of your project with the below content:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\nYou can deploy your VitePress project with [Hostinger](https://www.hostinger.com/web-apps-hosting) by following these [instructions](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/). While configuring build settings, choose VitePress as the framework and adjust the root directory to `./docs`.\n\n### Kinsta\n\nYou can deploy your VitePress website on [Kinsta](https://kinsta.com/static-site-hosting/) by following these [instructions](https://kinsta.com/docs/vitepress-static-site-example/).\n\n### Stormkit\n\nYou can deploy your VitePress project to [Stormkit](https://www.stormkit.io) by following these [instructions](https://stormkit.io/blog/how-to-deploy-vitepress).\n\n### Surge\n\n1. After running `npm run docs:build`, run this command to deploy:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\nHere is a example of an Nginx server block configuration. This setup includes gzip compression for common text-based assets, rules for serving your VitePress site's static files with proper caching headers as well as handling `cleanUrls: true`.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # content location\n        root /app;\n\n        # exact matches -> reverse clean urls -> folders -> not found\n        try_files $uri $uri.html $uri/ =404;\n\n        # non existent pages\n        error_page 404 /404.html;\n\n        # a folder without index.html raises 403 in this setup\n        error_page 403 /404.html;\n\n        # adjust caching headers\n        # files in the assets folder have hashes filenames\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nThis configuration assumes that your built VitePress site is located in the `/app` directory on your server. Adjust the `root` directive accordingly if your site's files are located elsewhere.\n\n::: warning Do not default to index.html\nThe try_files resolution must not default to index.html like in other Vue applications. This would result in an invalid page state.\n:::\n\nFurther information can be found in the [official nginx documentation](https://nginx.org/en/docs/), in these issues [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235) as well as in this [blog post](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) by Mehdi Merah.\n"
  },
  {
    "path": "docs/en/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# Extending the Default Theme\n\nVitePress' default theme is optimized for documentation, and can be customized. Consult the [Default Theme Config Overview](../reference/default-theme-config) for a comprehensive list of options.\n\nHowever, there are a number of cases where configuration alone won't be enough. For example:\n\n1. You need to tweak the CSS styling;\n2. You need to modify the Vue app instance, for example to register global components;\n3. You need to inject custom content into the theme via layout slots.\n\nThese advanced customizations will require using a custom theme that \"extends\" the default theme.\n\n::: tip\nBefore proceeding, make sure to first read [Using a Custom Theme](./custom-theme) to understand how custom themes work.\n:::\n\n## Customizing CSS\n\nThe default theme CSS is customizable by overriding root level CSS variables:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\nSee [default theme CSS variables](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) that can be overridden.\n\n## Using Different Fonts\n\nVitePress uses [Inter](https://rsms.me/inter/) as the default font, and will include the fonts in the build output. The font is also auto preloaded in production. However, this may not be desirable if you want to use a different main font.\n\nTo avoid including Inter in the build output, import the theme from `vitepress/theme-without-fonts` instead:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* normal text font */\n  --vp-font-family-mono: /* code font */\n}\n```\n\n::: warning\nIf you are using optional components like the [Team Page](../reference/default-theme-team-page) components, make sure to also import them from `vitepress/theme-without-fonts`!\n:::\n\nIf your font is a local file referenced via `@font-face`, it will be processed as an asset and included under `.vitepress/dist/assets` with hashed filename. To preload this file, use the [transformHead](../reference/site-config#transformhead) build hook:\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // adjust the regex accordingly to match your font\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## Registering Global Components\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // register your custom global components\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nIf you're using TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // register your custom global components\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nSince we are using Vite, you can also leverage Vite's [glob import feature](https://vitejs.dev/guide/features.html#glob-import) to auto register a directory of components.\n\n## Layout Slots\n\nThe default theme's `<Layout/>` component has a few slots that can be used to inject content at certain locations of the page. Here's an example of injecting a component into the before outline:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // override the Layout with a wrapper component that\n  // injects the slots\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      My custom sidebar top content\n    </template>\n  </Layout>\n</template>\n```\n\nOr you could use render function as well.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nFull list of slots available in the default theme layout:\n\n- When `layout: 'doc'` (default) is enabled via frontmatter:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- When `layout: 'home'` is enabled via frontmatter:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- When `layout: 'page'` is enabled via frontmatter:\n  - `page-top`\n  - `page-bottom`\n- On not found (404) page:\n  - `not-found`\n- Always:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## Using View Transitions API\n\n### On Appearance Toggle\n\nYou can extend the default theme to provide a custom transition when the color mode is toggled. An example:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\nResult (**warning!**: flashing colors, sudden movements, bright lights):\n\n<details>\n<summary>Demo</summary>\n\n![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)\n\n</details>\n\nRefer [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) from more details on view transitions.\n\n### On Route Change\n\nComing soon.\n\n## Overriding Internal Components\n\nYou can use Vite's [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) to replace default theme components with your custom ones:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./theme/components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\nTo know the exact name of the component refer [our source code](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Since the components are internal, there is a slight chance their name is updated between minor releases.\n"
  },
  {
    "path": "docs/en/guide/frontmatter.md",
    "content": "# Frontmatter\n\n## Usage\n\nVitePress supports YAML frontmatter in all Markdown files, parsing them with [gray-matter](https://github.com/jonschlinkert/gray-matter). The frontmatter must be at the top of the Markdown file (before any elements including `<script>` tags), and must take the form of valid YAML set between triple-dashed lines. Example:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\nMany site or default theme config options have corresponding options in frontmatter. You can use frontmatter to override specific behavior for the current page only. For details, see [Frontmatter Config Reference](../reference/frontmatter-config).\n\nYou can also define custom frontmatter data of your own, to be used in dynamic Vue expressions on the page.\n\n## Accessing Frontmatter Data\n\nFrontmatter data can be accessed via the special `$frontmatter` global variable:\n\nHere's an example of how you could use it in your Markdown file:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nGuide content\n```\n\nYou can also access current page's frontmatter data in `<script setup>` with the [`useData()`](../reference/runtime-api#usedata) helper.\n\n## Alternative Frontmatter Formats\n\nVitePress also supports JSON frontmatter syntax, starting and ending in curly braces:\n\n```json\n---\n{\n  \"title\": \"Blogging Like a Hacker\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/en/guide/getting-started.md",
    "content": "# Getting Started\n\n## Try It Online\n\nYou can try VitePress directly in your browser on [StackBlitz](https://vitepress.new).\n\n## Installation\n\n### Prerequisites\n\n- [Node.js](https://nodejs.org/) version 20 or higher.\n- Terminal for accessing VitePress via its command line interface (CLI).\n- Text Editor with [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax support.\n  - [VSCode](https://code.visualstudio.com/) is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nVitePress can be used on its own, or be installed into an existing project. In both cases, you can install it with:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip NOTE\n\nVitePress is an ESM-only package. Don't use `require()` to import it, and make sure your nearest `package.json` contains `\"type\": \"module\"`, or change the file extension of your relevant files like `.vitepress/config.js` to `.mjs`/`.mts`. Refer to [Vite's troubleshooting guide](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) for more details. Also, inside async CJS contexts, you can use `await import('vitepress')` instead.\n\n:::\n\n### Setup Wizard\n\nVitePress ships with a command line setup wizard that will help you scaffold a basic project. After installation, start the wizard by running:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nYou will be greeted with a few simple questions:\n\n<<< @/snippets/init.ansi\n\n::: tip Vue as Peer Dependency\nIf you intend to perform customization that uses Vue components or APIs, you should also explicitly install `vue` as a dependency.\n:::\n\n## File Structure\n\nIf you are building a standalone VitePress site, you can scaffold the site in your current directory (`./`). However, if you are installing VitePress in an existing project alongside other source code, it is recommended to scaffold the site in a nested directory (e.g. `./docs`) so that it is separate from the rest of the project.\n\nAssuming you chose to scaffold the VitePress project in `./docs`, the generated file structure should look like this:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\nThe `docs` directory is considered the **project root** of the VitePress site. The `.vitepress` directory is a reserved location for VitePress' config file, dev server cache, build output, and optional theme customization code.\n\n::: tip\nBy default, VitePress stores its dev server cache in `.vitepress/cache`, and the production build output in `.vitepress/dist`. If using Git, you should add them to your `.gitignore` file. These locations can also be [configured](../reference/site-config#outdir).\n:::\n\n### The Config File\n\nThe config file (`.vitepress/config.js`) allows you to customize various aspects of your VitePress site, with the most basic options being the title and description of the site:\n\n```js [.vitepress/config.js]\nexport default {\n  // site-level options\n  title: 'VitePress',\n  description: 'Just playing around.',\n\n  themeConfig: {\n    // theme-level options\n  }\n}\n```\n\nYou can also configure the behavior of the theme via the `themeConfig` option. Consult the [Config Reference](../reference/site-config) for full details on all config options.\n\n### Source Files\n\nMarkdown files outside the `.vitepress` directory are considered **source files**.\n\nVitePress uses **file-based routing**: each `.md` file is compiled into a corresponding `.html` file with the same path. For example, `index.md` will be compiled into `index.html`, and can be visited at the root path `/` of the resulting VitePress site.\n\nVitePress also provides the ability to generate clean URLs, rewrite paths, and dynamically generate pages. These will be covered in the [Routing Guide](./routing).\n\n## Up and Running\n\nThe tool should have also injected the following npm scripts to your `package.json` if you allowed it to do so during the setup process:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\nThe `docs:dev` script will start a local dev server with instant hot updates. Run it with the following command:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nInstead of npm scripts, you can also invoke VitePress directly with:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nMore command line usage is documented in the [CLI Reference](../reference/cli).\n\nThe dev server should be running at `http://localhost:5173`. Visit the URL in your browser to see your new site in action!\n\n## What's Next?\n\n- To better understand how markdown files are mapped to generated HTML, proceed to the [Routing Guide](./routing).\n\n- To discover more about what you can do on the page, such as writing markdown content or using Vue Components, refer to the \"Writing\" section of the guide. A great place to start would be to learn about [Markdown Extensions](./markdown).\n\n- To explore the features provided by the default documentation theme, check out the [Default Theme Config Reference](../reference/default-theme-config).\n\n- If you want to further customize the appearance of your site, explore how to either [Extend the Default Theme](./extending-default-theme) or [Build a Custom Theme](./custom-theme).\n\n- Once your documentation site takes shape, make sure to read the [Deployment Guide](./deploy).\n"
  },
  {
    "path": "docs/en/guide/i18n.md",
    "content": "# Internationalization\n\nTo use the built-in i18n features, one needs to create a directory structure as follows:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\nThen in `docs/.vitepress/config.ts`:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // shared properties and other top-level stuff...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    fr: {\n      label: 'French',\n      lang: 'fr', // optional, will be added  as `lang` attribute on `html` tag\n      link: '/fr/guide' // default /fr/ -- shows on navbar translations menu, can be external\n\n      // other locale specific properties...\n    }\n  }\n})\n```\n\nThe following properties can be overridden for each locale (including root):\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // will be merged with existing head entries, duplicate meta tags are automatically removed\n  themeConfig?: ThemeConfig // will be shallow merged, common stuff can be put in top-level themeConfig entry\n}\n```\n\nRefer [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) interface for details on customizing the placeholder texts of the default theme. Don't override `themeConfig.algolia` or `themeConfig.carbonAds` at locale-level. Refer [Algolia docs](../reference/default-theme-search#i18n) for using multilingual search.\n\n**Pro tip:** Config file can be stored at `docs/.vitepress/config/index.ts` too. It might help you organize stuff by creating a configuration file per locale and then merge and export them from `index.ts`.\n\n## Separate directory for each locale\n\nThe following is a perfectly fine structure:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\nHowever, VitePress won't redirect `/` to `/en/` by default. You'll need to configure your server for that. For example, on Netlify, you can add a `docs/public/_redirects` file like this:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**Pro tip:** If using the above approach, you can use `nf_lang` cookie to persist user's language choice:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## RTL Support (Experimental)\n\nFor RTL support, specify `dir: 'rtl'` in config and use some RTLCSS PostCSS plugin like <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> or <https://github.com/elchininet/postcss-rtlcss>. You'll need to configure your PostCSS plugin to use `:where([dir=\"ltr\"])` and `:where([dir=\"rtl\"])` as prefixes to prevent CSS specificity issues.\n"
  },
  {
    "path": "docs/en/guide/markdown.md",
    "content": "# Markdown Extensions\n\nVitePress comes with built in Markdown Extensions.\n\n## Header Anchors\n\nHeaders automatically get anchor links applied. Rendering of anchors can be configured using the `markdown.anchor` option.\n\n### Custom anchors\n\nTo specify a custom anchor tag for a heading instead of using the auto-generated one, add a suffix to the heading:\n\n```\n# Using custom anchors {#my-anchor}\n```\n\nThis allows you to link to the heading as `#my-anchor` instead of the default `#using-custom-anchors`.\n\n## Links\n\nBoth internal and external links get special treatment.\n\n### Internal Links\n\nInternal links are converted to router links for SPA navigation. Also, every `index.md` contained in each sub-directory will automatically be converted to `index.html`, with corresponding URL `/`.\n\nFor example, given the following directory structure:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nAnd providing you are in `foo/one.md`:\n\n```md\n[Home](/) <!-- sends the user to the root index.md -->\n[foo](/foo/) <!-- sends the user to index.html of directory foo -->\n[foo heading](./#heading) <!-- anchors user to a heading in the foo index file -->\n[bar - three](../bar/three) <!-- you can omit extension -->\n[bar - three](../bar/three.md) <!-- you can append .md -->\n[bar - four](../bar/four.html) <!-- or you can append .html -->\n```\n\n### Page Suffix\n\nPages and internal links get generated with the `.html` suffix by default.\n\n### External Links\n\nOutbound links automatically get `target=\"_blank\" rel=\"noreferrer\"`:\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## Frontmatter\n\n[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) is supported out of the box:\n\n```yaml\n---\ntitle: Blogging Like a Hacker\nlang: en-US\n---\n```\n\nThis data will be available to the rest of the page, along with all custom and theming components.\n\nFor more details, see [Frontmatter](../reference/frontmatter-config).\n\n## GitHub-Style Tables\n\n**Input**\n\n```md\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n```\n\n**Output**\n\n| Tables        |      Are      |   Cool |\n| ------------- | :-----------: | -----: |\n| col 3 is      | right-aligned | \\$1600 |\n| col 2 is      |   centered    |   \\$12 |\n| zebra stripes |   are neat    |    \\$1 |\n\n## Emoji :tada:\n\n**Input**\n\n```\n:tada: :100:\n```\n\n**Output**\n\n:tada: :100:\n\nA [list of all emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) is available.\n\n## Table of Contents\n\n**Input**\n\n```\n[[toc]]\n```\n\n**Output**\n\n[[toc]]\n\nRendering of the TOC can be configured using the `markdown.toc` option.\n\n## Custom Containers\n\nCustom containers can be defined by their types, titles, and contents.\n\n### Default Title\n\n**Input**\n\n```md\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n```\n\n**Output**\n\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n\n### Custom Title\n\nYou may set custom title by appending the text right after the \"type\" of the container.\n\n**Input**\n\n````md\n::: danger STOP\nDanger zone, do not proceed\n:::\n\n::: details Click me to toggle the code\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n````\n\n**Output**\n\n::: danger STOP\nDanger zone, do not proceed\n:::\n\n::: details Click me to toggle the code\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n\nAlso, you may set custom titles globally by adding the following content in site config, helpful if not writing in English:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: '提示',\n      warningLabel: '警告',\n      dangerLabel: '危险',\n      infoLabel: '信息',\n      detailsLabel: '详细信息'\n    }\n  }\n  // ...\n})\n```\n\n### Additional Attributes\n\nYou can add additional attributes to the custom containers. We use [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) for this feature, and it is supported on almost all markdown elements. For example, you can set the `open` attribute to make the details block open by default:\n\n**Input**\n\n````md\n::: details Click me to toggle the code {open}\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n````\n\n**Output**\n\n::: details Click me to toggle the code {open}\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n\n### `raw`\n\nThis is a special container that can be used to prevent style and router conflicts with VitePress. This is especially useful when you're documenting component libraries. You might also wanna check out [whyframe](https://whyframe.dev/docs/integrations/vitepress) for better isolation.\n\n**Syntax**\n\n```md\n::: raw\nWraps in a `<div class=\"vp-raw\">`\n:::\n```\n\n`vp-raw` class can be directly used on elements too. Style isolation is currently opt-in:\n\n- Install `postcss` with your preferred package manager:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- Create a file named `docs/postcss.config.mjs` and add this to it:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  You can pass its options like this:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // defaults to [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## GitHub-flavored Alerts\n\nVitePress also supports [GitHub-flavored alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) to render as callouts. They will be rendered the same as the [custom containers](#custom-containers).\n\n```md\n> [!NOTE]\n> Highlights information that users should take into account, even when skimming.\n\n> [!TIP]\n> Optional information to help a user be more successful.\n\n> [!IMPORTANT]\n> Crucial information necessary for users to succeed.\n\n> [!WARNING]\n> Critical content demanding immediate user attention due to potential risks.\n\n> [!CAUTION]\n> Negative potential consequences of an action.\n```\n\n> [!NOTE]\n> Highlights information that users should take into account, even when skimming.\n\n> [!TIP]\n> Optional information to help a user be more successful.\n\n> [!IMPORTANT]\n> Crucial information necessary for users to succeed.\n\n> [!WARNING]\n> Critical content demanding immediate user attention due to potential risks.\n\n> [!CAUTION]\n> Negative potential consequences of an action.\n\n## Syntax Highlighting in Code Blocks\n\nVitePress uses [Shiki](https://github.com/shikijs/shiki) to highlight language syntax in Markdown code blocks, using coloured text. Shiki supports a wide variety of programming languages. All you need to do is append a valid language alias to the beginning backticks for the code block:\n\n**Input**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**Output**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\nA [list of valid languages](https://shiki.style/languages) is available on Shiki's repository.\n\nYou may also customize syntax highlight theme, configure language aliases, and set custom language labels in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details.\n\n## Line Highlighting in Code Blocks\n\n**Input**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n\nIn addition to a single line, you can also specify multiple single lines, ranges, or both:\n\n- Line ranges: for example `{5-8}`, `{3-10}`, `{10-17}`\n- Multiple single lines: for example `{4,7,9}`\n- Line ranges and single lines: for example `{4,7-13,16,23-27,40}`\n\n**Input**\n\n````\n```js{1,4,6-8}\nexport default { // Highlighted\n  data () {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js{1,4,6-8}\nexport default { // Highlighted\n  data () {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\nAlternatively, it's possible to highlight directly in the line by using the `// [!code highlight]` comment.\n\n**Input**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Highlighted!' // [!code highlight]\n    }\n  }\n}\n```\n\n## Focus in Code Blocks\n\nAdding the `// [!code focus]` comment on a line will focus it and blur the other parts of the code.\n\nAdditionally, you can define a number of lines to focus using `// [!code focus:<lines>]`.\n\n**Input**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Focused!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Focused!' // [!code focus]\n    }\n  }\n}\n```\n\n## Colored Diffs in Code Blocks\n\nAdding the `// [!code --]` or `// [!code ++]` comments on a line will create a diff of that line, while keeping the colors of the codeblock.\n\n**Input**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!!code --]\n      msg: 'Added' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!code --]\n      msg: 'Added' // [!code ++]\n    }\n  }\n}\n```\n\n## Errors and Warnings in Code Blocks\n\nAdding the `// [!code warning]` or `// [!code error]` comments on a line will color it accordingly.\n\n**Input**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Error', // [!!code error]\n      msg: 'Warning' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!code error]\n      msg: 'Warning' // [!code warning]\n    }\n  }\n}\n```\n\n## Line Numbers\n\nYou can enable line numbers for each code blocks via config:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\nPlease see [`markdown` options](../reference/site-config#markdown) for more details.\n\nYou can add `:line-numbers` / `:no-line-numbers` mark in your fenced code blocks to override the value set in config.\n\nYou can also customize the starting line number by adding `=` after `:line-numbers`. For example, `:line-numbers=2` means the line numbers in code blocks will start from `2`.\n\n**Input**\n\n````md\n```ts {1}\n// line-numbers is disabled by default\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// line-numbers is enabled\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// line-numbers is enabled and start from 2\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n````\n\n**Output**\n\n```ts {1}\n// line-numbers is disabled by default\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// line-numbers is enabled\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// line-numbers is enabled and start from 2\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n\n## Import Code Snippets\n\nYou can import code snippets from existing files via following syntax:\n\n```md\n<<< @/filepath\n```\n\nIt also supports [line highlighting](#line-highlighting-in-code-blocks):\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**Input**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**Code file**\n\n<<< @/snippets/snippet.js\n\n**Output**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\nThe value of `@` corresponds to the source root. By default it's the VitePress project root, unless `srcDir` is configured. Alternatively, you can also import from relative paths:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\nYou can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file. You can provide a custom region name after a `#` following the filepath:\n\n**Input**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**Code file**\n\n<<< @/snippets/snippet-with-region.js\n\n**Output**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\nYou can also specify the language inside the braces (`{}`) like this:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- with line highlighting: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- with line numbers: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nThis is helpful if source language cannot be inferred from your file extension.\n\n## Code Groups\n\nYou can group multiple code blocks like this:\n\n**Input**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**Output**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nYou can also [import snippets](#import-code-snippets) in code groups:\n\n**Input**\n\n```md\n::: code-group\n\n<!-- filename is used as title by default -->\n\n<<< @/snippets/snippet.js\n\n<!-- you can provide a custom one too -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n```\n\n**Output**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n\n## Markdown File Inclusion\n\nYou can include a markdown file in another markdown file, even nested.\n\n::: tip\nYou can also prefix the markdown path with `@`, and it will act as the source root. By default, the source root is the VitePress project root, unless `srcDir` is configured.\n:::\n\nFor example, you can include a relative markdown file using this:\n\n**Input**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**Part file** (`parts/basics.md`)\n\n```md\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**Equivalent code**\n\n```md\n# Docs\n\n## Basics\n\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\nIt also supports selecting a line range:\n\n**Input**\n\n```md:line-numbers\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**Part file** (`parts/basics.md`)\n\n```md:line-numbers\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**Equivalent code**\n\n```md:line-numbers\n# Docs\n\n## Basics\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\nThe format of the selected line range can be: `{3,}`, `{,10}`, `{1,10}`\n\nYou can also use a [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) to only include the corresponding part of the code file. You can provide a custom region name after a `#` following the filepath:\n\n**Input**\n\n```md:line-numbers\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md#basic-usage{,2}-->\n<!--@@include: ./parts/basics.md#basic-usage{5,}-->\n```\n\n**Part file** (`parts/basics.md`)\n\n```md:line-numbers\n<!-- #region basic-usage -->\n## Usage Line 1\n\n## Usage Line 2\n\n## Usage Line 3\n<!-- #endregion basic-usage -->\n```\n\n**Equivalent code**\n\n```md:line-numbers\n# Docs\n\n## Basics\n\n## Usage Line 1\n\n## Usage Line 3\n```\n\n::: warning\nNote that this does not throw errors if your file is not present. Hence, when using this feature make sure that the contents are being rendered as expected.\n:::\n\nInstead of VS Code regions, you can also use header anchors to include a specific section of the file. For example, if you have a header in your markdown file like this:\n\n```md\n## My Base Section\n\nSome content here.\n\n### My Sub Section\n\nSome more content here.\n\n## Another Section\n\nContent outside `My Base Section`.\n```\n\nYou can include the `My Base Section` section like this:\n\n```md\n## My Extended Section\n<!--@@include: ./parts/basics.md#my-base-section-->\n```\n\n**Equivalent code**\n\n```md\n## My Extended Section\n\nSome content here.\n\n### My Sub Section\n\nSome more content here.\n```\n\nHere, `my-base-section` is the generated id of the heading element. In case it's not easily guessable, you can open the part file in your browser and click on the heading anchor (`#` symbol left to the heading when hovered) to see the id in the URL bar. Or use browser dev tools to inspect the element. Alternatively, you can also specify the id to the part file like this:\n\n```md\n## My Base Section {#custom-id}\n```\n\nand include it like this:\n\n```md\n<!--@@include: ./parts/basics.md#custom-id-->\n```\n\n## Math Equations\n\nThis is currently opt-in. To enable it, you need to install `markdown-it-mathjax3` and set `markdown.math` to `true` in your config file:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**Input**\n\n```md\nWhen $a \\ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Maxwell's equations:**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | divergence of $\\vec{\\mathbf{B}}$ is zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl of $\\vec{\\mathbf{E}}$ is proportional to the rate of change of $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                                 |\n```\n\n**Output**\n\nWhen $a \\ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Maxwell's equations:**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | divergence of $\\vec{\\mathbf{B}}$ is zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl of $\\vec{\\mathbf{E}}$ is proportional to the rate of change of $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                                 |\n\n## Image Lazy Loading\n\nYou can enable lazy loading for each image added via markdown by setting `lazyLoading` to `true` in your config file:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // image lazy loading is disabled by default\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## Advanced Configuration\n\nVitePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the Markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vitepress/config.js`:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // options for markdown-it-anchor\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // options for @mdit-vue/plugin-toc\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // use more markdown-it plugins!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\nSee full list of configurable properties in [Config Reference: App Config](../reference/site-config#markdown).\n"
  },
  {
    "path": "docs/en/guide/migration-from-vitepress-0.md",
    "content": "# Migration from VitePress 0.x\n\nIf you're coming from VitePress 0.x version, there're several breaking changes due to new features and enhancement. Please follow this guide to see how to migrate your app over to the latest VitePress.\n\n## App Config\n\n- The internationalization feature is not yet implemented.\n\n## Theme Config\n\n- `sidebar` option has changed its structure.\n  - `children` key is now named `items`.\n  - Top level item may not contain `link` at the moment. We're planning to bring it back.\n- `repo`, `repoLabel`, `docsDir`, `docsBranch`, `editLinks`, `editLinkText` are removed in favor of more flexible api.\n  - For adding GitHub link with icon to the nav, use [Social Links](../reference/default-theme-nav#navigation-links) feature.\n  - For adding \"Edit this page\" feature, use [Edit Link](../reference/default-theme-edit-link) feature.\n- `lastUpdated` option is now split into `config.lastUpdated` and `themeConfig.lastUpdatedText`.\n- `carbonAds.carbon` is changed to `carbonAds.code`.\n\n## Frontmatter Config\n\n- `home: true` option has changed to `layout: home`. Also, many Homepage related settings have been modified to provide additional features. See [Home Page guide](../reference/default-theme-home-page) for details.\n- `footer` option is moved to [`themeConfig.footer`](../reference/default-theme-config#footer).\n"
  },
  {
    "path": "docs/en/guide/migration-from-vuepress.md",
    "content": "# Migration from VuePress\n\n## Config\n\n### Sidebar\n\nThe sidebar is no longer automatically populated from frontmatter. You can [read the frontmatter yourself](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) to dynamically populate the sidebar. [Additional utilities for this](https://github.com/vuejs/vitepress/issues/96) may be provided in the future.\n\n## Markdown\n\n### Images\n\nUnlike VuePress, VitePress handles [`base`](./asset-handling#base-url) of your config automatically when you use static image.\n\nHence, now you can render images without `img` tag.\n\n```diff\n- <img :src=\"$withBase('/foo.png')\" alt=\"foo\">\n+ ![foo](/foo.png)\n```\n\n::: warning\nFor dynamic images you still need `withBase` as shown in [Base URL guide](./asset-handling#base-url).\n:::\n\nUse `<img.*withBase\\('(.*)'\\).*alt=\"([^\"]*)\".*>` regex to find and replace it with `![$2]($1)` to replace all the images with `![](...)` syntax.\n\n---\n\nmore to follow...\n"
  },
  {
    "path": "docs/en/guide/mpa-mode.md",
    "content": "# MPA Mode <Badge type=\"warning\" text=\"experimental\" />\n\nMPA (Multi-Page Application) mode can be enabled via the command line via `vitepress build --mpa`, or via config through the `mpa: true` option.\n\nIn MPA mode, all pages are rendered without any JavaScript included by default. As a result, the production site will likely have a better initial visit performance score from audit tools.\n\nHowever, due to the absence of SPA navigation, cross-page links will lead to full page reloads. Post-load navigations in MPA mode will not feel as instant as in SPA mode.\n\nAlso note that no-JS-by-default means you are essentially using Vue purely as a server-side templating language. No event handlers will be attached in the browser, so there will be no interactivity. To load client-side JavaScript, you will need to use the special `<script client>` tag:\n\n```html\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('client side JavaScript!')\n})\n</script>\n\n# Hello\n```\n\n`<script client>` is a VitePress-only feature, not a Vue feature. It works in both `.md` and `.vue` files, but only in MPA mode. Client scripts in all theme components will be bundled together, while client script for a specific page will be split for that page only.\n\nNote that `<script client>` is **not evaluated as Vue component code**: it's processed as a plain JavaScript module. For this reason, MPA mode should only be used if your site requires absolutely minimal client-side interactivity.\n"
  },
  {
    "path": "docs/en/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# Routing\n\n## File-Based Routing\n\nVitePress uses file-based routing, which means the generated HTML pages are mapped from the directory structure of the source Markdown files. For example, given the following directory structure:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\nThe generated HTML pages will be:\n\n```\nindex.md                  -->  /index.html (accessible as /)\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html (accessible as /guide/)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\nThe resulting HTML can be hosted on any web server that can serve static files.\n\n## Root and Source Directory\n\nThere are two important concepts in the file structure of a VitePress project: the **project root** and the **source directory**.\n\n### Project Root\n\nProject root is where VitePress will try to look for the `.vitepress` special directory. The `.vitepress` directory is a reserved location for VitePress' config file, dev server cache, build output, and optional theme customization code.\n\nWhen you run `vitepress dev` or `vitepress build` from the command line, VitePress will use the current working directory as project root. To specify a sub-directory as root, you will need to pass the relative path to the command. For example, if your VitePress project is located in `./docs`, you should run `vitepress dev docs`:\n\n```\n.\n├─ docs                    # project root\n│  ├─ .vitepress           # config dir\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nThis is going to result in the following source-to-HTML mapping:\n\n```\ndocs/index.md            -->  /index.html (accessible as /)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### Source Directory\n\nSource directory is where your Markdown source files live. By default, it is the same as the project root. However, you can configure it via the [`srcDir`](../reference/site-config#srcdir) config option.\n\nThe `srcDir` option is resolved relative to project root. For example, with `srcDir: 'src'`, your file structure will look like this:\n\n```\n.                          # project root\n├─ .vitepress              # config dir\n└─ src                     # source dir\n   ├─ getting-started.md\n   └─ index.md\n```\n\nThe resulting source-to-HTML mapping:\n\n```\nsrc/index.md            -->  /index.html (accessible as /)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## Linking Between Pages\n\nYou can use both absolute and relative paths when linking between pages. Note that although both `.md` and `.html` extensions will work, the best practice is to omit file extensions so that VitePress can generate the final URLs based on your config.\n\n```md\n<!-- Do -->\n[Getting Started](./getting-started)\n[Getting Started](../guide/getting-started)\n\n<!-- Don't -->\n[Getting Started](./getting-started.md)\n[Getting Started](./getting-started.html)\n```\n\nLearn more about linking to assets such images in [Asset Handling](./asset-handling).\n\n### Linking to Non-VitePress Pages\n\nIf you want to link to a page in your site that is not generated by VitePress, you'll either need to use the full URL (opens in a new tab) or explicitly specify the target:\n\n**Input**\n\n```md\n[Link to pure.html](/pure.html){target=\"_self\"}\n```\n\n**Output**\n\n[Link to pure.html](/pure.html){target=\"_self\"}\n\n::: tip Note\n\nIn Markdown links, the `base` is automatically prepended to the URL. This means that if you want to link to a page outside of your base, you'd need something like `../../pure.html` in the link (resolved relative to the current page by the browser).\n\nAlternatively, you can directly use the anchor tag syntax:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Link to pure.html</a>\n```\n\n:::\n\n## Generating Clean URLs\n\n::: warning Server Support Required\nTo serve clean URLs with VitePress, server-side support is required.\n:::\n\nBy default, VitePress resolves inbound links to URLs ending with `.html`. However, some users may prefer \"Clean URLs\" without the `.html` extension - for example, `example.com/path` instead of `example.com/path.html`.\n\nSome servers or hosting platforms (for example Netlify, Vercel, GitHub Pages) provide the ability to map a URL like `/foo` to `/foo.html` if it exists, without a redirect:\n\n- Netlify and GitHub Pages support this by default.\n- Vercel requires enabling the [`cleanUrls` option in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).\n\nIf this feature is available to you, you can then also enable VitePress' own [`cleanUrls`](../reference/site-config#cleanurls) config option so that:\n\n- Inbound links between pages are generated without the `.html` extension.\n- If current path ends with `.html`, the router will perform a client-side redirect to the extension-less path.\n\nIf, however, you cannot configure your server with such support, you will have to manually resort to the following directory structure:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## Route Rewrites\n\nYou can customize the mapping between the source directory structure and the generated pages. It's useful when you have a complex project structure. For example, let's say you have a monorepo with multiple packages, and would like to place documentations along with the source files like this:\n\n```\n.\n└─ packages\n   ├─ pkg-a\n   │  └─ src\n   │     ├─ foo.md\n   │     └─ index.md\n   └─ pkg-b\n      └─ src\n         ├─ bar.md\n         └─ index.md\n```\n\nAnd you want the VitePress pages to be generated like this:\n\n```\npackages/pkg-a/src/index.md  -->  /pkg-a/index.html\npackages/pkg-a/src/foo.md    -->  /pkg-a/foo.html\npackages/pkg-b/src/index.md  -->  /pkg-b/index.html\npackages/pkg-b/src/bar.md    -->  /pkg-b/bar.html\n```\n\nYou can achieve this by configuring the [`rewrites`](../reference/site-config#rewrites) option like this:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/index.md': 'pkg-a/index.md',\n    'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',\n    'packages/pkg-b/src/index.md': 'pkg-b/index.md',\n    'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'\n  }\n}\n```\n\nThe `rewrites` option also supports dynamic route parameters. In the above example, it would be verbose to list all the paths if you have many packages. Given that they all have the same file structure, you can simplify the config like this:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/:slug*': ':pkg/:slug*'\n  }\n}\n```\n\nThe rewrite paths are compiled using the `path-to-regexp` package - consult [its documentation](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters) for more advanced syntax.\n\n`rewrites` can also be a function that receives the original path and returns the new path:\n\n```ts\nexport default {\n  rewrites(id) {\n    return id.replace(/^packages\\/([^/]+)\\/src\\//, '$1/')\n  }\n}\n```\n\n::: warning Relative Links with Rewrites\n\nWhen rewrites are enabled, **relative links should be based on the rewritten paths**. For example, in order to create a relative link from `packages/pkg-a/src/pkg-a-code.md` to `packages/pkg-b/src/pkg-b-code.md`, you should use:\n\n```md\n[Link to PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## Dynamic Routes\n\nYou can generate many pages using a single Markdown file and dynamic data. For example, you can create a `packages/[pkg].md` file that generates a corresponding page for every package in a project. Here, the `[pkg]` segment is a route **parameter** that differentiates each page from the others.\n\n### Paths Loader File\n\nSince VitePress is a static site generator, the possible page paths must be determined at build time. Therefore, a dynamic route page **must** be accompanied by a **paths loader file**. For `packages/[pkg].md`, we will need `packages/[pkg].paths.js` (`.ts` is also supported):\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # route template\n   └─ [pkg].paths.js   # route paths loader\n```\n\nThe paths loader should provide an object with a `paths` method as its default export. The `paths` method should return an array of objects with a `params` property. Each of these objects will generate a corresponding page.\n\nGiven the following `paths` array:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\nThe generated HTML pages will be:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### Type-safe loader with `defineRoutes`\n\nIf you are using TypeScript, you can wrap the loader with `defineRoutes` from `vitepress` to get type hints for route hooks such as `paths`, `watch`, and `transformPageData`:\n\n```ts\n// packages/[pkg].paths.ts\nimport { defineRoutes } from 'vitepress'\n\nexport default defineRoutes({\n  watch: ['../data/**/*.json'],\n  async paths() {\n    return [\n      { params: { pkg: 'foo' } },\n      { params: { pkg: 'bar' } }\n    ]\n  },\n  async transformPageData(pageData) {\n    pageData.title = `${pageData.title} · Packages`\n  }\n})\n```\n\n`defineRoutes` is optional, but recommended when authoring `.paths.ts` files.\n\n### Multiple Params\n\nA dynamic route can contain multiple params:\n\n**File Structure**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**Paths Loader**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**Output**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### Dynamically Generating Paths\n\nThe paths loader module is run in Node.js and only executed during build time. You can dynamically generate the paths array using any data, either local or remote.\n\nGenerating paths from local files:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\nGenerating paths from remote data:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### Watching Template and Data Files\n\nWhen generating page content from templates or external data sources, you can use the watch option to automatically rebuild pages when those files change during development:\n\n```js\n// posts/[slug].paths.js\nimport fs from 'node:fs'\nimport { renderTemplate } from './templates/renderer.js'\n\nexport default {\n  // Watch for changes to template files and data sources\n  watch: [\n    './templates/**/*.njk',     // Template files\n    '../data/**/*.json'         // Data files\n  ],\n\n  paths(watchedFiles) {\n    // watchedFiles will be an array of absolute paths of the matched files\n    // Read data files to generate routes\n    const dataFiles = watchedFiles.filter(file => file.endsWith('.json'))\n\n    return dataFiles.map(file => {\n      const data = JSON.parse(fs.readFileSync(file, 'utf-8'))\n\n      return {\n        params: { slug: data.slug },\n        content: renderTemplate(data)  // Use template to generate content\n      }\n    })\n  }\n}\n```\n\nThe `watch` option works the same way as in [data loaders](./data-loading#data-from-local-files):\n\n- Accepts [glob patterns](https://github.com/mrmlnc/fast-glob#pattern-syntax) to match files\n- Patterns are relative to the `.paths.js` file itself\n- Changes to watched files trigger page regeneration and HMR during development\n- In production builds, all pages are generated once regardless of watch configuration\n\n### Accessing Params in Page\n\nYou can use the params to pass additional data to each page. The Markdown route file can access the current page params in Vue expressions via the `$params` global property:\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n\nYou can also access the current page's params via the [`useData`](../reference/runtime-api#usedata) runtime API. This is available in both Markdown files and Vue components:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params is a Vue ref\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### Rendering Raw Content\n\nParams passed to the page will be serialized in the client JavaScript payload, so you should avoid passing heavy data in params, for example raw Markdown or HTML content fetched from a remote CMS.\n\nInstead, you can pass such content to each page using the `content` property on each path object:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // raw Markdown or HTML\n      }\n    })\n  }\n}\n```\n\nThen, use the following special syntax to render the content as part of the Markdown file itself:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/en/guide/sitemap-generation.md",
    "content": "# Sitemap Generation\n\nVitePress comes with out-of-the-box support for generating a `sitemap.xml` file for your site. To enable it, add the following to your `.vitepress/config.js`:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\nTo have `<lastmod>` tags in your `sitemap.xml`, you can enable the [`lastUpdated`](../reference/default-theme-last-updated) option.\n\n## Options\n\nSitemap support is powered by the [`sitemap`](https://www.npmjs.com/package/sitemap) module. You can pass any options supported by it to the `sitemap` option in your config file. These will be passed directly to the `SitemapStream` constructor. Refer to the [`sitemap` documentation](https://www.npmjs.com/package/sitemap#options-you-can-pass) for more details. Example:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\nIf you're using `base` in your config, you should append it to the `hostname` option:\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## `transformItems` Hook\n\nYou can use the `sitemap.transformItems` hook to modify the sitemap items before they are written to the `sitemap.xml` file. This hook is called with an array of sitemap items and expects an array of sitemap items to be returned. Example:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // add new items or modify/filter existing items\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/en/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# SSR Compatibility\n\nVitePress pre-renders the app in Node.js during the production build, using Vue's Server-Side Rendering (SSR) capabilities. This means all custom code in theme components are subject to SSR Compatibility.\n\nThe [SSR section in official Vue docs](https://vuejs.org/guide/scaling-up/ssr.html) provides more context on what SSR is, the relationship between SSR / SSG, and common notes on writing SSR-friendly code. The rule of thumb is to only access browser / DOM APIs in `beforeMount` or `mounted` hooks of Vue components.\n\n## `<ClientOnly>`\n\nIf you are using or demoing components that are not SSR-friendly (for example, contain custom directives), you can wrap them inside the built-in `<ClientOnly>` component:\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## Libraries that Access Browser API on Import\n\nSome components or libraries access browser APIs **on import**. To use code that assumes a browser environment on import, you need to dynamically import them.\n\n### Importing in Mounted Hook\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // use code\n  })\n})\n</script>\n```\n\n### Conditional Import\n\nYou can also conditionally import a dependency using the `import.meta.env.SSR` flag (part of [Vite env variables](https://vitejs.dev/guide/env-and-mode.html#env-variables)):\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // use code\n  })\n}\n```\n\nSince [`Theme.enhanceApp`](./custom-theme#theme-interface) can be async, you can conditionally import and register Vue plugins that access browser APIs on import:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nIf you're using TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress provides a convenience helper for importing Vue components that access browser APIs on import.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nYou can also pass props/children/slots to the target component:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // args are passed to h() - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'default slot',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'one'), h('span', 'two')]\n    }\n  ],\n\n  // callback after the component is loaded, can be async\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nThe target component will only be imported in the mounted hook of the wrapper component.\n"
  },
  {
    "path": "docs/en/guide/using-vue.md",
    "content": "# Using Vue in Markdown\n\nIn VitePress, each Markdown file is compiled into HTML and then processed as a [Vue Single-File Component](https://vuejs.org/guide/scaling-up/sfc.html). This means you can use any Vue features inside the Markdown, including dynamic templating, using Vue components, or arbitrary in-page Vue component logic by adding a `<script>` tag.\n\nIt's worth noting that VitePress leverages Vue's compiler to automatically detect and optimize the purely static parts of the Markdown content. Static contents are optimized into single placeholder nodes and eliminated from the page's JavaScript payload for initial visits. They are also skipped during client-side hydration. In short, you only pay for the dynamic parts on any given page.\n\n::: tip SSR Compatibility\nAll Vue usage needs to be SSR-compatible. See [SSR Compatibility](./ssr-compat) for details and common workarounds.\n:::\n\n## Templating\n\n### Interpolation\n\nEach Markdown file is first compiled into HTML and then passed on as a Vue component to the Vite process pipeline. This means you can use Vue-style interpolation in text:\n\n**Input**\n\n```md\n{{ 1 + 1 }}\n```\n\n**Output**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### Directives\n\nDirectives also work (note that by design, raw HTML is also valid in Markdown):\n\n**Input**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**Output**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` and `<style>`\n\nRoot-level `<script>` and `<style>` tags in Markdown files work just like they do in Vue SFCs, including `<script setup>`, `<style module>`, etc. The main difference here is that there is no `<template>` tag: all other root-level content is Markdown. Also note that all tags should be placed **after** the frontmatter:\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## Markdown Content\n\nThe count is: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Increment</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning Avoid `<style scoped>` in Markdown\nWhen used in Markdown, `<style scoped>` requires adding special attributes to every element on the current page, which will significantly bloat the page size. `<style module>` is preferred when locally-scoped styling is needed in a page.\n:::\n\nYou also have access to VitePress' runtime APIs such as the [`useData` helper](../reference/runtime-api#usedata), which provides access to current page's metadata:\n\n**Input**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**Output**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"Using Vue in Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## Using Components\n\nYou can import and use Vue components directly in Markdown files.\n\n### Importing in Markdown\n\nIf a component is only used by a few pages, it's recommended to explicitly import them where they are used. This allows them to be properly code-split and only loaded when the relevant pages are shown:\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# Docs\n\nThis is a .md using a custom component\n\n<CustomComponent />\n\n## More docs\n\n...\n```\n\n### Registering Components Globally\n\nIf a component is going to be used on most of the pages, they can be registered globally by customizing the Vue app instance. See relevant section in [Extending Default Theme](./extending-default-theme#registering-global-components) for an example.\n\n::: warning IMPORTANT\nMake sure a custom component's name either contains a hyphen or is in PascalCase. Otherwise, it will be treated as an inline element and wrapped inside a `<p>` tag, which will lead to hydration mismatch because `<p>` does not allow block elements to be placed inside it.\n:::\n\n### Using Components In Headers <ComponentInHeader />\n\nYou can use Vue components in the headers, but note the difference between the following syntaxes:\n\n| Markdown                                                | Output HTML                               | Parsed Header |\n| ------------------------------------------------------- | ----------------------------------------- | ------------- |\n| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre>     | `<h1>text <Tag/></h1>`                    | `text`        |\n| <pre v-pre><code> # text \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>` |\n\nThe HTML wrapped by `<code>` will be displayed as-is; only the HTML that is **not** wrapped will be parsed by Vue.\n\n::: tip\nThe output HTML is accomplished by [Markdown-it](https://github.com/Markdown-it/Markdown-it), while the parsed headers are handled by VitePress (and used for both the sidebar and document title).\n:::\n\n\n## Escaping\n\nYou can escape Vue interpolations by wrapping them in a `<span>` or other elements with the `v-pre` directive:\n\n**Input**\n\n```md\nThis <span v-pre>{{ will be displayed as-is }}</span>\n```\n\n**Output**\n\n<div class=\"escape-demo\">\n  <p>This <span v-pre>{{ will be displayed as-is }}</span></p>\n</div>\n\nAlternatively, you can wrap the entire paragraph in a `v-pre` custom container:\n\n```md\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n```\n\n**Output**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n\n</div>\n\n## Unescape in Code Blocks\n\nBy default, all fenced code blocks are automatically wrapped with `v-pre`, so no Vue syntax will be processed inside. To enable Vue-style interpolation inside fences, you can append the language with the `-vue` suffix, e.g. `js-vue`:\n\n**Input**\n\n````md\n```js-vue\nHello {{ 1 + 1 }}\n```\n````\n\n**Output**\n\n```js-vue\nHello {{ 1 + 1 }}\n```\n\nNote that this might prevent certain tokens from being syntax highlighted properly.\n\n## Using CSS Pre-processors\n\nVitePress has [built-in support](https://vitejs.dev/guide/features.html#css-pre-processors) for CSS pre-processors: `.scss`, `.sass`, `.less`, `.styl` and `.stylus` files. There is no need to install Vite-specific plugins for them, but the corresponding pre-processor itself must be installed:\n\n```\n# .scss and .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl and .stylus\nnpm install -D stylus\n```\n\nThen you can use the following in Markdown and theme components:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## Using Teleports\n\nVitePress currently has SSG support for teleports to body only. For other targets, you can wrap them inside the built-in `<ClientOnly>` component or inject the teleport markup into the correct location in your final page HTML through [`postRender` hook](../reference/site-config#postrender).\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n\n\n## VS Code IntelliSense Support\n\n<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->\n\nVue provides IntelliSense support out of the box via the [Vue - Official VS Code plugin](https://marketplace.visualstudio.com/items?itemName=Vue.volar). However, to enable it for `.md` files, you need to make some adjustments to the configuration files.\n\n\n1. Add `.md` pattern to the `include` and `vueCompilerOptions.vitePressExtensions` options in the tsconfig/jsconfig file:\n\n::: code-group\n```json [tsconfig.json]\n{\n  \"include\": [\n    \"docs/**/*.ts\",\n    \"docs/**/*.vue\",\n    \"docs/**/*.md\",\n  ],\n  \"vueCompilerOptions\": {\n    \"vitePressExtensions\": [\".md\"],\n  },\n}\n```\n:::\n\n2. Add `markdown` to the `vue.server.includeLanguages` option in the VS Code setting:\n\n::: code-group\n```json [.vscode/settings.json]\n{\n  \"vue.server.includeLanguages\": [\"vue\", \"markdown\"]\n}\n```\n:::\n"
  },
  {
    "path": "docs/en/guide/what-is-vitepress.md",
    "content": "# What is VitePress?\n\nVitePress is a [Static Site Generator](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) designed for building fast, content-centric websites. In a nutshell, VitePress takes your source content written in [Markdown](https://en.wikipedia.org/wiki/Markdown), applies a theme to it, and generates static HTML pages that can be easily deployed anywhere.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nJust want to try it out? Skip to the [Quickstart](./getting-started).\n\n</div>\n\n## Use Cases\n\n- **Documentation**\n\n  VitePress ships with a default theme designed for technical documentation. It powers this page you are reading right now, along with the documentation for [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) and [many more](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code).\n\n  The [official Vue.js documentation](https://vuejs.org/) is also based on VitePress, but uses a custom theme shared between multiple translations.\n\n- **Blogs, Portfolios, and Marketing Sites**\n\n  VitePress supports [fully customized themes](./custom-theme), with the developer experience of a standard Vite + Vue application. Being built on Vite also means you can directly leverage Vite plugins from its rich ecosystem. In addition, VitePress provides flexible APIs to [load data](./data-loading) (local or remote) and [dynamically generate routes](./routing#dynamic-routes). You can use it to build almost anything as long as the data can be determined at build time.\n\n  The official [Vue.js blog](https://blog.vuejs.org/) is a simple blog that generates its index page based on local content.\n\n## Developer Experience\n\nVitePress aims to provide a great Developer Experience (DX) when working with Markdown content.\n\n- **[Vite-Powered:](https://vitejs.dev/)** instant server start, with edits always instantly reflected (<100ms) without page reload.\n\n- **[Built-in Markdown Extensions:](./markdown)** Frontmatter, tables, syntax highlighting... you name it. Specifically, VitePress provides many advanced features for working with code blocks, making it ideal for highly technical documentation.\n\n- **[Vue-Enhanced Markdown:](./using-vue)** each Markdown page is also a Vue [Single-File Component](https://vuejs.org/guide/scaling-up/sfc.html), thanks to Vue template's 100% syntax compatibility with HTML. You can embed interactivity in your static content using Vue templating features or imported Vue components.\n\n## Performance\n\nUnlike many traditional SSGs where each navigation results in a full page reload, a website generated by VitePress serves static HTML on the initial visit, but becomes a [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA) for subsequent navigation within the site. This model, in our opinion, provides an optimal balance for performance:\n\n- **Fast Initial Load**\n\n  The initial visit to any page will be served the static, pre-rendered HTML for fast loading speed and optimal SEO. The page then loads a JavaScript bundle that turns the page into a Vue SPA (\"hydration\"). Contrary to common assumptions of SPA hydration being slow, this process is actually extremely fast thanks to Vue 3's raw performance and compiler optimizations. On [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), typical VitePress sites achieve near-perfect performance scores even on low-end mobile devices with a slow network.\n\n- **Fast Post-load Navigation**\n\n  More importantly, the SPA model leads to better user experience **after** the initial load. Subsequent navigation within the site will no longer cause a full page reload. Instead, the incoming page's content will be fetched and dynamically updated. VitePress also automatically pre-fetches page chunks for links that are within viewport. In most cases, post-load navigation will feel instant.\n\n- **Interactivity Without Penalty**\n\n  To be able to hydrate the dynamic Vue parts embedded inside static Markdown, each Markdown page is processed as a Vue component and compiled into JavaScript. This may sound inefficient, but the Vue compiler is smart enough to separate the static and dynamic parts, minimizing both the hydration cost and payload size. For the initial page load, the static parts are automatically eliminated from the JavaScript payload and skipped during hydration.\n\n## What About VuePress?\n\nVitePress is the spiritual successor of VuePress 1. The original VuePress 1 was based on Vue 2 and webpack. With Vue 3 and Vite under the hood, VitePress provides significantly better DX, better production performance, a more polished default theme, and a more flexible customization API.\n\nThe API difference between VitePress and VuePress 1 mostly lies in theming and customization. If you are using VuePress 1 with the default theme, it should be relatively straightforward to migrate to VitePress.\n\nMaintaining two SSGs in parallel isn't sustainable, so the Vue team has decided to focus on VitePress as the main recommended SSG in the long run. Now VuePress 1 has been deprecated, and VuePress 2 has been handed over to the VuePress community team for further development and maintenance.\n"
  },
  {
    "path": "docs/en/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue Powered Static Site Generator\n  tagline: Markdown to beautiful docs in minutes\n  actions:\n    - theme: brand\n      text: What is VitePress?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: Quickstart\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: Focus on your content\n    details: Effortlessly create beautiful documentation sites with just markdown.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Enjoy the Vite DX\n    details: Instant server start, lightning fast hot updates, and leverage Vite ecosystem plugins.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Customize with Vue\n    details: Use Vue syntax and components directly in markdown, or build custom themes with Vue.\n  - icon: 🚀\n    title: Ship fast sites\n    details: Fast initial load with static HTML, fast post-load navigation with client-side routing.\n---\n"
  },
  {
    "path": "docs/en/reference/cli.md",
    "content": "# Command Line Interface\n\n## `vitepress dev`\n\nStart VitePress dev server using designated directory as root. Defaults to current directory. The `dev` command can also be omitted when running in current directory.\n\n### Usage\n\n```sh\n# start in current directory, omitting `dev`\nvitepress\n\n# start in sub directory\nvitepress dev [root]\n```\n\n### Options\n\n| Option          | Description                                                       |\n| --------------- | ----------------------------------------------------------------- |\n| `--open [path]` | Open browser on startup (`boolean \\| string`)                     |\n| `--port <port>` | Specify port (`number`)                                           |\n| `--base <path>` | Public base path (default: `/`) (`string`)                        |\n| `--cors`        | Enable CORS                                                       |\n| `--strictPort`  | Exit if specified port is already in use (`boolean`)              |\n| `--force`       | Force the optimizer to ignore the cache and re-bundle (`boolean`) |\n\n## `vitepress build`\n\nBuild the VitePress site for production.\n\n### Usage\n\n```sh\nvitepress build [root]\n```\n\n### Options\n\n| Option                         | Description                                                                                                         |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |\n| `--mpa` (experimental)         | Build in [MPA mode](../guide/mpa-mode) without client-side hydration (`boolean`)                                    |\n| `--base <path>`                | Public base path (default: `/`) (`string`)                                                                          |\n| `--target <target>`            | Transpile target (default: `\"modules\"`) (`string`)                                                                  |\n| `--outDir <dir>`               | Output directory relative to **cwd** (default: `<root>/.vitepress/dist`) (`string`)                                 |\n| `--assetsInlineLimit <number>` | Static asset base64 inline threshold in bytes (default: `4096`) (`number`)                                          |\n\n## `vitepress preview`\n\nLocally preview the production build.\n\n### Usage\n\n```sh\nvitepress preview [root]\n```\n\n### Options\n\n| Option          | Description                                |\n| --------------- | ------------------------------------------ |\n| `--base <path>` | Public base path (default: `/`) (`string`) |\n| `--port <port>` | Specify port (`number`)                    |\n\n## `vitepress init`\n\nStart the [Setup Wizard](../guide/getting-started#setup-wizard) in current directory.\n\n### Usage\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-badge.md",
    "content": "# Badge\n\nThe badge lets you add status to your headers. For example, it could be useful to specify the section's type, or supported version.\n\n## Usage\n\nYou may use the `Badge` component which is globally available.\n\n```html\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n```\n\nCode above renders like:\n\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n\n## Custom Children\n\n`<Badge>` accept `children`, which will be displayed in the badge.\n\n```html\n### Title <Badge type=\"info\">custom element</Badge>\n```\n\n### Title <Badge type=\"info\">custom element</Badge>\n\n## Customize Type Color\n\nYou can customize the style of badges by overriding css variables. The following are the default values:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\n`<Badge>` component accepts following props:\n\n```ts\ninterface Props {\n  // When `<slot>` is passed, this value gets ignored.\n  text?: string\n\n  // Defaults to `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-carbon-ads.md",
    "content": "# Carbon Ads\n\nVitePress has built in native support for [Carbon Ads](https://www.carbonads.net/). By defining the Carbon Ads credentials in config, VitePress will display ads on the page.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\nThese values are used to call carbon CDN script as shown below.\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nTo learn more about Carbon Ads configuration, please visit [Carbon Ads website](https://www.carbonads.net/).\n"
  },
  {
    "path": "docs/en/reference/default-theme-config.md",
    "content": "# Default Theme Config\n\nTheme config lets you customize your theme. You can define theme config via the `themeConfig` option in the config file:\n\n```ts\nexport default {\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // Theme related configurations.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**The options documented on this page only apply to the default theme.** Different themes expect different theme config. When using a custom theme, the theme config object will be passed to the theme so the theme can define conditional behavior based on it.\n\n## i18nRouting\n\n- Type: `boolean`\n\nChanging locale to say `zh` will change the URL from `/foo` (or `/en/foo/`) to `/zh/foo`. You can disable this behavior by setting `themeConfig.i18nRouting` to `false`.\n\n## logo\n\n- Type: `ThemeableImage`\n\nLogo file to display in nav bar, right before the site title. Accepts a path string, or an object to set a different logo for light/dark mode.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- Type: `string | false`\n\nYou can customize this item to replace the default site title (`title` in app config) in nav. When set to `false`, title in nav will be disabled. Useful when you have `logo` that already contains the site title text.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hello World'\n  }\n}\n```\n\n## nav\n\n- Type: `NavItem`\n\nThe configuration for the nav menu item. More details in [Default Theme: Nav](./default-theme-nav#navigation-links).\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- Type: `Sidebar`\n\nThe configuration for the sidebar menu item. More details in [Default Theme: Sidebar](./default-theme-sidebar).\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n}\n\nexport type SidebarItem = {\n  /**\n   * The text label of the item.\n   */\n  text?: string\n\n  /**\n   * The link of the item.\n   */\n  link?: string\n\n  /**\n   * The children of the item.\n   */\n  items?: SidebarItem[]\n\n  /**\n   * If not specified, group is not collapsible.\n   *\n   * If `true`, group is collapsible and collapsed by default\n   *\n   * If `false`, group is collapsible but expanded by default\n   */\n  collapsed?: boolean\n\n  /**\n   * Base path for the children items.\n   */\n  base?: string\n\n  /**\n   * Customize text that appears on the footer of previous/next page.\n   */\n  docFooterText?: string\n\n  rel?: string\n  target?: string\n}\n```\n\n## aside\n\n- Type: `boolean | 'left'`\n- Default: `true`\n- Can be overridden per page via [frontmatter](./frontmatter-config#aside)\n\nSetting this value to `false` prevents rendering of aside container.\\\nSetting this value to `true` renders the aside to the right.\\\nSetting this value to `left` renders the aside to the left.\n\nIf you want to disable it for all viewports, you should use `outline: false` instead.\n\n## outline\n\n- Type: `Outline | Outline['level'] | false`\n- Level can be overridden per page via [frontmatter](./frontmatter-config#outline)\n\nSetting this value to `false` prevents rendering of outline container. Refer this interface for more details:\n\n```ts\ninterface Outline {\n  /**\n   * The levels of headings to be displayed in the outline.\n   * Single number means only headings of that level will be displayed.\n   * If a tuple is passed, the first number is the minimum level and the second number is the maximum level.\n   * `'deep'` is same as `[2, 6]`, which means all headings from `<h2>` to `<h6>` will be displayed.\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * The title to be displayed on the outline.\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- Type: `SocialLink[]`\n\nYou may define this option to show your social account links with icons in nav.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      // You can add any icon from simple-icons (https://simpleicons.org/):\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // You can also add custom icons by passing SVG as string:\n      {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // You can include a custom label for accessibility too (optional but recommended):\n        ariaLabel: 'cool link'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- Type: `Footer`\n- Can be overridden per page via [frontmatter](./frontmatter-config#footer)\n\nFooter configuration. You can add a message or copyright text on the footer, however, it will only be displayed when the page doesn't contain a sidebar. This is due to design concerns.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- Type: `EditLink`\n- Can be overridden per page via [frontmatter](./frontmatter-config#editlink)\n\nEdit Link lets you display a link to edit the page on Git management services such as GitHub, or GitLab. See [Default Theme: Edit Link](./default-theme-edit-link) for more details.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- Type: `LastUpdatedOptions`\n\nAllows customization for the last updated text and date format.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Updated at',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- Type: `AlgoliaSearch`\n\nAn option to support searching your docs site using [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Learn more in [Default Theme: Search](./default-theme-search)\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\nView full options [here](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts).\n\n## carbonAds {#carbon-ads}\n\n- Type: `CarbonAdsOptions`\n\nAn option to display [Carbon Ads](https://www.carbonads.net/).\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\nLearn more in [Default Theme: Carbon Ads](./default-theme-carbon-ads)\n\n## docFooter\n\n- Type: `DocFooter`\n\nCan be used to customize text appearing above previous and next links. Helpful if not writing docs in English. Also can be used to disable prev/next links globally. If you want to selectively enable/disable prev/next links, you can use [frontmatter](./default-theme-prev-next-links).\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Pagina prior',\n      next: 'Proxima pagina'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- Type: `string`\n- Default: `Appearance`\n\nCan be used to customize the dark mode switch label. This label is only displayed in the mobile view.\n\n## lightModeSwitchTitle\n\n- Type: `string`\n- Default: `Switch to light theme`\n\nCan be used to customize the light mode switch title that appears on hovering.\n\n## darkModeSwitchTitle\n\n- Type: `string`\n- Default: `Switch to dark theme`\n\nCan be used to customize the dark mode switch title that appears on hovering.\n\n## sidebarMenuLabel\n\n- Type: `string`\n- Default: `Menu`\n\nCan be used to customize the sidebar menu label. This label is only displayed in the mobile view.\n\n## returnToTopLabel\n\n- Type: `string`\n- Default: `Return to top`\n\nCan be used to customize the label of the return to top button. This label is only displayed in the mobile view.\n\n## langMenuLabel\n\n- Type: `string`\n- Default: `Change language`\n\nCan be used to customize the aria-label of the language toggle button in navbar. This is only used if you're using [i18n](../guide/i18n).\n\n## skipToContentLabel\n\n- Type: `string`\n- Default: `Skip to content`\n\nCan be used to customize the label of the skip to content link. This link is shown when the user is navigating the site using a keyboard.\n\n## externalLinkIcon\n\n- Type: `boolean`\n- Default: `false`\n\nWhether to show an external link icon next to external links in markdown.\n\n## `useLayout` <Badge type=\"info\" text=\"composable\" />\n\nReturns layout-related data. The returned object has the following type:\n\n```ts\ninterface {\n  isHome: ComputedRef<boolean>\n\n  sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>\n  sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>\n  hasSidebar: ComputedRef<boolean>\n  isSidebarEnabled: ComputedRef<boolean>\n\n  hasAside: ComputedRef<boolean>\n  leftAside: ComputedRef<boolean>\n\n  headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>\n  hasLocalNav: ComputedRef<boolean>\n}\n```\n\n**Example:**\n\n```vue\n<script setup>\nimport { useLayout } from 'vitepress/theme'\n\nconst { hasSidebar } = useLayout()\n</script>\n\n<template>\n  <div v-if=\"hasSidebar\">Only show when sidebar exists</div>\n</template>\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-edit-link.md",
    "content": "# Edit Link\n\n## Site-Level Config\n\nEdit Link lets you display a link to edit the page on Git management services such as GitHub, or GitLab. To enable it, add `themeConfig.editLink` options to your config.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\nThe `pattern` option defines the URL structure for the link, and `:path` is going to be replaced with the page path.\n\nYou can also put a pure function that accepts [`PageData`](./runtime-api#usedata) as the argument and returns the URL string.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nIt should not have side-effects nor access anything outside of its scope since it will be serialized and executed in the browser.\n\nBy default, this will add the link text \"Edit this page\" at the bottom of the doc page. You may customize this text by defining the `text` option.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    }\n  }\n}\n```\n\n## Frontmatter Config\n\nThis can be disabled per-page using the `editLink` option on frontmatter:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-footer.md",
    "content": "# Footer\n\nVitePress will display global footer at the bottom of the page when `themeConfig.footer` is present.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // The message shown right before copyright.\n  message?: string\n\n  // The actual copyright text.\n  copyright?: string\n}\n```\n\nThe above configuration also supports HTML strings. So, for example, if you want to configure footer text to have some links, you can adjust the configuration as follows:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">MIT License</a>.',\n      copyright: 'Copyright © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning\nOnly inline elements can be used in `message` and `copyright` as they are rendered inside a `<p>` element. If you want to add block elements, consider using [`layout-bottom`](../guide/extending-default-theme#layout-slots) slot instead.\n:::\n\nNote that footer will not be displayed when the [SideBar](./default-theme-sidebar) is visible.\n\n## Frontmatter Config\n\nThis can be disabled per-page using the `footer` option on frontmatter:\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-home-page.md",
    "content": "# Home Page\n\nVitePress default theme provides a homepage layout, which you can also see used on [the homepage of this site](../). You may use it on any of your pages by specifying `layout: home` in the [frontmatter](./frontmatter-config).\n\n```yaml\n---\nlayout: home\n---\n```\n\nHowever, this option alone wouldn't do much. You can add several different pre templated \"sections\" to the homepage by setting additional other options such as `hero` and `features`.\n\n## Hero Section\n\nThe Hero section comes at the top of the homepage. Here's how you can configure the Hero section.\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: Get Started\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: View on GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // The string shown top of `text`. Comes with brand color\n  // and expected to be short, such as product name.\n  name?: string\n\n  // The main text for the hero section. This will be defined\n  // as `h1` tag.\n  text: string\n\n  // Tagline displayed below `text`.\n  tagline?: string\n\n  // The image is displayed next to the text and tagline area.\n  image?: ThemeableImage\n\n  // Action buttons to display in home hero section.\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // Color theme of the button. Defaults to `brand`.\n  theme?: 'brand' | 'alt'\n\n  // Label of the button.\n  text: string\n\n  // Destination link of the button.\n  link: string\n\n  // Link target attribute.\n  target?: string\n\n  // Link rel attribute.\n  rel?: string\n}\n```\n\n### Customizing the name color\n\nVitePress uses the brand color (`--vp-c-brand-1`) for the `name`. However, you may customize this color by overriding `--vp-home-hero-name-color` variable.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nAlso you may customize it further by combining `--vp-home-hero-name-background` to give the `name` gradient color.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## Features Section\n\nIn Features section, you can list any number of features you would like to show right after the Hero section. To configure it, pass `features` option to the frontmatter.\n\nYou can provide an icon for each feature, which can be an emoji or any type of image. When the configured icon is an image (svg, png, jpeg...), you must provide the icon with the proper width and height; you can also provide the description, its intrinsic size as well as its variants for dark and light theme when required.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Simple and minimal, always\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // Show icon on each feature box.\n  icon?: FeatureIcon\n\n  // Title of the feature.\n  title: string\n\n  // Details of the feature.\n  details: string\n\n  // Link when clicked on feature component. The link can\n  // be both internal or external.\n  //\n  // e.g. `guide/reference/default-theme-home-page` or `https://example.com`\n  link?: string\n\n  // Link text to be shown inside feature component. Best\n  // used with `link` option.\n  //\n  // e.g. `Learn more`, `Visit page`, etc.\n  linkText?: string\n\n  // Link rel attribute for the `link` option.\n  //\n  // e.g. `external`\n  rel?: string\n\n  // Link target attribute for the `link` option.\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## Markdown Content\n\nYou can add additional content to your site's homepage just by adding Markdown below the `---` frontmatter divider.\n\n````md\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n---\n\n## Getting Started\n\nYou can get started using VitePress right away using `npx`!\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n\n::: info\nVitePress didn't always auto-style the extra content of the `layout: home` page. To revert to older behavior, you can add `markdownStyles: false` to the frontmatter.\n:::\n"
  },
  {
    "path": "docs/en/reference/default-theme-last-updated.md",
    "content": "# Last Updated\n\nThe update time of the last content will be displayed in the lower right corner of the page. To enable it, add `lastUpdated` options to your config.\n\n::: info\nVitePress displays the \"last updated\" time using the timestamp of the most recent Git commit for each file. To enable this, the Markdown file must be committed to Git.\n\nInternally, VitePress runs `git log -1 --pretty=\"%ai\"` on each file to retrieve its timestamp. If all pages show the same update time, it's likely due to shallow cloning (common in CI environments), which limits Git history.\n\nTo fix this in **GitHub Actions**, use the following in your workflow:\n\n```yaml{4}\n- name: Checkout\n  uses: actions/checkout@v5\n  with:\n    fetch-depth: 0\n```\n\nOther CI/CD platforms have similar settings.\n\nIf such options aren't available, you can prepend the `docs:build` command in your `package.json` with a manual fetch:\n\n```json\n\"docs:build\": \"git fetch --unshallow && vitepress build docs\"\n```\n:::\n\n## Site-Level Config\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## Frontmatter Config\n\nThis can be disabled per-page using the `lastUpdated` option on frontmatter:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nAlso refer [Default Theme: Last Updated](./default-theme-config#lastupdated) for more details. Any truthy value at theme-level will also enable the feature unless explicitly disabled at site or page level.\n"
  },
  {
    "path": "docs/en/reference/default-theme-layout.md",
    "content": "# Layout\n\nYou may choose the page layout by setting `layout` option to the page [frontmatter](./frontmatter-config). There are 3 layout options, `doc`, `page`, and `home`. If nothing is specified, then the page is treated as `doc` page.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## Doc Layout\n\nOption `doc` is the default layout and it styles the whole Markdown content into \"documentation\" look. It works by wrapping whole content within `vp-doc` css class, and applying styles to elements underneath it.\n\nAlmost all generic elements such as `p`, or `h2` get special styling. Therefore, keep in mind that if you add any custom HTML inside a Markdown content, those will get affected by those styles as well.\n\nIt also provides documentation specific features listed below. These features are only enabled in this layout.\n\n- Edit Link\n- Prev Next Link\n- Outline\n- [Carbon Ads](./default-theme-carbon-ads)\n\n## Page Layout\n\nOption `page` is treated as \"blank page\". The Markdown will still be parsed, and all of the [Markdown Extensions](../guide/markdown) work as same as `doc` layout, but it wouldn't get any default stylings.\n\nThe page layout will let you style everything by you without VitePress theme affecting the markup. This is useful when you want to create your own custom page.\n\nNote that even in this layout, sidebar will still show up if the page has a matching sidebar config.\n\n## Home Layout\n\nOption `home` will generate templated \"Homepage\". In this layout, you can set extra options such as `hero` and `features` to customize the content further. Please visit [Default Theme: Home Page](./default-theme-home-page) for more details.\n\n## No Layout\n\nIf you don't want any layout, you can pass `layout: false` through frontmatter. This option is helpful if you want a fully-customizable landing page (without any sidebar, navbar, or footer by default).\n\n## Custom Layout\n\nYou can also use a custom layout:\n\n```md\n---\nlayout: foo\n---\n```\n\nThis will look for a component named `foo` registered in context. For example, you can register your component globally in `.vitepress/theme/index.ts`:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-nav.md",
    "content": "# Nav\n\nThe Nav is the navigation bar displayed on top of the page. It contains the site title, global menu links, etc.\n\n## Site Title and Logo\n\nBy default, nav shows the title of the site referencing [`config.title`](./site-config#title) value. If you would like to change what's displayed on nav, you may define custom text in `themeConfig.siteTitle` option.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'My Custom Title'\n  }\n}\n```\n\nIf you have a logo for your site, you can display it by passing in the path to the image. You should place the logo within `public` directly, and define the absolute path to it.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nWhen adding a logo, it gets displayed along with the site title. If your logo is all you need and if you would like to hide the site title text, set `false` to the `siteTitle` option.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nYou can also pass an object as logo if you want to add `alt` attribute or customize it based on dark/light mode. Refer [`themeConfig.logo`](./default-theme-config#logo) for details.\n\n## Navigation Links\n\nYou may define `themeConfig.nav` option to add links to your nav.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      { text: 'Config', link: '/config' },\n      { text: 'Changelog', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\nThe `text` is the actual text displayed in nav, and the `link` is the link that will be navigated to when the text is clicked. For the link, set path to the actual file without `.md` prefix, and always start with `/`.\n\nThe `link` can also be a function that accepts [`PageData`](./runtime-api#usedata) as the argument and returns the path.\n\nNav links can also be dropdown menus. To do this, set `items` key on link option.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nNote that dropdown menu title (`Dropdown Menu` in the above example) can not have `link` property since it becomes a button to open dropdown dialog.\n\nYou may further add \"sections\" to the dropdown menu items as well by passing in more nested items.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // Title for the section.\n            text: 'Section A Title',\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // You may also omit the title.\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Customize link's \"active\" state\n\nNav menu items will be highlighted when the current page is under the matching path. if you would like to customize the path to be matched, define `activeMatch` property and regex as a string value.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // This link gets active state when the user is\n      // on `/config/` path.\n      {\n        text: 'Guide',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch` is expected to be a regex string, but you must define it as a string. We can't use actual RegExp object here because it isn't serializable during the build time.\n:::\n\n### Customize link's \"target\" and \"rel\" attributes\n\nBy default, VitePress automatically determines `target` and `rel` attributes based on whether the link is an external link. But if you want, you can customize them too.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Merchandise',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## Social Links\n\nRefer [`socialLinks`](./default-theme-config#sociallinks).\n\n## Custom Components\n\nYou can include custom components in the navigation bar by using the `component` option. The `component` key should be the Vue component name, and must be registered globally using [Theme.enhanceApp](../guide/custom-theme#theme-interface).\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'My Menu',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // Optional props to pass to the component\n            props: {\n              title: 'My Custom Component'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\nThen, you need to register the component globally:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\nYour component will be rendered in the navigation bar. VitePress will provide the following additional props to the component:\n\n- `screenMenu`: an optional boolean indicating whether the component is inside mobile navigation menu\n\nYou can check an example in the e2e tests [here](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress).\n"
  },
  {
    "path": "docs/en/reference/default-theme-prev-next-links.md",
    "content": "# Prev Next Links\n\nYou can customize the text and link for the previous and next pages (shown at doc footer). This is helpful if you want a different text there than what you have on your sidebar. Additionally, you may find it useful to disable the footer or link to a page that is not included in your sidebar.\n\n## prev\n\n- Type: `string | false | { text?: string; link?: string }`\n\n- Details:\n\n  Specifies the text/link to show on the link to the previous page. If you don't set this in frontmatter, the text/link will be inferred from the sidebar config.\n\n- Examples:\n\n  - To customize only the text:\n\n    ```yaml\n    ---\n    prev: 'Get Started | Markdown'\n    ---\n    ```\n\n  - To customize both text and link:\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - To hide previous page:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\nSame as `prev` but for the next page.\n"
  },
  {
    "path": "docs/en/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# Search\n\n## Local Search\n\nVitePress supports fuzzy full-text search using an in-browser index thanks to [minisearch](https://github.com/lucaong/minisearch/). To enable this feature, simply set the `themeConfig.search.provider` option to `'local'` in your `.vitepress/config.ts` file:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\nExample result:\n\n![screenshot of the search modal](/search.png)\n\nAlternatively, you can use [Algolia DocSearch](#algolia-search) or some community plugins like:\n\n- <https://www.npmjs.com/package/vitepress-plugin-search>\n- <https://www.npmjs.com/package/vitepress-plugin-pagefind>\n- <https://www.npmjs.com/package/@orama/plugin-vitepress>\n- <https://www.npmjs.com/package/vitepress-plugin-typesense>\n\n### i18n {#local-search-i18n}\n\nYou can use a config like this to use multilingual search:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          zh: { // make this `root` if you want to translate the default locale\n            translations: {\n              button: {\n                buttonText: '搜索',\n                buttonAriaLabel: '搜索'\n              },\n              modal: {\n                displayDetails: '显示详细列表',\n                resetButtonTitle: '重置搜索',\n                backButtonTitle: '关闭搜索',\n                noResultsText: '没有结果',\n                footer: {\n                  selectText: '选择',\n                  selectKeyAriaLabel: '输入',\n                  navigateText: '导航',\n                  navigateUpKeyAriaLabel: '上箭头',\n                  navigateDownKeyAriaLabel: '下箭头',\n                  closeText: '关闭',\n                  closeKeyAriaLabel: 'esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### miniSearch options\n\nYou can configure MiniSearch like this:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nLearn more in [MiniSearch docs](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).\n\n### Custom content renderer\n\nYou can customize the function used to render the markdown content before indexing it:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // return html string\n        }\n      }\n    }\n  }\n})\n```\n\nThis function will be stripped from client-side site data, so you can use Node.js APIs in it.\n\n#### Example: Excluding pages from search\n\nYou can exclude pages from search by adding `search: false` to the frontmatter of the page. Alternatively:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Note\nIn case a custom `_render` function is provided, you need to handle the `search: false` frontmatter yourself. Also, the `env` object won't be completely populated before `md.renderAsync` is called, so any checks on optional `env` properties like `frontmatter` should be done after that.\n:::\n\n#### Example: Transforming content - adding anchors\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Algolia Search\n\nVitePress supports searching your docs site using [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Refer to their getting started guide. In your `.vitepress/config.ts` you'll need to provide at least the following to make it work:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\nYou can use a config like this to use multilingual search:\n\n<details>\n<summary>View full example</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\nRefer [official Algolia docs](https://docsearch.algolia.com/docs/api#translations) to learn more about them. To quickly get started, you can also copy the translations used by this site from [our GitHub repo](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code).\n\n### Algolia Ask AI Support {#ask-ai}\n\nIf you would like to include **Ask AI**, pass the `askAi` option (or any of the partial fields) inside `options`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"YOUR-ASSISTANT-ID\"\n        // OR\n        askAi: {\n          // at minimum you must provide the assistantId you received from Algolia\n          assistantId: 'XXXYYY',\n          // optional overrides – if omitted, the top-level appId/apiKey/indexName values are reused\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Note\nIf you want to default to keyword search and do not want to use Ask AI, omit the `askAi` property.\n:::\n\n### Ask AI Side Panel {#ask-ai-side-panel}\n\nDocSearch v4.5+ supports an optional **Ask AI side panel**. When enabled, it can be opened with **Ctrl/Cmd+I** by default. The [Sidepanel API Reference](https://docsearch.algolia.com/docs/sidepanel/api-reference) contains the full list of options.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            panel: {\n              variant: 'floating', // or 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nIf you need to disable the keyboard shortcut, use the `keyboardShortcuts` option at the sidepanel root level:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### Mode (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nYou can optionally control how VitePress integrates keyword search and Ask AI:\n\n- `mode: 'auto'` (default): infer `hybrid` when keyword search is configured, otherwise `sidePanel` when Ask AI side panel is configured.\n- `mode: 'sidePanel'`: force side panel only (hides the keyword search button).\n- `mode: 'hybrid'`: enable keyword search modal + Ask AI side panel (requires keyword search configuration).\n- `mode: 'modal'`: keep Ask AI inside the DocSearch modal (even if you configured the side panel).\n\n#### Ask AI only (no keyword search) {#ask-ai-only}\n\nIf you want to use **Ask AI side panel only**, you can omit top-level keyword search config and provide credentials under `askAi`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### Crawler Config\n\nHere is an example config based on what this site uses:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/en/reference/default-theme-sidebar.md",
    "content": "# Sidebar\n\nThe sidebar is the main navigation block for your documentation. You can configure the sidebar menu in [`themeConfig.sidebar`](./default-theme-config#sidebar).\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## The Basics\n\nThe simplest form of the sidebar menu is passing in a single array of links. The first level item defines the \"section\" for the sidebar. It should contain `text`, which is the title of the section, and `items` which are the actual navigation links.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        items: [\n          { text: 'Item A', link: '/item-a' },\n          { text: 'Item B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Section Title B',\n        items: [\n          { text: 'Item C', link: '/item-c' },\n          { text: 'Item D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\nEach `link` should specify the path to the actual file starting with `/`. If you add trailing slash to the end of link, it will show `index.md` of the corresponding directory.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          // This shows `/guide/index.md` page.\n          { text: 'Introduction', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nYou may further nest the sidebar items up to 6 level deep counting up from the root level. Note that deeper than 6 level of nested items gets ignored and will not be displayed on the sidebar.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Level 1',\n        items: [\n          {\n            text: 'Level 2',\n            items: [\n              {\n                text: 'Level 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Multiple Sidebars\n\nYou may show different sidebar depending on the page path. For example, as shown on this site, you might want to create a separate sections of content in your documentation like \"Guide\" page and \"Config\" page.\n\nTo do so, first organize your pages into directories for each desired section:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nThen, update your configuration to define your sidebar for each section. This time, you should pass an object instead of an array.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // This sidebar gets displayed when a user\n      // is on `guide` directory.\n      '/guide/': [\n        {\n          text: 'Guide',\n          items: [\n            { text: 'Index', link: '/guide/' },\n            { text: 'One', link: '/guide/one' },\n            { text: 'Two', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // This sidebar gets displayed when a user\n      // is on `config` directory.\n      '/config/': [\n        {\n          text: 'Config',\n          items: [\n            { text: 'Index', link: '/config/' },\n            { text: 'Three', link: '/config/three' },\n            { text: 'Four', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## Collapsible Sidebar Groups\n\nBy adding `collapsed` option to the sidebar group, it shows a toggle button to hide/show each section.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\nAll sections are \"open\" by default. If you would like them to be \"closed\" on initial page load, set `collapsed` option to `true`.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/en/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Developer',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# Team Page\n\nIf you would like to introduce your team, you may use Team components to construct the Team Page. There are two ways of using these components. One is to embed it in doc page, and another is to create a full Team Page.\n\n## Show team members in a page\n\nYou may use `<VPTeamMembers>` component exposed from `vitepress/theme` to display a list of team members on any page.\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# Our Team\n\nSay hello to our awesome team.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\nThe above will display a team member in card looking element. It should display something similar to below.\n\n<VPTeamMembers size=\"small\" :members />\n\n`<VPTeamMembers>` component comes in 2 different sizes, `small` and `medium`. While it boils down to your preference, usually `small` size should fit better when used in doc page. Also, you may add more properties to each member such as adding \"description\" or \"sponsor\" button. Learn more about it in [`<VPTeamMembers>`](#vpteammembers).\n\nEmbedding team members in doc page is good for small size team where having dedicated full team page might be too much, or introducing partial members as a reference to documentation context.\n\nIf you have large number of members, or simply would like to have more space to show team members, consider [creating a full team page](#create-a-full-team-page).\n\n## Create a full Team Page\n\nInstead of adding team members to doc page, you may also create a full Team Page, similar to how you can create a custom [Home Page](./default-theme-home-page).\n\nTo create a team page, first, create a new md file. The file name doesn't matter, but here lets call it `team.md`. In this file, set frontmatter option `layout: page`, and then you may compose your page structure using `TeamPage` components.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\nWhen creating a full team page, remember to wrap all components with `<VPTeamPage>` component. This component will ensure all nested team related components get the proper layout structure like spacings.\n\n`<VPPageTitle>` component adds the page title section. The title being `<h1>` heading. Use `#title` and `#lead` slot to document about your team.\n\n`<VPMembers>` works as same as when used in a doc page. It will display list of members.\n\n### Add sections to divide team members\n\nYou may add \"sections\" to the team page. For example, you may have different types of team members such as Core Team Members and Community Partners. You can divide these members into sections to better explain the roles of each group.\n\nTo do so, add `<VPTeamPageSection>` component to the `team.md` file we created previously.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Our Team</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\nThe `<VPTeamPageSection>` component can have `#title` and `#lead` slot similar to `VPTeamPageTitle` component, and also `#members` slot for displaying team members.\n\nRemember to put in `<VPTeamMembers>` component within `#members` slot.\n\n## `<VPTeamMembers>`\n\nThe `<VPTeamMembers>` component displays a given list of members.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // Size of each members. Defaults to `medium`.\n  size?: 'small' | 'medium'\n\n  // List of members to display.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // Avatar image for the member.\n  avatar: string\n\n  // Name of the member.\n  name: string\n\n  // Title to be shown below member's name.\n  // e.g. Developer, Software Engineer, etc.\n  title?: string\n\n  // Organization that the member belongs.\n  org?: string\n\n  // URL for the organization.\n  orgLink?: string\n\n  // Description for the member.\n  desc?: string\n\n  // Social links. e.g. GitHub, Twitter, etc. You may pass in\n  // the Social Links object here.\n  // See: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // URL for the sponsor page for the member.\n  sponsor?: string\n\n  // Text for the sponsor link. Defaults to 'Sponsor'.\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\nThe root component when creating a full team page. It only accepts a single slot. It will style all passed in team related components.\n\n## `<VPTeamPageTitle>`\n\nAdds \"title\" section of the page. Best use at the very beginning under `<VPTeamPage>`. It accepts `#title` and `#lead` slot.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\nCreates a \"section\" with in team page. It accepts `#title`, `#lead`, and `#members` slot. You may add as many sections as you like inside `<VPTeamPage>`.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/en/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# Frontmatter Config\n\nFrontmatter enables page based configuration. In every markdown file, you can use frontmatter config to override site-level or theme-level config options. Also, there are config options which you can only define in frontmatter.\n\nExample usage:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\nYou can access frontmatter data via the `$frontmatter` global in Vue expressions:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- Type: `string`\n\nTitle for the page. It's same as [config.title](./site-config#title), and it overrides the site-level config.\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- Type: `string | boolean`\n\nThe suffix for the title. It's same as [config.titleTemplate](./site-config#titletemplate), and it overrides the site-level config.\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Vite & Vue powered static site generator\n---\n```\n\n## description\n\n- Type: `string`\n\nDescription for the page. It's same as [config.description](./site-config#description), and it overrides the site-level config.\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- Type: `HeadConfig[]`\n\nSpecify extra head tags to be injected for the current page. Will be appended after head tags injected by site-level config.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## Default Theme Only\n\nThe following frontmatter options are only applicable when using the default theme.\n\n### layout\n\n- Type: `doc | home | page`\n- Default: `doc`\n\nDetermines the layout of the page.\n\n- `doc` - It applies default documentation styles to the markdown content.\n- `home` - Special layout for \"Home Page\". You may add extra options such as `hero` and `features` to rapidly create beautiful landing page.\n- `page` - Behave similar to `doc` but it applies no styles to the content. Useful when you want to create a fully custom page.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"home page only\" />\n\nDefines contents of home hero section when `layout` is set to `home`. More details in [Default Theme: Home Page](./default-theme-home-page).\n\n### features <Badge type=\"info\" text=\"home page only\" />\n\nDefines items to display in features section when `layout` is set to `home`. More details in [Default Theme: Home Page](./default-theme-home-page).\n\n### navbar\n\n- Type: `boolean`\n- Default: `true`\n\nWhether to display [navbar](./default-theme-nav).\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- Type: `boolean`\n- Default: `true`\n\nWhether to display [sidebar](./default-theme-sidebar).\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- Type: `boolean | 'left'`\n- Default: `true`\n\nDefines the location of the aside component in the `doc` layout.\n\nSetting this value to `false` prevents rendering of aside container.\\\nSetting this value to `true` renders the aside to the right.\\\nSetting this value to `'left'` renders the aside to the left.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- Type: `number | [number, number] | 'deep' | false`\n- Default: `2`\n\nThe levels of header in the outline to display for the page. It's same as [config.themeConfig.outline.level](./default-theme-config#outline), and it overrides the value set in site-level config.\n\n```yaml\n---\noutline: [2, 4]\n---\n```\n\n### lastUpdated\n\n- Type: `boolean | Date`\n- Default: `true`\n\nWhether to display [last updated](./default-theme-last-updated) text in the footer of the current page. If a datetime is specified, it will be displayed instead of the last git modified timestamp.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- Type: `boolean`\n- Default: `true`\n\nWhether to display [edit link](./default-theme-edit-link) in the footer of the current page.\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- Type: `boolean`\n- Default: `true`\n\nWhether to display [footer](./default-theme-footer).\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- Type: `string`\n\nAdd extra class name to a specific page.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nThen you can customize styles of this specific page in `.vitepress/theme/custom.css` file:\n\n```css\n.custom-page-class {\n  /* page-specific styles */\n}\n```\n\n### isHome\n\n- Type: `boolean`\n\nThe default theme relies on checks like `frontmatter.layout === 'home'` to determine if the current page is the home page.\\\nThis is useful when you want to force show the home page elements in a custom layout.\n\n```yaml\n---\nisHome: true\n---\n```\n"
  },
  {
    "path": "docs/en/reference/runtime-api.md",
    "content": "# Runtime API\n\nVitePress offers several built-in APIs to let you access app data. VitePress also comes with a few built-in components that can be used globally.\n\nThe helper methods are globally importable from `vitepress` and are typically used in custom theme Vue components. However, they are also usable inside `.md` pages because markdown files are compiled into Vue [Single-File Components](https://vuejs.org/guide/scaling-up/sfc.html).\n\nMethods that start with `use*` indicates that it is a [Vue 3 Composition API](https://vuejs.org/guide/introduction.html#composition-api) function (\"Composable\") that can only be used inside `setup()` or `<script setup>`.\n\n## `useData` <Badge type=\"info\" text=\"composable\" />\n\nReturns page-specific data. The returned object has the following type:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * Site-level metadata\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig from .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Page-level metadata\n   */\n  page: Ref<PageData>\n  /**\n   * Page frontmatter\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * Dynamic route params\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  /**\n   * Current location hash\n   */\n  hash: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**Example:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" />\n\nReturns the current route object with the following type:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" />\n\nReturns the VitePress router instance so you can programmatically navigate to another page.\n\n```ts\ninterface Router {\n  /**\n   * Current route.\n   */\n  route: Route\n  /**\n   * Navigate to a new URL.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * Called before the route changes. Return `false` to cancel the navigation.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Called before the page component is loaded (after the history state is updated).\n   * Return `false` to cancel the navigation.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Called after the page component is loaded (before the page component is updated).\n   */\n  onAfterPageLoad?: (to: string) => Awaitable<void>\n  /**\n   * Called after the route changes.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" />\n\n- **Type**: `(path: string) => string`\n\nAppends the configured [`base`](./site-config#base) to a given URL path. Also see [Base URL](../guide/asset-handling#base-url).\n\n## `<Content />` <Badge type=\"info\" text=\"component\" />\n\nThe `<Content />` component displays the rendered markdown contents. Useful [when creating your own theme](../guide/custom-theme).\n\n```vue\n<template>\n  <h1>Custom Layout!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" />\n\nThe `<ClientOnly />` component renders its slot only at client side.\n\nBecause VitePress applications are server-rendered in Node.js when generating static builds, any Vue usage must conform to the universal code requirements. In short, make sure to only access Browser / DOM APIs in beforeMount or mounted hooks.\n\nIf you are using or demoing components that are not SSR-friendly (for example, contain custom directives), you can wrap them inside the `ClientOnly` component.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- Related: [SSR Compatibility](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" />\n\nDirectly access current page's [frontmatter](../guide/frontmatter) data in Vue expressions.\n\n```md\n---\ntitle: Hello\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" />\n\nDirectly access current page's [dynamic route params](../guide/routing#dynamic-routes) in Vue expressions.\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/en/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# Site Config\n\nSite config is where you can define the global settings of the site. App config options define settings that apply to every VitePress site, regardless of what theme it is using. For example, the base directory or the title of the site.\n\n## Overview\n\n### Config Resolution\n\nThe config file is always resolved from `<root>/.vitepress/config.[ext]`, where `<root>` is your VitePress [project root](../guide/routing#root-and-source-directory), and `[ext]` is one of the supported file extensions. TypeScript is supported out of the box. Supported extensions include `.js`, `.ts`, `.mjs`, and `.mts`.\n\nIt is recommended to use ES modules syntax in config files. The config file should default export an object:\n\n```ts\nexport default {\n  // app level config options\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n  ...\n}\n```\n\n::: details Dynamic (Async) Config\n\nIf you need to dynamically generate the config, you can also default export a function. For example:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // app level config options\n    lang: 'en-US',\n    title: 'VitePress',\n    description: 'Vite & Vue powered static site generator.',\n\n    // theme level config options\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nYou can also use top-level `await`. For example:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // app level config options\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // theme level config options\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### Config Intellisense\n\nUsing the `defineConfig` helper will provide TypeScript-powered intellisense for config options. Assuming your IDE supports it, this should work in both JavaScript and TypeScript.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### Typed Theme Config\n\nBy default, `defineConfig` helper expects the theme config type from default theme:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // Type is `DefaultTheme.Config`\n  }\n})\n```\n\nIf you use a custom theme and want type checks for the theme config, you'll need to use `defineConfigWithTheme` instead, and pass the config type for your custom theme via a generic argument:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // Type is `ThemeConfig`\n  }\n})\n```\n\n### Vite, Vue & Markdown Config\n\n- **Vite**\n\n  You can configure the underlying Vite instance using the [vite](#vite) option in your VitePress config. No need to create a separate Vite config file.\n\n- **Vue**\n\n  VitePress already includes the official Vue plugin for Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)). You can configure its options using the [vue](#vue) option in your VitePress config.\n\n- **Markdown**\n\n  You can configure the underlying [Markdown-It](https://github.com/markdown-it/markdown-it) instance using the [markdown](#markdown) option in your VitePress config.\n\n## Site Metadata\n\n### title\n\n- Type: `string`\n- Default: `VitePress`\n- Can be overridden per page via [frontmatter](./frontmatter-config#title)\n\nTitle for the site. When using the default theme, this will be displayed in the nav bar.\n\nIt will also be used as the default suffix for all individual page titles, unless [`titleTemplate`](#titletemplate) is defined. An individual page's final title will be the text content of its first `<h1>` header, combined with the global `title` as the suffix. For example with the following config and page content:\n\n```ts\nexport default {\n  title: 'My Awesome Site'\n}\n```\n\n```md\n# Hello\n```\n\nThe title of the page will be `Hello | My Awesome Site`.\n\n### titleTemplate\n\n- Type: `string | boolean`\n- Can be overridden per page via [frontmatter](./frontmatter-config#titletemplate)\n\nAllows customizing each page's title suffix or the entire title. For example:\n\n```ts\nexport default {\n  title: 'My Awesome Site',\n  titleTemplate: 'Custom Suffix'\n}\n```\n\n```md\n# Hello\n```\n\nThe title of the page will be `Hello | Custom Suffix`.\n\nTo completely customize how the title should be rendered, you can use the `:title` symbol in `titleTemplate`:\n\n```ts\nexport default {\n  titleTemplate: ':title - Custom Suffix'\n}\n```\n\nHere `:title` will be replaced with the text inferred from the page's first `<h1>` header. The title of the previous example page will be `Hello - Custom Suffix`.\n\nThe option can be set to `false` to disable title suffixes.\n\n### description\n\n- Type: `string`\n- Default: `A VitePress site`\n- Can be overridden per page via [frontmatter](./frontmatter-config#description)\n\nDescription for the site. This will render as a `<meta>` tag in the page HTML.\n\n```ts\nexport default {\n  description: 'A VitePress site'\n}\n```\n\n### head\n\n- Type: `HeadConfig[]`\n- Default: `[]`\n- Can be appended per page via [frontmatter](./frontmatter-config#head)\n\nAdditional elements to render in the `<head>` tag in the page HTML. The user-added tags are rendered before the closing `head` tag, after VitePress tags.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### Example: Adding a favicon\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // put favicon.ico in public directory, if base is set, use /base/favicon.ico\n\n/* Would render:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### Example: Adding Google Fonts\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* Would render:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### Example: Registering a service worker\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* Would render:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### Example: Using Google Analytics\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* Would render:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- Type: `string`\n- Default: `en-US`\n\nThe lang attribute for the site. This will render as a `<html lang=\"en-US\">` tag in the page HTML.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- Type: `string`\n- Default: `/`\n\nThe base URL the site will be deployed at. You will need to set this if you plan to deploy your site under a sub path, for example, GitHub pages. If you plan to deploy your site to `https://foo.github.io/bar/`, then you should set base to `'/bar/'`. It should always start and end with a slash. Relative bases are not supported.\n\nThe base is automatically prepended to all the URLs that start with / in other options, so you only need to specify it once.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## Routing\n\n### cleanUrls\n\n- Type: `boolean`\n- Default: `false`\n\nWhen set to `true`, VitePress will remove the trailing `.html` from URLs. Also see [Generating Clean URLs](../guide/routing#generating-clean-urls).\n\n::: warning Server Support Required\nEnabling this may require additional configuration on your hosting platform. For it to work, your server must be able to serve `/foo.html` when visiting `/foo` **without a redirect**.\n:::\n\n### rewrites\n\n- Type: `Record<string, string>`\n\nDefines custom directory &lt;-&gt; URL mappings. See [Routing: Route Rewrites](../guide/routing#route-rewrites) for more details.\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## Build\n\n### srcDir\n\n- Type: `string`\n- Default: `.`\n\nThe directory where your markdown pages are stored, relative to project root. Also see [Root and Source Directory](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- Type: `string[]`\n- Default: `undefined`\n\nA [glob pattern](https://github.com/mrmlnc/fast-glob#pattern-syntax) for matching markdown files that should be excluded as source content.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- Type: `string`\n- Default: `./.vitepress/dist`\n\nThe build output location for the site, relative to [project root](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- Type: `string`\n- Default: `assets`\n\nSpecify the directory to nest generated assets under. The path should be inside [`outDir`](#outdir) and is resolved relative to it.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- Type: `string`\n- Default: `./.vitepress/cache`\n\nThe directory for cache files, relative to [project root](../guide/routing#root-and-source-directory). See also: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- Type: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- Default: `false`\n\nWhen set to `true`, VitePress will not fail builds due to dead links.\n\nWhen set to `'localhostLinks'`, the build will fail on dead links, but won't check `localhost` links.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\nIt can also be an array of exact url string, regex patterns, or custom filter functions.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // ignore exact url \"/playground\"\n    '/playground',\n    // ignore all localhost links\n    /^https?:\\/\\/localhost/,\n    // ignore all links include \"/repl/\"\"\n    /\\/repl\\//,\n    // custom function, ignore all links include \"ignore\"\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"experimental\" />\n\n- Type: `boolean`\n- Default: `false`\n\nWhen set to `true`, extract pages metadata to a separate JavaScript chunk instead of inlining it in the initial HTML. This makes each page's HTML payload smaller and makes the pages metadata cacheable, thus reducing server bandwidth when you have many pages in the site.\n\n### mpa <Badge type=\"warning\" text=\"experimental\" />\n\n- Type: `boolean`\n- Default: `false`\n\nWhen set to `true`, the production app will be built in [MPA Mode](../guide/mpa-mode). MPA mode ships 0kb JavaScript by default, at the cost of disabling client-side navigation and requires explicit opt-in for interactivity.\n\n## Theming\n\n### appearance\n\n- Type: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`\n- Default: `true`\n\nWhether to enable dark mode (by adding the `.dark` class to the `<html>` element).\n\n- If the option is set to `true`, the default theme will be determined by the user's preferred color scheme.\n- If the option is set to `dark`, the theme will be dark by default, unless the user manually toggles it.\n- If the option is set to `false`, users will not be able to toggle the theme.\n- If the option is set to `'force-dark'`, the theme will always be dark and users will not be able to toggle it.\n- If the option is set to `'force-auto'`, the theme will always be determined by the user's preferred color scheme and users will not be able to toggle it.\n\nThis option injects an inline script that restores users settings from local storage using the `vitepress-theme-appearance` key. This ensures the `.dark` class is applied before the page is rendered to avoid flickering.\n\n`appearance.initialValue` can only be `'dark' | undefined`. Refs or getters are not supported.\n\n### lastUpdated\n\n- Type: `boolean`\n- Default: `false`\n\nWhether to get the last updated timestamp for each page using Git. The timestamp will be included in each page's page data, accessible via [`useData`](./runtime-api#usedata).\n\nWhen using the default theme, enabling this option will display each page's last updated time. You can customize the text via [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) option.\n\n## Customization\n\n### markdown\n\n- Type: `MarkdownOption`\n\nConfigure Markdown parser options. VitePress uses [Markdown-it](https://github.com/markdown-it/markdown-it) as the parser, and [Shiki](https://github.com/shikijs/shiki) to highlight language syntax. Inside this option, you may pass various Markdown related options to fit your needs.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\nCheck the [type declaration and jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) for all the options available.\n\n### vite\n\n- Type: `import('vite').UserConfig`\n\nPass raw [Vite Config](https://vitejs.dev/config/) to internal Vite dev server / bundler.\n\n```js\nexport default {\n  vite: {\n    // Vite config options\n  }\n}\n```\n\n### vue\n\n- Type: `import('@vitejs/plugin-vue').Options`\n\nPass raw [`@vitejs/plugin-vue` options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) to the internal plugin instance.\n\n```js\nexport default {\n  vue: {\n    // @vitejs/plugin-vue options\n  }\n}\n```\n\n## Build Hooks\n\nVitePress build hooks allow you to add new functionality and behaviors to your website:\n\n- Sitemap\n- Search Indexing\n- PWA\n- Teleports\n\n### buildEnd\n\n- Type: `(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd` is a build CLI hook, it will run after build (SSG) finish but before VitePress CLI process exits.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender\n\n- Type: `(context: SSGContext) => Awaitable<SSGContext | void>`\n\n`postRender` is a build hook, called when SSG rendering is done. It will allow you to handle the teleports content during SSG.\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead\n\n- Type: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` is a build hook to transform the head before generating each page. It will allow you to add head entries that cannot be statically added to your VitePress config. You only need to return extra entries, they will be merged automatically with the existing ones.\n\n::: warning\nDon't mutate anything inside the `context`.\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // e.g. index.md (relative to srcDir)\n  assets: string[] // all non-js/css assets as fully resolved public URL\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nNote that this hook is only called when generating the site statically. It is not called during dev. If you need to add dynamic head entries during dev, you can use the [`transformPageData`](#transformpagedata) hook instead:\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `VitePress`\n            : `${pageData.title} | VitePress`\n      }\n    ])\n  }\n}\n```\n\n#### Example: Adding a canonical URL `<link>`\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n\n- Type: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml` is a build hook to transform the content of each page before saving to disk.\n\n::: warning\nDon't mutate anything inside the `context`. Also, modifying the html content may cause hydration problems in runtime.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n\n- Type: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` is a hook to transform the `pageData` of each page. You can directly mutate `pageData` or return changed values which will be merged into the page data.\n\n::: warning\nDon't mutate anything inside the `context` and be careful that this might impact the performance of dev server, especially if you have some network requests or heavy computations (like generating images) in the hook. You can check for `process.env.NODE_ENV === 'production'` for conditional logic.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // or return data to be merged\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/es/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Generador de Sitios Estáticos desarrollado con Vite y Vue.',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/es/guide/': { base: '/es/guide/', items: sidebarGuide() },\n      '/es/reference/': { base: '/es/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Editar esta página en GitHub'\n    },\n\n    footer: {\n      message: 'Liberado bajo la licencia MIT',\n      copyright: 'Todos los derechos reservados © 2019-PRESENTE Evan You'\n    },\n\n    docFooter: {\n      prev: 'Anterior',\n      next: 'Siguiente'\n    },\n\n    outline: {\n      label: 'En esta página'\n    },\n\n    lastUpdated: {\n      text: 'Actualizado el'\n    },\n\n    notFound: {\n      title: 'PÁGINA NO ENCONTRADA',\n      quote:\n        'Pero si no cambias de dirección y sigues buscando, podrías terminar donde te diriges.',\n      linkLabel: 'ir a inicio',\n      linkText: 'Llévame a inicio'\n    },\n\n    langMenuLabel: 'Cambiar Idioma',\n    returnToTopLabel: 'Volver arriba',\n    sidebarMenuLabel: 'Menu Lateral',\n    darkModeSwitchLabel: 'Tema Oscuro',\n    lightModeSwitchTitle: 'Cambiar a modo claro',\n    darkModeSwitchTitle: 'Cambiar a modo oscuro',\n    skipToContentLabel: 'Saltar al contenido'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'Guía',\n      link: '/es/guide/what-is-vitepress',\n      activeMatch: '/es/guide/'\n    },\n    {\n      text: 'Referencia',\n      link: '/es/reference/site-config',\n      activeMatch: '/es/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/es/'\n        },\n        {\n          text: 'Registro de cambios',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'Contribuir',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Introducción',\n      collapsed: false,\n      items: [\n        { text: '¿Qué es VitePress？', link: 'what-is-vitepress' },\n        { text: 'Iniciando', link: 'getting-started' },\n        { text: 'Enrutamiento', link: 'routing' },\n        { text: 'Despliegue', link: 'deploy' }\n      ]\n    },\n    {\n      text: 'Escribiendo',\n      collapsed: false,\n      items: [\n        { text: 'Extensiones Markdown', link: 'markdown' },\n        { text: 'Manejo de assets', link: 'asset-handling' },\n        { text: 'Frontmatter', link: 'frontmatter' },\n        { text: 'Usando Vue en Markdown', link: 'using-vue' },\n        { text: 'Internacionalización', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'Pesonalización',\n      collapsed: false,\n      items: [\n        { text: 'Usando un tema personalizado', link: 'custom-theme' },\n        {\n          text: 'Extendiendo el tema por defecto',\n          link: 'extending-default-theme'\n        },\n        {\n          text: 'Carga de datos en tiempo de compilación',\n          link: 'data-loading'\n        },\n        { text: 'Compatibilidad SSR', link: 'ssr-compat' },\n        { text: 'Conectando a un CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: 'Experimental',\n      collapsed: false,\n      items: [\n        { text: 'Modo MPA', link: 'mpa-mode' },\n        { text: 'Generación de Sitemap', link: 'sitemap-generation' }\n      ]\n    },\n    {\n      text: 'Configuración y Referencia de la API',\n      base: '/es/reference/',\n      link: 'site-config'\n    }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Referencia',\n      items: [\n        { text: 'Configuración del sitio', link: 'site-config' },\n        { text: 'Configuración Frontmatter', link: 'frontmatter-config' },\n        { text: 'API de tiempo de ejecución', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: 'Tema por defecto',\n          base: '/es/reference/default-theme-',\n          items: [\n            { text: 'Visión general', link: 'config' },\n            { text: 'Navegación', link: 'nav' },\n            { text: 'Barra Lateral', link: 'sidebar' },\n            { text: 'Página Inicial', link: 'home-page' },\n            { text: 'Pie de página', link: 'footer' },\n            { text: 'Layout', link: 'layout' },\n            { text: 'Distintivo', link: 'badge' },\n            { text: 'Página del equipo', link: 'team-page' },\n            { text: 'Links Anterior / Siguiente', link: 'prev-next-links' },\n            { text: 'Editar Link', link: 'edit-link' },\n            { text: 'Sello temporal de actualización', link: 'last-updated' },\n            { text: 'Búsqueda', link: 'search' },\n            { text: 'Carbon Ads', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: 'Buscar',\n        buttonAriaLabel: 'Buscar'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: 'Limpiar',\n          clearButtonAriaLabel: 'Borrar la consulta',\n          closeButtonText: 'Cerrar',\n          closeButtonAriaLabel: 'Cerrar',\n          placeholderText: 'Buscar en la documentación o preguntar a Ask AI',\n          placeholderTextAskAi: 'Haz otra pregunta...',\n          placeholderTextAskAiStreaming: 'Respondiendo...',\n          searchInputLabel: 'Buscar',\n          backToKeywordSearchButtonText:\n            'Volver a la búsqueda por palabras clave',\n          backToKeywordSearchButtonAriaLabel:\n            'Volver a la búsqueda por palabras clave',\n          newConversationPlaceholder: 'Haz una pregunta',\n          conversationHistoryTitle: 'Mi historial de conversaciones',\n          startNewConversationText: 'Iniciar una nueva conversación',\n          viewConversationHistoryText: 'Historial de conversaciones',\n          threadDepthErrorPlaceholder: 'Se alcanzó el límite de conversación'\n        },\n        newConversation: {\n          newConversationTitle: '¿Cómo puedo ayudarte hoy?',\n          newConversationDescription:\n            'Busco en tu documentación para ayudarte a encontrar guías de configuración, detalles de funciones y consejos de solución de problemas rápidamente.'\n        },\n        footer: {\n          selectText: 'Seleccionar',\n          submitQuestionText: 'Enviar pregunta',\n          selectKeyAriaLabel: 'Tecla Enter',\n          navigateText: 'Navegar',\n          navigateUpKeyAriaLabel: 'Flecha arriba',\n          navigateDownKeyAriaLabel: 'Flecha abajo',\n          closeText: 'Cerrar',\n          backToSearchText: 'Volver a la búsqueda',\n          closeKeyAriaLabel: 'Tecla Escape',\n          poweredByText: 'Con la tecnología de'\n        },\n        errorScreen: {\n          titleText: 'No se pueden obtener resultados',\n          helpText: 'Puede que quieras comprobar tu conexión de red.'\n        },\n        startScreen: {\n          recentSearchesTitle: 'Recientes',\n          noRecentSearchesText: 'No hay búsquedas recientes',\n          saveRecentSearchButtonTitle: 'Guardar esta búsqueda',\n          removeRecentSearchButtonTitle: 'Eliminar esta búsqueda del historial',\n          favoriteSearchesTitle: 'Favoritos',\n          removeFavoriteSearchButtonTitle:\n            'Eliminar esta búsqueda de favoritos',\n          recentConversationsTitle: 'Conversaciones recientes',\n          removeRecentConversationButtonTitle:\n            'Eliminar esta conversación del historial'\n        },\n        noResultsScreen: {\n          noResultsText: 'No se encontraron resultados para',\n          suggestedQueryText: 'Intenta buscar',\n          reportMissingResultsText:\n            '¿Crees que esta consulta debería devolver resultados?',\n          reportMissingResultsLinkText: 'Avísanos.'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'Preguntar a la IA: ',\n          noResultsAskAiPlaceholder:\n            '¿No lo encontraste en la documentación? Pide ayuda a Ask AI: '\n        },\n        askAiScreen: {\n          disclaimerText:\n            'Las respuestas se generan con IA y pueden contener errores. Verifícalas.',\n          relatedSourcesText: 'Fuentes relacionadas',\n          thinkingText: 'Pensando...',\n          copyButtonText: 'Copiar',\n          copyButtonCopiedText: '¡Copiado!',\n          copyButtonTitle: 'Copiar',\n          likeButtonTitle: 'Me gusta',\n          dislikeButtonTitle: 'No me gusta',\n          thanksForFeedbackText: '¡Gracias por tu comentario!',\n          preToolCallText: 'Buscando...',\n          duringToolCallText: 'Buscando...',\n          afterToolCallText: 'Buscado',\n          stoppedStreamingText: 'Has detenido esta respuesta',\n          errorTitleText: 'Error de chat',\n          threadDepthExceededMessage:\n            'Esta conversación se ha cerrado para mantener respuestas precisas.',\n          startNewConversationButtonText: 'Iniciar una nueva conversación'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'Preguntar a la IA',\n            buttonAriaLabel: 'Preguntar a la IA'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'Preguntar a la IA',\n              conversationHistoryTitle: 'Mi historial de conversaciones',\n              newConversationText: 'Iniciar una nueva conversación',\n              viewConversationHistoryText: 'Historial de conversaciones'\n            },\n            promptForm: {\n              promptPlaceholderText: 'Haz una pregunta',\n              promptAnsweringText: 'Respondiendo...',\n              promptAskAnotherQuestionText: 'Haz otra pregunta',\n              promptDisclaimerText:\n                'Las respuestas se generan con IA y pueden contener errores.',\n              promptLabelText:\n                'Pulsa Enter para enviar, o Shift+Enter para una nueva línea.',\n              promptAriaLabelText: 'Entrada de prompt'\n            },\n            conversationScreen: {\n              preToolCallText: 'Buscando...',\n              searchingText: 'Buscando...',\n              toolCallResultText: 'Buscado',\n              conversationDisclaimer:\n                'Las respuestas se generan con IA y pueden contener errores. Verifícalas.',\n              reasoningText: 'Razonando...',\n              thinkingText: 'Pensando...',\n              relatedSourcesText: 'Fuentes relacionadas',\n              stoppedStreamingText: 'Has detenido esta respuesta',\n              copyButtonText: 'Copiar',\n              copyButtonCopiedText: '¡Copiado!',\n              likeButtonTitle: 'Me gusta',\n              dislikeButtonTitle: 'No me gusta',\n              thanksForFeedbackText: '¡Gracias por tu comentario!',\n              errorTitleText: 'Error de chat'\n            },\n            newConversationScreen: {\n              titleText: '¿Cómo puedo ayudarte hoy?',\n              introductionText:\n                'Busco en tu documentación para ayudarte a encontrar guías de configuración, detalles de funciones y consejos de solución de problemas rápidamente.'\n            },\n            logo: {\n              poweredByText: 'Con la tecnología de'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/es/guide/asset-handling.md",
    "content": "# Manejo de Assets {#asset-handling}\n\n## Referenciando Assets Estáticos {#referencing-static-assets}\n\nTodos los archivos Markdown son compilados en componentes Vue y procesados por [Vite](https://vitejs.dev/guide/assets.html). Usted puede **y debe** referenciar cualquier asset usando URLs relativas:\n\n```md\n![Una imagen](./imagen.png)\n```\n\nPuede referenciar assets estáticos en sus archivos markdown, sus componentes `*.vue` en el tema, estilos y simples archivos `.css`, usando paths públicos absolutos (com base en la raiz del projeto) o paths relativos (con base en su sistema de arhivos). Este último es semejante al comportamiento que está acostumbrado se ya usó Vite, Vue CLI o el `file-loader` de webpack.\n\nTipos comunes de archivos de imagen, media y fuente son detectados e incluidos automaticamente como assets.\n\nTodos los assets referenciados, incluyendo aquellos usando paths absolutos, serán copiados al directorio de salida con un nombre de archivo hash en la compilación de producción. Assets nunca referenciados no serán copiados. Assets de imagen menores que 4KB serán incorporados en base64 - esto puede ser configurado por la opción [`vite`](../reference/site-config#vite) en configuración.\n\nTodas las referencias de path **estáticas**, incluyendo paths absolutos, deben ser basadas en la estructura de su directorio de trabajo.\n\n## El directorio público {#the-public-directory}\n\nA veces, puede ser necesario proveer assets estáticos que no son referenciados directamente en ninguno de sus componentes del tema o Markdown, o usted puede querer servir ciertos archivos con el nombre del archivo original. Ejemplos de tales archivos incluyen `robots.txt`, favicons e iconos PWA.\n\nPuede colocar esos archivos en el directorio `public` sobre el [directorio de origen](./routing#source-directory). Por ejemplo, se la raiz de su proyecto fuera `./docs` y estuviera usando localización por defecto del directorio fuente, entonces el directorio público será `./docs/public`.\n\nLos assets colocados en `public` serán copiados a la raiz del directorio de salida tal como son.\n\nObserve que usted debe referenciar archivos colocados en `public` usando e path absoluto de la raiz - por ejemplo, `public/icon.png` debe siempre ser referenciado en el código fuente como `/icon.png`.\n\n## URL Base {#base-url}\n\nSi su sitio estuviera implantado en una URL que no sea la raiz, será necesario definir la opción `base` en `.vitepress/config.js`. Por ejemplo, se planea implantar su sitio en `https://foo.github.io/bar/`, entonces `base` debe ser definido como `'/bar/'` (siempre debe comenzar y terminar con una barra).\n\nTodos los paths de sus assets estáticos son procesados automáticamente para ajustarse a los diferentes valores de configuración `base`. Por ejemplo, se tuviera una referencia absoluta a un asset sobre `public` en su Markdown:\n\n```md\n![Una imagen](/imagen-dentro-de-public.png)\n```\n\n**No** necesita actualizarlo cuando altere el valor de configuración `base` en ese caso.\n\nSin embargo, se estuviera creando un componente de tema que vincula assets dinámicamente, por ejemplo, una imagen cuyo `src` esta basado en un valor de configuración del tema:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nEn este caso, es recomendable complementar el path con el [`auxiliar withBase`](../reference/runtime-api#withbase) proporcionado por VitePress:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/es/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# Conectando a un CMS {#connecting-to-a-cms}\n\n## Flujo de Trabajo general {#general-workflow}\n\nConectar VitePress a un CMS girará mayormente en torno a [Rutas dinámicas](./routing#dynamic-routes). Asegurese de entender cómo funcionan antes de proceder.\n\nComo cada CMS funcionará de forma diferente, aqui podemos proveer apenas un flujo de trabajo genérico que requiere ser adaptado para cada escenario específico.\n\n1. Si su CMS exige autenticación, cree un archivo `.env` para almacenar los tokens del API y cargarlos como:\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. Obtenga los datos necesarios del CMS y aplique formato en paths de datos apropiados:\n\n    ```js\n    export default {\n      async paths() {\n        // use la biblioteca del cliente CMS respectiva si es necesario\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // token caso necesario\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* título, autores, data, etc. */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. Presente el contenido en la página:\n\n    ```md\n    # {{ $params.title }}\n\n    - por {{ $params.author }} en {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## Guias de Integración {#integration-guides}\n\nSe usted escribió una guía sobre cómo integrar VitePress con un CMS específico, por favor use el link \"Edite esta página\" abajo para enviarlo hacia aqui!\n"
  },
  {
    "path": "docs/es/guide/custom-theme.md",
    "content": "# Usando un Tema Personalizado {#using-a-custom-theme}\n\n## Carga de Tema {#theme-resolving}\n\nPuede habilitar un tema personalizado creando un archivo `.vitepress/theme/index.js` o `.vitepress/theme/index.ts` (o \"archivo de entrada de tema\"):\n\n```\n.\n├─ docs                # raiz del proyecto\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # entrada de tema\n│  │  └─ config.js     # archivo de configuración\n│  └─ index.md\n└─ package.json\n```\n\nVitePress siempre usará el tema personalizado en vez del tema por defecto cuando detecte la precencia de un archivo de entrada de tema. Sin embargo, puede [extender el tema por defecto](./extending-default-theme) para realizar personalizaciones avanzadas sobre el.\n\n## Interfaz del Tema {#theme-interface}\n\nUn tema personalizado de VitePress es definifo como un objeto con la siguiente interfaz:\n\n```ts\ninterface Theme {\n  /**\n   * Componente raiz de layout para todas las páginas\n   * @required\n   */\n  Layout: Component\n  /**\n   * Mejora la instancia de la aplicación Vue\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * Extiende otro tema, llamando su `enhanceApp` antes de nuestro\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // instancia de la aplicación Vue\n  router: Router // instancia del enrutador VitePress\n  siteData: Ref<SiteData> // Metadata a nivel del sitio\n}\n```\n\nEl archivo de entrada del tema debe exportar el tema como su exportación por defecto:\n\n```js [.vitepress/theme/index.js]\n\n// Puede importar archivos Vue directamente en el archivo de entrada del tema\n// VitePress ya está preconfigurado con @vitejs/plugin-vue.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nLa exportación por defecto es el único contrato para un tema personalizado, y apenas la propiedad `Layout` es exigida. Tecnicamente, un tema de VitePress puede ser tan simple como un único componente Vue.\n\nDentro de su componente de layout, el funciona como una aplicación Vite + Vue 3 normal. Note que el tema también necesita ser [compatible con SSR](./ssr-compat).\n\n## Construyendo un Layout {#building-a-layout}\n\nEl componente de layout más básico necesita un componente [`<Content />`](../reference/runtime-api#content):\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <!-- aqui es donde el contenido markdown será presentado -->\n  <Content />\n</template>\n```\n\nEl layout encima simplemente renderiza el markdown de todas las páginas cómo HTML. La primera mejora que podemos adicionar es lidiar con errores 404:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Página 404 personalizada!\n  </div>\n  <Content v-else />\n</template>\n```\n\nEl auxiliar [`useData()`](../reference/runtime-api#usedata) proporciona todos los datos en tiempo de ejecución que necesitamos para mostrar layouts diferentes. Uno de los otros datos que podemos accesar es el frontmatter de la página actual. Podemos aprovechar esto para permitir que el usuario final controle el layout en cada página. Por ejemplo, el usuario puede indicar que la página debe usar un layout especial de la pagina inicial con:\n\n```md\n---\nlayout: home\n---\n```\n\nY podemos ajustar nuestro tema para lidiar con esto:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Página 404 personalizada!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Página inicial personalizada!\n  </div>\n  <Content v-else />\n</template>\n```\n\nPuede, claro está, dividir el layout en más componentes:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> renders <Content /> -->\n</template>\n```\n\nConsulte la [Referencia del API en tiempo de Ejecución](../reference/runtime-api) para todo lo que está disponible en componentes de tema. Además, puede aprovechar la [Carga de datos en Tiempo de Compilación](./data-loading) para generar layouts orientados por datos - por ejemplo, una página que lista todos los posts del blog en el proyecto actual.\n\n## Distribuyendo un Tema Personalizado {#distributing-a-custom-theme}\n\nLa manera más facil de distribuir un tema personalizado es proporcionarlo como un [repositorio de template en GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).\n\nSi desea distribuir su tema como un paquete npm, siga estos pasos:\n\n1. Exporte el objeto del tema como la exportación por defecto en su archivo de paquete.\n\n2. Si aplica, exporte la definición de configuración del tipo de tema como `ThemeConfig`.\n\n3. Si su tema exige ajustes en la configuración de VitePress, exporte esa configuración en un subdirectorio del paquete (por ejemplo, `mi-tema/config`) para que el usuario pueda extenderlo.\n\n4. Documente las opciones de configuración del tema (Ambos, via archivo y frontmatter).\n\n5. Proporcione instrucciones claras sobre cómo consumir su tema(vea abajo).\n\n## Consumiendo un Tema Personalizado {#consuming-a-custom-theme}\n\nPara consumir un tema extereno, importelo e reexportelo a partir del archivo de entrada del tema personalizado:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nSi el tema necesita ser extendido:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nSi el tema exige una configuración especial de VitePress, también necesitará extenderlo en su propia configuración:\n\n```ts\n// .vitepress/theme/config.ts\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // extienda la configuración base del tema (de ser necesario)\n  extends: baseConfig\n}\n```\n\nFinalmente, si el tema proporciona tipos para la configuración del tema:\n\n```ts\n// .vitepress/theme/config.ts\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // El tipo es `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/es/guide/data-loading.md",
    "content": "# Carga de Datos en Tiempo de Compilacion {#build-time-data-loading}\n\nVitePress proporciona un recurso llamado **cargadores de dato** que permite cargar datos arbitrarios e importarlos desde páginas o componentes. La carga de datos es ejecutada **apenas en el tiempo del build** los datos resultantes serán serializados como JSON en el paquete de JavaScript final.\n\nLos cargadores de datos pueden ser usados para buscar datos remotos o generar metadatos con base en archivos locales. Por ejemplo, puede usar cargadores de datos para procesar todas sus pagínas API locales y generar automáticamente un indice de todas las entradas del API.\n\n## Uso Básico {#basic-usage}\n\nUn archivo de cargados de datos debe terminar con `.data.js` o `.data.ts`. El archivo debe proporcionar una exportación por defecto de un objeto con el método `load()`:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\nEl módulo del cargador es validado apenas en Node.js, entonces puede importar APIs Node y dependencias npm caso necesario.\nPuede importar entonces datos de este archivo en páginas `.md` y componentes `.vue` usando la exportación llamada `data`:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\nSalida:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\nNotará que el propio cargados de datos no exporta `data`. Es VitePress llamando el método `load()` entre bastidores y exponiendo implicitamente el resultado por medio de la exportación llamada `data`.\n\nEsto funciona incluso si el cargador fuera asíncrono:\n\n```js\nexport default {\n  async load() {\n    // buscar datos remotos\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## Datos de Archivos Locales {#data-from-local-files}\n\nCuando necesita generar datos con base en archivos locales, debe usar la opción `watch` en el cargador de datos para que los cambios hechos en esos archivos puedan accionar actualizaciones rápidas.\n\nLa opción `watch` tabién es conveniente porque puede usar [patrones glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para corresponder a vários archivos. Los patrones pueden ser relativos al propio archivo del cargador, y la función `load()` recibirá los archivos correspondientes como paths absolutos.\n\nEl siguiente ejemplo muestra el cargamento de archivos CSV y la transformación de estos en JSON usando [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Como este archivo solo es ejecutado en el tiempo del build, usted no enviará el procesador de CSV para el cliente!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles será un array de paths absolutos de los archivos um array de caminhos absolutos dos arquivos correspondientes.\n    // generar un array de metadatos de post que puede ser usado para mostrar\n    // una lista en el layout del tema\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\nAl construir un sitio enfocado en contenido, frecuentemente necesitamos crear una página de \"archivo\" o \"índice\": una página donde listamos todas las entradas disponibles en nuestra colección de contenido, por ejemplo, articulos de blog o páginas de API. Nosotros **podemos** implementar esto directamente con el API de cargador de datos, pero como este es un caso de uso tan común, VitePress también proporciona un auxiliar `createContentLoader` para simplificar esto:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* opciones */)\n```\n\nEl auxiliar acepta un patrón glob relativo al [diretório fuente](./routing#source-directory) y retorna un objeto de cargador de datos `{ watch, load }` que puede ser usado como exportación por defecto en un archivo de cargador de datos. El también implementa cache con base en los sellos se datos del archivo para mejorar el desempeño en el desarrollo.\n\nNote que el cargador solo funciona con archivos Markdown - archivos no Markdown encontrados serán ignorados.\n\nLos datos cargados serán un _array_ con el tipo `ContentData[]`:\n\n```ts\ninterface ContentData {\n  // URL mapeada para la página. Ex: /posts/hello.html (no incluye la base)\n  // itere manualmente o use `transform` personalizado para normalizar los paths\n  url: string\n  // datos frontmatter de la página\n  frontmatter: Record<string, any>\n\n  // los siguientes están presentes si las opciones relevantes están habilitadas\n  // discutiremos sobre eso abajo\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nPor defecto, apenas `url` y `frontmatter` son proporcionados. Esto ocurre porque los datos cargados serán incorporados como JSON en el paquete del cliente, entonces necesitamos ser cautelosos con su tamaño. Aqui está un ejemplo de cómo usar los datos para construir una página de índice de blog mínima:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>Todos los posts del blog</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>por {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### Opciones {#options}\n\nLos datos por defecto pueden no atender todas las necesidades - puede optar por transformar los datos usando opciones:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // incluir fuente markdown en crudo?\n  render: true,     // incluir HTML completo de la página presentada?\n  excerpt: true,    // incluir extracto?\n  transform(rawData) {\n    // mapee, ordene o filtre los datos en crudo como desee.\n    // el resultado final es lo que será enviado al cliente.\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // fuente markdown en crudo\n      page.html    // HTML completo de la página presentada\n      page.excerpt // HTML del extracto presentado (contenido encima del primer `---`)\n      return {/* ... */}\n    })\n  }\n})\n```\n\nVea cómo es usado en el [blog Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).\n\nEl API `createContentLoader` también puede ser usada dentro de los [build hooks](../reference/site-config#build-hooks):\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // generar archivos con base en los metadatos de los posts, por ejemplo, feed RSS\n  }\n}\n```\n\n**Tipos**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * Incluir src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * Renderizar src para HTML e incluir en los datos?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * Si `boolean`, debe procesarse e incluir el resumen? (presentado como HTML)\n   *\n   * Si `function`, controla como el extracto es extraido del contenido.\n   *\n   * Si `string`, define un separador personalizado usado para extraer el\n   * extracto. El separados por defecto es `---` si `excerpt` fuera `true`.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * Transforma los datos. Observe que los datos serán incorporados como JSON en el paquete del cliente\n   * caso sean importados de componentes o archivos markdown.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## Cargadores de datos con Tipos {#typed-data-loaders}\n\nAl usar TypeScript, puede tipar su cargador de datos y exportar `data` de la siguiente forma:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // tipo de dato\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // opciones del cargador verificadas por el tipo\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## Configuración {#configuration}\n\nPara obtener información de configuración dentro de un cargador, puede usar un código como este:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/es/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# Despliegue su Sitio VitePress {#deploy-your-vitepress-site}\n\nLas siguientes orientaciones están basadas en algunos supuestos:\n\n- El sitio VitePress está dentro del directorio `docs` de su proyecto.\n- Está usando la directorio por defecto para el build (`.vitepress/dist`).\n- VitePress está instalado como una dependencia local en su proyecto, y usted configuró los siguientes scripts en su `package.json`:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## Compilar y Testear Localmente {#build-and-test-locally}\n\n1. Ejecute este comando para compilar la documentación:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. Después de la compilación, vea la vista previa ejecutando:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   El comando `preview` inicializará un servidor web estático local que servirá la directorio de salida `.vitepress/dist` en `http://localhost:4173`. Puede usar eso para garantizar que todo esté correcto antes de enviar a producción.\n\n3. Puede configurar el puerto del servidor pasando `--port` como argumento.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   Ahora el método `docs:preview` implantará el servidor en `http://localhost:8080`.\n\n## Configurando un Path Base Publico {#setting-a-public-base-path}\n\nPor defecto, asumimos que el sitio será implantado en el path raiz de un dominio (`/`). Si su sitio fuera servido en un subpath, por ejemplo, `https://meusite.com/blog/`, necesitará entonces configurar la opción [`base`](../reference/site-config#base) para `'/blog/'` en la configuración VitePress.\n\n**Ejemplo:** Al usar GitHub Pages (ou GitLab Pages) e implantar en `user.github.io/repo/`, defina su `base` como `/repo/`.\n\n## Headers de Cache HTTP {#http-cache-headers}\n\nSi tiene control sobre los headers HTTP de su servidor en producción, se puede configurar headers `cache-control` para obtener mejor desempeño en vistar repetidas.\n\nLa compilación de producción usa nombres de archivos con hash para assets estáticos (JavaScript, CSS e otros assets que no están en `public`). Se inspecciona la previa de producción usando las herramientas de desarrollador de su navegador en la pestaña red, verá archivos como `app.4f283b18.js`.\n\nEste hash `4f283b18` es generado a partir del contenido de este archivo. La misma URL con hash es garantizada para servir el mismo contenido del archivo - se el contenido cambia, las URLs también cambian. Esto significa que puede utilizar con seguridad los headers de cahe más fuertespara esos archivos. Todos esos archivos serán colocados en `assets/` en la directorio de salida, entonces puede configurar el siguiente header para ellos:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Ejemplo de archivo `_headers` do Netlify\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\nNota: el archivo `_headers` debe ser colocado en [diretório public](./asset-handling#the-public-directory) - en nuestro caso, `docs/public/_headers` - para que el sea copiado exactamente para la directorio de salida.\n\n[Documentación de headers personalizados de Netlify](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details de Ejemplo de configuración Vercel em `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nNota: el archivo `vercel.json` debe ser colocado en la raiz de su **repositório**.\n\n[Documentación Vercel sobre configuración de headers ](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## Guias de Plataforma {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\nConfigure un nuevo proyecto y altere estas configuraciones usando su panel:\n\n- **Comando de Compilación:** `npm run docs:build`\n- **directorio de Salida:** `docs/.vitepress/dist`\n- **Versión de Node:** `20` (o superior)\n\n::: warning\nNo active opciones como _Auto Minify_ para código HTML. Eso removera comentarios de salida que tiene significado para Vue. Habrán errores de incompatibilidad de hidratación se fueran removidos.\n:::\n\n### GitHub Pages\n\n1. Cree un archivo llamado `deploy.yml` dentro del directorio `.github/workflows` do seu projeto com algum conteúdo como este:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Ejemplo de flujo de trabajo para compilar e implantar un sitio VitePress en GitHub Pages\n   #\n   name: Implante el sitio VitePress en Pages\n\n   on:\n     # Ejecute en push direccionados a la branch `main`.\n     # Cambie para `master` si estuviera usando la branch `master` por defecto.\n     push:\n       branches: [main]\n\n     # Permite ejecutar manualmente este flujo de trabajo en la guia Actions\n     workflow_dispatch:\n\n   # Define permisos GITHUB_TOKEN para la implementación en GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Permite apenas una implantación simultánea, omitiendo ejecuciones en fila entre la ejecución en progreso y la última de la fila.\n   # Sin embargo, NO cancela ejecuciones en progreso, pues queremos permitir que esas implantaciones de producción sean concuidas.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Trabajo de compilación\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # No necesario se lastUpdated no estuviera habilitado\n         # - uses: pnpm/action-setup@v4 # Desconecte eso si estuviera usando pnpm\n         #   with:\n         #     version: 9\n         # - uses: oven-sh/setup-bun@v1 # Desconecte eso se estuviera usando Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # o pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # o pnpm install / yarn install / bun install\n        - name: Build with VitePress\n          run: npm run docs:build # o pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Trabajo de implantación\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   Asegurese de que la opción `base` en su VitePress esté configurada correctamentse. Vea [Configuranco un Path base Público](#setting-a-public-base-path) para más detalles.\n   :::\n\n2. En las configuraciones de su repositorio sobre el item del menú \"Pages\", seleccione \"GitHub Actions\" en \"Build and deployment > Source\".\n\n3. Envie sus modificaciones para el branch `main` y espere la conclusión del flujo de trabajo de GitHub Actions. Verá su sitio implantado en `https://<username>.github.io/[repository]/` o `https://<custom-domain>/` dependiendo de sus configuraciones. Su sitio será implantado automáticamente en cada push para la branch `main`.\n\n### GitLab Pages\n\n1. Defina `outDir` en la configuración VitePress como `../public`. Configure la opción `base` para `'/<repository>/'` se desea implantar en `https://<username>.gitlab.io/<repository>/`. No necesita `base` si está implementando en un dominio personalizado, páginas de usuario o grupo, o si la configuración \"Use unique domain\" está habilitada en GitLab.\n\n2. Cree un archivo llamado `.gitlab-ci.yml` en la raiz del proyecto con el contenido abajo. Esto construirá e implantará su sitio siempre que haga alteraciones en el contenido.\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Desconecte eso se estuviera usando imagenes pequeñas de Docker como Alpine y tuviera lastUpdated habilitado\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. Siga la [documentación oficial](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration).\n\n2. Configure esos valores en su archivo de configuración (y remueva aquellos que no necesita, como `api_location`):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\nPuedes desplegar tu proyecto VitePress con [CloudRay](https://cloudray.io/) siguiendo estas [instrucciones](https://cloudray.io/articles/how-to-deploy-vitepress-site).\n\n### Firebase\n\n1. Cree `firebase.json` y `.firebaserc` en la raiz de su proyecto:\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<SU_ID_FIREBASE>\"\n     }\n   }\n   ```\n\n2. Después de ejecutar `npm run docs:build`, ejecute este comando para implantar:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. Siga la documentación y el guia proporcionados por [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static).\n\n2. Cree un archivo llamado `static.json` en la raiz de su proyecto con el contenido abajo:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\nPuedes desplegar tu proyecto VitePress con [Hostinger](https://www.hostinger.com/web-apps-hosting) siguiendo estas [instrucciones](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/). Al configurar los ajustes de compilación, elige VitePress como framework y ajusta el directorio raíz a `./docs`.\n\n### Kinsta\n\nPuede implantar su sitio VitePress em [Kinsta](https://kinsta.com/static-site-hosting/) siguiendo estas [instrucciones](https://kinsta.com/docs/vitepress-static-site-example/).\n\n### Stormkit\n\nPuedes desplegar tu proyecto VitePress en [Stormkit](https://www.stormkit.io) siguiendo estas [instrucciones](https://stormkit.io/blog/how-to-deploy-vitepress).\n\n### Surge\n\n1. Después de ejecutar `npm run docs:build`, ejecute este comando para implantar:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\nAquí hay un ejemplo de configuración de bloque de servidor Nginx. Esta configuración incluye compresión gzip para recursos comunes basados en texto, reglas para servir los archivos estáticos de su sitio VitePress con encabezados de caché adecuados, así como el manejo de `cleanUrls: true`.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # content location\n        root /app;\n\n        # exact matches -> reverse clean urls -> folders -> not found\n        try_files $uri $uri.html $uri/ =404;\n\n        # non existent pages\n        error_page 404 /404.html;\n\n        # a folder without index.html raises 403 in this setup\n        error_page 403 /404.html;\n\n        # adjust caching headers\n        # files in the assets folder have hashes filenames\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nEsta configuración asume que su sitio VitePress compilado está ubicado en el directorio `/app` de su servidor. Ajuste la directiva `root` según corresponda si los archivos de su sitio se encuentran en otro lugar.\n\n::: warning No predeterminar index.html\nLa resolución de try_files no debe predeterminar index.html como en otras aplicaciones Vue. Esto resultará en un estado de página inválido.\n:::\n\nSe puede encontrar más información en la [documentación oficial de nginx](https://nginx.org/en/docs/), en estos issues [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235) así como en este [post del blog](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) de Mehdi Merah.\n"
  },
  {
    "path": "docs/es/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# Extendiendo el Tema por defecto {#extending-the-default-theme}\n\nEl tema por defecto de VitePress es optimizado para documentación y puede ser personalizado. Consulte la [Visión General de Configuración del Tema por Defecto](../reference/default-theme-config) para una lista completa de opciones.\n\nSin embargo, hay casos en que apenas la configuración no será suficiente. Por ejemplo:\n\n1. Es necesario ajustar los estilos CSS;\n2. Es necesario modificar la instancia de la aplicación Vue, por ejemplo para registrar componentes globales;\n3. Es necesario inyectar contenido personalizado en el tema por medio de _slots_ en el layout.\n\nEsas personalizaciones avanzadas exigirán el uso de un tema personalizado que \"extiende\" el tema por defecto.\n\n::: tip\nAntes de seguir, asegurese de leer primero [Usando un Tema Personalizado](./custom-theme) para entender como funcionan los temas personalizados.\n:::\n\n## Personalizando el CSS {#customizing-css}\n\nEl CSS del tema por defecto puede ser personalizado substuyendo las variables CSS a nivel de la raiz:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\nVea las [variables CSS del tema por defecto](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) que pueden ser substituídas.\n\n## Usando Fuentes Diferentes {#using-different-fonts}\n\nVitePress usa [Inter](https://rsms.me/inter/) como fuente por defecto e incluirá las fuentes en la salida de compilación. La fuente también es pre-cargada automaticamente en producción. Sin embargo, eso puede no ser deseable se quiere usar una fuente principal diferente.\n\nPara evitar la inclusión de Inter en la salida de compilación, importe el tema de `vitepress/theme-without-fonts`:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* fuente de texto normal */\n  --vp-font-family-mono: /* fuente de código */\n}\n```\n\n::: warning\nSi está usando componentes opcionales como los componentes de la [Página del equipo](../reference/default-theme-team-page), asegurese de también importarlos de `vitepress/theme-without-fonts`!\n:::\n\nSi su fuente es un archivo local referenciado via `@font-face`, ella será procesada como un asset e incluida en `.vitepress/dist/assets` con un nombre de archivo hash. Para pre-cargar ese archivo, use el hook de construcción [transformHead](../reference/site-config#transformhead):\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // ajuste el regex para corresponder a su fuente\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## Registrando Componentes Globales {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // registre sus componentes globales personalizados\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nSi está usando TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // registre sus componentes globales personalizados\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nComo estamos usando Vite, puede también aprovechar la [funcionalidad de importación glob](https://vitejs.dev/guide/features.html#glob-import) de Vite para registrar automaticamente un directorio de componetes.\n\n## _Slots_ en el Layout {#layout-slots}\n\nEl componente `<Layout/>` del tema por defecto posee algunos _slots_ que pueden ser usados para inyectar contenido en lugares específicos de la página. Aqui un ejemplo de como inyectar un componente antes del esquema:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // substituya el Layout por un componente wrapper que\n  // inyecta los slots\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      Mi contenido personalizado superior de la barra lateral\n    </template>\n  </Layout>\n</template>\n```\n\nO puede también usar la función _render_.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nLista completa de _slots_ disponibles en el layout del tema por defecto:\n\n- Cuando `layout: 'doc'` (por defecto) está habilitado via frontmatter:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- Cuando `layout: 'home'` está habilitado via frontmatter:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- Cuando `layout: 'page'` está habilitado via frontmatter:\n  - `page-top`\n  - `page-bottom`\n- En la página no encontrada (404):\n  - `not-found`\n- Siempre:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## Usando el API View Transitions\n\n### En la Alternancia de Apariencia {#on-appearance-toggle}\n\nPuede extender el tema por defecto para proporcionar una transición personalizada cuando el modo de color es alternado. Un ejemplo:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\nResultado (**atención!**: colores destellantes, movimientos súbitos, luces brillantes):\n\n<details>\n<summary>Demo</summary>\n\n![Demo de Transición de Alternancia de Apariencia](/appearance-toggle-transition.webp)\n\n</details>\n\nConsulte [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) para mas detalles sobre _view transitions_.\n\n### En el Cambio de Ruta {#on-route-change}\n\nEn breve.\n\n## Substituyendo Componentes Internos {#overriding-internal-components}\n\nPuede usar los [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) Vite para substituir los componentes del tema por defecto por los suyos personalizados:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\nPara saber el nombre exacto del componente consulte [nuestro código fuente](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Como los componentes son internos, hay una pequeña chance de que el nombre sea actualizado entre lanzamientos secundarios.\n"
  },
  {
    "path": "docs/es/guide/frontmatter.md",
    "content": "# Frontmatter\n\n## Uso {#usage}\n\nVitePress soporta frontmatter YAML en todos los archivos Markdown, procesandolos con [gray-matter](https://github.com/jonschlinkert/gray-matter). El frontmatter debe estar en la parte superior del archivo Markdown (antes de cualquier elemento, incluyendo tags `<script>`), y debe tener la forma de un YAML válido entre lineas con trazos de triple guion. Ejemplo:\n\n```md\n---\ntitle: Documentación con VitePress\neditLink: true\n---\n```\n\nMuchas opciones de configuración del sitio o del tema por defecto tienen opciones correspondientes en el frontmatter. Puede usar el frontmatter para sobreponer un comportamiento específico solamente para la página actual. Para más detalles, vea [Referencia de Configuración del Frontmatter](../reference/frontmatter-config).\n\nPuede también definir datos propios del frontmatter personalizados, para ser usados en expresiones Vue dinámicas en la página.\n\n## Acceso a los Datos del Frontmatter {#accessing-frontmatter-data}\n\nLos datos del frontmatter pueden ser accedidos por medio de la variable global especial `$frontmatter`:\n\nAqui está un ejemplo de como podría usarlo en su archivo Markdown:\n\n```md\n---\ntitle: Documentación con VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nContenido de guia\n```\n\nPuede acceder los datos del frontmatter de la página actual en `<script setup>` con el auxiliar [`useData()`](../reference/runtime-api#usedata).\n\n## Formatos Alternativos del Frontmatter {#alternative-frontmatter-formats}\n\nVitePress también soporta la sintaxis frontmatter JSON, comenzando y terminando con llaves:\n\n```json\n---\n{\n  \"title\": \"Creando blog como un hacker\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/es/guide/getting-started.md",
    "content": "# Iniciando {#getting-started}\n\n## Experimente Online {#try-it-online}\n\nPuede experimentar VitePress directamente en su navegador en [StackBlitz](https://vitepress.new).\n\n## Instalación {#installation}\n\n### Prerrequisitos {#prerequisites}\n\n- [Node.js](https://nodejs.org/) versión 20 o superior.\n- Terminal para acessar VitePress a través de su interfaz de linea de comando (CLI).\n- Editor de texto con soporte a sintaxis [Markdown](https://en.wikipedia.org/wiki/Markdown).\n  - [VSCode](https://code.visualstudio.com/) es recomendado, junto con la [extensión oficial Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nVitePress puede ser usado solo, o ser instalado en un proyecto ya existente. En ambos casos, puede instalarlo con:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip NOTA\n\nVitePress es un paquete apenas para ESM. No use `require()` para importarlo, y asegurese de que el `package.json` más cercano contiene `\"type\": \"module\"`, o cambie la extensión de archivo de sus archivos relevantes como `.vitepress/config.js` a `.mjs`/`.mts`. Consulte la [Guía de resolución de problemas Vite](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) para más detalles. Además de eso, dentro de contextos de JavaScript asíncronos, puede usar `await import('vitepress')`.\n\n:::\n\n### Asistente de Instalación {#setup-wizard}\n\nVitePress tiene embutido un asistente de instalación por linea de comando que ayudará a construir un proyecto básico. Después de la instalación, inicie el asistente ejecutando:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nSerá saludado con algunas preguntas simples:\n\n<<< @/snippets/init.ansi\n\n::: tip Vue como Dependencia Correspondiente\nSi tiene la intención de realizar una personalización que usa componentes Vue o APIs, debe instalar explicitamente `vue` como una dependencia correspondiente.\n:::\n\n## Estrutura de Archivos {#file-structure}\n\nSe está construyendo un sitio VitePress individual, puede desarrollar su sitio en el directorio actual (`./`). Sin embargo, si está instalando VitePress en un proyecto existente junto con otro código fuente, es recomendado construir el sitio en un directorio anidado (e.g. `./docs`) para que esté separado del resto de su proyecto.\n\nAsumiendo la opción de desarrollar el proyecto VitePress en `./docs`, la estructura de archivos generada debe parecerse a la siguiente:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\nEl directorio `docs` es considerado la **raiz del proyecto** de su sitio VitePress. El directorio `.vitepress` es un lugar reservado para archivos de configuración VitePress, caché del servidor de desarrollo, resultado del build, y código de personalización de tema opcional.\n\n::: tip\nPor defecto, VitePress almacena el caché del servidor de desarrollo en `.vitepress/cache`, y el resultado del build de producción en `.vitepress/dist`. Se usa Git, debe adicionarlos a su archivo `.gitignore`. Estas ubicaciones también pueden ser [configuradas](../reference/site-config#outdir).\n:::\n\n### El archivo de configuración {#the-config-file}\n\nEl archivo de configuración (`.vitepress/config.js`) permite que personalice vários aspectos de su sitio VitePress, con las opciones más básicas siendo el titulo y la descripción del sitio:\n\n```js [.vitepress/config.js]\nexport default {\n  // opciones a nivel del sitio\n  title: 'VitePress',\n  description: 'Solo una broma.',\n\n  themeConfig: {\n    // opciones a nivel del tema\n  }\n}\n```\n\nPuede también configurar el comportamiento del tema a través de la opción `themeConfig`. Consulte la [Referencia de Configuración](../reference/site-config) para detaller completos sobre todas las opciones de configuración.\n\n### Archivos fuente {#source-files}\n\nArchivos Markdown fuera del directorio `.vitepress` son considerados **archivos fuente**.\n\nVitePress usa **enrutamiento basado en archivos**: cada archivo `.md` es compilado en un archivo `.html` correspondiente con el mismo path. Por ejemplo, `index.md` será compilado en `index.html`, y puede ser visitado en el path raiz `/` del sitio VitePress resultante.\n\nVitePress también proporciona la habilidad de generar URLs limpias, retambém fornece a habilidade de gerar URLs limpas, reescribir paths, y generare páginas dinámicamente. Estos serán tratados en la [Guía de Enrutamiento](./routing).\n\n## Instalado y Funcionando {#up-and-running}\n\nLa herramienta debe tener también inyectado los siguientes scripts npm en su `package.json` si permitió esto durante el proceso de instalación:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\nEl script `docs:dev` iniciará un servidor de desarrollo local con actualizaciones instantáneas. Ejecutelo con el siguiente comando:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nEn vez de scripts npm, también puede invocar VitePress directamente con:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nMás usos de la linea de comandos están documaentados en la [Referencia CLI](../reference/cli).\n\nEl servidor de desarrollo debe estar corriendo en `http://localhost:5173`. Visite la URL en su navegador para ver su nuevo sitio en acción!\n\n## Qué viene después? {#what-s-next}\n\n- Para entender mejor cómo archivos Markdown son mapeados en HTML, consulte la [Guía de Enrutamiento](./routing).\n\n- Para descubrir más sobre lo que puede hacer en una página, cómo escribir contenido markdown o usar un componente Vue, consulte la sección \"Escribiendo\" de la guía. Un optimo lugar para comenzar sería aprendiendo más sobre [Extensiones Markdown](./markdown).\n\n- Para explorar las funcionalidades proporcionadas por el tema por defecto de la documentación, consulte la [Referencia de Configuración del Tema por Defecto](../reference/default-theme-config).\n\n- Se quiere profundizar la personalización de la apariencia de su sitio, explore tanto [Extienda el Tema por Defecto](./extending-default-theme) como [Construya un Tema Personalizado](./custom-theme).\n\n- Una vez que su documentación tome forma, asegurese de leer la [Guia de Despliegue](./deploy).\n"
  },
  {
    "path": "docs/es/guide/i18n.md",
    "content": "# Internacionalización {#internationalization}\n\nPara usar recursos de i18n integrados, es necesario crear una estructura de directorios de la siguiente forma:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\nEn seguida, en el archivo `docs/.vitepress/config.ts`:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // propiedades compartidas e otras cosas de nivel superior...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    fr: {\n      label: 'French',\n      lang: 'fr', // opcional, será adicionado como atributo `lang` en el tag `html`\n      link: '/fr/guide' // por defecto /fr/ -- aparece en el menu de traducciones de la barra de navegación, puede ser externo\n\n      // otras propiedades específicas de cada idioma...\n    }\n  }\n})\n```\n\nLas siguientes propiedades pueden ser substituidas para cada idioma (incluyendo la raiz):\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // será mezclado con las entradas head existentes, las metatags duplicadas son removidas automáticamente\n  themeConfig?: ThemeConfig // será mezclado superficialmente, cosas comunes pueden ser colocadas en la entrada superios  de themeConfig\n}\n```\n\nConsulte la interfaz [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) para obtener detaller sobre la personalización de los textos marcadores del tema por defecto. No substituya `themeConfig.algolia` o `themeConfig.carbonAds` en el nivel de idioma. Consulte la [documentação Algolia](../reference/default-theme-search#i18n) para usar la busqueda multilenguaje.\n\n**Consejo profesional:** El archivo de configuración puede ser almacenado en `docs/.vitepress/config/index.ts` también. Esto puede ayudar a organizar las cosas creando un archivo de configuración por idioma y entonces mezclarlos y exportarlos a partir de `index.ts`.\n\n## Directorio separado para cada localización {#separate-directory-for-each-locale}\n\nLa siguiente estructura es totalmente válida:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\nSin embargo, VitePress no redireccionará `/` para `/en/` por defecto. Necesitará configurar su servidor para esto. Por ejemplo, en Netlify, puede adicionar un archivo `docs/public/_redirects` asi:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**Consejo profesional:** Si está usando la forma descrita arriba, puede usar el cookie `nf_lang` para persistir la selección de idioma del usuario:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## Soporte a RTL (Experimental) {#rtl-support-experimental}\n\nPara soporte a RTL (Right to Left), especifique `dir: 'rtl'` en la configuración y use algún plugin RTLCSS PostCSS como <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> o <https://github.com/elchininet/postcss-rtlcss>. Necesitará configurar su plugin PostCSS para usar `:where([dir=\"ltr\"])` y `:where([dir=\"rtl\"])` como prefijos para evitar problemas de especificidad CSS.\n"
  },
  {
    "path": "docs/es/guide/markdown.md",
    "content": "# Extensiones Markdown {#markdown-extensions}\n\nVitePress viene con Extensiones embutidas.\n\n## Anchors de Header {#header-anchors}\n\nLos Header reciben la aplicación automáticamente de links anchor. La presentación de los anchor puede ser configurada usando la opción `markdown.anchor`.\n\n### Anchor personalizados {#custom-anchors}\n\nPara especificar un _tag_ anchor personalizado para um header en vex de usar la generada automáticamente, adicione un sufijo al header:\n\n```\n# Usando anchors personalizados {#mi-anchor}\n```\n\nEsto permite que tenga un link del header como `#mi-anchor` en vez del default `#usando-anchors-personalizados`.\n\n## Links {#links}\n\nAmbos links internos y externos reciben tratamiento especial.\n\n### Links Internos {#internal-links}\n\nLos links internos son convertidos en links de enrutador para navegación SPA. Además de eso , todo archivo `index.md` contenido en cada subdirectorio será automáticamente convertido en `index.html`, con la URL correspondiente `/`.\n\nPor ejemplo, dada la siguiente estructura de directorios:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nY suponiendo que está en `foo/one.md`:\n\n```md\n[Página Inicial](/) <!-- lleva al usuario al index.md raiz -->\n[foo](/foo/) <!-- lleva al usuario al index.html del directorio foo -->\n[foo heading](./#heading) <!-- ancla al usuario a un header del archivo índice foo -->\n[bar - three](../bar/three) <!-- puede omitir la extensión -->\n[bar - three](../bar/three.md) <!-- puede adicionar .md -->\n[bar - four](../bar/four.html) <!-- o puede adicionar .html -->\n```\n\n### Sufijo de Página {#page-suffix}\n\nPáginas y links internos son generados con el sufijo `.html` por defecto.\n\n### Links Externos {#external-links}\n\nLinks externos reciben automáticamente `target=\"_blank\" rel=\"noreferrer\"`:\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress no GitHub](https://github.com/vuejs/vitepress)\n\n## Frontmatter {#frontmatter}\n\n[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) es soportado por defecto:\n\n```yaml\n---\ntítulo: Escribiendo como un Hacker\nidioma: es-CO\n---\n```\n\nEsos datos estarán disponibles para el resto de la página, junto con todos los componentes personalizados y de temas.\n\nPara más detalles, vea [Frontmatter](../reference/frontmatter-config).\n\n## Tablas al Estilo GitHub {#github-style-tables}\n\n**Entrada**\n\n```md\n| Tablas        |    Son        | Geniales|\n| ------------- | :-----------: |   ----: |\n| col 3 está    | à direita     |   $1600 |\n| col 2 está    | centralizada  |     $12 |\n| listras       |   são legais  |      $1 |\n```\n\n**Salida**\n\n| Tablas        |    Son        | Geniales |\n| ------------- | :-----------: |   -----: |\n| col 3 está    | à direita     |   \\$1600 |\n| col 2 está    | centralizada  |     \\$12 |\n| listras       |   são legais  |      \\$1 |\n\n## Emoji :tada:\n\n**Entrada**\n\n```\n:tada: :100:\n```\n\n**Salida**\n\n:tada: :100:\n\nUna [lista de todos los emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) está disponible.\n\n## Tabla de Contenido (TOC)\n\n**Entrada**\n\n```\n[[toc]]\n```\n\n**Salida**\n\n[[toc]]\n\nLa presentación de TOC (Table of Contents) puede ser configurada usando la opción `markdown.toc`.\n\n## Contenedores Personalizados {#custom-containers}\n\nContenedores personalizados pueden ser definidos por sus tipos, títulos y contenidos.\n\n### Título por Defecto {#default-title}\n\n**Entrada**\n\n```md\n::: info\nEste es un bloque de información.\n:::\n\n::: tip\nEste es un aviso.\n:::\n\n::: warning\nEsto es una advertencia.\n:::\n\n::: danger\nEste es un aviso de peligro.\n:::\n\n::: details\nEste es un bloque de detalles.\n:::\n```\n\n**Salida**\n\n::: info\nEste es un bloque de información.\n:::\n\n::: tip\nEste es un aviso.\n:::\n\n::: warning\nEsto es una advertencia.\n:::\n\n::: danger\nEste es un aviso de peligro.\n:::\n\n::: details\nEste es un bloque de detalles.\n:::\n\n### Título Personalizado {#custom-title}\n\nPuede definir un título personalizado adicionando el texto inmediatamente después del \"tipo\" del recipiente.\n\n**Entrada**\n\n```md\n::: danger STOP\nZona de peligro, no siga\n:::\n\n::: details Click para ver el código\n```js\nconsole.log('Hola, VitePress!')\n```\n:::\n```\n```\n\n**Salida**\n\n::: danger STOP\nZona de peligro, no siga\n:::\n\n::: details Click para ver el código\n```js\nconsole.log('Hola, VitePress!')\n```\n:::\n\nAdemás de eso, puede definir títulos personalizados globalmente adicionando el siguiente contenifo en el archivo de configuración del sitio, útil si no estuviera escribiendo en ingles:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: '提示',\n      warningLabel: '警告',\n      dangerLabel: '危险',\n      infoLabel: '信息',\n      detailsLabel: '详细信息'\n    }\n  }\n  // ...\n})\n```\n\n### `raw`\n\nEste es un recipiente especial que puee ser usado para evitar conflictos de estilo y enrutador con VitePress. Esto es especialmente útil al documentar bibliotecas de componentes. Puede tambien verificar [whyframe](https://whyframe.dev/docs/integrations/vitepress) para mejor aislamiento.\n\n**Sintaxis**\n\n```md\n::: raw\nEnvuelve en un `<div class=\"vp-raw\">`\n:::\n```\n\nLa clase `vp-raw` también puede ser usada directamente en elementos. El aislamiento de estilo es actualmente opcional:\n\n- Instale `postcss` con su gestor de paquetes preferido:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- Cree un archivo llamado `docs/postcss.config.mjs` y adicione lo siguiente:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  Puede pasar opciones así:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // o padrão é [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## Alertas en estilo GitHub {#github-flavored-alerts}\n\nVitePress también soporta [alertas en estilo GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) para presentar como un bloque de llamada. Ellos serán presentados de la misma forma que [elementos personalizados](#custom-containers).\n\n```md\n> [!NOTE]\n> Destaca informaciones que los usuarios deben tener en consideración, incluso leyendo rapidamente.\n\n> [!TIP]\n> Informaciones opcionales para ayudar al usuario a tener más éxito.\n\n> [!IMPORTANT]\n> Informaciones cruciales necesarias par que los usuarios tengan éxito.\n\n> [!WARNING]\n> Contenido critico exigiendo atención inmediata del usuario debido a riesgos potenciales.\n\n> [!CAUTION]\n> Potenciales consecuencias negativas de una acción.\n```\n\n> [!NOTE]\n> Destaca informaciones que los usuarios deben tener en consideración, incluso leyendo rapidamente.\n\n> [!TIP]\n> Informaciones opcionales para ayudar al usuario a tener más éxito.\n\n> [!IMPORTANT]\n> Informaciones cruciales necesarias par que los usuarios tengan éxito.\n\n> [!WARNING]\n> Contenido critico exigiendo atención inmediata del usuario debido a riesgos potenciales.\n\n> [!CAUTION]\n> Potenciales consecuencias negativas de una acción.\n\n## Destaque de Sintaxis en Bloques de Código {#syntax-highlighting-in-code-blocks}\n\nVitePress utiliza [Shiki](https://github.com/shikijs/shiki) para destacar la sintaxis del lenguaje en bloques de código Markdown, usando texto coloreado. Shiki soporta una amplia variedad de lenguajes de programación. Todo lo que necesita es adicionar un _alias_ de lenguaje válido después de los backticks iniciales del bloque de código:\n\n**Entrada**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**Salida**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\nUna [lista de lenguajes válidas](https://shiki.style/languages) está disponible en el repositório Shiki.\n\nTambién puede personalizar el tema de destaque de sintaxis en la configuración de la aplicación. Consulte las [opciones `markdown`](../reference/site-config#markdown) para más detalles.\n\n## Destaque de Linea en Bloques de Código {#line-highlighting-in-code-blocks}\n\n**Entrada**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!'\n    }\n  }\n}\n```\n````\n\n**Salida**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!'\n    }\n  }\n}\n```\n\nAdemás de una única linea, puede también especificar múltiples lineas únicas, intervalos, o ambos:\n\n- Intervalos de linea: por ejemplo, `{5-8}`, `{3-10}`, `{10-17}`\n- Múltiples lineas únicas: por ejemplo, `{4,7,9}`\n- Intervalos de linea y lineas únicas: por ejemplo, `{4,7-13,16,23-27,40}`\n\n**Entrada**\n\n````\n```js{1,4,6-8}\nexport default { // Destacado\n  data () {\n    return {\n      msg: `Destacado!\n      Esta linea no está destacada,\n      pero esta y las próximas están.`,\n      motd: 'VitePress es increible',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**Salida**\n\n```js{1,4,6-8}\nexport default { // Destacado\n  data () {\n    return {\n      msg: `Destacado!\n      Esta linea no está destacada,\n      pero esta y las próximas están.`,\n      motd: 'VitePress es increible',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\nAlternativamente, es posible destacar directamente en la linea usando el comentario `// [!code highlight]`.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Destacado!' // [!code highlight]\n    }\n  }\n}\n```\n\n## Enfoque en Bloques de Código {#focus-in-code-blocks}\n\nAdicionando el comentario `// [!code focus]` en una linea, esta será destacada y desenfocará las otras partes del código.\n\nAdemás, puede definir el número de lineas para enfocar usando `// [!code focus:<lineas>]`.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Enfocado!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**Salida**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Enfocado!' // [!code focus]\n    }\n  }\n}\n```\n\n## Diferencias Coloreadas en Bloques de Código {#colored-diffs-in-code-blocks}\n\nAdicionar los comentarios `// [!code --]` o `// [!code ++]` en una linea creará una diferencia en esa linea, manteniendo los colores del bloque de código.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Borrado' // [!!code --]\n      msg: 'Adicionado' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**Salida**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Borrado' // [!code --]\n      msg: 'Adicionado' // [!code ++]\n    }\n  }\n}\n```\n\n## Errores y Avisos en Bloques de Código {#errors-and-warnings-in-code-blocks}\n\nAdicionar los comentarios `// [!code warning]` o `// [!code error]` en una linea coloreará los bloques conforme necesário.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Error', // [!!code error]\n      msg: 'Aviso' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**Salida**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!code error]\n      msg: 'Aviso' // [!code warning]\n    }\n  }\n}\n```\n\n## Números de Linea {#line-numbers}\n\nPuede habilitar números de linea para cada bloque de código a través del archivo de configuración:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\nConsulte las [opciones markdown](../reference/site-config#markdown) para más detalles.\n\nPuede adicionar la marca `:line-numbers` / `:no-line-numbers` en sus bloques de código para substituir el valor definido en la configuración.\n\nTambién puede personalizar el número inicial de linea adicionando `=` después `:line-numbers`. Por ejemplo, `:line-numbers=2` significa que los números de las lineas en los bloques de código comenzarán a partir de `2`.\n\n**Entrada**\n\n````md\n```ts {1}\n// números de linea desactivados por defecto\nconst line2 = 'Esta es la linea 2'\nconst line3 = 'Esta es la linea 3'\n```\n\n```ts:line-numbers {1}\n// números de linea activados\nconst line2 = 'Esta es la linea 2'\nconst line3 = 'Esta es la linea 3'\n```\n\n```ts:line-numbers=2 {1}\n// números de linea activados y comienzan en 2\nconst line3 = 'Esta es la linea 3'\nconst line4 = 'Esta es la linea 4'\n```\n````\n\n**Salida**\n\n```ts {1}\n// números de linea desactivados por defecto\nconst line2 = 'Esta es la linea 2'\nconst line3 = 'Esta es la linea 3'\n```\n\n```ts:line-numbers {1}\n// números de linea activados\nconst line2 = 'Esta es la linea 2'\nconst line3 = 'Esta es la linea 3'\n```\n\n```ts:line-numbers=2 {1}\n// números de linea activados y comienzan en 2\nconst line3 = 'Esta es la linea 3'\nconst line4 = 'Esta es la linea 4'\n```\n\n## Importar _Snippets_ de Código {#import-code-snippets}\n\nPuede importar pedazos de código de archivos existentes usando la siguiente sintaxis:\n\n```md\n<<< @/filepath\n```\n\nTambién soporta [destaque de linea](#line-highlighting-in-code-blocks):\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**Entrada**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**Archivo de Código**\n\n<<< @/snippets/snippet.js\n\n**Salida**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\n\nEl valor de `@` corresponde a la raiz del código fuente. Por defecto, es la raiz del proyecto VitePress, a menos que `srcDir` sea configurado. Alternativamente, puede también importar de paths relativos:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\nTambién puede usar una [región VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) para incluir apenas la parte correspondiente del archivo de código. Puede proporcionar un nombre de región personalizado después de `#` siguiendo el path del archivo:\n\n**Entrada**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**Archivo de Código**\n\n<<< @/snippets/snippet-with-region.js\n\n**Salida**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\nTambién puede especificar el idioma dentro de llaves (`{}`), así:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- con destaque de linea: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- con números de linea: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nEsto es útil si el lenguaje original no puede ser inferida por la extensión de archivo.\n\n## Grupos de Código {#code-groups}\n\nPuede agrupar varios bloques de código así:\n\n**Entrada**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**Salída**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nTambién puede [importar _snippets_ de código](#import-code-snippets) en grupos de código:\n\n**Entrada**\n\n```md\n::: code-group\n\n<!-- nombre de archivo usado como título por defecto -->\n\n<<< @/snippets/snippet.js\n\n<!-- puede proporcionar uno personalizado también -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n```\n\n**Output**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n\n## Inclusión de Archivo Markdown {#markdown-file-inclusion}\n\nPuede incluir un archivo markdown en otro archvo markdown, incluso anidado.\n\n::: tip\nPuede prefijar el path del markdown con `@`, el actuará como la raiz de origen. Por defecto, es la raiz del projecto VitePress, a menos que `srcDir` sea configurado.\n:::\n\nPor ejemplo, puede incluir un archivo markdown relativo usando esto:\n\n**Entrada**\n\n```md\n# Documentación\n\n## Conceptos Básicos\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**Archivo de Parte** (`parts/basics.md`)\n\n```md\nAlgunas cosas básicas.\n\n### Configuración\n\nPuede ser creada usando `.foorc.json`.\n```\n\n**Código Equivalente**\n\n```md\n# Documentación\n\n## Conceptos básicos\n\nAlgunas cosas básicas\n\n### Configuración\n\nPuede ser creada usando `.foorc.json`.\n```\n\nTambién soporta la selección de un intervalo de lineas:\n\n**Entrada**\n\n```md\n# Documentación\n\n## Conceptos Básicos\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**Archivo de Parte** (`parts/basics.md`)\n\n```md\nAlgunas cosas básicas.\n\n### Configuración\n\nPuede ser creada usando `.foorc.json`.\n```\n\n**Código Equivalente**\n\n```md\n# Documentación\n\n## Conceptos Básicos\n\n### Configuración\n\nPuede ser creada usando `.foorc.json`.\n```\n\nEl formato del intervalo de lineas seleccionado puede ser: `{3,}`, `{,10}`, `{1,10}`\n\n::: warning\nObserve que esto no genera errores si el archivo no está presente. Por lo tanto, al usar este recurso, asegurese de que el contenido está siendo mostrado como se espera.:::\n\n## Ecuaciones Matemáticas {#math-equations}\n\nEsto es actualmente opcional. Para activarlo, necesita instalar `markdown-it-mathjax3` y definir `markdown.math` como `true` en su archivo de configuración:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**Entrada**\n\n```md\nCuando $a \\ne 0$, existen dos soluciones para $(ax^2 + bx + c = 0)$ y ellas son\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Ecuaciones de Maxwell:**\n\n| ecuación                                                                                                                                                                  | descripción                                                                                |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | la divergencia de $\\vec{\\mathbf{B}}$ es cero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | la rotacional de $\\vec{\\mathbf{E}}$ es proporcional a la tasa de variación de $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _hã?_                                                                                     |\n\n**Salída**\n\nCuando $a \\ne 0$, existen dos soluciones para $(ax^2 + bx + c = 0)$ y ellas son\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Ecuaciones de Maxwell:**\n\n| ecuación                                                                                                                                                                  | descripción                                                                                |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | la divergencia de $\\vec{\\mathbf{B}}$ es cero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | la rotacional de $\\vec{\\mathbf{E}}$ es proporcional a la tasa de variación de $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _hã?_                                                                                     |\n\n## _Lazy Loading_ de Imagenes {#image-lazy-loading}\n\nPuede activar la \"carga perezosa\" para cada imagen adicionada via markdown definiendo `lazyLoading` como `true` en su archivo de configuración:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // la carga perezosa de imagenes está desactivada por defecto\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## Configuración Avanzada {#advanced-configuration}\n\nVitePress usa [markdown-it](https://github.com/markdown-it/markdown-it) como interprete Markdown. Muchas de las extensiones arriba son implementadas por medio de _plugins_ personalizados. Puede personalizar más la instancia `markdown-it` usando la opción `markdown` en `.vitepress/config.js`:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // opciones para markdown-it-anchor\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // opciones para @mdit-vue/plugin-toc\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // use más plugins markdown-it!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\nConsulte la lista completa de propiedades configurables en [Referencia de Configuración: Configuración de la Aplicación](../reference/site-config#markdown).\n"
  },
  {
    "path": "docs/es/guide/mpa-mode.md",
    "content": "# Modo MPA <Badge type=\"warning\" text=\"experimental\" /> {#mpa-mode}\n\nEl modo MPA (Aplicación de multiples páginas) puede ser habilitado por la linea de comandos con `vitepress build --mpa`, o a través de la configuración por la opción `mpa: true`.\n\nEn el modo MPA, todas las páginas son presentadas por defecto sin JavaScript incluído. Como resultado, el sitio en producción probablemente tendrá una marca de desempeño de visita inicial superior con herramientas de auditoría.\n\nSin embargo, debido a la ausencia de navegación SPA, los links entre páginas resultan en recargas de página completos. Navegaciones después de la carga en el modo MPA no parecerán tan instantáneos en comparación con el modo SPA.\n\nTambién note que no tener JavaScript por defecto significa que está esencialmente utilizando Vue como modelo de lenguaje en el lado del servidor. Nungun manipulador de eventos será embutido en el navegador, entonces no habrá interactividad. Para cargar JavaScript en el lado del cliente, necesitará usar el tag especial `<script client>`:\n\n```html\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('JavaScript en el lado del cliente!')\n})\n</script>\n\n# Hola\n```\n\n`<script client>` es una funcionalidad exclusiva VitePress, no una funcionalidad Vue. Funciona tanto en archivos `.md` como en archivos `.vue`, pero solo en el modo MPA. Scripts de cliente en todos los componentes del tema serán empaquetados juntos, mientras el script del cliente para una página específica será dividido solo para esa página.\n\nNote que `<script client>` **no es calificado como código de componente Vue**: es procesado como un simple módulo JavaScript. Por esta razón, el modo MPA debe ser usado apenas si su sitio exige el mínimo absoluto de interactividad del lado del cliente.\n"
  },
  {
    "path": "docs/es/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# Enrutamiento {#routing}\n\n## Enrutamiento basasdo en Archivos {#file-based-routing}\n\nVitePress utiliza enrutamiento basado en archivos, esto significa que las páginas HTML generadas son mapeadas de la estructura de directorios de los archivos Markdown. Por ejemplo, dada la siguiente estructura de directorio:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\nLas páginas HTML generadas serán:\n\n```\nindex.md                  -->  /index.html (accesible por /)\nprologue.md                -->  /prologue.html\nguide/index.md             -->  /guide/index.html (accesible por /guide/)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\nEl HTML resultante puede ser hospedado en cualquier servidor web que pueda servir archivos estáticos.\n\n## Diretório Raiz y fuente {#root-and-source-directory}\n\nExisten dos conceptos importantes en la estructura de archivos de un proyecto VitePress: el **directorio raiz** y el **directorio fuente**.\n\n### Directorio Raiz {#project-root}\n\nEl directorio raiz es donde VitePress busca por el directorio especial `.vitepress`. El directorio `.vitepress` es un lugar reservado para el archivo de configuración de VitePress, el caché del servidor de desarrollo, el resultado de la compilación y el código de personalización del tema opcional.\n\nAl ejecutar `vitepress dev` o `vitepress build` en el terminal, VitePress usará el directorio actual como directorio raiz del proyecto. Para especificar un subdirectorio como raiz, es necesario pasar el camino relativo para el comando. Por ejemplo, si el proyecto VitePress estuviera localizado en `./docs`, debe ejecutarse `vitepress dev docs`:\n\n```\n.\n├─ docs                    # directorio raiz\n│  ├─ .vitepress           # directorio de configuración\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nEsto resultará en el siguiente mapeamento de fuente para HTML:\n\n```\ndocs/index.md            -->  /index.html (accesible como /)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### Directorio Fuente {#source-directory}\n\nEl directorio fuente es donde sus archivos fuente en Markdown están. Por defecto, es el mismo que el directorio raiz. Sin embargo, puede configurarlo por medio de la opción de configuración [`srcDir`](../reference/site-config#srcdir).\n\nLa opción `srcDir` es resuelta en relación al directorio raiz del proyecto. Por ejemplo, con `srcDir: 'src'`, su estructura de archivos quedará así:\n\n```\n.                          # directorio raiz\n├─ .vitepress              # directorio de configuración\n└─ src                     # directorio fuente\n   ├─ getting-started.md\n   └─ index.md\n```\n\nEl mapeamente resultante de la fuente para HTML:\n\n```\nsrc/index.md            -->  /index.html (accesible como /)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## Links Entre Páginas {#linking-between-pages}\n\nPuede usar tanto paths absolutos como relativos al vincular páginas. Note que, incluso si ambas extensiones `.md` y `.html` funcionan, funcionem, la práctica recomendada es omitir las extensiones de archivo para que VitePress pueda generar las URLs finales con base en su configuración.\n\n```md\n<!-- Hacer -->\n[Getting Started](./getting-started)\n[Getting Started](../guide/getting-started)\n\n<!-- No hacer -->\n[Getting Started](./getting-started.md)\n[Getting Started](./getting-started.html)\n```\n\nAverigue más sobre la vinculación de assets, como imagenes, en [Manipulación de Assets](./asset-handling).\n\n### Vinculación de Páginas No VitePress {#linking-to-non-vitepress-pages}\n\nSi desea vincular a una página en su sitio que no es generada por VitePress, será necesario usar la URL completa (abre en una nueva pestaña) o especificar explícitamente el destino:\n\n**Entrada**\n\n```md\n[Link para pure.html](/pure.html){target=\"_self\"}\n```\n\n**Salida**\n\n[Link para pure.html](/pure.html){target=\"_self\"}\n\n::: tip Nota\n\nEn los links Markdown, la `base` es automáticamente adicionada a la URL. Esto significa que, si desea vincular a una página fuera de su base, será necesario algo como `../../pure.html` en el link (resuelto en relación a la página actual por el navegador).\n\nAlternativamente, puede usarse directamente la sintaxis de tag anchor:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Link para pure.html</a>\n```\n\n:::\n\n## Generación de URLs Limpias {#generating-clean-urls}\n\n::: warning Soporte del Servidor Necesario\nPara servir URLs limpias con VitePress, es necesario soporte en el lado del servidor.\n:::\n\nPor defecto, VitePress resuelve links de entrada para URLs que terminan con `.html`. Sin embargo, algunos usuarios pueden preferir \"URLs limpias\" sin la extensión `.html`, por ejemplo, `example.com/path` en vez de `example.com/path.html`.\n\nAlgunos servidores o plataformas de hospedaje (por ejemplo, Netlify, Vercel, GitHub Pages) proporcionan la habilidad de mapear una URL como `/foo` para `/foo.html` si existir, sin redireccionamiento:\n\n- Netlify y GitHub Pages soportan esto por defecto.\n- Vercel requiere activación de la opción [`cleanUrls` en `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).\n\nSi esa funcionalidad está disponible para usted, también se puede activar la propia opción de configuración [`cleanUrls`](../reference/site-config#cleanurls) de VitePress para que:\n\n- Links de entrada entre páginas sean generados sin la extensión `.html`.\n- Si el path actual termina con `.html`, el enrutador realizará un redireccionamiento en el lado del cliente para el path sin extensión.\n\nSin embargo, si no puede configurar el servidor con ese soporte, será necesario recorrer manualmente la siguiente estructura de directorio:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n# Reescritura de Ruta {#route-rewrites}\n\nPuede personalizar el mapeamento entre la estructura de directorios fuente y las páginas generadas. Esto es útil cuando tiene una estructura de proyecto compleja. Por ejemplo, digamos que tiene un monorepo con varios paquetes y le gustaría colocar la documentación junto con los archivos fuente de esta forma:\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ pkg-a-code.ts\n│  │      └─ pkg-a-docs.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ pkg-b-code.ts\n│         └─ pkg-b-docs.md\n```\n\nY desea que las páginas VitePress sean generadas así:\n\n```\npackages/pkg-a/src/pkg-a-docs.md  -->  /pkg-a/index.html\npackages/pkg-b/src/pkg-b-docs.md  -->  /pkg-b/index.html\n```\n\nPuede realizar esto configurando la opción [`rewrites`](../reference/site-config#rewrites) así:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',\n    'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'\n  }\n}\n```\n\nLa opción `rewrites` también soporta parametros de ruta dinámicos. En el ejemplo arriba, sería tedioso listar todos los paths si tiene muchos paquetes. Dado que todos ellos tienen la misma estructura de archivo, puede simplificar la configuración así:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/(.*)': ':pkg/index.md'\n  }\n}\n```\n\nLos paths reesctritos son compilados usando el paquete `path-to-regexp` - consulte [su documentación](https://github.com/pillarjs/path-to-regexp#parameters) para una sintaxis más avanzada.\n\n::: warning Links Relativos con Reescrituras\n\nCuando las reescrituras están habilitadas, **links relativos deben ser basados en los paths reescritos**. Por ejemplo, para crear un link relativo de `packages/pkg-a/src/pkg-a-code.md` para `packages/pkg-b/src/pkg-b-code.md`, debe usarse:\n\n```md\n[Link para PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## Rutas Dinámicas {#dynamic-routes}\n\nPuede generar muchas páginas usando un único archivo Markdown y datos dinámicos. Por ejemplo, puede crear un archivo `packages/[pkg].md` que genera una página correspondiente para cáda paquete en un proyecto. Aqui, el segmento `[pkg]` es un **parámetro** de ruta que diferencia cada página de las otras.\n\n### Archivo de Carga de Paths {#paths-loader-file}\n\nComo VitePress es un generador de sitios estáticos, los paths posibles de las páginas deben ser determinados en el momento de la compilación. Por lo tanto, una página de ruta dinámica **debe** estar acompañada por un **archivo de carga de paths**. Para `packages/[pkg].md`, necesitaremos de `packages/[pkg].paths.js` (`.ts` también es soportado):\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # modelo de ruta\n   └─ [pkg].paths.js   # cargador de paths de la ruta\n```\n\nEl cargador de paths debe proporcionar un objeto con un método `paths` como su exportación por defecto. El método `paths` debe retornar un _array_ de objetos con una propiedad `params`. Cada uno de esos objetos generará una página correspondiente.\n\nDado el siguiente _array_ `paths`:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\nLas páginas HTML generadas serán:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### Múltiples Parámetros {#multiple-params}\n\nUna ruta dinámica puede contener múltiples parámetros:\n\n**Estrutura de Archivo**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**Cargador de Paths**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**Salida**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### Generando Paths Dinámicamente {#dynamically-generating-paths}\n\nEl módulo de carga de paths es ejecutado en Node.js y apenas durante el momento de la compilación. Puede generar dinámicamente el _array_ de paths usando cualquier dato, sea local o remoto.\n\nGenerando paths a partir de archivos locales:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\nGenerando paths a partir de datos remotos:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### Accediendo Parámetros en la Página {#accessing-params-in-page}\n\nPuede usar los parámetros para pasar datos adicionales para cada página. El archivo de ruta Markdown puede acceder a los parámetros de la página actual en expresiones Vue a través de la propiedad global `$params`:\n\n```md\n- nombre del paquete: {{ $params.pkg }}\n- versión: {{ $params.version }}\n```\n\nTambién puede acceder los parámetros de la página actual a través del API de tiempo de ejecución [`useData`](../reference/runtime-api#usedata). Esto está disponible tanto en archivos Markdown así como en componentes Vue:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params es una ref Vue\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### Presentando Contenido Crudo {#rendering-raw-content}\n\nParámetros pasados para una página serán serializados en la carga JavaScript del cliente, por lo tanto, evite pasar datos pesados en los parámetros, como Markdown crudo o contenido HTML obtenido de un CSS remoto.\n\nEn lugar de eso, puede pasar tal contenido para cada página usando la propiedad `content` en cada objeto de path:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // Markdown o HTML crudo\n      }\n    })\n  }\n}\n```\n\nEn seguida, use la siguiente sintaxis especial para presentar el contenido como parte del propio archivo Markdown:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/es/guide/sitemap-generation.md",
    "content": "# Generación de Sitemap {#sitemap-generation}\n\nVitePress viene con soporte embutido para generar un archivo `sitemap.xml` para su sitio. Para habilitar, adicione lo siguiente a su `.vitepress/config.js`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n})\n```\n\nPara tener tags `<lastmod>` en su `sitemap.xml`, puede habilitar la opción [`lastUpdated`](../reference/default-theme-last-updated).\n\n## Opciones {#options}\n\nEl soporte de Sitemap es alimentado por el módulo [`sitemap`](https://www.npmjs.com/package/sitemap). Puede pasar cualquiera de las opciones soportadas por el en la opción `sitemap` de su archivo de configuración. Estos serán pasados directamente al constructor `SitemapStream`. Consulte la [documentación `sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass) para más detalles. Ejemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n})\n```\n\n## Hook `transformItems`\n\nPuede usar el hook `sitemap.transformItems` para modificar los items del sitemap antes de ser escritos en el archivo `sitemap.xml`. Este hook es llamado como un _array_ de items sitemap y espera un _array_ de items sitemap como retorno. Ejemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // adiciona nuevos items o modifica/filtra items existentes\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n})\n```\n"
  },
  {
    "path": "docs/es/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# Compatibilidad SSR {#ssr-compatibility}\n\nVitePress pre-renderiza la aplicación en Node.js durante la compilación de producción, utilizando las capacidades de Renderizado del Lado del Servidor (SSR) de Vue. Esto significa que todo el código personalizado en los componentes del tema está sujeto a la Compatibilidad con SSR.\n\nLa [sección SSR en la documentación Vue oficial](https://vuejs.org/guide/scaling-up/ssr.html) proporciona más contexto sobre lo que es SSR, la relación entre SSR / SSG y notas comunes sobre escribir código amigable para SSR. La regla general es acceder a las APIs del navegador / DOM solo en los hooks `beforeMount` o `mounted` de los componentes de Vue.\n\n## `<ClientOnly>`\n\nSi está usando o demostrando componentes que no son compatibles con SSR (por ejemplo, contienen directivas personalizadas), puede envolverlos en el componente incorporado `<ClientOnly>`:\n\n```md\n<ClientOnly>\n  <ComponenteNoCompatibleConSSR />\n</ClientOnly>\n```\n\n## Bibliotecas que Acceden el API del Navegador en la Importación {#libraries-that-access-browser-api-on-import}\n\nAlgunos componentes o librerías acceden a las APIs del navegador **al momento de ser importados**. Para usar código que asume un entorno de navegador en la importación, necesita importarlos dinámicamente.\n\n### Importando en el Hook `mounted` {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-que-accede-a-window-en-la-importacion').then((module) => {\n    // usar código\n  })\n})\n</script>\n```\n\n### Importación Condicional {#conditional-import}\n\nTambién puede importar una dependencia condicionalmente utilizando la bandera `import.meta.env.SSR` (que forma parte de las [variables de entorno Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-que-accede-a-window-en-la-importacion').then((module) => {\n    // usar código\n  })\n}\n```\n\nDado que [`Theme.enhanceApp`](./custom-theme#theme-interface) puede ser asíncrono, puede importar y registrar condicionalmente plugins de Vue que accedan a las APIs del navegador al ser importados:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-que-accede-a-window-en-la-importacion')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nSi está usando TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-que-accede-a-window-en-la-importacion')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress proporciona un auxiliar de conveniencia (helper) para importar componentes Vue que acceden a las APIs del navegador al ser importados.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('componente-que-accede-a-window-en-la-importacion')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nPuede pasar propiedades/hijos/_slots_ al componente objetivo:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('componente-que-accede-a-window-en-la-importacion'),\n\n  // los argumentos se pasan a h() - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'slot por defecto',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'uno'), h('span', 'dos')]\n    }\n  ],\n\n  // callback después de que el componente es cargado, puede ser asíncrono\n\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nEl componente objetivo solo será importado en el hook `mounted` del componente que lo envuelve.\n"
  },
  {
    "path": "docs/es/guide/using-vue.md",
    "content": "# Usando Vue en Markdown {#using-vue-in-markdown}\n\nEn VitePress, cada archivo Markdown es compilado para HTML y entonces procesado como un [Componente de Archivo Único de Vue](https://vuejs.org/guide/scaling-up/sfc.html). Esto significa que puede usar cualquier funcionalidad de Vue dentro del Markdown, incluyendo la interpolación dinámica, usar componentes Vue o lógica arbitrária de componentes Vue dentro de la página adicionando una tag `<script>`.\n\nVale resaltar que VitePress aprovecha el compilador Vue para detectar y optimizar automáticamente las partes puramente estáticas del contenido Markdown. Los contenidos estáticaos son optimizados en nodos de espacio reservado únicos y eliminados de la carga JavaScript de la página para visitas iniciales. Ellos también son ignorados durante la hidratación en el lado del cliente. En resumen, solo paga por las partes dinámicas en cualquier página específica.\n\n::: tip Compatibilidad SSR\nTodo uso de Vue necesita ser compatible con SSR. Consulte [Compatibilidad SSR](./ssr-compat) para detalles y soluciones comunes.\n:::\n\n## Creación de _Templates_ {#templating}\n\n### Interpolación {#interpolation}\n\nCada archivo Markdown es primero compilado para HTML y después pasado como un componente Vue para la canalización de procesos Vite. Esto significa que puede usar interpolación en el estilo Vue en el texto:\n\n**Entrada**\n\n```md\n{{ 1 + 1 }}\n```\n\n**Salida**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### Directivas {#directives}\n\nLas Directivas también funcionan (observe que, por definición, HTML crudo también es válido en Markdown):\n\n**Entrada**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**Salida**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` e `<style>`\n\nlas tags `<script>` e `<style>` en nivel raiz en los archivos Markdown funcionan igualmente como en los componentes de archivo único Vue, incluyendo `<script setup>`, `<style module>`, y etc. La principal diferencia aquí es que no hay una tag `<template>`: todo contenido en nivel raiz es Markdown. Además, observe que todas las tags deben ser colocadas **después** del frontmatter:\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## Contenido Markdown\n\nEl conteo es: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Incrementar</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning Evite `<style scoped>` en el Markdown\nCuando es usado en Markdown, `<style scoped>` exige la adición de atributos especiales a cada elemento en la página actual, lo que aumentará significativamente el tamaño de la página. `<style module>` es preferido cuando es necesaria una estilización localizada en una página.\n:::\n\nTambién tiene acceso a los APIs de tiempo de ejecución VitePress, como el [auxiliar `useData`](../reference/runtime-api#usedata), que proporciona acceso a los metadados de la página actual:\n\n**Entrada**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**Salida**\n\n```json\n{\n  \"path\": \"/usando-vue.html\",\n  \"title\": \"Usando Vue en Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## Usando Componentes {#using-components}\n\nPuede importar y usar componentes Vue directamente en los archivos Markdown.\n\n### Importando en el Markdown {#importing-in-markdown}\n\nSi un componente es usado apenas por algunas páginas, es recomendable importarlos explicitamente donde son usados. Esto permite que ellos sean divididos adecuadamente y cargados apenas cuando las páginas relevantes son mostradas.\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# Documentación\n\nEste es un archivo .md usando un componente personalizado\n\n<CustomComponent />\n\n## Más documentación\n\n...\n```\n\n### Registrando Componentes Globalmente {#registering-components-globally}\n\nSi un componente fuera usado en la mayoría de las páginas, ellos pueden ser registrados globalmente personalizando la instancia de la aplicación Vue. Consulte la sección relevante en [Extendiendo el Tema por Defecto](./extending-default-theme#registering-global-components) para un ejemplo.\n\n::: warning IMPORTANT\nAsegurese de que el nombre de un componente personalizado contenga un hífen o esté en PascalCase. Caso contrario, el será tratado como un elemento alineado y envuelto dentro de una tag `<p>`, lo que llevará a una incompatibilidad de hidratación pues `<p>` no permite que elementos de bloque sean colocados dentro de el.\n:::\n\n### Usando Componentes En Headers <ComponentInHeader /> {#using-components-in-headers}\n\nPuede usar componentes Vue en los headers, pero observe la diferencia entre las siguientes sintaxis:\n\n| Markdown                                                 | HTML de Salida                             | Header Procesado |\n| -------------------------------------------------------  | -----------------------------------------  | -------------    |\n| <pre v-pre><code> # texto &lt;Tag/&gt; </code></pre>     | `<h1>texto <Tag/></h1>`                    | `texto`          |\n| <pre v-pre><code> # texto \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>texto <code>&lt;Tag/&gt;</code></h1>` | `texto <Tag/>`   |\n\nEl HTML envuelto por `<code>` será mostrado como es, solamente el HTML que **no** estuviera envuelto será analizado por Vue.\n\n::: tip\nEL HTML de salida es realizado por [Markdown-it](https://github.com/Markdown-it/Markdown-it), en cuanto los headers procesados son manipulados por VitePress (y usados tanto en la barra lateral como dentro del título del video).\n:::\n\n## Escapes {#escaping}\n\nPuede escapar de interpolaciones Vue envolvientdolas en un `<span>` u otros elementos con la directiva `v-pre`:\n\n**Entrada**\n\n```md\nEsto <span v-pre>{{ será exibido como es }}</span>\n```\n\n**Salida**\n\n<div class=\"escape-demo\">\n  <p>Esto <span v-pre>{{ será exibido como es }}</span></p>\n</div>\n\nAlternativamente, puede envolver todo el paragrafo en un contenedor personalizadon `v-pre`:\n\n```md\n::: v-pre\n{{ Esto será exibido como es }}\n:::\n```\n\n**Output**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ Esto será exibido como es }}\n:::\n\n</div>\n\n## \"Desescape\" en bloques de Código {#unescape-in-code-blocks}\n\nPor defecto, todos los bloques de código cercados son automáticamente envueltos con `v-pre`, entonces ninguna sintaxis Vue será procesada dentro de ellos. Para permitir la interpolación en el estilo Vue dentro de la valla, puede adicionar el lenguaje con el sufijo `-vue`, por ejemplo, `js-vue`:\n\n**Entrada**\n\n````md\n```js-vue\nHola {{ 1 + 1 }}\n```\n````\n\n**Salida**\n\n```js-vue\nHola {{ 1 + 1 }}\n```\n\n\nObserve que esto puede impedir que ciertos tokens sean realzados correctamente.\n\n## Usando Preprocesadores CSS {#using-css-pre-processors}\n\nVitePress poseé [soporte embutido](https://vitejs.dev/guide/features.html#css-pre-processors) para preprocesadores CSS: archivos `.scss`, `.sass`, `.less`, `.styl` e `.stylus`. No es necesario instalar plugins específicos de Vite para ellos, pero el propio preprocesados correspondiente debe ser instalado:\n\n```\n# .scss e .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl e .stylus\nnpm install -D stylus\n```\n\nEntonces puede usar lo siguiente en Markdown y en los componentes del tema:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## Usando _Teleports_ {#using-teleports}\n\nVitePress actualmente ofrece soporte a SSG para _teleports_ apenas para el cuerpo. Para otros objetivos, puede envolverlos dentro del componente embutido `<ClientOnly>` o inyectar la marcación de _teleport_ en la localización correcta en su página final HTML por medio del [hook `postRender`](../reference/site-config#postrender).\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n\n## Soporte de IntelliSense en VS Code\n\n<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->\n\nVue ofrece soporte para IntelliSense de forma predeterminada mediante el [Plugin oficial de Vue para VS Code](https://marketplace.visualstudio.com/items?itemName=Vue.volar). Sin embargo, para habilitarlo en archivos `.md`, es necesario realizar algunos ajustes en los archivos de configuración.\n\n1. Agrega el patrón `.md` a las opciones `include` y `vueCompilerOptions.vitePressExtensions` en el archivo tsconfig/jsconfig:\n\n::: code-group\n```json [tsconfig.json]\n{\n  \"include\": [\n    \"docs/**/*.ts\",\n    \"docs/**/*.vue\",\n    \"docs/**/*.md\",\n  ],\n  \"vueCompilerOptions\": {\n    \"vitePressExtensions\": [\".md\"],\n  },\n}\n```\n:::\n\n2. Agrega `markdown` a la opción `vue.server.includeLanguages` en el archivo de configuración de VS Code\n\n::: code-group\n```json [.vscode/settings.json]\n{\n  \"vue.server.includeLanguages\": [\"vue\", \"markdown\"]\n}\n```\n:::\n"
  },
  {
    "path": "docs/es/guide/what-is-vitepress.md",
    "content": "# ¿Qué es VitePress? {#what-is-vitepress}\n\nVitePress es un [Generador de Sitios Estáticos](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) diseñado para construir sitios web rápidos y enfocados en el contenido. En pocas palabras, VitePress toma tu contenido fuente escrito en [Markdown](https://en.wikipedia.org/wiki/Markdown), le aplica un tema y genera páginas HTML estáticas que se pueden desplegar fácilmente en cualquier lugar.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n  \n¿Quieres probarlo? Ve directo al [Inicio Rápido](./getting-started).\n\n</div>\n\n## Casos de Uso {#use-cases}\n\n- **Documentación**\n\n  VitePress incluye un tema por defecto diseñado para documentación técnica. Este tema es el que se utiliza en la página que estás leyendo ahora, así como en la documentación de [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) y [muchos otros](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code).\n\n  La [documentación oficial Vue.js](https://vuejs.org/) también está basada en VitePress, pero utiliza un tema personalizado compartido entre varias traducciones.\n\n- **Blogs, Portfolios y sitios de Marketing**\n\n  VitePress soporta [temas completamente personalizables](./custom-theme), con la experiencia de desarrollo de una aplicación estándar de Vite + Vue. Al estar construido sobre Vite, también puedes aprovechar directamente los plugins de su rico ecosistema. Adicionalmente, VitePress proporciona APIs flexibles para [cargar datos](./data-loading) (locales o remotos) y [generar rutas dinámicamente](./routing#dynamic-routes). Puedes usarlo para construir prácticamente cualquier cosa, siempre y cuando los datos puedan ser determinados en el momento de la construcción.\n\n  El [blog oficial Vue.js](https://blog.vuejs.org/) es un blog simple que genera su página de inicio basándose en contenido local.\n\n## Experiencia de Desarrollador {#developer-experience}\n\nVitePress busca ofrecer una excelente Experiencia de Desarrollador (DX) al trabajar con contenido Markdown.\n\n- **[Con tecnología Vite:](https://vitejs.dev/)** inicio instantáneo del servidor, con los cambios reflejados al instante (<100ms) sin recargar la página.\n\n- **[Extensiones Markdown Integradas:](./markdown)** Frontmatter, tablas, destaque de sintaxis... tú decides. Específicamente, VitePress proporciona muchos recursos para trabajar con bloques de código, tornándolo ideal para documentación altamente técnica.\n\n- **[Markdown Mejorado con Vue:](./using-vue)** cada página Markdown es también un [Componente de Archivo único](https://vuejs.org/guide/scaling-up/sfc.html) de Vue, gracias a la compatibilidad del 100% de la sintaxis de las plantillas de Vue con HTML.  Puedes incrustar interactividad en tu contenido estático usando las funciones de plantillas de Vue o componentes de Vue importados.\n\n## Desempeño {#performance}\n\nA diferencia de muchos SSG tradicionales donde cada navegación resulta en una recarga completa de la página, un sitio web generado por VitePress sirve HTML estático en la visita inicial, pero se convierte en una [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) (SPA) para las navegaciones posteriores dentro del sitio. Este modelo, en nuestra opinión, ofrece un equilibrio óptimo para el rendimiento:\n\n- **Carga Inicial Rápida**\n\n  La visita inicial a cualquier página será servida con el HTML estático pre-renderizado para una velocidad de carga rápida y SEO óptimo. La página entonces carga un paquete JavaScript que transforma la página en una SPA de Vue (a este proceso se le llama \"hidratación\"). A diferencia de la creencia popular de que la hidratación de una SPA es lenta, este proceso es de hecho extremadamente rápido gracias al rendimiento nativo y a las optimizaciones del compilador de Vue 3. En [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), los sitios típicos VitePress alcanzan puntuaciones de desempeño casi perfectas, incluso en dispositivos móbiles de gama baja con una red lenta.\n\n- **Navegación Rápida pos-carga**\n\n  Más importante aún, el modelo SPA conduce a una mejor experiencia de usuario **después** de la carga inicial. Las navegaciones posteriores dentro del sitio ya no causarán una recarga completa de la página. En vez de eso, el contenido de la página a la que se accede se buscará y actualizará dinámicamente. VitePress también pre-carga automáticamente fragmentos de las páginas para los enlaces que están dentro del viewport. En la mayoría de los casos, la navegación pos-carga se sentirá instantánea.\n\n- **Interactividad Sin Penalización**\n\n  Para ser capaz de hidratar las partes dinámicas de Vue incrustadas dentro del Markdown estático, cada página Markdown es procesada como un componente Vue y compilada en JavaScript. Esto puede parecer ineficiente, pero el compilador de Vue es lo suficientemente inteligente como para separar las partes estáticas y dinámicas, minimizando tanto el costo de hidratación así como el tamaño de carga útil (payload). Para la carga inicial de la página, las partes estáticas son automáticamente eliminadas del payload de JavaScript y se omiten durante la hidratación.\n\n## ¿Y VuePress? {#what-about-vuepress}\n\nVitePress es el sucesor espiritual de VuePress. El VuePress original se basó en Vue 2 y webpack. Con Vue 3 y Vite como base, VitePress ofrece una Experiencia de Desarrollador (DX) significativamente mejor, un mejor rendimiento en producción, un tema por defecto más pulido y una API de personalización más flexible.\n\nLa diferencia entre la API de VitePress y VuePress radica principalmente en los temas y la personalización. Si estás usando VuePress 1 con el tema por defecto, debería ser relativamente sencillo migrar a VitePress.\n\nTambién se ha invertido esfuerzo en VuePress 2, que también es compatible con Vue 3 y Vite, y tiene mayor compatibilidad con VuePress 1. Sin embargo, mantener dos SSG en paralelo no es sostenible, por lo que el equipo de Vue ha decidido centrarse en VitePress como el principal SSG recomendado a largo plazo.\n"
  },
  {
    "path": "docs/es/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Generador de Sitios Estáticos Vite y Vue\n  tagline: Markdown para obtener lindos documentos en minutos\n  actions:\n    - theme: brand\n      text: Qué es VitePress?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: Iniciar\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: Concéntrese en su contenido\n    details: Cree lindos sitios de documentación apenas con markdown.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Disfruta de la experiencia Vite\n    details: Inicio instantaneo de servidor, actualizaciones ultrarrápidas, y plugins del ecosistema Vite.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Personaliza con Vue\n    details: Usa la sintaxis y componentes Vue directamente en markdown, o construye temas personalizados con Vue.\n  - icon: 🚀\n    title: Entrega rápida de sitios\n    details: Carga inicial rápida con HTML estático, navegación rápida con enrutamiento del lado del cliente.\n---\n"
  },
  {
    "path": "docs/es/reference/cli.md",
    "content": "# Intefaz de Linea de Comando {#command-line-interface}\n\n## `vitepress dev`\n\n Inicia el servidor de desarrollo VitePress con el directorio designado como raíz. Por defecto, utiliza el director actual. el comando `dev` también se puede omitir cuando se ejecuta el directorio actual.\n\n### Uso\n\n```sh\n# Comienza en el directorio actual, omite el `dev`\nvitepress\n\n# iniciar en un subdirectorio\nvitepress dev [root]\n```\n\n### Opciones {#options}\n\n| Opciones        | Descripción                                                       |\n| --------------- | ----------------------------------------------------------------- |\n| `--open [path]` | Abre el navegador en el inicio (`boolean \\| string`)                     |\n| `--port <port>` | Especifica el puerto (`number`)                                           |\n| `--base <path>` | Ruta de base pública (por defecto: `/`) (`string`)                        |\n| `--cors`        | Habilitar CORS                                                       |\n| `--strictPort`  | Salir si el puerto especificado ya esta en uso (`boolean`)              |\n| `--force`       | Obligar al optimizador a ignorar el cache y volver a empaquetar (`boolean`) |\n\n## `vitepress build`\n\nCompilar el sitio web de VitePress para producción.\n\n### Uso\n\n```sh\nvitepress build [root]\n```\n\n### Opciones\n\n| Opción                         | Descripción                                                                                                         |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |\n| `--mpa` (experimental)         | Compilar en [Modo MPA](../guide/mpa-mode) Sin hidratación del lado del cliente  (`boolean`)                                    |\n| `--base <path>`                | Ruta de base pública (por defecto: `/`) (`string`)                                                                          |\n| `--target <target>`            | Transpilar objetivo (por defecto: `\"modules\"`) (`string`)                                                                  |\n| `--outDir <dir>`               | Directorio de salida relativo a **cwd** (por defecto: `<root>/.vitepress/dist`) (`string`)                                 |\n| `--assetsInlineLimit <number>` | Limitar los bytes para alinear los activos en base 64 (por defecto: `4096`) (`number`)                                      |\n\n## `vitepress preview`\n\nProporciona localmente la compilación de la producción.\n\n### Uso\n\n```sh\nvitepress preview [root]\n```\n\n### Opciones\n\n| Opción          | Descripción                                |\n| --------------- | ------------------------------------------ |\n| `--base <path>` | Ruta de base pública (por defecto: `/`) (`string`) |\n| `--port <port>` | Especifica el puerto (`number`)                    |\n\n## `vitepress init`\n\nInicia el [Asistente de Instalación](../guide/getting-started#setup-wizard) en el directorio actual.\n\n### Uso\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-badge.md",
    "content": "# Badge {#badge}\n\nLos Badge te permite agregar estados a tus encabezados. Por ejemplo, podría resultar útil especificar el tipo de sección o la version compatible.\n\n## Uso {#usage}\n\nPuedes usar el componente `Badge` que está disponible globalmente.\n\n```html\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n```\n\nel código anterior se representa como:\n\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n\n## Personalizar hijos {#custom-children}\n\n`<Badge>` acepta `children` (hijos), que se mostrará en el badge.\n\n```html\n### Title <Badge type=\"info\">custom element</Badge>\n```\n\n### Title <Badge type=\"info\">custom element</Badge>\n\n## Personalizar Tipo de Color {#customize-type-color}\n\nPuedes personalizar el estilo del badge anulando las variables CSS. los siguiente son los valores predeterminados:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\nEl componente `<Badge>` acepta las siguiente propiedades:\n\n```ts\ninterface Props {\n  // Cuando se pasa `<slot>` ese valor es ignorado.\n  text?: string\n\n  // El valor predeterminado es `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-carbon-ads.md",
    "content": "# Carbon Ads {#carbon-ads}\n\nVitePress ha incorporado soporte nativo para [Carbon Ads](https://www.carbonads.net/). Al definir las credenciales de Carbon Ads en la configuración, VitePress mostrará anuncios en la página.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'tu-código-carbon',\n      placement: 'tu-vinculación-carbon'\n    }\n  }\n}\n```\n\nEstos valores se utilizan para llamar al script en CDN de carbon como se muestra a continuación.\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nPara obtener más información de la configuración de Carbono Ads, por favor visite [Site Carbon Ads](https://www.carbonads.net/).\n"
  },
  {
    "path": "docs/es/reference/default-theme-config.md",
    "content": "# Configuración del Tema Predeterminado {#default-theme-config}\n\nLa configuración del tema te permite personalizar tu tema. puedes definir la configuración del tema a través de la opción `themeConfig` en el archivo de configuración:\n\n```ts\nexport default {\n  lang: 'pt-BR',\n  title: 'VitePress',\n  description: 'Generador de site estático Vite & Vue.',\n\n  // Configuraciones relacionadas con el tema.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**Las opciones documentadas de esta página se aplican unicamente al tema por defecto.** Diferentes temas esperan configuraciones diferentes de tema. Cuando se utiliza un tema personalizado, el objeto de configuración del tema se pasará al tema para que se puedan definir comportamientos condicionales.\n\n## i18nRouting\n\n- Tipo: `boolean`\n\nCambie la configuración a, por ejemplo, `zh` será alterado para URL `/foo` (ou `/en/foo/`) para `/zh/foo`. Puedes desactivar este comportamiento configurado `themeConfig.i18nRouting` como `false`.\n\n## logo\n\n- Tipo: `ThemeableImage`\n\nArchivo de logotipo que se mostrará en la barra de navegación, justo antes del título del sitio. Acepta una ruta de cadena o un objeto para definir un logotipo diferente para los modos claro/oscuro.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- Tipo: `string | false`\n\nPuedes personalizar este elemento para reemplazar el título del sitio predeterminado (`title` en configuración de la aplicación) en navegación. Cuando se establece como `false`, el título en la navegación quedará deshabilitado. Útil cuando tienes un `logo` que ya contiene el título del sitio.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hola mundo'\n  }\n}\n```\n\n## nav\n\n- Tipo: `NavItem`\n\nLa configuración del elemento del menú de navegación. Más detalles en [Tema Predeterminado: Navegación](./default-theme-nav#navigation-links).\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      {\n        text: 'Menú Dropdown',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- Tipo: `Sidebar`\n\nLa configuración del elemento del menú de la barra lateral. Más detalles en [Tema Predeterminado: Barra Lateral](./default-theme-sidebar).\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          { text: 'Introducción', link: '/introduction' },\n          { text: 'A partir de', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[]\n}\n\nexport type SidebarItem = {\n  /**\n   * El rotulo del item.\n   */\n  text?: string\n\n  /**\n   * El link del item.\n   */\n  link?: string\n\n  /**\n   * Los hijos del item.\n   */\n  items?: SidebarItem[]\n\n  /**\n   * Si no se especifica, el grupo no es retráctil.\n   *\n   * Si es 'true', el grupo se puede contraer y está contraído de forma predeterminada.\n   *\n   * Si es 'false', el grupo se puede contraer pero se expande de forma predeterminada.\n   */\n  collapsed?: boolean\n}\n```\n\n## aside\n\n- Tipo: `boolean | 'left'`\n- Estandar: `true`\n- Puede ser anulado por la página a través de [frontmatter](./frontmatter-config#aside)\n\nDefinir este valor como `false` evita que se muestre el elemento lateral.\\\nDefinir este valor como `true` presenta el lado de la derecha.\\\nDefinir este valor como `left` presenta el lado de la izquierda.\n\nSi desea deshabilitarlo para todas las vistas, debe usar `outline: false` en vez de eso.\n\n## outline\n\n- Tipo: `Outline | Outline['level'] | false`\n- El nivel se puede superponer por página mediante [frontmatter](./frontmatter-config#outline)\n\nDefinir este valor como `false` evita que el elemento se muestre _outline_. Consulte la interfaz para más detalles:\n\n```ts\ninterface Outline {\n  /**\n   * Los niveles de título que se mostrarán en el esquema.\n   * Un solo número significa que solo se mostrarán los títulos de ese nivel.\n   * Si se pasa una tupla, el primer número es el nivel mínimo y el segundo número es el nivel máximo.\n   * `'deep'` es lo mismo que `[2, 6]`, lo que significa que todos los titulos `<h2>` a `<h6>` serán mostrados.\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * El titulo que se mostrará en el equema.\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- Tipo: `SocialLink[]`\n\nPuedes configurar esta opción para mostrar enlaces de redes sociales con íconos en la navegación.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // También puedes agregar íconos personalizados pasando SVG como string:\n       {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // También puedes incluir una etiqueta personalizada de accesibilidad (opcional pero recomendada):\n        ariaLabel: 'cool link'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- Tipo: `Footer`\n- Se puede superponer por página mediante [frontmatter](./frontmatter-config#footer)\n\nConfiguración de pie de página. Puede agregar un mensaje o texto de derechos de autor en el pie de página; sin embargo, solo se mostrará cuando la página no contenga una barra lateral. Esto se debe a preocupaciones de diseño.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Publicado bajo la licencia MIT.',\n      copyright: 'Derechos de autor © 2019-presente Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- Tipo: `EditLink`\n- Se puede superponer por página mediante [frontmatter](./frontmatter-config#editlink)\n\n_EditLink_ le permite mostrar un enlace para editar la página en los servicios de administración Git, como GitHub o GitLab. Consulte [Tema por defecto: Editar Link](./default-theme-edit-link) para más detalles.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Editar esta página en GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- Tipo: `LastUpdatedOptions`\n\nPermite la personalización del formato de fecha y texto actualizado por ultima vez.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Actualizado en',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- Tipo: `AlgoliaSearch`\n\nUna opción para dar soporte para buscar en su sitio de documentación usando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Obtenga más información en [Tema predeterminado: Buscar](./default-theme-search).\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\nVer todas las opciones [aquí](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts).\n\n## carbonAds {#carbon-ads}\n\n- Tipo: `CarbonAdsOptions`\n\nUna opción para mostrar [Carbon Ads](https://www.carbonads.net/).\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'su-código-carbon',\n      placement: 'su-colocación-carbon'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\nObtenga más información en [Tema Predeterminado: Carbon Ads](./default-theme-carbon-ads).\n\n## docFooter\n\n- Tipo: `DocFooter`\n\nSe puede utilizar para personalizar el texto que aparece encima de los enlaces anterior y siguiente. Útil si no estás escribiendo documentación en inglés. También se puede utilizar para desactivar globalmente los enlaces anteriores/siguientes. Si desea habilitar/deshabilitar selectivamente enlaces anteriores/siguientes, puede usar [frontmatter](./default-theme-prev-next-links).\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Página anterior',\n      next: 'Próxima página'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- Tipo: `string`\n- Estandar: `Appearance`\n\nSe puede utilizar para personalizar la etiqueta del botón del modo oscuro. Esta etiqueta solo se muestra en la vista móvil.\n\n## lightModeSwitchTitle\n\n- Tipo: `string`\n- Estandar: `Switch to light theme`\n\nSe puede utilizar para personalizar el título del botón borrar que aparece al pasar el mouse.\n\n## darkModeSwitchTitle\n\n- Tipo: `string`\n- Estandar: `Switch to dark theme`\n\nSe puede utilizar para personalizar el título del botón del modo oscuro que aparece al pasar el mouse.\n\n## sidebarMenuLabel\n\n- Tipo: `string`\n- Estandar: `Menu`\n\nSe puede utilizar para personalizar la etiqueta del menú de la barra lateral. Esta etiqueta solo se muestra en la vista móvil.\n\n## returnToTopLabel\n\n- Tipo: `string`\n- Estandar: `Return to top`\n\nSe puede utilizar para personalizar la etiqueta del botón Volver al principio. Esta etiqueta solo se muestra en la vista móvil.\n\n## langMenuLabel\n\n- Tipo: `string`\n- Estandar: `Change language`\n\nSe puede utilizar para personalizar la etiqueta aria del botón de idioma en la barra de navegación. Esto sólo se usa si estás usando [i18n](../guide/i18n).\n\n## externalLinkIcon\n\n- Tipo: `boolean`\n- Estandar: `false`\n\nSe debe mostrar um ícono de link externo junto a los enlaces externos en markdown.\n"
  },
  {
    "path": "docs/es/reference/default-theme-edit-link.md",
    "content": "# Editar Link {#edit-link}\n\n## Configuración a nivel de sitio {#site-level-config}\n\nEditar enlace le permite mostrar un enlace para editar la página con servicios de administración de Git como GitHub o GitLab. Para habilitar, agregue la opción `themeConfig.editLink` en su configuración.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\nLa opción `pattern` define una estructura de URL para el enlace, y `:path` se reemplaza con la misma ruta de la página\n\nTambién puedes poner una función pura que acepte [`PageData`](./runtime-api#usedata) como argumento y retorna una URL en string.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nEsto no debería generar efectos secundarios ni acceder a nada fuera de su alcance, ya que será serializado y ejecutado en el navegador.\n\nDe forma predeterminada, esto agregará el enlace con el texto 'Editar esta página' al final de la página de documentación. Puedes personalizar este texto configurando la opción `text`.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edite la página en GitHub'\n    }\n  }\n}\n```\n\n## Configuración Frontmatter {#frontmatter-config}\n\nLa funcionalidad se puede desactivar por página utilizando la opción `editLink` en frontmatter:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-footer.md",
    "content": "# Pie de página {#footer}\n\nVitePress mostrará un pie de página global en la parte inferior de la página cuando `themeConfig.footer` está presente.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Publicado bajo la licencia MIT.',\n      copyright: 'Derechos de autor © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // El mensaje mostrado justo antes del copyright.\n  message?: string\n\n  // El texto real de copyright.\n  copyright?: string\n}\n```\n\nLa configuración anterior también admite cadenas HTML. Entonces, por ejemplo, si desea configurar el texto de su pie de página para que tenga algunos enlaces, puede ajustar la configuración de la siguiente manera:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Publicado bajo <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">Licencia MIT</a>.',\n      copyright: 'Derechos de autor © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning\nSolo se utilizan elementos _inline_ será utilizado en `message` y `copyright` tal como se presenta dentro del elemento  `<p>`. Si desea agregar elementos de tipo _block_, considere usar un _slot_ [`layout-bottom`](../guide/extending-default-theme#layout-slots).\n:::\n\nTenga en cuenta que el pie de página no se mostrará cuando la [Barra Lateral](./default-theme-sidebar) es visible.\n\n## Configuración Frontmatter {#frontmatter-config}\n\nEsto se puede desactivar por página usando la opción `footer` en frontmatter:\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-home-page.md",
    "content": "# Página Inicial {#home-page}\n\nEl tema predeterminado de VitePress proporciona un diseño de página de inicio, que también puedes ver en uso [en la página de inicio de este sitio web](../). Puedes usarlo en cualquiera de sus páginas especificando `layout: home` en [frontmatter](./frontmatter-config).\n\n```yaml\n---\nlayout: home\n---\n```\n\nSin embargo, esta opción por sí sola no sirve de mucho. Puede agregar varias \"secciones\" predefinidas diferentes a la página de inicio configurando opciones adicionales como `hero` y `features`.\n\n## Sección Hero {#hero-section}\n\nLa sección _Hero_ queda en la parte superior de la página de inicio. Asi es como se puede configurar la sección _Hero_.\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Generador de sitios web estáticos con Vite & Vue.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: Iniciar\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: Ver en GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // El string que se muestra encima del `text`. Viene con el color de la marca\n  // y se espera que sea breve, como el nombre del producto.\n  name?: string\n\n  // El texto principal de la sección de hero.\n  // Esto se definirá como un tag `h1`.\n  text: string\n\n  // Eslogan que se muestra abajo del `text`.\n  tagline?: string\n\n  // La imagen se muestra junto al área de texto y eslogan.\n  image?: ThemeableImage\n\n  // Botones accionables para mostrar en la sección principal de la página de inicio.\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // Tema de color de botón. Estándar: `brand`.\n  theme?: 'brand' | 'alt'\n\n  // Etiqueta del botón.\n  text: string\n\n  // Destino del enlace del botón.\n  link: string\n\n  // Atributo target del link.\n  target?: string\n\n  // Atributo rel del link.\n  rel?: string\n}\n```\n\n### Personalizando el color del nombre {#customizing-the-name-color}\n\nVitePress usa el color de la marca (`--vp-c-brand-1`) para `name`. Sin embargo, puedes personalizar este color anulando la variable `--vp-home-hero-name-color`.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nTambién puedes personalizarlo aún más combinando  `--vp-home-hero-name-background` para dar al `name` un color degradado.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## Sección de caracteristicas {#features-section}\n\nEn la sección de funciones, puede enumerar cualquier cantidad de funciones que desee mostrar inmediatamente después de la sección. _Hero_. Para configurarlo seleccione la opción `features` para el frontmatter.\n\nPuede proporcionar un icono para cada función, que puede ser un emoji o cualquier tipo de imagen. Cuando el icono configurado es una imagen (svg, png, jpeg...), debes proporcionar al ícono el ancho y alto apropiados; También puedes proporcionar la descripción, su tamaño intrínseco y sus variantes para temas oscuros y claros cuando sea necesario.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Sencillo y minimalista, siempre\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Otra caracteristica interesante\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Otra caracteristica interesante\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // Muestra el icono en cada cuadro de función.\n  icon?: FeatureIcon\n\n  // Título de la caracteristica.\n  title: string\n\n  // Detalles de la caracteristicas.\n  details: string\n\n  // Enlace al hacer clic en el componente de funcionalidad\n  // El vínculo puede ser interno o externo.\n  //\n  // ej. `guide/reference/default-theme-home-page` ou `https://example.com`\n  link?: string\n\n  // Texto del enlace que se mostrará dentro del componente de funcionalidad.\n  //  Mejor usado con opción `link`.\n  //\n  // ej. `Sepa más`, `Visitar página`, etc.\n  linkText?: string\n\n  // Atributo rel de enlace para la opción `link`.\n  //\n  // ej. `external`\n  rel?: string\n\n  // Atributo de destino del enlace para la opción `link`.\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-last-updated.md",
    "content": "# Última Actualización {#last-updated}\n\nLa hora en que se actualizó el contenido por última vez se mostrará en la esquina inferior derecha de la página. Para habilitar, agregue la opción `lastUpdated` en su confirguración.\n\n::: tip\nNecesitas hacer un _commit_ en el archivo markdown para ver el clima actualizado.\n:::\n\n## Configuración a nivel de sitio {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## Configuración Frontmatter {#frontmatter-config}\n\nEsto se puede desactivar por página usando la opción `lastUpdated` en frontmatter:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nConsulte [Tema Personalizado: Última Actualización](./default-theme-config#lastupdated) para obtener más. Cualquier valor positivo a nivel de tema también habilitará la funcionalidad a menos que esté explícitamente deshabilitado a nivel de página o sitio.\n"
  },
  {
    "path": "docs/es/reference/default-theme-layout.md",
    "content": "# Layout {#layout}\n\nPuedes elegir el layout de la página definiendo una opción de `layout` para el [frontmatter](./frontmatter-config) De la página. Hay tres opciones de layout: `doc`, `page` y `home`. Si no se especifica nada, la página será tratada como una página. `doc`.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## Layout del documento {#doc-layout}\n\nLa opción `doc` es el layout predeterminado y aplica estilo a todo el contenido de Markdown el aspecto de \"documentación\". Funciona agrupando todo el contenido en la clase CSS `vp-doc`, y aplicando estilos a los elementos debajo de ella.\n\nCasi todos los elementos genéricos como `p` o `h2`, recibirá un estilo especial. Por tanto, recuerda que si añades algún HTML contenido personalizado dentro del contenido Markdown, también se verá afectado por estos estilos.\n\nTambién proporciona recursos de documentación específicos que se enumeran a continuación. Estas funciones solo están habilitadas en este layout.\n\n- Editar link\n- Links Anterior y próximo.\n- _Outline_\n- [Carbon Ads](./default-theme-carbon-ads)\n\n## Layout de la Página {#page-layout}\n\nLa opción `page` se trata como una 'página en blanco'. Markdown aún se procesará y todo [Extensiones Markdown](../guide/markdown) funcionará de la misma manera que el layout `doc`, pero esto no recibirá ningún estilo predeterminado.\n\nEl layout de la página le permitirá diseñar todo sin que el tema de VitePress afecte el marcado. Esto es útil cuando desea crear su propia página personalizada.\n\nTenga en cuenta que incluso en este mismo layout, la barra lateral seguirá apareciendo si la página tiene una configuración de barra lateral correspondiente.\n\n## Layout de Home {#home-layout}\n\nLa opción `home` gerará un modelo de _\"Homepage\"_. En este layout podrás definir opciones extras, como `hero` y `features`, para personalizar todavá más el contenido. Visite [Tema predeterminado: Página Inicial](./default-theme-home-page)  para obter más detalles.\n\n## Sin Layout {#no-layout}\n\nSi no quieres ningún diseño, puedes pasar `layout: false` a través del frontmatter. Esta opción es útil si deseas una página de destino completamente personalizable (sin barra lateral, barra de navegacón o pie de página por defecto).\n\n## Layout Personalizado {#custom-layout}\n\nTambién puedes usar un layout personalizado:\n\n```md\n---\nlayout: foo\n---\n```\n\nEsto buscará un componente llamado `foo` registrado en contexto. Por ejemplo, puede registrar su componente globalmente en `.vitepress/theme/index.ts`:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-nav.md",
    "content": "# Navegación {#nav}\n\nRefiriéndose a la barra de navegación que se muestra en la parte superior de la página. Contiene el título del sitio, enlaces del menú global, etc.\n\n## Título y logotipo del sitio {#site-title-and-logo}\n\nPor defecto, la navegación muestra el título del sitio que hace referencia al valor de [`config.title`](./site-config#title). Si desea cambiar lo que se muestra en la navegación, puede configurar un texto personalizado en el `themeConfig.siteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'Mi Título Personalizado'\n  }\n}\n```\n\nSi tiene un logotipo para su sitio web, puede mostrarlo pasando la ruta a la imagen. Debes colocar el logo directamente dentro de la carpeta. `public`, y establezca la ruta absoluta hacia él.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nCuando agrega un logotipo, se muestra junto con el título del sitio. Si su logotipo tiene todo lo que necesita y desea ocultar el texto del título, configure `false` en la opción `siteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nTambién puedes pasar un objeto como logotipo si quieres agregar un atributo. `alt` o personalizarlo según el modo claro/oscuro. Consultar [`themeConfig.logo`](./default-theme-config#logo) para obtener más detalles.\n\n## Links de Navegación {#navigation-links}\n\nPuedes configurar la opción `themeConfig.nav` para añadir enlaces a tu navegación.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      { text: 'Configuración', link: '/config' },\n      { text: 'Registro de Cambios', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` es el texto que se muestra en la navegación, y el `link` es el link al que será navegando cuando se hace click en el texto. Para el enlace, establezca la ruta al archivo sin el prefijo `.md` y siempre comenzar por `/`.\n\nEl `link` también puede ser una función que acepte [`PageData`](./runtime-api#usedata) como argumento y devuelva la ruta.\n\nLinks de navegación también pueden ser menus _dropdown_. Para hacer eso, establezca la clave de `items` en la opción del link.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      {\n        text: 'Menú Dropdown',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nTenga en cuenta que el titulo del menú _dropdown_ (`Menu Dropdown` en el ejemplo anterior) no puede tener una propiedad `link`, ya que se convierte en un botón para abrir el cuadro del dialogo dropdown.\n\nTambién puedes agregar \"secciones\" a los elementos del menú _dropdown_ pasando más elementos anidados.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guia' },\n      {\n        text: 'Menú Dropdown',\n        items: [\n          {\n            // Título da seção.\n            text: 'Título de la sección A',\n            items: [\n              { text: 'Item A de la sección A', link: '...' },\n              { text: 'Item B de la sección B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Menú Dropdown',\n        items: [\n          {\n            // También puedes omitir el título\n            items: [\n              { text: 'Item A da Seção A', link: '...' },\n              { text: 'Item B da Seção B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Personaliza el estado \"activo\" del link {#customize-link-s-active-state}\n\nLos elementos del menú de navegación se resaltarán cuando la página actual esté en la ruta correspondiente. Si desea personalizar la ruta que debe coincidir, establezca la propiedad `activeMatch` el regex como um valor en string.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // Este link esta en estado activo cuando\n      // el usuario esta en el camino `/config/`.\n      {\n        text: 'Guia',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch` Debería ser un string regex, pero deberías definirla como un string. No podemos usar un objeto RegExp real aquí porque no es serializable durante el tiempo de construcción.\n:::\n\n### Personalizar los atributos \"target\" y \"rel\" de links {#customize-link-s-target-and-rel-attributes}\n\nPor defecto, VitePress determina automáticamente lod atributos `target` y `rel` en función de si existe un enlace externo o no. Pero si quieres, también puedes personalizarlos.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Merchandise',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## Links Scociales {#social-links}\n\nConsulte [`socialLinks`](./default-theme-config#sociallinks).\n"
  },
  {
    "path": "docs/es/reference/default-theme-prev-next-links.md",
    "content": "# Links Anterior y Próximo {#prev-next-links}\n\nPuede personalizar el texto y el enlace de los botones Anterior y Siguiente que se muestran en la parte inferior de la página. Esto es útil cuando desea mostrar un texto diferente al que tiene en la barra lateral. Además, puede resultarle útil desactivar el pie de página o el enlace a la página para que no se incluya en la barra lateral.\n\n## prev\n\n- Tipo: `string | false | { text?: string; link?: string }`\n\n- Detalles:\n\n  Especifica el text/enlace que se mostrará en el enlace a la página anterior. Si no ve esto al principio, el text/enlace se deducirá de la configuración de la barra lateral.\n\n- Ejemplos:\n\n  - Para personalizar solo texto:\n\n    ```yaml\n    ---\n    prev: 'Iniciar | Markdown'\n    ---\n    ```\n\n  - Para personalizar ambos texto y link:\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - Para esconder la página anterior:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\nIgual que el `prev` pero para la página siguiente.\n"
  },
  {
    "path": "docs/es/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# Buscar {#search}\n\n## Busqueda local {#local-search}\n\nVitePress admite la búsqueda de texto completo utilizando un índice en el navegador gracias a [minisearch](https://github.com/lucaong/minisearch/). Para habilitar esta función, simplemente configure la opción `themeConfig.search.provider` como `'local'` en el archivo `.vitepress/config.ts`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\nResultado de ejemplo:\n\n![captura de pantalla del modo de búsqueda](/search.png)\n\nAlternativamente, puedes usar [Algolia DocSearch](#algolia-search) o algunos complementos comunitarios como <https://www.npmjs.com/package/vitepress-plugin-search> o <https://www.npmjs.com/package/vitepress-plugin-pagefind>.\n\n### i18n {#local-search-i18n}\n\nPuede utilizar una configuración como esta para utilizar la búsqueda multilingüe:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          es: { // usa `root` si quieres traducir la configuración regional predeterminada\n            translations: {\n              button: {\n                buttonText: 'Buscar',\n                buttonAriaLabel: 'Buscar'\n              },\n              modal: {\n                displayDetails: 'Mostrar lista detallada',\n                resetButtonTitle: 'Restablecer búsqueda',\n                backButtonTitle: 'Cerrar búsqueda',\n                noResultsText: 'No hay resultados',\n                footer: {\n                  selectText: 'Seleccionar',\n                  selectKeyAriaLabel: 'Intro',\n                  navigateText: 'Navegar',\n                  navigateUpKeyAriaLabel: 'Flecha arriba',\n                  navigateDownKeyAriaLabel: 'Flecha abajo',\n                  closeText: 'Cerrar',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### Opciones MiniSearch {#minisearch-options}\n\nPuedes configurar MiniSearch de esta manera:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nObtenga más información en [documentación de MiniSearch](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).\n\n### Presentador de contenido personalizado {#custom-content-renderer}\n\nPuedes personalizar la función utilizada para presentar el contenido de rebajas antes de indexarlo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // devuelve una cadena HTML\n        }\n      }\n    }\n  }\n})\n```\n\nEsta función se eliminará de los datos del sitio web en el lado del cliente, por lo que podrá utilizar las API de Node.js en ella.\n\n#### Ejemplo: Excluir páginas de la busqueda {#example-excluding-pages-from-search}\n\nPuedes excluir páginas de la busqueda adicionando `search: false` al principio de la página. Alternativamente:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Nota\nEn este caso, una función `_render` se proporciona, es necesario manipular el `search: false` desde el frente por su cuenta. Además, el objeto `env` no estará completamente poblado antes que `md.renderAsync` se llama, luego verifica las propiedades opcionales `env`, como `frontmatter`, debe hacerse después de eso.\n:::\n\n#### Ejemplo: Transformar contenido - agregar anclajes {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Busqueda de Algolia {#algolia-search}\n\nVitePress admite la búsqueda en su sitio de documentación utilizando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Consulte su guía de introducción. en tu archivo `.vitepress/config.ts`, Deberá proporcionar al menos lo siguiente para que funcione:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\nPuedes utilizar una configuración como esta para utilizar la búsqueda multilingüe:\n\n<details>\n<summary>Haz clic para expandir</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\nConsulta la [documentación oficial de Algolia](https://docsearch.algolia.com/docs/api#translations) para conocer más detalles. Para empezar rápidamente, también puedes copiar las traducciones usadas por este sitio desde [nuestro repositorio de GitHub](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code).\n\n### Algolia Ask AI Support {#ask-ai}\n\nSi deseas incluir **Ask AI**, pasa la opción `askAi` (o alguno de sus campos parciales) dentro de `options`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"TU-ID-DE-ASISTENTE\"\n        // O\n        askAi: {\n          // como mínimo debes proporcionar el assistantId que recibiste de Algolia\n          assistantId: 'XXXYYY',\n          // anulaciones opcionales — si se omiten, se reutilizan los valores appId/apiKey/indexName de nivel superior\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Nota\nSi prefieres solo la búsqueda por palabra clave y no la Ask AI, simplemente omite `askAi`.\n:::\n\n### Panel lateral de Ask AI {#ask-ai-side-panel}\n\nDocSearch v4.5+ admite un **panel lateral de Ask AI** opcional. Cuando está habilitado, se puede abrir con **Ctrl/Cmd+I** por defecto. La [Referencia de API del Panel Lateral](https://docsearch.algolia.com/docs/sidepanel/api-reference) contiene la lista completa de opciones.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // Refleja la API de @docsearch/sidepanel-js SidepanelProps\n            panel: {\n              variant: 'floating', // o 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nSi necesitas deshabilitar el atajo de teclado, usa la opción `keyboardShortcuts` del panel lateral:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### Modo (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nPuedes controlar opcionalmente cómo VitePress integra la búsqueda por palabra clave y Ask AI:\n\n- `mode: 'auto'` (por defecto): infiere `hybrid` cuando la búsqueda por palabra clave está configurada, de lo contrario `sidePanel` cuando el panel lateral de Ask AI está configurado.\n- `mode: 'sidePanel'`: fuerza solo el panel lateral (oculta el botón de búsqueda por palabra clave).\n- `mode: 'hybrid'`: habilita el modal de búsqueda por palabra clave + panel lateral de Ask AI (requiere configuración de búsqueda por palabra clave).\n- `mode: 'modal'`: mantiene Ask AI dentro del modal de DocSearch (incluso si configuraste el panel lateral).\n\n#### Solo Ask AI (sin búsqueda por palabra clave) {#ask-ai-only}\n\nSi quieres usar **solo el panel lateral de Ask AI**, puedes omitir la configuración de búsqueda por palabra clave de nivel superior y proporcionar las credenciales bajo `askAi`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### Configuración _Crawler_ {#crawler-config}\n\nA continuación se muestra un ejemplo de la configuración que utiliza este sitio:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/es/reference/default-theme-sidebar.md",
    "content": "# Barra Lateral {#sidebar}\n\nLa barra lateral es el bloque de navegación principal de su documentación. Puede configurar el menú de la barra lateral en [`themeConfig.sidebar`](./default-theme-config#sidebar).\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          { text: 'Introducción', link: '/introduction' },\n          { text: 'Iniciando', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Conceptos básicos {#the-basics}\n\nLa forma más sencilla del menú de la barra lateral es pasar una único _array_ de links. El elemento de primer nivel define la \"sección\" de la barra latera. debe contener `text`, cuál es el título de la sección, y `items` que son los propios enlaces de navegación.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título de la sección A',\n        items: [\n          { text: 'Item A', link: '/item-a' },\n          { text: 'Item B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Título de la sección B',\n        items: [\n          { text: 'Item C', link: '/item-c' },\n          { text: 'Item D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\nCada `link` debe especificar la ruta al archivo en sí comenzando con `/`.\nSi agrega una barra al final del enlace, mostrará el `index.md` del directorio correspondiente.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          // Esto muestra la página `/guide/index.md`.\n          { text: 'Introducción', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nPuede anidar aún más elementos de la barra lateral hasta 6 niveles de profundidad contando desde el nivel raíz. Tenga en cuenta que los niveles superiores a 6 se ignorarán y no se mostrarán en la barra lateral.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Nivel 1',\n        items: [\n          {\n            text: 'Nivel 2',\n            items: [\n              {\n                text: 'Nivel 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Varias Barras Laterales {#multiple-sidebars}\n\nPuedes mostrar una barra lateral diferente según la ruta de la página. Por ejemplo, como se muestra en este sitio, es posible que desee crear secciones separadas de contenido en su documentación, como la página \"Guía\" y la página \"Configuración\".\n\nPara hacer esto, primero organice sus páginas en directorios para cada sección deseada:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nLuego actualice su configuración para definir su barra lateral para cada sección. Esta vez debes pasar un objeto en lugar de un array.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // Esta barra lateral se muestra cuando un usuario\n      // está en el directorio `guide`.\n      '/guide/': [\n        {\n          text: 'Guia',\n          items: [\n            { text: 'Índice', link: '/guide/' },\n            { text: 'Um', link: '/guide/one' },\n            { text: 'Dois', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // Esta barra lateral se muestra cuando un usuario\n      // está en el directorio `config`.\n      '/config/': [\n        {\n          text: 'Configuración',\n          items: [\n            { text: 'Índice', link: '/config/' },\n            { text: 'Tres', link: '/config/three' },\n            { text: 'Cuatro', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## Grupos Retráctiles en la Barra Lateral {#collapsible-sidebar-groups}\n\nAdicionando una opción `collapsed` al grupo de la barra lateral, muestra un botón para ocultar/mostrar cada sección\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título de la sección A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\nTodas las secciones están 'abiertas' de forma predeterminada. Si desea que estén 'cerrados' al cargar la página inicial, configure la opción `collapsed` como `true`.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título de la sección A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/es/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Criador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Desenvolvedor',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# Página de Equipo {#team-page}\n\nSi deseas presentar a tu equipo, puedes utilizar componentes del equipo para crear la página del equipo. Hay dos formas de utilizar estos componentes. Una es incrustarlo en la página del documento y otra es crear una página de equipo completa.\n\n## Mostrar miembros del equipo en una página {#show-team-members-in-a-page}\n\nPuedes usar el componente `<VPTeamMembers>` expuesto en `vitepress/theme` para mostrar una lista de los miembros del equipo en cualquier página.\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# Nuestro equipo\n\nSaluda a nuestro increible equipo.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\nEl código anterior mostrará a un miembro del equipo en un elemento similar a una tarjeta. Debería mostrar algo similar a lo siguiente.\n\n<VPTeamMembers size=\"small\" :members />\n\nEl componente `<VPTeamMembers>` viene en dos tamaños diferentes, pequeño `small` y médio `medium`. Si bien es una cuestión de preferencia, generalmente el tamaño `small` debería encajar mejor cuando se use en la página del documento. Además, puede agregar más propiedades a cada miembro, como agregar el botón \"descripción\" o \"patrocinador\". Obtenga más información sobre en [`<VPTeamMembers>`](#vpteammembers).\n\nIncrustar miembros del equipo en la página del documento es bueno para equipos pequeños donde tener una página de equipo dedicada completa puede ser demasiado, o introducir miembros parciales como referencia al contexto de la documentación.\n\nSi tienes una gran cantidad de miembros o simplemente deseas más espacio para exhibir a los miembros del equipo, considere [crear una página de equipo completa.](#create-a-full-team-page)\n\n## Creando una página de equipo completa {#create-a-full-team-page}\n\nEn lugar de agregar miembros del equipo a la página del documento, también puede crear una página de equipo completa, del mismo modo que puede crear una [Página Inicial](./default-theme-home-page) personalizada.\n\nPara crear una página de equipo, primero cree un nuevo md. El nombre del archivo no importa, pero aquí lo llamaremos `team.md`. En este archivo, configure la opción `layout: page` desde frontmatter,  y luego puedes componer la estructura de tu página usando componentes `TeamPage`.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Nuestro equipo\n    </template>\n    <template #lead>\n      El desarrollo de VitePress está guiado por un equipo internacional,\n      Algunos de los miembros han elegido aparecer a continuación.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\nAl crear una página de equipo completa, recuerde agrupar todos los componentes con el componente `<VPTeamPage>`. Este componente garantizará que todos los componentes anidados relacionados con el equipo obtengan la estructura de diseño adecuada, como los espacios.\n\nEl componente `<VPPageTitle>` adiciona la sección de título de la página. El título es `<h1>`. Use los _slots_ `#title` y `#lead` para poder documentar sobre su equipo.\n\n`<VPMembers>` funciona igual que cuando se usa en una página de documento. Mostrará la lista de miembros.\n\n### Agregar secciones para dividir a los miembros del equipo {#add-sections-to-divide-team-members}\n\nPuede agregar \"secciones\" a la página de su equipo. Por ejemplo, puede tener diferentes tipos de miembros del equipo, como miembros del equipo central y socios de la comunidad. Puede dividir a estos miembros en secciones para explicar mejor las funciones de cada grupo.\n\nPara poder hacerlo, agregue al componente `<VPTeamPageSection>` al archivo `team.md` que creamos anteriormente.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Nuestro equipo</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Amigos</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\nEl componente `<VPTeamPageSection>` Puede tener los _slots_ `#title` y `#lead` similares al componente `VPTeamPageTitle`, y también al _slot_ `#members` para mostrar a los miembros del equipo.\n\nRecuerde colocar el componente `<VPTeamMembers>` dentro del _slot_ `#members`.\n\n## `<VPTeamMembers>`\n\nEl componente `<VPTeamMembers>` muestra una determinada lista de miembros.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // Tamaño de cada miembro. El valor predeterminado es `medium`.\n  size?: 'small' | 'medium'\n\n  //  Lista de miembros que se mostrará.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // Imagen de avatar de miembro.\n  avatar: string\n\n  // Nombre del miembro.\n  name: string\n\n  // Título a ser mostrado a bajo del nombre del miembro.\n  // Ej.: Desarrollador, Ingeniero de Software, etc.\n  title?: string\n\n  // Organización a la que pertenece al miembro.\n  org?: string\n\n  // URL de la organización.\n  orgLink?: string\n\n  // Descripción del miembro.\n  desc?: string\n\n  // Links sociales, por ejemplo, GitHub, Twitter, etc.\n  // Puedes pasar un objeto de Links Sociales aquí.\n  // Vea: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // URL de la página del patrocinador del miembro.\n  sponsor?: string\n\n  // Texto para enlace del patrocinador. El valor predeterminado es 'Sponsor'.\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\nEl componente raíz al crear una página de equipo completa. Sólo acepta una _slot_. Aplicará estilo a todos los componentes anteriores relacionados con el equipo.\n\n## `<VPTeamPageTitle>`\n\nAgrega la sección \"título\" a la página. Es mejor usarlo desde el principio debajo `<VPTeamPage>`. Acepta los _slots_ `#title` y `#lead`.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Nuestro equipo\n    </template>\n    <template #lead>\n      El desarrollo de VitePress está guiado por un equipo internacional,\n      Algunos de los miembros han elegido aparecer a continuación.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\nCrea una 'sección' en la página del equipo. Aceptar los _slots_ `#title`, `#lead` y `#members`. Puedes agregar tantas secciones como quieras dentro `<VPTeamPage>`.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Amigos</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/es/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# Configuración Frontmatter {#frontmatter-config}\n\nFrontmatter permite la configuración basada en páginas. En cada archivo markdown, puede utilizar la configuración de frontmatter para anular las opciones de configuración a nivel de sitio o tema. Además, hay opciones de configuración que sólo se pueden establecer en frontmatter.\n\nEjemplo de uso:\n\n```md\n---\ntitle: Documentación con VitePress\neditLink: true\n---\n```\n\nPuede acceder a los datos del frontmatter a través de la variable global `$frontmatter` en expresiones Vue:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- Tipo: `string`\n\nTítulo de la página. Es lo mismo que [config.title](./site-config#title), y anula la configuración a nivel de sitio.\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- Tipo: `string | boolean`\n\nEl sufijo del título. Es lo mismo que [config.titleTemplate](./site-config#titletemplate), y anula la configuración a nivel de sitio.\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Generador de sitios web estáticos con Vite & Vue\n---\n```\n\n## descripción\n\n- Tipo: `string`\n\nDescripción de la página. Es lo mismo que [config.description](./site-config#description), y anula la configuración a nivel de sitio.\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- Tipo: `HeadConfig[]`\n\nEspecifica etiquetas de encabezado adicionales que se inyectarán en la página actual. Se agregarán después de las etiquetas principales inyectadas por la configuración a nivel de sitio.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## Solo Tema Predeterminado {#default-theme-only}\n\nLas siguientes opciones de frontmatter solo se aplican cuando se usa el tema predeterminado.\n\n### layout\n\n- Tipo: `doc | home | page`\n- Predeterminado: `doc`\n\nDetermina el layout de la página.\n\n- `doc` - Aplica estilos de documentación por defecto al contenido markdown.\n- `home` - Layout especial para la \"Página Inicial\". Puedes agregar opciones extras como `hero` y `features` para crear rapidamente una hermosa página inicial.\n- `page` - Se comporta de manera similar a `doc`, pero no aplica estilos al contenido. Útil cuando desea crear una página totalmente personalizada.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"apenas para página inicial\" />\n\nDefine el contenido de la sección _hero_ en la página inicial cuando `layout` está definido como `home`. Más detalles en [Tema Predeterminado: Página Inicial](./default-theme-home-page).\n\n### features <Badge type=\"info\" text=\"apenas para página inicial\" />\n\nDefine los elementos que se mostrarán en la sección de características cuando `layout` está definido como `home`. Más detalles en [Tema Predeterminado: Página Inicial](./default-theme-home-page).\n\n### navbar\n\n- Tipo: `boolean`\n- Predeterminado: `true`\n\nSe debe mostrar una [barra de navegación](./default-theme-nav).\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- Tipo: `boolean`\n- Predeterminado: `true`\n\nSe debe mostrar una [barra lateral](./default-theme-sidebar).\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- Tipo: `boolean | 'left'`\n- Predeterminado: `true`\n\nDefine la localización del componente aside en el layout `doc`.\n\nConfigurar este valor como `false` evita que se muestre el elemento lateral.\\\nConfigurar este valor como `true` presenta el lado de la derecha.\\\nConfigurar este valor como `'left'` presenta el lado de la izquierda.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- Tipo: `number | [number, number] | 'deep' | false`\n- Predeterminado: `2`\n\nLos niveles del encabezado en _outline_ que se mostrará para la página. Es lo mismo que [config.themeConfig.outline.level](./default-theme-config#outline), y anula el valor establecido en la configuración a nivel de sitio.\n\n### lastUpdated\n\n- Tipo: `boolean | Date`\n- Predeterminado: `true`\n\nSe debe mostrar el texto de [última actualización](./default-theme-last-updated) en el pie de página de la página actual. Si se especifica una fecha y hora específicas, se mostrarán en lugar de la hora de la última modificación de git.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- Tipo: `boolean`\n- Predeterminado: `true`\n\nSe debe mostrar el [link de edición](./default-theme-edit-link) en el pie de página de la página actual.\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- Tipo: `boolean`\n- Predeterminado: `true`\n\nSe debe mostrar el [pie de página](./default-theme-footer).\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- Tipo: `string`\n\nAgrega un nombre de clase adicional a una página específica.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nLuego puede personalizar los estilos para esta página específica en el archivo. `.vitepress/theme/custom.css`:\n\n```css\n.custom-page-class {\n  /* estilos especificos de la página */\n}\n```\n"
  },
  {
    "path": "docs/es/reference/runtime-api.md",
    "content": "# API en Tiempo de Ejecución {#runtime-api}\n\nVitePress ofrece varias API integradas para permitir el acceso a los datos de la aplicación. VitePress también viene con algunos componentes integrados que se pueden utilizar globalmente.\n\nLos métodos auxiliares son importaciones globales de `vitepress` y se utilizan a menudo en componentes Vue de temas personalizados. Sin embargo, también se pueden utilizar dentro de páginas `.md` porque los archivos de rebajas se compilan en [Componentes de Archivo Único Vue (SFC)](https://vuejs.org/guide/scaling-up/sfc.html).\n\nMétodos que comienzan con `use*` indican que es una función de [API de Composición Vue 3](https://vuejs.org/guide/introduction.html#composition-api) (\"Composable\") que solo puede ser utilizada dentro de `setup()` o `<script setup>`.\n\n## `useData` <Badge type=\"info\" text=\"composable\" />\n\nRetorna datos específicos de la página. El objeto devuelto tiene el siguiente tipo:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * Metadátos a nivel del sitio\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig de .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Metadátos a nível de la página\n   */\n  page: Ref<PageData>\n  /**\n   * Frontmatter de la página\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * Parámetros de ruta dinámica\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**Ejemplo:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" />\n\nDevuelve el objeto de ruta actual con el siguiente tipo:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" />\n\nDevuelve la instancia del enrutador VitePress para que pueda navegar mediante programación a otra página.\n\n```ts\ninterface Router {\n  /**\n   * Ruta atual.\n   */\n  route: Route\n  /**\n   * Navegar para una nueva URL.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * Llamado antes del cambio de ruta. Devuelve 'falso' para cancelar la navegación.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Se llama antes de que se cargue el componente de la página (después de que se haya actualizado el estado del historial).\n   * atualizado). Retorne `false` para cancelar la navegación.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Llamado después del cambio de ruta.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" />\n\n- **Tipo**: `(path: string) => string`\n\nagrega la [`base`](./site-config#base) configurada a una ruta URL determinada. Consulte también [Base URL](../guide/asset-handling#base-url).\n\n## `<Content />` <Badge type=\"info\" text=\"component\" />\n\nEl componente `<Content />` muestra el contenido de markdown renderizado. Útil [al crear tu propio tema](../guide/custom-theme).\n\n```vue\n<template>\n  <h1>Layout Personalizado!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" />\n\nEl componente `<ClientOnly />` muestra tu _slot_ solo del lado del cliente.\n\nDebido a que las aplicaciones VitePress se interpretan en el lado del servidor en Node.js cuando generan compilaciones estáticas, cualquier uso de Vue debe seguir los requisitos del código universal. En resumen, asegúrese de acceder solo a las API del navegador/DOM en ganchos `beforeMount` o `mounted`.\n\nSi está utilizando o demostrando componentes que no son compatibles con SSR (por ejemplo, contienen directivas personalizadas), puede incluirlos dentro del componente. `ClientOnly`.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- Relacionado: [Compatibilidad SSR](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" />\n\nAccede directamente a los datos [frontmatter](../guide/frontmatter) de la página actual en expresiones Vue.\n\n```md\n---\ntitle: Olá\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" />\n\nAccede directamente a los [parámetros de ruta dinámica](../guide/routing#dynamic-routes) de la página actual en expresiones Vue.\n\n```md\n- nombre del paquete: {{ $params.pkg }}\n- versión: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/es/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# Configuración de site {#site-config}\n\nLa configuración del site es donde puede configurar los ajustes globales del site. Las opciones de configuración de la aplicación definen las configuraciones que se aplican a todos los sites de VitePress, independientemente del tema que estén utilizando. Por ejemplo, el directorio base o el título del site.\n\n## Vista general {#overview}\n\n### Resolución de configuración {#config-resolution}\n\nEl archivo de configuración siempre se resuelve desde `<root>/.vitepress/config.[ext]`, donde `<root>` es la [raiz del proyecto](../guide/routing#root-and-source-directory) VitePress y `[ext]` es una de las extensiones de archivo compatibles. TypeScript es compatible desde el primer momento. Las extensiones compatibles incluyen `.js`, `.ts`, `.mjs` y `.mts`.\n\nRecuerde usar la sintaxis de módulos ES en los archivos de configuración. El archivo de configuración debe exportar por defecto un objeto:\n\n```ts\nexport default {\n  // opciones de configuración a nivel de aplicación\n  lang: 'pt-BR',\n  title: 'VitePress',\n  description: 'Generador de site estático Vite & Vue.',\n  ...\n}\n```\n\n::: details Configuración dinámica (Assíncrona)\n\nSi necesitas generar dinamicamente la configuración, también puedes exportar por defecto una función. Por ejemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n  // opciones de configuración a nivel de aplicación\n    lang: 'pt-BR',\n    title: 'VitePress',\n    description: 'Generador de site estático Vite & Vue.',\n\n    // opciones de configuración a nivel de tema\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nTambién puedes utilizar `await` en el nivel superior. Como:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // opciones de configuración a nivel de aplicación\n    lang: 'pt-BR',\n    title: 'VitePress',\n    description: 'Generador de site estático Vite & Vue.',\n\n  // opciones de configuración a nivel de tema\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### Configuración Intellisense {#config-intellisense}\n\nUsar el auxiliar `defineConfig` proporcionará Intellisense con tecnología TypeScript para las opciones de configuración. Suponiendo que su IDE lo admita, esto debería funcionar tanto en JavaScript como en TypeScript.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### Configuración de Tema Escrito {#typed-theme-config}\n\nPor defecto, el auxiliar `defineConfig` espera el tipo de configuración del tema por defecto:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // El tipo es `DefaultTheme.Config`\n  }\n})\n```\n\nSi usa un tema personalizado y desea realizar comprobaciones de tipo para la configuración del tema, deberá usar `defineConfigWithTheme` en su lugar, y pase el tipo de configuración para su tema personalizado a través de un argumento genérico:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // El tipo es `ThemeConfig`\n  }\n})\n```\n\n### Configuración Vite, Vue & Markdown\n\n- **Vite**\n\n  Puede configurar la instancia de Vite subyacente usando la opción [vite](#vite) en su configuración de VitePress. No es necesario crear un archivo de configuración de Vite por separado.\n\n- **Vue**\n\n  VitePress ya incluye el plugin oficial de Vue para Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)). Puede configurar sus opciones usando la opción [vue](#vue) en su configuración VitePress.\n\n- **Markdown**\n\n  Puede configurar la instancia subyacente de [Markdown-It](https://github.com/markdown-it/markdown-it) usando la opción [markdown](#markdown) en su configuración VitePress.\n\n## Metadatos de Site {#site-metadata}\n\n### title\n\n- Tipo: `string`\n- Predeterminado: `VitePress`\n- Puede ser reemplazado por página a través de [frontmatter](./frontmatter-config#title)\n\nTítulo de site. Al usar el tema por defecto, este será mostrado en la barra de navegación.\n\nTambién se utilizará como sufijo predeterminado para todos los títulos de páginas individuales a menos que [`titleTemplate`](#titletemplate) definirse. El título final de una página individual será el contenido textual de su primer encabezado. `<h1>`, combinado con el título global como sufijo. Por ejemplo, con la siguiente configuración y contenido de página:\n\n```ts\nexport default {\n  title: 'Mi increible sitio web'\n}\n```\n\n```md\n# Hola\n```\n\nEl título de la página será `Hola | Mi increible sitio web`.\n\n### titleTemplate\n\n- Tipo: `string | boolean`\n- Puede ser reemplazado por página a través de [frontmatter](./frontmatter-config#titletemplate)\n\nLe permite personalizar el sufijo del título de cada página o el título completo. Por ejemplo:\n\n```ts\nexport default {\n  title: 'Mi increible sitio web',\n  titleTemplate: 'Sufijo Personalizado'\n}\n```\n\n```md\n# Hola\n```\n\nEl título de la página será `Hola | Sufijo Personalizado`.\n\nPara personalizar completamente cómo se debe representar el título, puedes usar el símbolo `:title` en `titleTemplate`:\n\n```ts\nexport default {\n  titleTemplate: ':title - Sufijo Personalizado'\n}\n```\n\nAqui, `:title` será reemplazado por el texto que se deduce del primer título `<h1>` de la página. El título del ejemplo de la página anterior será `Hola - Sufijo Personalizado`.\n\nUna opción puede ser definida como `false` para desactivar sufijos del título.\n\n### description\n\n- Tipo: `string`\n- Predeterminado: `Um site VitePress`\n- Puede ser sustituído por página a través de [frontmatter](./frontmatter-config#descrição)\n\nDescripción del sitio web. Esto se presentará como una etiqueta. `<meta>` en la página HTML.\n\n```ts\nexport default {\n  descripción: 'Un site VitePress'\n}\n```\n\n### head\n\n- Tipo: `HeadConfig[]`\n- Predeterminado: `[]`\n- Se puede agregar por página a través de [frontmatter](./frontmatter-config#head)\n\nElementos adicionales para agregar a la etiqueta `<head>` de la página HTML. Las etiquetas agregadas por los usuarios son mostradas antes de la etiqueta `head` de cierre, despues de las etiquetas VitePress.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### Ejemplo: Agregando un favicon {#example-adding-a-favicon}\n\n```ts\nexport default {\n  cabecera: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // coloque favicon.ico en el directorio público, si la base está definida, use /base/favicon.ico\n\n/* Mostraría:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### Ejemplo: Agregando Fuentes de Google {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* Mostraría:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### Ejemplo: Registrando un _service worker_ {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* Mostraría:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### Ejemplo: Usando Google Analytics {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* Mostraría:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- Tipo: `string`\n- Predeterminado: `en-US`\n\nEl atributo de idioma del sitio. Esto se mostrará como una etiqueta. `<html lang=\"en-US\">` en la página HTML.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- Tipo: `string`\n- Predeterminado: `/`\n\nLa URL base donde se implementará el sitio. Deberá configurar esto si planea implementar su sitio en un subdirectorio, por ejemplo, en páginas de GitHub. Si planea implementar su sitio web en `https://foo.github.io/bar/` entonces deberías definir la base como `'/bar/'`. Siempre debe comenzar y terminar con una barra.\n\nLa base se agrega automáticamente a todas las URL que comienzan con / en otras opciones, por lo que solo necesitas especificarla una vez.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## Roteamento {#routing}\n\n### cleanUrls\n\n- Tipo: `boolean`\n- Predeterminado: `false`\n\nCuando se establece en `true`, VitePress eliminará el `.html` al final de las URLs. Consulte también [Generación de URLs Limpias](../guide/routing#generating-clean-urls).\n\n::: warning Soporte de Servidor Requerido\nHabilitar esto puede requerir configurar adicional en su plataforma de alojamiento. Para funcionar, su servidor debe poder servir `/foo.html` cuando visite `/foo` **sin redirección**.\n:::\n\n### rewrites\n\n- Tipo: `Record<string, string>`\n\nDefine asignaciones de directorios personalizados &lt;-&gt; URL. Visite [Rutas: Reescribir Rutas](../guide/routing#route-rewrites) para obtener más detalles.\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## Construcción {#build}\n\n### srcDir\n\n- Tipo: `string`\n- Predeterminado: `.`\n\nEl directorio donde se almacenan tus páginas de rebajas, en relación con la raíz del proyecto. vea también [Directorio Raiz y de origen](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- Tipo: `string`\n- Predeterminado: `undefined`\n\nUn [patrón glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para hacer coincidir los archivos de rebajas que deben exluirse como contenido de origen.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- Tipo: `string`\n- Predeterminado: `./.vitepress/dist`\n\nLa ubicación de la salida de compilación para el sitio, en relación con el [raiz del proyecto](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- Tipo: `string`\n- Predeterminado: `assets`\n\nEspecifica el directorio para anidar los activos generados. El camino debe estar dentro [`outDir`](#outdir) y se resuelve en relación con el mismo.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- Tipo: `string`\n- Predeterminado: `./.vitepress/cache`\n\nEl directorio para los archivos de caché, en relación con el [raiz del proyecto](../guide/routing#root-and-source-directory). Vea también: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- Tipo: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- Predeterminado: `false`\n\nCuando se establece en `true`, VitePress no dejará de compilarse debido a links rotos.\n\nCuando se establece en `'localhostLinks'`, la compilación fallará en links rotos, per no verificará los links `localhost`.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\nTambién puede ser un _array_ de una exacta URL en string, patrones regex, o funciones de filtro personalizadas.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // ignora URL exacta \"/playground\"\n    '/playground',\n    // ignora todos los links localhost\n    /^https?:\\/\\/localhost/,\n    // ignora todos los links incluyendo \"/repl/\"\"\n    /\\/repl\\//,\n    // función personalizada, ignora todos los links incluyendo \"ignore\"\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### mpa <Badge type=\"warning\" text=\"experimental\" />\n\n- Tipo: `boolean`\n- Predeterminado: `false`\n\nCuando se define como `true`, la aplicación de producción se compilará en [Modo MPA](../guide/mpa-mode). El modo MPA envía 0 kb de JavaScript de forma predeterminada, a expensas de deshabilitar la navegación del lado del cliente y requerir permiso explícito para la interactividad.\n\n## Tematización {#theming}\n\n### appearance\n\n- Tipo: `boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`\n- Predeterminado: `true`\n\nSe habilitará el modo oscuro (agregando una classe `.dark` al elemento `<html>`).\n\n- Si la opción está configurada en `true` El tema predeterminado está determinado por la combinación de colores preferida del usuario.\n- Si la opción está configurada en `dark` El tema es oscuro de forma predeterminada a menos que el usuario lo cambie manualmente.\n- Si la opción está configurada en `false` los usuarios no podrán cambiar el tema.\n\nEsta opción inyecta un script en línea que restaura la configuración de los usuarios desde el almacenamiento local. (_local storage_) usando una llave `vitepress-theme-appearance`. Eso asegurará que la clase `.dark` se aplicará antes de que se muestre la página para evitar el parpadeo.\n\n`appearance.initialValue` puede ser `'dark' | undefined`. Refs o getters no son soportados.\n\n### lastUpdated\n\n- Tipo: `boolean`\n- Predeterminado: `false`\n\nPara obtener la marca de tiempo de la última actualización para cada página usando Git. El sello de fecha se incluirá en los datos de cada página, accesible a través de [`useData`](./runtime-api#usedata).\n\nCuando se utiliza el tema predeterminado, al habilitar esta opción se mostrará la última hora de actualización de cada página. Puedes personalizar el texto mediante la opción [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext).\n\n## Personalización {#customization}\n\n### markdown\n\n- Tipo: `MarkdownOption`\n\nConfigure las opciones de procesador Markdown. VitePress usa [Markdown-it](https://github.com/markdown-it/markdown-it) como procesador y [Shiki](https://github.com/shikijs/shiki) para resaltar la sintaxis del idioma. Dentro de esta opción, puede pasar varias opciones de Markdown relacionadas para satisfacer sus necesidades.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\nConsulte la [declaración de tipo y jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) para conocer todas las opciones disponibles.\n\n### vite\n\n- Tipo: `import('vite').UserConfig`\n\nPase la [Configuración Vite](https://vitejs.dev/config/) sin procesar al servidor interno / empaquetador Vite.\n\n```js\nexport default {\n  vite: {\n    // Opciones de configuración Vite\n  }\n}\n```\n\n### vue\n\n- Tipo: `import('@vitejs/plugin-vue').Options`\n\nPase las opciones [`@vitejs/plugin-vue`](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) sin formato a la instancia del complemento interno.\n\n```js\nexport default {\n  vue: {\n    // Opciones @vitejs/plugin-vue\n  }\n}\n```\n\n## Construir Ganchos {#build-hooks}\n\nLos enlaces de compilación VitePress permiten agregar nuevas funciones al su sitio web:\n\n- Sitemap\n- Indexación de busqueda\n- PWA\n- _Teleports_\n\n## buildEnd\n- Tipo: `(siteConfig: SiteConfig) => Awaitable<void>`\n`buildEnd` es un enlace de compilación CLI (Interfaz de línea de comando), se ejecutará después de que se complete la compilación (SSG) pero antes de que finalice el proceso CLI de VitePress.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n## postRender\n- Tipo: `(context: SSGContext) => Awaitable<SSGContext | void>`\n- `postRender` es un gancho de compilación, llamado cuando se completa la interpretación de SSG. Le permitirá manipular el contenido de los _teleports_ durante la generación de sitios estáticos.\n\n  ```ts\n  export default {\n    async postRender(context) {\n      // ...\n    }\n  }\n  ```\n\n  ```ts\n  interface SSGContext {\n    content: string\n    teleports?: Record<string, string>\n    [key: string]: any\n  }\n  ```\n\n## transformHead\n- Tipo: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` es un enlace de compilación para transformar el encabezado antes de generar cada página. Esto le permite agregar entradas de encabezado que no se pueden agregar estáticamente a la configuración de VitePress. Sólo necesita devolver entradas adicionales, que se fusionarán automáticamente con las existentes.\n\n::: warning\nNo mutes ningún elemento dentro `context`.\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // e.g. index.md (relativo a srcDir)\n  assets: string[] // todos los activos no-js/css con URL pública completamente resuelta\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nTenga en cuenta que este enlace solo se llama cuando se genera el sitio de forma estática. No se llama durante el desarrollo. Si necesita agregar entradas de encabezado dinámicas durante el desarrollo, puede usar el enlace [`transformPageData`](#transformpagedata) en su lugar.\n\n  ```ts\n  export default {\n    transformPageData(pageData) {\n      pageData.frontmatter.head ??= []\n      pageData.frontmatter.head.push([\n        'meta',\n        {\n          name: 'og:title',\n          content:\n            pageData.frontmatter.layout === 'home'\n              ? `VitePress`\n              : `${pageData.title} | VitePress`\n        }\n      ])\n    }\n  }\n  ```\n\n#### Ejemplo: Agregando una URL canónica `<link>` {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n- Tipo: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n`transformHtml` es un gancho de compilación para transformar el contenido de cada página antes de guardarla en el disco.\n\n::: warning\nNo mute ningún elemento dentro del `context`. Además, modificar el contenido HTML puede provocar problemas de hidratación en tiempo de ejecución.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n- Tipo: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` es un gancho para transformar los datos de cada página. Puedes hacer mutaciones directamente en `pageData` o devolver valores modificados que se fusionarán con los datos de la página.\n\n::: warning\nNo mute ningún elemento dentro del `context` y tenga cuidado ya que esto puede afectar el rendimiento del servidor de desarrollo, especialmente si tiene algunas solicitudes de red o cálculos pesados (como generar imágenes) en el gancho. Puede consultar  `process.env.NODE_ENV === 'production'` para ver la lógica condicional.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // o devolver datos para fusionar\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/fa/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'ژنراتور استاتیک وب‌سایت با Vite و Vue',\n\n  // prettier-ignore\n  head: [\n    ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],\n    ['link', { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }],\n    ['link', { href: 'https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100..900&display=swap', rel: 'stylesheet' }],\n  ],\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/fa/guide/': { base: '/fa/guide/', items: sidebarGuide() },\n      '/fa/reference/': { base: '/fa/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'ویرایش این صفحه در گیت‌هاب'\n    },\n\n    footer: {\n      message: 'انتشار یافته تحت لایسنس MIT',\n      copyright: 'حق نسخه‌برداری © 2019-کنون Evan You'\n    },\n\n    docFooter: {\n      prev: 'قبلی',\n      next: 'بعدی'\n    },\n\n    outline: {\n      label: 'در این صفحه'\n    },\n\n    lastUpdated: {\n      text: 'آخرین به‌روزرسانی‌'\n    },\n\n    notFound: {\n      title: 'صفحه پیدا نشد',\n      quote:\n        'اما اگر جهت خود را تغییر ندهید و همچنان به جستجو ادامه دهید، ممکن است در نهایت به جایی برسید که در حال رفتن به آن هستید.',\n      linkLabel: 'برو به خانه',\n      linkText: 'من را به خانه ببر'\n    },\n\n    langMenuLabel: 'تغییر زبان',\n    returnToTopLabel: 'بازگشت به بالا',\n    sidebarMenuLabel: 'منوی جانبی',\n    darkModeSwitchLabel: 'تم تاریک',\n    lightModeSwitchTitle: 'رفتن به حالت روشن',\n    darkModeSwitchTitle: 'رفتن به حالت تاریک',\n    siteTitle: 'ویت‌پرس'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'راهنما',\n      link: 'fa/guide/what-is-vitepress',\n      activeMatch: '/guide/'\n    },\n    {\n      text: 'مرجع',\n      link: 'fa/reference/site-config',\n      activeMatch: '/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/fa/'\n        },\n        {\n          text: 'Changelog',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'مشارکت',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'معرفی',\n      collapsed: false,\n      items: [\n        { text: 'ویت‌پرس چیست؟', link: 'what-is-vitepress' },\n        { text: 'شروع کار', link: 'getting-started' },\n        { text: 'مسیریابی', link: 'routing' },\n        { text: 'استقرار', link: 'deploy' }\n      ]\n    },\n    {\n      text: 'نوشتن',\n      collapsed: false,\n      items: [\n        { text: 'افزونه‌های Markdown', link: 'markdown' },\n        { text: 'مدیریت منابع', link: 'asset-handling' },\n        { text: 'Frontmatter', link: 'frontmatter' },\n        { text: 'استفاده از Vue در Markdown', link: 'using-vue' },\n        { text: 'بین‌المللی سازی', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'شخصی‌سازی',\n      collapsed: false,\n      items: [\n        { text: 'استفاده از تم شخصی', link: 'custom-theme' },\n        {\n          text: 'گسترش تم پیش‌فرض',\n          link: 'extending-default-theme'\n        },\n        { text: 'بارگیری داده در زمان Build', link: 'data-loading' },\n        { text: 'سازگاری SSR', link: 'ssr-compat' },\n        { text: 'اتصال به CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: 'آزمایشی',\n      collapsed: false,\n      items: [\n        { text: 'حالت MPA', link: 'mpa-mode' },\n        { text: 'جنریت کردن Sitemap', link: 'sitemap-generation' }\n      ]\n    },\n    { text: 'پیکربندی و مرجع API', base: 'fa/reference/', link: 'site-config' }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'مرجع',\n      base: 'fa/reference/',\n      items: [\n        { text: 'پیکربندی Site', link: 'site-config' },\n        { text: 'پیکربندی Frontmatter', link: 'frontmatter-config' },\n        { text: 'Runtime API', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: 'تم پیش‌فرض',\n          base: 'fa/reference/default-theme-',\n          items: [\n            { text: 'بررسی اجمالی', link: 'config' },\n            { text: 'ناوبری', link: 'nav' },\n            { text: 'نوار کنار صفحه', link: 'sidebar' },\n            { text: 'صفحه اصلی', link: 'home-page' },\n            { text: 'پاورقی', link: 'footer' },\n            { text: 'طرح', link: 'layout' },\n            { text: 'نشان', link: 'badge' },\n            { text: 'صفحه تیم', link: 'team-page' },\n            { text: 'لینک‌های قبلی / بعدی', link: 'prev-next-links' },\n            { text: 'ویرایش لینک', link: 'edit-link' },\n            { text: 'Timestamp آخرین به‌روزرسانی', link: 'last-updated' },\n            { text: 'جستجو', link: 'search' },\n            { text: 'تبلیغات Carbon', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: 'جستجو',\n        buttonAriaLabel: 'جستجو'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: 'پاک کردن',\n          clearButtonAriaLabel: 'پاک کردن عبارت جستجو',\n          closeButtonText: 'بستن',\n          closeButtonAriaLabel: 'بستن',\n          placeholderText: 'در مستندات جستجو کنید یا از Ask AI بپرسید',\n          placeholderTextAskAi: 'سؤال دیگری بپرسید...',\n          placeholderTextAskAiStreaming: 'در حال پاسخ گویی...',\n          searchInputLabel: 'جستجو',\n          backToKeywordSearchButtonText: 'بازگشت به جستجوی کلیدواژه',\n          backToKeywordSearchButtonAriaLabel: 'بازگشت به جستجوی کلیدواژه',\n          newConversationPlaceholder: 'یک سؤال بپرسید',\n          conversationHistoryTitle: 'تاریخچه گفت وگوی من',\n          startNewConversationText: 'شروع گفت وگوی جدید',\n          viewConversationHistoryText: 'تاریخچه گفت وگو',\n          threadDepthErrorPlaceholder: 'محدودیت گفت وگو رسید'\n        },\n        newConversation: {\n          newConversationTitle: 'امروز چگونه می توانم کمک کنم؟',\n          newConversationDescription:\n            'در مستندات شما جستجو می کنم تا سریع راهنماهای راه اندازی، جزئیات ویژگی ها و نکات رفع اشکال را پیدا کنم.'\n        },\n        footer: {\n          selectText: 'انتخاب',\n          submitQuestionText: 'ارسال سؤال',\n          selectKeyAriaLabel: 'کلید Enter',\n          navigateText: 'پیمایش',\n          navigateUpKeyAriaLabel: 'پیکان بالا',\n          navigateDownKeyAriaLabel: 'پیکان پایین',\n          closeText: 'بستن',\n          backToSearchText: 'بازگشت به جستجو',\n          closeKeyAriaLabel: 'کلید Escape',\n          poweredByText: 'قدرت گرفته از'\n        },\n        errorScreen: {\n          titleText: 'امکان دریافت نتایج وجود ندارد',\n          helpText: 'ممکن است لازم باشد اتصال شبکه را بررسی کنید.'\n        },\n        startScreen: {\n          recentSearchesTitle: 'اخیر',\n          noRecentSearchesText: 'جستجوی اخیر وجود ندارد',\n          saveRecentSearchButtonTitle: 'ذخیره این جستجو',\n          removeRecentSearchButtonTitle: 'حذف این جستجو از تاریخچه',\n          favoriteSearchesTitle: 'علاقه مندی ها',\n          removeFavoriteSearchButtonTitle: 'حذف این جستجو از علاقه مندی ها',\n          recentConversationsTitle: 'گفت وگوهای اخیر',\n          removeRecentConversationButtonTitle: 'حذف این گفت وگو از تاریخچه'\n        },\n        noResultsScreen: {\n          noResultsText: 'هیچ نتیجه ای برای',\n          suggestedQueryText: 'سعی کنید جستجو کنید',\n          reportMissingResultsText:\n            'فکر می کنید این جستجو باید نتیجه داشته باشد؟',\n          reportMissingResultsLinkText: 'به ما اطلاع دهید.'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'از هوش مصنوعی بپرسید: ',\n          noResultsAskAiPlaceholder:\n            'در مستندات پیدا نکردید؟ از Ask AI کمک بگیرید: '\n        },\n        askAiScreen: {\n          disclaimerText:\n            'پاسخ ها توسط هوش مصنوعی تولید می شوند و ممکن است اشتباه باشند. بررسی کنید.',\n          relatedSourcesText: 'منابع مرتبط',\n          thinkingText: 'در حال فکر کردن...',\n          copyButtonText: 'کپی',\n          copyButtonCopiedText: 'کپی شد!',\n          copyButtonTitle: 'کپی',\n          likeButtonTitle: 'پسندیدم',\n          dislikeButtonTitle: 'نپسندیدم',\n          thanksForFeedbackText: 'از بازخورد شما متشکریم!',\n          preToolCallText: 'در حال جستجو...',\n          duringToolCallText: 'در حال جستجو...',\n          afterToolCallText: 'جستجو برای',\n          stoppedStreamingText: 'شما این پاسخ را متوقف کردید',\n          errorTitleText: 'خطای گفتگو',\n          threadDepthExceededMessage:\n            'برای حفظ دقت پاسخ ها، این گفت وگو بسته شد.',\n          startNewConversationButtonText: 'شروع گفت وگوی جدید'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'از هوش مصنوعی بپرسید',\n            buttonAriaLabel: 'از هوش مصنوعی بپرسید'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'از هوش مصنوعی بپرسید',\n              conversationHistoryTitle: 'تاریخچه گفت وگوی من',\n              newConversationText: 'شروع گفت وگوی جدید',\n              viewConversationHistoryText: 'تاریخچه گفت وگو'\n            },\n            promptForm: {\n              promptPlaceholderText: 'یک سؤال بپرسید',\n              promptAnsweringText: 'در حال پاسخ گویی...',\n              promptAskAnotherQuestionText: 'سؤال دیگری بپرسید',\n              promptDisclaimerText:\n                'پاسخ ها توسط هوش مصنوعی تولید می شوند و ممکن است اشتباه باشند.',\n              promptLabelText:\n                'برای ارسال Enter را بزنید، یا برای خط جدید Shift+Enter.',\n              promptAriaLabelText: 'ورودی پرسش'\n            },\n            conversationScreen: {\n              preToolCallText: 'در حال جستجو...',\n              searchingText: 'در حال جستجو...',\n              toolCallResultText: 'جستجو برای',\n              conversationDisclaimer:\n                'پاسخ ها توسط هوش مصنوعی تولید می شوند و ممکن است اشتباه باشند. بررسی کنید.',\n              reasoningText: 'در حال استدلال...',\n              thinkingText: 'در حال فکر کردن...',\n              relatedSourcesText: 'منابع مرتبط',\n              stoppedStreamingText: 'شما این پاسخ را متوقف کردید',\n              copyButtonText: 'کپی',\n              copyButtonCopiedText: 'کپی شد!',\n              likeButtonTitle: 'پسندیدم',\n              dislikeButtonTitle: 'نپسندیدم',\n              thanksForFeedbackText: 'از بازخورد شما متشکریم!',\n              errorTitleText: 'خطای گفتگو'\n            },\n            newConversationScreen: {\n              titleText: 'امروز چگونه می توانم کمک کنم؟',\n              introductionText:\n                'در مستندات شما جستجو می کنم تا سریع راهنماهای راه اندازی، جزئیات ویژگی ها و نکات رفع اشکال را پیدا کنم.'\n            },\n            logo: {\n              poweredByText: 'قدرت گرفته از'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/fa/guide/asset-handling.md",
    "content": "# مدیریت منابع {#asset-handling}\n\n## ارجاع به منابع ایستا {#referencing-static-assets}\n\nتمام فایل‌های Markdown به کامپوننت‌های Vue تبدیل و توسط [Vite](https://vitejs.dev/guide/assets.html) پردازش می‌شوند. شما می‌توانید، **و باید**، هر نوع دارایی را با استفاده از URL‌های نسبی مرجع قرار دهید:\n\n```md\n![تصویر](./image.png)\n```\n\nشما می‌توانید منابع ایستا را در فایل‌های Markdown خود، کامپوننت‌های `*.vue` در قالب، استایل‌ها و فایل‌های `.css` ساده، با استفاده از مسیرهای عمومی مطلق (براساس ریشه پروژه) یا مسیرهای نسبی (براساس سیستم فایل شما) ارجاع دهید. روش دوم مشابه رفتاری است که در صورت استفاده از Vite، Vue CLI یا `file-loader` webpack با آن آشنا هستید.\n\nانواع شایع تصویر، رسانه و فایل فونت به طور خودکار شناسایی و به عنوان منابع درج می‌شوند.\n\n::: tip فایل‌های لینک شده به عنوان دارایی محسوب نمی‌شوند\nPDFها یا سند‌های دیگر که از طریق پیوندها در فایل‌های Markdown ارجاع داده شده‌اند به طور خودکار به عنوان دارایی در نظر گرفته نمی‌شوند. برای دسترسی به فایل‌های لینک شده، باید آن‌ها را به صورت دستی در دایرکتوری [`public`](#the-public-directory) پروژه قرار دهید.\n:::\n\nتمام منابع ارجاع داده شده، شامل آن‌هایی که از مسیرهای مطلق استفاده می‌کنند، در مرحله تولید به دایرکتوری خروجی با نام فایلی بر اساس یک هش کپی خواهند شد. دارایی‌هایی که هرگز ارجاع نداده شوند، کپی نخواهند شد. منابع تصویر کوچک‌تر از 4 کیلوبایت به صورت base64 درون خطی می‌شوند - این می‌تواند از طریق گزینه پیکربندی [`vite`](../reference/site-config#vite) تنظیم شود.\n\nتمام ارجاع‌های مسیر **ایستا**، شامل مسیرهای مطلق، باید بر اساس ساختار دایرکتوری کاری شما تعیین شوند.\n\n## دایرکتوری عمومی {#the-public-directory}\n\nگاهی اوقات ممکن است نیاز داشته باشید منابع ایستا را فراهم کنید که به صورت مستقیم در هیچ‌یک از Markdown یا کامپوننت‌های قالب شما ارجاع نشده‌اند، یا ممکن است بخواهید برخی فایل‌ها را با نام اصلی خود سرویس دهید. به عنوان مثال، فایل‌هایی مانند `robots.txt`، آیکون‌های fav، و آیکون‌های PWA.\n\nشما می‌توانید این فایل‌ها را در دایرکتوری `public` تحت [دایرکتوری منبع](./routing#source-directory) قرار دهید. به عنوان مثال، اگر ریشه پروژه شما `./docs` است و از محل پیش‌فرض دایرکتوری منبع استفاده می‌کنید، آنگاه دایرکتوری عمومی شما `./docs/public` خواهد بود.\n\nمنابع قرار داده شده در `public` به صورت اصلی در ریشه دایرکتوری خروجی کپی خواهند شد.\n\nتوجه داشته باشید که باید به فایل‌های قرار داده شده در `public` با استفاده از مسیر مطلق ریشه ارجاع دهید - به عنوان مثال، `public/icon.png` همیشه باید به عنوان `/icon.png` در کد منبع ارجاع داده شود.\n\n## URL پایه {#base-url}\n\nاگر وب‌سایت شما به URL غیر ریشه استقرار می‌یابد، باید گزینه `base` را در `.vitepress/config.js` تنظیم کنید. به عنوان مثال، اگر قصد دارید وب‌سایت خود را به `https://foo.github.io/bar/` استقرار دهید، آنگاه `base` باید به `'/bar/'` تنظیم شود (همیشه باید با یک خط شروع و پایان یابد).\n\nتمام مسیرهای دارایی ایستا شما به صورت خودکار پردازش می‌شوند تا با ارزش‌های `base` مختلف تطبیق یابند. به عنوان مثال، اگر به یک ارجاع مطلق به یک دارایی زیر `public` در Markdown خود اشاره کرده‌اید:\n\n```md\n![تصویر](/image-inside-public.png)\n```\n\nدر این حالت، شما **نیازی ندارید** که آن را به روز کنید وقتی که مقدار پیکربندی `base` را تغییر می‌دهید.\n\nاما، اگر شما در حال نویسندگی یک کامپوننت قالب هستید که به صورت پویا به منابع لینک می‌دهد، به عنوان مثال یک تصویر که `src` آن براساس مقدار پیکربندی قالب است:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nدر این حالت، توصیه می‌شود که مسیر را با استفاده از کمکی [`withBase`](../reference/runtime-api#withbase) ارائه شده توسط ویت‌پرس بپوشانید:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/fa/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# اتصال به یک سیستم مدیریت محتوا (CMS) {#connecting-to-a-cms}\n\n## گام‌های کلی {#general-workflow}\n\nاتصال ویت‌پرس به یک سیستم مدیریت محتوا به طور عمده بر اساس [مسیریابی پویا](./routing#dynamic-routes) خواهد بود. حتماً قبل از شروع، با روش کار آن آشنا شوید.\n\nاز آنجایی که هر سیستم مدیریت محتوا به طریقی متفاوت کار می‌کند، در اینجا تنها می‌توانیم یک جریان کاری عمومی را ارائه دهیم که شما باید آن را برای حالت خاص خودتان سفارشی کنید.\n\n1. اگر سیستم مدیریت محتوا نیاز به احراز هویت دارد، یک فایل `.env` برای ذخیره توکن‌های API خود ایجاد کنید و آن را بارگذاری کنید:\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. داده‌های مورد نیاز را از سیستم مدیریت محتوا بازیابی کرده و به شکل داده‌های مسیر مناسب فرمت کنید:\n\n    ```js\n    export default {\n      async paths() {\n        // از کتابخانه مشتری مربوط به سیستم مدیریت محتوا استفاده کنید اگر نیاز دارید\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // توکن در صورت لزوم\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* عنوان، نویسندگان، تاریخ و غیره */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. نمایش محتوا در صفحه:\n\n    ```md\n    # {{ $params.title }}\n\n    - نوشته شده توسط {{ $params.author }} در تاریخ {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## راهنماهای ادغام {#integration-guides}\n\nاگر راهنمایی درباره ادغام ویت‌پرس با یک سیستم مدیریت محتوا خاص نوشته‌اید، لطفاً از لینک \"ویرایش این صفحه\" زیر استفاده کنید تا آن را ارسال کنید!\n"
  },
  {
    "path": "docs/fa/guide/custom-theme.md",
    "content": "---\noutline: deep\n---\n\n# استفاده از یک تم سفارشی {#using-a-custom-theme}\n\n## Resolve کردن تم {#theme-resolving}\n\nمی‌توانید با ایجاد یک فایل `.vitepress/theme/index.js` یا `.vitepress/theme/index.ts` (فایل ورودی تم) تم سفارشی را فعال کنید:\n\n```\n.\n├─ docs                # ریشه پروژه\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # ورودی تم\n│  │  └─ config.js     # فایل پیکربندی\n│  └─ index.md\n└─ package.json\n```\n\nوقتی ویت‌پرس حضور یک فایل ورودی تم را شناسایی کند، همواره از تم سفارشی به جای تم پیش‌فرض استفاده می‌کند. با این حال، شما می‌توانید [تم پیش‌فرض را گسترش دهید](./extending-default-theme) تا سفارشی‌سازی‌های پیشرفته‌تری را روی آن اعمال کنید.\n\n## رابط تم {#theme-interface}\n\nیک تم سفارشی ویت‌پرس به عنوان یک شی تعریف می‌شود که شامل رابط زیر است:\n\n```ts\ninterface Theme {\n  /**\n   * کامپوننت لایه‌ی ریشه برای هر صفحه\n   * @required\n   */\n  Layout: Component\n  /**\n   * تقویت نمونه Vue اپلیکیشن\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * گسترش یک تم دیگر، با فراخوانی `enhanceApp` آن پیش از ما\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // نمونه Vue اپلیکیشن\n  router: Router // نمونه روتر ویت‌پرس\n  siteData: Ref<SiteData> // متادیتاهای سطح سایت\n}\n```\n\nفایل ورودی تم باید تم را به عنوان export پیش‌فرض خود export کند:\n\n```js [.vitepress/theme/index.js]\n\n// شما می‌توانید فایل‌های Vue را مستقیماً در ورودی تم وارد کنید\n// ویت‌پرس با @vitejs/plugin-vue پیش‌تنظیم شده است.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nexport پیش‌فرض تنها قراردادی برای یک تم سفارشی است و تنها ویژگی `Layout` لازم است. بنابراین، به شیء تم ویت‌پرس می‌توان به عنوان یک کامپوننت Vue ساده ترتیب داد.\n\nدرون کامپوننت لایه‌ی خود، دقیقاً مانند یک برنامه Vite + Vue 3 عادی عمل می‌کند. با این وجود، توجه داشته باشید که تم همچنین باید [سازگار با SSR](./ssr-compat) باشد.\n\n## ساخت یک لایه {#building-a-layout}\n\nبیشترین لایه‌ی پایه‌ای نیازمند دارای یک کامپوننت `<Content />` است:\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>طرح سفارشی!</h1>\n\n  <!-- اینجا محتوای markdown نمایش داده می‌شود -->\n  <Content />\n</template>\n```\n\nلایه‌ی بالا به سادگی تمام محتوای markdown هر صفحه را به عنوان HTML نمایش می‌دهد. اولین بهبودی که می‌توانیم اعمال کنیم، مدیریت خطاهای 404 است:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>طرح سفارشی!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    صفحه 404 سفارشی!\n  </div>\n  <Content v-else />\n</template>\n```\n\nکمک‌کننده [`useData()`](../reference/runtime-api#usedata) اطلاعات اجرایی مورد نیاز ما را برای رندر شرایطی صفحات مختلف فراهم می‌کند. یکی از دیگر اطلاعاتی که ما می‌توانیم به آن دسترسی داشته باشیم، اطلاعات اولیه صفحه فعلی است. ما می‌توانیم از این اطلاعات برای اجازه دادن به کاربر برای کنترل لایه در هر صفحه استفاده کنیم. به عنوان مثال، کاربر می‌تواند مشخص کند که صفحه باید از یک طرح صفحه خانه خاص استفاده کند با:\n\n```md\n---\nlayout: home\n---\n```\n\nو ما می‌توانیم تم خود را تنظیم کنیم تا با این موضوع برخورد کند:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>طرح سفارشی!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    صفحه 404 سفارشی!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    صفحه خانه سفارشی!\n  </div>\n  <Content v-else />\n</template>\n```\n\nطبیعتا، شما می‌توانید لایه‌ی خود را به کامپوننت‌های بیشتری تقسیم کنید:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>طرح سفارشی!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> با `<Content />` را نمایش می‌دهد -->\n</template>\n```\n\nبرای همه چیزی که در کامپوننت‌های تم موجود است، به [مستندات API اجرایی](../reference/runtime-api) مراجعه کنید. به علاوه، شما می‌توانید از [بارگذاری داده در زمان ساخت](./data-loading) استفاده کنید تا لایه‌های مبتنی بر داده را تولید کنید - به عنوان مثال، یک صفحه که تمام پست‌های وبلاگ در پروژه فعلی را لیست می‌کند.\n\n## توزیع یک تم سفارشی {#distributing-a-custom-theme}\n\nآسان‌ترین روش برای توزیع یک تم سفارشی ارائه آن به عنوان [قالب مخزن در GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository) است.\n\nاگر می‌خواهید تم را به عنوان یک بسته npm توزیع کنید، مراحل زیر را دنبال کنید:\n\n1. شیء تم را به عنوان export پیش‌فرض در ورودی بسته‌تان export کنید.\n\n2. اگر امکان دارد، تعریف نوع پیکربندی تم خود را به عنوان `ThemeConfig` export کنید.\n\n3. اگر تم شما نیاز به تنظیم پیکربندی ویت‌پرس دارد، پیکربندی را تحت یک زیر‌مسیر بسته (مانند `my-theme/config`) export کنید تا کاربر بتواند آن را گسترش دهد.\n\n4. گزینه‌های پیکربندی تم را مستند کنید (هم از طریق فایل پیکربندی و هم از طریق frontmatter).\n\n5. دستورالعمل‌های روشنی برای مصرف تم خود ارائه دهید (مانند زیر).\n\n## مصرف یک تم سفارشی {#consuming-a-custom-theme}\n\nبرای مصرف یک تم خارجی، آن را از ورودی تم سفارشی وارد و دوباره export کنید:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nاگر تم نیاز به گسترش دارد:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nاگر تم نیاز به پیکربندی خاص ویت‌پرس دارد، شما همچنین باید آن را در پیکربندی خود گسترش دهید:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // گسترش پیکربندی پایه‌ی تم (اگر لازم باشد)\n  extends: baseConfig\n}\n```\n\nسرانجام، اگر تم انواع خود را برای پیکربندی تم‌اش ارائه می‌دهد:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // نوع `ThemeConfig` است\n  }\n})\n```\n"
  },
  {
    "path": "docs/fa/guide/data-loading.md",
    "content": "# بارگذاری داده در زمان ساخت {#build-time-data-loading}\n\nویت‌پرس یک ویژگی به نام **بارگذارهای داده** ارائه می‌دهد که به شما این امکان را می‌دهد که داده‌های دلخواه را بارگیری کنید و آن‌ها را از صفحات یا اجزا وارد کنید. بارگذاری داده فقط **در زمان ساخت** اجرا می‌شود: داده‌های حاصل به صورت JSON در بسته JavaScript نهایی سریالیزه می‌شوند.\n\nبارگذارهای داده می‌توانند برای بارگیری داده‌های از راه دور یا تولید فراداده‌ها بر اساس فایل‌های محلی استفاده شوند. به عنوان مثال، می‌توانید از بارگذارهای داده استفاده کنید تا تمام صفحات API محلی خود را تجزیه کنید و به طور خودکار یک فهرست از تمام ورودی‌های API تولید کنید.\n\n## استفاده ابتدایی {#basic-usage}\n\nیک فایل بارگذار داده باید با `.data.js` یا `.data.ts` پایان یابد. فایل باید یک صادرات پیش‌فرض از یک شی با متد `load()` داشته باشد:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\nماژول بارگذار فقط در Node.js ارزیابی می‌شود، بنابراین شما می‌توانید API ‌های Node و وابستگی‌های npm را به عنوان نیازهای خود وارد کنید.\n\nسپس می‌توانید داده را از این فایل در صفحات `.md` و اجزا `.vue` با استفاده از صادرات نام‌گذاری شده `data` وارد کنید:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\nخروجی:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\nشما متوجه خواهید شد که بارگذار داده خودش داده را صادر نمی‌کند. ویت‌پرس پشت صحنه متد `load()` را فراخوانی می‌کند و به طور ضمنی نتیجه را از طریق صادرات نام‌گذاری شده `data` ارائه می‌دهد.\n\nاین کار حتی اگر بارگذار async باشد انجام می‌شود:\n\n```js\nexport default {\n  async load() {\n    // دریافت داده از راه دور\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## داده از فایل‌های محلی {#data-from-local-files}\n\nوقتی نیاز به تولید داده بر اساس فایل‌های محلی دارید، باید از گزینه `watch` در بارگذار داده استفاده کنید تا تغییرات اعمال شده به این فایل‌ها بتواند به روزرسانی‌های سریع منجر شود.\n\nگزینه `watch` همچنین در آنجا مفید است که می‌توانید از [الگوهای glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) برای تطابق با چندین فایل استفاده کنید. الگوها می‌توانند نسبت به فایل بارگذار خود نسبی باشند و تابع `load()` فایل‌های تطابق یافته را به عنوان مسیرهای مطلق دریافت می‌کند.\n\nمثال زیر نشان می‌دهد که چگونه فایل‌های CSV را بارگذاری کرده و آن‌ها را با استفاده از [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) به JSON تبدیل می‌کند. این فایل تنها در زمان ساخت اجرا می‌شود، بنابراین شما نیازی به ارسال پارسر CSV به مشتری ندارید!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles یک آرایه از مسیرهای مطلق فایل‌های تطابق یافته خواهد بود.\n    // تولید یک آرایه از فراداده‌های پست وبلاگ که می‌تواند برای نمایش\n    // یک لیست در طرح استفاده شود\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader` {#createcontentloader}\n\nوقتی که در حال ساختن یک سایت متمرکز بر محتوا هستیم، اغلب نیاز به ایجاد یک \"بایگانی\" یا \"فهرست\" صفحه داریم: یک صفحه که ما همه ورودی‌های موجود در مجموعه محتوای خود را لیست می‌کنیم، به عنوان مثال پست‌های وبلاگ یا صفحات API. ما می‌توانیم این کار را مستقیماً با API بارگذار داده انجام دهیم، اما از آنجا که این یک حالت استفاده رایج است، ویت‌پرس همچنین یک کمک‌کننده به نام `createContentLoader` را فراهم می‌کند تا این فرآیند را ساده‌تر کند:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* گزینه‌ها */)\n```\n\nکمک‌کننده یک الگوی glob را نسبت به [دایرکتوری منبع](./routing#source-directory) مشخص می‌کند و یک شی `{ watch، load }` را که می‌تواند به عنوان صادرات پیش‌فرض در یک فایل بارگذار داده استفاده شود، برمی‌گرداند. همچنین پیاده‌سازی حافظه پنهانی بر اساس برچسب‌های تغییر مدیریت\n\nمی‌کند تا عملکرد توسعه را بهبود بخشد.\n\nلطفاً توجه داشته باشید که بارگذار فقط با فایل‌های Markdown کار می‌کند - فایل‌های غیر-Markdown تطابق یافته حذف می‌شوند.\n\nداده بارگذاری شده یک آرایه با نوع `ContentData[]` خواهد بود:\n\n```ts\ninterface ContentData {\n  // آدرس URL برای صفحه. به عنوان مثال /posts/hello.html (شامل پایه نمی‌شود)\n  // تکرار دستی یا استفاده از `transform` سفارشی برای نرمال کردن مسیرها\n  url: string\n  // اطلاعات frontmatter صفحه\n  frontmatter: Record<string, any>\n\n  // موارد زیر فقط وقتی که گزینه‌های مربوط فعال باشند\n  // ما در زیر آنها را بررسی می‌کنیم\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nبه طور پیش‌فرض، تنها `url` و `frontmatter` ارائه می‌شوند. این به خاطر این است که داده بارگذاری شده به عنوان JSON در بسته مشتری نهایی درج می‌شود، بنابراین ما باید در مورد اندازه آن محتاط باشیم. در زیر مثالی از استفاده از داده برای ساخت یک صفحه فهرست کمینه وبلاگ آورده شده است:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>همه پست‌های وبلاگ</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>توسط {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### گزینه‌ها {#options}\n\nاحتمالاً داده پیش‌فرض به تمام نیازها پاسخ نمی‌دهد - شما می‌توانید با استفاده از گزینه‌ها به تبدیل داده‌ها مشترک شوید:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // آیا منبع اصلی مارک‌داون را اضافه کنیم؟\n  render: true,     // آیا صفحه HTML را نیز شامل کنیم؟\n  excerpt: true,    // آیا خلاصه را نیز شامل کنیم؟\n  transform(rawData) {\n    // نقشه‌برداری، مرتب‌سازی یا فیلتر کردن داده‌های اصلی به دلخواه.\n    // نتیجه نهایی آنچه است که به مشتری ارسال خواهد شد.\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // منبع اصلی مارک‌داون\n      page.html    // صفحه HTML کامل\n      page.excerpt // خلاصه HTML (محتوای بالای اولین `---`)\n      return {/* ... */}\n    })\n  }\n})\n```\n\nبررسی کنید که چگونه در [وبلاگ Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts) استفاده شده است.\n\nAPI `createContentLoader` همچنین می‌تواند در داخل [هوک‌های ساخت](../reference/site-config#build-hooks) استفاده شود:\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // تولید فایل‌های بر اساس فراداده‌های پست‌ها، مثلاً فید RSS\n  }\n}\n```\n\n**انواع**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * آیا منبع اصلی را اضافه کنیم؟\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * آیا منبع را به HTML تبدیل کرده و در داده شامل کنیم؟\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * اگر `boolean` باشد، آیا باید خلاصه را تجزیه و شامل کنیم؟ (به صورت HTML)\n   *\n   * اگر `function` باشد، کنترل نحوه استخراج خلاصه از محتوا.\n   *\n   * اگر `string` باشد، تعیین کنید که چگونه جداکننده سفارشی باید برای استخراج خلاصه استفاده شود.\n   * جداکننده پیش‌فرض `---` است اگر `excerpt` `true` باشد.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * تبدیل داده. توجه داشته باشید که داده به عنوان JSON در بسته مشتری درج خواهد شد\n   * اگر از اجزا یا فایل‌های مارک‌داون وارد شود.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## بارگذارهای داده تایپ شده  {#typed-data-loaders}\n\nزمان استفاده از TypeScript، می‌توانید بارگذار و صادرات `data` خود را به این شکل تایپ کنید:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // نوع داده\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // گزینه‌های بارگذاری با تایپ چک شده\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## پیکربندی {#configuration}\n\nبرای دریافت اطلاعات پیکربندی در داخل یک بارگذار، می‌توانید از کدی مانند زیر استفاده کنید:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/fa/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# استقرار وب‌سایت ویت‌پرس شما {#deploy-your-vitepress-site}\n\nراهنماهای زیر بر اساس برخی فرضیات مشترک است:\n\n- وب‌سایت ویت‌پرس در دایرکتوری `docs` پروژه شما قرار دارد.\n- شما از دایرکتوری خروجی پیش‌فرض ساخته‌شده (`.vitepress/dist`) استفاده می‌کنید.\n- ویت‌پرس به‌عنوان یک وابستگی محلی در پروژه شما نصب شده است و شما اسکریپت‌های زیر را در `package.json` پیکربندی کرده‌اید:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## ساخت و تست محلی  {#build-and-test-locally}\n\n1. برای ساخت اسناد، این دستور را اجرا کنید:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. پس از ساخت، آن را به‌صورت محلی پیش‌نمایش دهید با اجرای این دستور:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   دستور `preview` یک سرور وب ایستا محلی راه‌اندازی می‌کند که دایرکتوری خروجی `.vitepress/dist` را در آدرس `http://localhost:4173` ارائه می‌دهد. شما می‌توانید از این امکان استفاده کنید تا اطمینان حاصل کنید که همه چیز قبل از رفع به محیط تولیدی به‌درستی نمایش داده می‌شود.\n\n3. می‌توانید پورت سرور را با انتقال `--port` به‌عنوان یک آرگمان پیکربندی کنید.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   حالا اسکریپت `docs:preview` سرور را در `http://localhost:8080` راه‌اندازی خواهد کرد.\n\n## تنظیم مسیر پایه عمومی {#setting-a-public-base-path}\n\nبه‌طور پیش‌فرض، ما فرض می‌کنیم که وب‌سایت در مسیر ریشه دامنه (`/`) انتشار می‌یابد. اگر وب‌سایت شما باید در یک زیرمسیر ارائه شود، مانند `https://mywebsite.com/blog/`، در این صورت باید گزینه [`base`](../reference/site-config#base) را به `'/blog/'` در پیکربندی ویت‌پرس تنظیم کنید.\n\n**مثال:** اگر از صفحات GitHub (یا GitLab) استفاده می‌کنید و به `user.github.io/repo/` انتشار می‌دهید، آنگاه `base` را به `/repo/` تنظیم کنید.\n\n## سربرگ‌های حافظه نهان HTTP {#http-cache-headers}\n\nاگر شما کنترلی بر روی سربرگ‌های HTTP در سرور تولیدی خود دارید، می‌توانید سربرگ‌های `cache-control` را پیکربندی کنید تا بهبود عملکرد در بازدیدهای تکراری داشته باشید.\n\nبسیاری از فایل‌های ایستا (مانند JavaScript، CSS و سایر فایل‌های وارد شده که در `public` نیستند) از نام‌های فایل با هش استفاده می‌کنند. اگر پیش‌نمایش تولیدی را با استفاده از تب شبکه ابزارهای توسعه مرورگر خود بررسی کنید، فایل‌هایی مانند `app.4f283b18.js` را خواهید دید.\n\nاین هش `4f283b18` از محتوای این فایل تولید شده است. اگر محتوا تغییر کند، URL‌ها نیز تغییر می‌کنند. این به این معنی است که می‌توانید برای این فایل‌ها سربرگ‌های حافظه نهان قدرتمند را استفاده کنید. همه این فایل‌ها در زیردایرکتوری `assets/` در دایرکتوری خروجی قرار می‌گیرند، بنابراین می‌توانید برای آن‌ها سربرگ زیر را پیکربندی کنید:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details مثال فایل `_headers` برای Netlify\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\nتوجه: فایل `_headers` باید در [دایرکتوری عمومی](./asset-handling#the-public-directory) قرار گیرد - در این مورد، `docs/public/_headers` - تا کپی شود بطور صحیح به دایرکتوری خروجی.\n\n[مستندات سربرگ‌های سفارشی Netlify](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details پیکربندی مثال Vercel در `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nتوجه: فایل `vercel.json` باید در ریشه مخزن شما قرار گیرد.\n\n[مستندات Vercel در مورد پیکربندی سربرگ‌ها](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## راهنمای‌های پلتفرم {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\nیک پروژه جدید راه‌اندازی کرده و این تنظیمات را با استفاده از داشبورد خود تغییر دهید:\n\n- **دستور ساخت:** `npm run docs:build`\n- **دایرکتوری خروجی:** `docs/.vitepress/dist`\n- **نسخه Node:** `20` (یا بالاتر)\n\n::: warning هشدار\nگزینه‌هایی مانند _Auto Minify_ را برای کد HTML فعال نکنید. این گزینه‌ها ممکن است توضیحاتی را که به Vue معنا دارد، از خروجی حذف کنند. ممکن است خطاهای ناسازگاری را در اجرا ببینید اگر حذف شوند.\n:::\n\n### صفحات GitHub {#github-pages}\n\n1. یک فایل به نام `deploy.yml` در دایرکتوری `.github/workflows` پروژه خود ایجاد کنید با محتوایی مانند زیر:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Sample workflow for building and deploying a ویت‌پرس site to GitHub Pages\n   #\n   name: Deploy ویت‌پرس site to Pages\n\n   on:\n     # Runs on pushes targeting the `main` branch. Change this to `master` if you're\n     # using the `master` branch as the default branch.\n     push:\n       branches: [main]\n\n     # Allows you to run this workflow manually from the Actions tab\n     workflow_dispatch:\n\n   # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n   # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Build job\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # Not needed if lastUpdated is not enabled\n         # - uses: pnpm/action-setup@v4 # Uncomment this if you're using pnpm\n         # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # or pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # or pnpm install / yarn install / bun install\n         - name: Build with ویت‌پرس\n           run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Deployment job\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n::: warning هشدار\n   مطمئن شوید که گزینه `base` در ویت‌پرس به‌درستی پیکربندی شده است. برای اطلاعات بیشتر به [تنظیم مسیر پایه عمومی](#setting-a-public-base-path) مراجعه کنید.\n   :::\n\n2. در تنظیمات مخزن خود در زیرمنوی \"Build and deployment > Source\" در \"Github Actions\"  را انتخاب کنید.\n\n3. تغییرات خود را به شاخه `main` ارسال کنید و منتظر GitHub Actions workflow بمانید. شما باید وب‌سایت خود را در `https://<username>.github.io/[repository]/` یا `https://<custom-domain>/` بسته به تنظیمات خود دیده شده است. وب‌سایت شما به‌طور خودکار در هر بار فشرده‌سازی به شاخه `main` ارسال می‌شود.\n\n### صفحات GitLab {#gitlab-pages}\n\n1. `outDir` را در پیکربندی ویت‌پرس به `../public` تنظیم کنید. گزینه `base` را به `'/<repository>/'` تنظیم کنید اگر می‌خواهید در `https://<username>.gitlab.io/<repository>/` انتشار دهید. اگر روی دامنه سفارشی، صفحات کاربر یا گروه منتشر می‌کنید یا تنظیمات \"Use unique domain\" در GitLab فعال است، نیازی به `base` ندارید.\n\n2. یک فایل به نام `.gitlab-ci.yml` در ریشه پروژه خود با محتوای زیر ایجاد کنید. این کار به ساخت و انتشار وب‌سایت شما هر زمانی که تغییری در محتوا ایجاد می‌کنید، می‌پردازد:\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Uncomment this if you're using small docker images like alpine and have lastUpdated enabled\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. دستورالعمل [رسمی](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration) را دنبال کنید.\n\n2. این مقادیر را در فایل پیکربندی خود تنظیم کنید (و مواردی که نیازی به آن‌ها ندارید، مانند `api_location` را حذف کنید):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\nمی‌توانید پروژه ویت‌پرس خود را با [CloudRay](https://cloudray.io/) با دنبال کردن این [دستورالعمل‌ها](https://cloudray.io/articles/how-to-deploy-vitepress-site) منتشر کنید.\n\n### Firebase\n\n1. فایل‌های `firebase.json` و `.firebaserc` را در ریشه پروژه خود ایجاد کنید:\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. بعد از اجرای `npm run docs:build`، دستور زیر را برای انتشار اجرا کنید:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. دستورالعمل و راهنماها را در [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) دنبال کنید.\n\n2. یک فایل به نام `static.json` در ریشه پروژه خود با محتوای زیر ایجاد کنید:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\nمی‌توانید پروژه ویت‌پرس خود را با [Hostinger](https://www.hostinger.com/web-apps-hosting) با دنبال کردن این [دستورالعمل‌ها](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/) منتشر کنید. هنگام پیکربندی تنظیمات ساخت، VitePress را به عنوان فریم‌ورک انتخاب کنید و ریشه دایرکتوری را به `./docs` تنظیم کنید.\n\n### Kinsta\n\nشما می‌توانید وب‌سایت ویت‌پرس خود را بر روی [Kinsta](https://kinsta.com/static-site-hosting/) با دنبال کردن این [دستورالعمل‌ها](https://kinsta.com/docs/vitepress-static-site-example/) انتشار دهید.\n\n### Stormkit\n\nشما می‌توانید پروژه ویت‌پرس خود را به [Stormkit](https://www.stormkit.io) با دنبال کردن این [دستورالعمل‌ها](https://stormkit.io/blog/how-to-deploy-vitepress) انتشار دهید.\n\n### Surge\n\n1. بعد از اجرای `npm run docs:build`، دستور زیر را برای انتشار اجرا کنید:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\nاینجا یک مثال از پیکربندی بلوک سرور Nginx است. این تنظیم شامل فشرده‌سازی gzip برای فایل‌های متن معمولی، قوانین برای سرویس فایل‌های ایستا سایت ویت‌پرس شما با هدرهای مناسب برای حافظه‌نگهداری مناسب است و همچنین مدیریت `cleanUrls: true` می‌کند.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # content location\n        root /app;\n\n        # exact matches -> reverse clean urls -> folders -> not found\n        try_files $uri $uri.html $uri/ =404;\n\n        # non existent pages\n        error_page 404 /404.html;\n\n        # a folder without index.html raises 403 in this setup\n        error_page 403 /404.html;\n\n        # adjust caching headers\n        # files in the assets folder have hashes filenames\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nاین پیکربندی فرض می‌کند که سایت ویت‌پرس ساخته شده شما در دایرکتوری `/app` در سرور شما قرار دارد. دستورالعمل `root` را از ابزارهای مربوطه استفاده کنید اگر فایل‌های سایت شما در جای دیگری قرار دارد.\n\n::: warning هشدار\nمسیر تنظیمات try_files نباید به طور پیش‌فرض به index.html مانند برنامه‌های دیگر Vue مشخص شود. این کار باعث وضعیت نامعتبر صفحه می‌شود.\n:::\n\nاطلاعات بیشتر را در [مستندات رسمی nginx](https://nginx.org/en/docs/)، در این مسائل [#2837](https://github.com/vuejs/vitepress/discussions/2837)، [#3235](https://github.com/vuejs/vitepress/issues/3235) و همچنین در این [پست وبلاگ](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) از Mehdi Merah پیدا کنید.\n"
  },
  {
    "path": "docs/fa/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# گسترش تم پیش‌فرض {#extending-the-default-theme}\n\nتم پیش‌فرض ویت‌پرس برای مستندات بهینه‌سازی شده است و قابلیت سفارشی‌سازی دارد. برای دریافت لیست جامع گزینه‌ها، به [نمای کلی از تنظیمات تم پیش‌فرض](../reference/default-theme-config) مراجعه کنید.\n\nبا این حال، مواردی وجود دارد که فقط با تنظیمات کافی نخواهد بود. به عنوان مثال:\n\n1. نیاز به تنظیم استایل CSS دارید؛\n2. نیاز به اصلاح نمونه برنامه Vue، به عنوان مثال برای ثبت مولفه‌های عمومی؛\n3. نیاز به درج محتوای سفارشی در تم از طریق slot‌های طرح.\n\nاین سفارش‌های پیشرفته نیازمند استفاده از یک تم سفارشی هستند که از تم پیش‌فرض \"گسترش\" می‌کند.\n\n::: tip نکته\nقبل از ادامه، ابتدا [استفاده از یک تم سفارشی](./custom-theme) را بخوانید تا نحوه کار تم‌های سفارشی را درک کنید.\n:::\n\n## سفارشی‌سازی CSS {#customizing-css}\n\nCSS تم پیش‌فرض با نادیده گرفتن متغیرهای CSS سطح ریشه قابل سفارشی‌سازی است:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\nلیست متغیرهای CSS [تم پیش‌فرض](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) که می‌توانند سفارشی‌سازی شوند را ببینید.\n\n## استفاده از فونت‌های مختلف {#using-different-fonts}\n\nویت‌پرس از [Inter](https://rsms.me/inter/) به عنوان فونت پیش‌فرض استفاده می‌کند و فونت‌ها را در خروجی ساخته‌شده شامل می‌شود. این فونت همچنین در محصولات خودکار پیش‌بارگذاری می‌شود. با این حال، این ممکن است مطلوب نباشد اگر می‌خواهید از یک فونت اصلی مختلف استفاده کنید.\n\nبرای جلوگیری از شامل شدن Inter در خروجی ساخته‌شده، تم را به جای `vitepress/theme-without-fonts` وارد کنید:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-font-family-base: /* فونت متن عادی */\n  --vp-font-family-mono: /* فونت کد */\n}\n```\n\n::: warning هشدار\nاگر از مولفه‌های اختیاری مانند مولفه‌های [صفحه تیم](../reference/default-theme-team-page) استفاده می‌کنید، اطمینان حاصل کنید که آن‌ها را هم از `vitepress/theme-without-fonts` وارد می‌کنید!\n:::\n\nاگر فونت شما یک فایل محلی است که از طریق `@font-face` ارجاع شده است، به عنوان یک دارایی پردازش می‌شود و با نام فایل هشداردار در `.vitepress/dist/assets` شامل می‌شود. برای پیش‌بارگذاری این فایل، از هوک ساخت [transformHead](../reference/site-config#transformhead) استفاده کنید:\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // منظور شده برای همسان سازی font خود، regex مورد نیاز را تنظیم کنید\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## ثبت مولفه‌های عمومی {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // ثبت مولفه‌های عمومی سفارشی‌شده خود را\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nاگر از TypeScript استفاده می‌کنید:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // ثبت مولفه‌های عمومی سفارشی‌شده خود را\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nاز آنجا که از Vite استفاده می‌کنیم، می‌توانید از ویژگی [import glob](https://vitejs.dev/guide/features.html#glob-import) در Vite برای خودکار ثبت یک پوشه از مولفه‌ها استفاده کنید.\n\n## slot ‌های طرح {#layout-slots}\n\nکامپوننت `<Layout/>` تم پیش‌فرض چندین slot دارد که می‌توانید محتوا را در موقعیت‌های مختلف صفحه در آن‌ها درج کنید. در زیر مثالی از درج یک کامپوننت در قبل از طرح داده شده است:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // جایگزینی Layout با یک کامپوننت پوشه‌بندی که slot‌ها را درج می‌کند\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      محتوای سفارشی بالای نوار کناری من\n    </template>\n  </Layout>\n\n\n</template>\n```\n\nیا می‌توانید از تابع رندر نیز استفاده کنید.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nلیست کاملی از slot‌های موجود در طرح پیش‌فرض:\n\n- وقتی `layout: 'doc'` (پیش‌فرض) از طریق frontmatter فعال است:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- وقتی `layout: 'home'` از طریق frontmatter فعال است:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- وقتی `layout: 'page'` از طریق frontmatter فعال است:\n  - `page-top`\n  - `page-bottom`\n- در صفحه یافت نشد (404):\n  - `not-found`\n- همیشه:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n\n## استفاده از API انتقال نمایش {#using-view-transitions-api}\n\n### در تغییر ظاهر {#on-appearance-toggle}\n\nشما می‌توانید تم پیش‌فرض را گسترش دهید تا هنگام تغییر حالت رنگ، یک انتقال سفارشی را فراهم کند. به عنوان مثال:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\nنتیجه (**هشدار!**: رنگ‌های فلاشینگ، حرکات ناگهانی، نورهای شدید):\n\n<details>\n<summary>نمایش</summary>\n\n![نمایش انتقال ظاهر تغییر](/appearance-toggle-transition.webp)\n\n</details>\n\nبرای جزئیات بیشتر در مورد انتقال‌های نمایش به [اسناد کروم](https://developer.chrome.com/docs/web-platform/view-transitions/) مراجعه کنید.\n\n### در تغییر مسیر {#on-route-change}\n\nبه زودی.\n\n## جایگزینی کامپوننت‌های داخلی {#overriding-internal-components}\n\nشما می‌توانید با استفاده از [alias های Vite](https://vitejs.dev/config/shared-options.html#resolve-alias)، کامپوننت‌های تم پیش‌فرض را با کامپوننت‌های سفارشی خود جایگزین کنید:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\nبرای دریافت نام دقیق کامپوننت به [کد منبع ما](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components) مراجعه کنید. از آنجا که کامپوننت‌ها داخلی هستند، احتمال آنکه نام آن‌ها بین انتشارات کوچک تغییر کند، وجود دارد.\n"
  },
  {
    "path": "docs/fa/guide/frontmatter.md",
    "content": "# Frontmatter\n\n## استفاده {#usage}\n\nویت‌پرس پشتیبانی از frontmatter YAML در تمام فایل‌های Markdown را دارد و آن‌ها را با استفاده از [gray-matter](https://github.com/jonschlinkert/gray-matter) تجزیه می‌کند. Frontmatter باید در بالای فایل Markdown قرار داشته باشد (قبل از هر عنصر از جمله برچسب‌های `<script>`) و باید به صورت YAML معتبر واقع در بین خطوط خط کشیده شود. به عنوان مثال:\n\n```md\n---\ntitle: مستندات با ویت‌پرس\neditLink: true\n---\n```\n\nبسیاری از گزینه‌های پیکربندی سایت یا پیش‌فرض در تمام frontmatter گزینه‌های متناظر دارند. شما می‌توانید از frontmatter برای لغو عملکرد خاص برای صفحه فعلی استفاده کنید. برای جزئیات بیشتر، به [مرجع پیکربندی Frontmatter](../reference/frontmatter-config) مراجعه کنید.\n\nهمچنین می‌توانید داده‌های اختصاصی frontmatter خود را تعریف کنید تا در بیانیه‌های پویا Vue در صفحه استفاده شود.\n\n## دسترسی به داده‌های Frontmatter {#accessing-frontmatter-data}\n\nداده‌های frontmatter می‌توانند از طریق متغیر global ویژه `$frontmatter` دسترسی داشته باشند:\n\nاینجا یک مثال از نحوه استفاده از آن در فایل Markdown شما است:\n\n```md\n---\ntitle: مستندات با ویت‌پرس\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nمحتوای راهنما\n```\n\nشما همچنین می‌توانید داده‌های frontmatter صفحه فعلی را در `<script setup>` با استفاده از راهنمای [`useData()`](../reference/runtime-api#usedata) به دست آورید.\n\n## فرمت‌های جایگزین Frontmatter {#alternative-frontmatter-formats}\n\nویت‌پرس همچنین از نحوه نوشتاری frontmatter JSON با استفاده از تکیه‌گاه‌های آغازین و پایانی در آکولاد پشتیبانی می‌کند:\n\n```json\n---\n{\n  \"title\": \"عنوان\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/fa/guide/getting-started.md",
    "content": "# شروع کار {#getting-started}\n\n## تست آنلاین {#try-it-online}\n\nمی‌توانید ویت‌پرس را مستقیماً در مرورگر خود در [StackBlitz](https://vitepress.new) امتحان کنید.\n\n## نصب {#installation}\n\n### پیش‌نیازها {#prerequisites}\n\n- [Node.js](https://nodejs.org/) نسخه 20 یا بالاتر.\n- ترمینال برای دسترسی به ویت‌پرس از طریق رابط خط فرمان (CLI).\n- ویرایشگر متنی با پشتیبانی از [Markdown](https://en.wikipedia.org/wiki/Markdown).\n  - [VSCode](https://code.visualstudio.com/) به همراه [افزونه رسمی Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nویت‌پرس می‌تواند به صورت مستقل استفاده شود یا در یک پروژه موجود نصب شود. در هر دو حالت، می‌توانید آن را با دستور زیر نصب کنید:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip نکته\n\nویت‌پرس یک بسته فقط ESM است. از `require()` برای وارد کردن آن استفاده نکنید و اطمینان حاصل کنید که نزدیک‌ترین `package.json` شما شامل `\"type\": \"module\"` است، یا پسوند فایل‌های مربوطه خود مانند `.vitepress/config.js` را به `.mjs`/`.mts` تغییر دهید. برای جزئیات بیشتر به [راهنمای عیب‌یابی Vite](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) مراجعه کنید. همچنین، در زمینه‌های async CJS می‌توانید از `await import('vitepress')` استفاده کنید.\n\n:::\n\n### Wizard راه‌اندازی\n\nویت‌پرس با یک جادوگر راه‌اندازی خط فرمان ارائه می‌شود که به شما کمک می‌کند یک پروژه پایه را بسازید. پس از نصب، با اجرای دستور زیر جادوگر را راه‌اندازی کنید:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nچند سوال ساده از شما پرسیده خواهد شد:\n\n<<< @/snippets/init.ansi\n\n::: tip Vue به عنوان peer dependency\n\nاگر قصد دارید سفارشی‌سازی‌هایی که از کامپوننت‌ها یا APIهای Vue استفاده می‌کنند را انجام دهید، باید `vue` را به عنوان dependency نیز نصب کنید.\n\n:::\n\n## ساختار فایل‌ها {#file-structure}\n\nاگر در حال ساخت یک سایت مستقل ویت‌پرس هستید، می‌توانید سایت را در دایرکتوری فعلی خود (`./`) بسازید. اما، اگر ویت‌پرس را در یک پروژه موجود به همراه سایر کدهای منبع نصب می‌کنید، توصیه می‌شود سایت را در یک دایرکتوری تودرتو (مثلاً `./docs`) بسازید تا از بقیه پروژه جدا باشد.\n\nفرض کنیم که پروژه ویت‌پرس را در `./docs` ساخته‌اید، ساختار فایل‌های تولید شده باید به این شکل باشد:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\nدایرکتوری `docs` به عنوان **ریشه پروژه** سایت ویت‌پرس در نظر گرفته می‌شود. دایرکتوری `.vitepress` محل ذخیره فایل‌های پیکربندی ویت‌پرس، حافظه نهان سرور توسعه، خروجی ساخت و کد سفارشی‌سازی تم اختیاری است.\n\n::: tip نکته\n\nبه طور پیش‌فرض، ویت‌پرس حافظه نهان سرور توسعه خود را در `.vitepress/cache` و خروجی ساخت تولیدی را در `.vitepress/dist` ذخیره می‌کند. اگر از Git استفاده می‌کنید، باید آنها را به فایل `.gitignore` خود اضافه کنید. این مکان‌ها همچنین قابل [پیکربندی](../reference/site-config#outdir) هستند.\n\n:::\n\n### فایل پیکربندی {#the-config-file}\n\nفایل پیکربندی (`.vitepress/config.js`) به شما اجازه می‌دهد جنبه‌های مختلف سایت ویت‌پرس خود را سفارشی کنید، با گزینه‌های پایه‌ای مانند عنوان و توضیحات سایت:\n\n```js [.vitepress/config.js]\nexport default {\n  // گزینه‌های سطح سایت\n  title: 'ویت‌پرس',\n  description: 'فقط در حال بازی کردن.',\n\n  themeConfig: {\n    // گزینه‌های سطح تم\n  }\n}\n```\n\nهمچنین می‌توانید رفتار تم را از طریق گزینه `themeConfig` پیکربندی کنید. برای جزئیات کامل درباره همه گزینه‌های پیکربندی، به [راهنمای پیکربندی](../reference/site-config) مراجعه کنید.\n\n### فایل‌های منبع {#source-files}\n\nفایل‌های Markdown خارج از دایرکتوری `.vitepress` به عنوان **فایل‌های منبع** در نظر گرفته می‌شوند.\n\nویت‌پرس از **مسیر یابی مبتنی بر فایل** استفاده می‌کند: هر فایل `.md` به یک فایل `.html` متناظر با همان مسیر کامپایل می‌شود. برای مثال، `index.md` به `index.html` کامپایل می‌شود و می‌تواند در مسیر ریشه `/` سایت ویت‌پرس نتیجه‌گیری شده بازدید شود.\n\nویت‌پرس همچنین قابلیت تولید URL‌های تمیز، بازنویسی مسیرها و تولید پویا صفحات را فراهم می‌کند. این موارد در [راهنمای مسیر یابی](./routing) پوشش داده خواهند شد.\n\n## راه‌اندازی و اجرا {#up-and-running}\n\nاین ابزار باید اسکریپت‌های npm زیر را به `package.json` شما اضافه کرده باشد اگر اجازه این کار را در طول فرآیند راه‌اندازی داده باشید:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\nاسکریپت `docs:dev` یک سرور توسعه محلی با به‌روزرسانی‌های فوری راه‌اندازی می‌کند. آن را با دستور زیر اجرا کنید:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nبه جای اسکریپت‌های npm، می‌توانید ویت‌پرس را مستقیماً با دستور زیر اجرا کنید:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nاستفاده بیشتر از خط فرمان در [مرجع CLI](../reference/cli) مستند شده است.\n\nسرور توسعه باید در `http://localhost:5173` اجرا شود. URL را در مرورگر خود بازدید کنید تا سایت جدید خود را در عمل ببینید!\n\n## مراحل بعدی {#what-s-next}\n\n- برای درک بهتر چگونگی نگاشت فایل‌های markdown به HTML تولید شده، به [راهنمای مسیر یابی](./routing) مراجعه کنید.\n\n- برای کشف بیشتر درباره اینکه چه کارهایی می‌توانید در صفحه انجام دهید، مانند نوشتن محتوای markdown یا استفاده از کامپوننت‌های Vue، به بخش \"نوشتن\" راهنما مراجعه کنید. یک مکان عالی برای شروع یادگیری درباره [افزونه‌های Markdown](./markdown) است.\n\n- برای کشف ویژگی‌های ارائه شده توسط تم پیش‌فرض مستندات، به [مرجع پیکربندی تم پیش‌فرض](../reference/default-theme-config) مراجعه کنید.\n\n- اگر می‌خواهید ظاهر سایت خود را بیشتر سفارشی کنید، بررسی کنید که چگونه [تم پیش‌فرض را گسترش دهید](./extending-default-theme) یا [یک تم سفارشی بسازید](./custom-theme).\n\n- هنگامی که سایت مستندات شما شکل گرفت، حتماً [راهنمای استقرار](./deploy) را بخوانید.\n"
  },
  {
    "path": "docs/fa/guide/i18n.md",
    "content": "# بین‌المللی‌سازی {#internationalization}\n\nبرای استفاده از ویژگی‌های داخلی بین‌المللی‌سازی، نیاز است که یک ساختار دایرکتوری به شکل زیر ایجاد کنید:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\nسپس در `docs/.vitepress/config.ts` به شکل زیر عمل کنید:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ویژگی‌های مشترک و دیگر موارد در سطح بالا...\n\n  locales: {\n    root: {\n      label: 'انگلیسی',\n      lang: 'en'\n    },\n    fr: {\n      label: 'فرانسوی',\n      lang: 'fr', // اختیاری، به عنوان `lang` در `html` tag اضافه خواهد شد\n      link: '/fr/guide' // پیش‌فرض /fr/ -- در منوی ترجمه‌ها نمایش داده می‌شود، می‌تواند خارجی باشد\n\n      // سایر ویژگی‌های مختص به هر زبان...\n    }\n  }\n})\n```\n\nمی‌توانید خصوصیات زیر را برای هر زبان (شامل ریشه) نیز تغییر دهید:\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // با ورودی‌های head موجود ادغام خواهد شد، meta tags تکراری به طور خودکار حذف می‌شوند\n  themeConfig?: ThemeConfig // ادغام سطح بالا، می‌توان اطلاعات مشترک را در ورودی themeConfig اضافه کرد\n}\n```\n\nبرای جزئیات درباره تنظیمات پیش‌فرض، به رابط `DefaultTheme.Config` در [اینجا](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) مراجعه کنید. لطفاً خصوصیات `themeConfig.algolia` یا `themeConfig.carbonAds` را در سطح زبان تغییر ندهید. برای استفاده از جستجوی چندزبانه، به [مستندات Algolia](../reference/default-theme-search#i18n) مراجعه کنید.\n\n**نکته حرفه‌ای:** فایل پیکربندی را می‌توانید در `docs/.vitepress/config/index.ts` نیز ذخیره کنید. این کار به شما کمک می‌کند که با ایجاد یک فایل پیکربندی برای هر زبان و سپس ادغام و صدور آنها از `index.ts`، موارد را سازماندهی کنید.\n\n## دایرکتوری جداگانه برای هر زبان {#separate-directory-for-each-locale}\n\nساختار زیر به طور کاملاً صحیح است:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\nبا این حال، ویت‌پرس به طور پیش‌فرض به `/` به `/en/` هدایت نمی‌کند. برای این کار باید سرور خود را پیکربندی کنید. به عنوان مثال، در Netlify، می‌توانید فایل `docs/public/_redirects` را به این شکل اضافه کنید:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**نکته حرفه‌ای:** در صورت استفاده از روش فوق، می‌توانید از کوکی `nf_lang` برای ثبت انتخاب زبان کاربر استفاده کنید:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## پشتیبانی از RTL (آزمایشی) {#rtl-support-experimental}\n\nبرای پشتیبانی از RTL، `dir: 'rtl'` را در پیکربندی مشخص کنید و از پلاگین‌های PostCSS RTLCSS مانند <https://github.com/MohammadYounes/rtlcss>، <https://github.com/vkalinichev/postcss-rtl> یا <https://github.com/elchininet/postcss-rtlcss> استفاده کنید. باید پلاگین PostCSS خود را به کارگیری `:where([dir=\"ltr\"])` و `:where([dir=\"rtl\"])` به عنوان پیشوندها جلوگیری از مشکلات اولویت CSS استفاده کنید.\n"
  },
  {
    "path": "docs/fa/guide/markdown.md",
    "content": "# افزونه‌های Markdown {#markdown-extensions}\n\nویت‌پرس با افزونه‌های markdown داخلی ارائه شده است.\n\n## لینک‌های هدر {#header-anchors}\n\nهدرها به طور خودکار لینک‌های anchor دریافت می‌کنند. نمایش anchor ها با استفاده از گزینه `markdown.anchor` قابل پیکربندی است.\n\n### anchor های سفارشی {#custom-anchors}\n\nبرای مشخص کردن تگ anchor سفارشی برای یک هدینگ به جای استفاده از تگ خودکار، یک پسوند به هدینگ اضافه کنید:\n\n```\n# Using custom anchors {#my-anchor}\n```\n\nاین به شما امکان می‌دهد که به جای استفاده از به جای استفاده از `#using-custom-anchors`، به هدینگ به عنوان `#my-anchor` لینک دهید.\n\n## لینک‌ها {#links}\n\nهم لینک‌های داخلی و هم خارجی با دستورالعمل‌های خاصی ارائه می‌شوند.\n\n### لینک‌های داخلی {#internal-links}\n\nلینک‌های داخلی به لینک روتر برای ناوبری SPA تبدیل می‌شوند. همچنین، هر `index.md` موجود در هر زیرپوشه به طور خودکار به `index.html` تبدیل می‌شود، با URL متناظر `/`.\n\nبه عنوان مثال، با توجه به ساختار پوشه زیر:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nو با فرض این که شما در `foo/one.md` هستید:\n\n```md\n[Home](/) <!-- sends the user to the root index.md -->\n[foo](/foo/) <!-- sends the user to index.html of directory foo -->\n[foo heading](./#heading) <!-- anchors user to a heading in the foo index file -->\n[bar - three](../bar/three) <!-- you can omit extension -->\n[bar - three](../bar/three.md) <!-- you can append .md -->\n[bar - four](../bar/four.html) <!-- or you can append .html -->\n```\n\n### پسوند صفحه  {#page-suffix}\n\nصفحات و لینک‌های داخلی به طور پیش‌فرض با پسوند `.html` تولید می‌شوند.\n\n### لینک‌های خارجی {#external-links}\n\nلینک‌های خروجی به طور خودکار دارای `target=\"_blank\" rel=\"noreferrer\"` هستند:\n\n- [vuejs.org](https://vuejs.org)\n- [ویت‌پرس در GitHub](https://github.com/vuejs/vitepress)\n\n## Frontmatter {#frontmatter}\n\n[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) به طور پیش‌فرض پشتیبانی می‌شود:\n\n```yaml\n---\ntitle: عنوان صفحه\nlang: fa-IR\n---\n```\n\nاین داده‌ها برای بقیه صفحه در دسترس خواهد بود، همراه با تمامی اجزاهای سفارشی و تم.\n\nبرای اطلاعات بیشتر، به [Frontmatter](../reference/frontmatter-config) مراجعه کنید.\n\n## جداول مانند Github   {#github-style-tables}\n\n**ورودی**\n\n```md\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n```\n\n**خروجی**\n\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n\n## اموجی :tada: {#emoji}\n\n**ورودی**\n\n```\n:tada: :100:\n```\n\n**خروجی**\n\n:tada: :100:\n\nیک [لیست از همه اموجی ها](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) در دسترس است.\n\n## فهرست مطالب {#table-of-contents}\n\n**ورودی**\n\n```\n[[toc]]\n```\n\n**خروجی**\n\n[[toc]]\n\nنحوه پردازش فهرست مطالب با استفاده از گزینه `markdown.toc` قابل پیکربندی است.\n\n## کانتینرهای سفارشی {#custom-containers}\n\nکانتینرهای سفارشی می‌توانند توسط انواع، عناوین و محتویات خود تعریف شوند.\n\n### عنوان پیش‌فرض {#default-title}\n\n**ورودی**\n\n```md\n::: info\nاین یک جعبه اطلاعات است.\n:::\n\n::: tip\nاین یک نکته است.\n:::\n\n::: warning\nاین یک هشدار است.\n:::\n\n::: danger\nاین یک هشدار خطرناک است.\n:::\n\n::: details\nاین یک بلوک جزئیات است.\n:::\n```\n\n**خروجی**\n\n::: info اطلاعات\nاین یک جعبه اطلاعات است.\n:::\n\n::: tip نکته\nاین یک نکته است.\n:::\n\n::: warning هشدار\nاین یک هشدار است.\n:::\n\n::: danger خطر\nاین یک هشدار خطرناک است.\n:::\n\n::: details جزئیات\nاین یک بلوک جزئیات است.\n:::\n\n### عنوان سفارشی {#custom-title}\n\nمی‌توانید عنوان سفارشی را با اضافه کردن متن به انتهای نوع کانتینر تنظیم کنید.\n\n**ورودی**\n\n````md\n::: danger ایست!\nمنطقه خطرناک، ادامه ندهید\n:::\n\n::: details برای مشاهده کد کلیک کنید\n```js\nconsole.log('Hello, ویت‌پرس!')\n```\n:::\n````\n\n**خروجی**\n\n::: danger ایست!\nمنطقه خطرناک، ادامه ندهید\n:::\n\n::: details برای مشاهده کد کلیک کنید\n```js\nconsole.log('Hello, ویت‌پرس!')\n```\n:::\n\nاین همچنین امکان دارد که شما عنوان‌های سفارشی را به صورت global تنظیم کنید با اضافه کردن محتوای زیر به تنظیمات سایت. این امکان خاصا اگر به زبان انگلیسی نوشته نمی‌شود، بسیار مفید است:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: 'نکته',\n      warningLabel: 'اخطار',\n      dangerLabel: 'خطر',\n      infoLabel: 'اطلاعات',\n      detailsLabel: 'جزئیات'\n    }\n  }\n  // ...\n})\n```\n\n### `raw` {#raw}\n\nاین یک کانتینر ویژه است که می‌تواند برای جلوگیری از تداخل استایل و روتر با ویت‌پرس استفاده شود. این به ویژه زمانی مفید است که شما کتابخانه‌های کامپوننت را مستند کنید. می‌توانید همچنین [whyframe](https://whyframe.dev/docs/integrations/vitepress) را برای ایزوله‌تر شدن بیشتر بررسی کنید.\n\n**نحوه استفاده**\n\n```md\n::: raw\nبسته‌بندی در یک `<div class=\"vp-raw\">`\n:::\n```\n\nکلاس `vp-raw` می‌تواند به صورت مستقیم بر روی عناصر استفاده شود. ایزوله‌سازی استایل در حال حاضر انتخابی است:\n\n- `postcss` را با مدیر بسته‌های مورد علاقه‌تان نصب کنید:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- یک فایل با نام `docs/postcss.config.mjs` ایجاد کنید و کد زیر را به آن اضافه کنید:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  می‌توانید گزینه‌های آن را به این صورت پاس بدهید:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // به طور پیش‌فرض [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## هشدارهای GitHub {#github-flavored-alerts}\n\nویت‌پرس همچنین [هشدارهای GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) را برای نمایش به عنوان تماس‌ها پشتیبانی می‌کند. آن‌ها به همان شکلی که [کانتینرهای سفارشی](#custom-containers) نمایش داده می‌شوند.\n\n```md\n> [!NOTE]\n> اطلاعاتی که کاربران باید به آن توجه کنند، حتی اگر سریع بخوانند.\n\n> [!TIP]\n> اطلاعات اختیاری برای کمک به کاربر برای موفقیت بیشتر.\n\n> [!IMPORTANT]\n> اطلاعات حیاتی برای موفقیت کاربران.\n\n> [!WARNING]\n> محتوای بحرانی که نیاز به توجه فوری کاربر دارد به دلیل خطرات پتانسیلی.\n\n> [!CAUTION]\n> پیامدهای منفی احتمالی یک عمل.\n```\n\n> [!NOTE]\n> اطلاعاتی که کاربران باید به آن توجه کنند، حتی اگر سریع بخوانند.\n\n> [!TIP]\n> اطلاعات اختیاری برای کمک به کاربر برای موفقیت بیشتر.\n\n> [!IMPORTANT]\n> اطلاعات حیاتی برای موفقیت کاربران.\n\n> [!WARNING]\n> محتوای بحرانی که نیاز به توجه فوری کاربر دارد به دلیل خطرات پتانسیلی.\n\n> [!CAUTION]\n> پیامدهای منفی احتمالی یک عمل.\n\n## Syntax Highlighting در بلوک‌های کد {#syntax-highlighting-in-code-blocks}\n\nویت‌پرس از [Shiki](https://github.com/shikijs/shiki) برای syntax highlighting زبان در بلوک‌های کد Markdown با استفاده از متن رنگی استفاده می‌کند. Shiki از تنوع وسیعی از زبان‌های برنامه‌نویسی پشتیبانی می‌کند. تنها کافی است که یک نام مستعار زبان معتبر به بکتیک‌ها ابتدایی کد اضافه کنید:\n\n**ورودی**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**خروجی**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\nیک [لیست از زبان‌های معتبر](https://shiki.style/languages) در مخزن Shiki موجود است.\n\nهمچنین می‌توانید تم syntax highlighting را در تنظیمات برنامه سفارشی کنید. لطفاً به [گزینه‌های Markdown](../reference/site-config#markdown) برای جزئیات بیشتر مراجعه کنید.\n\n## برجسته‌سازی خطوط در بلوک‌های کد {#line-highlighting-in-code-blocks}\n\n**ورودی**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'برجسته‌سازی شده!'\n    }\n  }\n}\n```\n````\n\n**خروجی**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'برجسته‌سازی شده!'\n    }\n  }\n}\n```\n\nعلاوه بر یک خط، می‌توانید چندین خط تکی، محدوده‌ها یا هر دو را نیز مشخص کنید:\n\n- محدوده‌های خط: به عنوان مثال `{5-8}`, `{3-10}`, `{10-17}`\n- چند خط تک: به عنوان مثال `{4,7,9}`\n- محدوده‌های خط و خط‌های تک: به عنوان مثال `{4,7-13,16,23-27,40}`\n\n**ورودی**\n\n````\n```js{1,4-6}\nconst message = 'Hello, World!';\n\nconsole.log(message);\n```\n````\n\n**خروجی**\n\n```js{1,4-6}\nconst message = 'Hello, World!';\n\nconsole.log(message);\n```\n\n## فکوس در بلاک‌های کد {#focus-in-code-blocks}\n\nافزودن کامنت `// [!code focus]` به یک خط، روی آن فکوس می‌کند و بخش‌های دیگر کد را مات می‌کند.\n\nبه‌علاوه، می‌توانید با استفاده از `// [!code focus:<lines>]` تعدادی خط را برای فکوس تعیین کنید.\n\n**ورودی**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Focused!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**خروجی**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Focused!' // [!code focus]\n    }\n  }\n}\n```\n\n## تفاوت‌های رنگی در بلاک‌های کد {#colored-diffs-in-code-blocks}\n\nافزودن کامنت `// [!code --]` یا `// [!code ++]` به یک خط، یک تفاوت را در آن خط ایجاد می‌کند، با حفظ رنگ‌های بلاک کد.\n\n**ورودی**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!!code --]\n      msg: 'Added' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**خروجی**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!code --]\n      msg: 'Added' // [!code ++]\n    }\n  }\n}\n```\n\n## خطاها و هشدارها در بلاک‌های کد {#errors-and-warnings-in-code-blocks}\n\nافزودن کامنت `// [!code warning]` یا `// [!code error]` به یک خط، آن را مطابق با نوع، رنگ می‌کند.\n\n**ورودی**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Error', // [!!code error]\n      msg: 'Warning' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**خروجی**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!code error]\n      msg: 'Warning' // [!code warning]\n    }\n  }\n}\n```\n\n## شماره‌گذاری خطوط {#line-numbers}\n\nمی‌توانید با استفاده از تنظیمات، شماره‌گذاری خطوط را برای هر بلاک کد فعال کنید:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\nلطفاً [گزینه‌های markdown](../reference/site-config#markdown) را برای جزئیات بیشتر ببینید.\n\nمی‌توانید با استفاده از `:line-numbers` / `:no-line-numbers` در بلاک‌های کد شماره‌گذاری خطوط را نادیده بگیرید یا تنظیمات اصلی را با `=` پس از `:line-numbers` سفارشی کنید. به عنوان مثال، `:line-numbers=2` به معنای شروع شماره‌گذاری از خط `2` است.\n\n**ورودی**\n\n````md\n```ts {1}\n// شماره‌گذاری خطوط به طور پیش‌فرض غیرفعال است\nconst line2 = 'این خط ۲ است'\nconst line3 = 'این خط ۳ است'\n```\n\n```ts:line-numbers {1}\n// شماره‌گذاری خطوط فعال است\nconst line2 = 'این خط ۲ است'\nconst line3 = 'این خط ۳ است'\n```\n\n```ts:line-numbers=2 {1}\n// شماره‌گذاری خطوط فعال است و از خط ۲ شروع می‌شود\nconst line3 = 'این خط ۳ است'\nconst line4 = 'این خط ۴ است'\n```\n````\n\n**خروجی**\n\n```ts {1}\n// شماره‌گذاری خطوط به طور پیش‌فرض غیرفعال است\nconst line2 = 'این خط ۲ است'\nconst line3 = 'این خط ۳ است'\n```\n\n```ts:line-numbers {1}\n// شماره‌گذاری خطوط فعال است\nconst line2 = 'این خط ۲ است'\nconst line3 = 'این خط ۳ است'\n```\n\n```ts:line-numbers=2 {1}\n// شماره‌گذاری خطوط فعال است و از خط ۲ شروع می‌شود\nconst line3 = 'این خط ۳ است'\nconst line4 = 'این خط ۴ است'\n```\n\n## وارد کردن Snippet کد {#import-code-snippets}\n\nمی‌توانید snippet های کد را از فایل‌های موجود با استفاده از دستور زیر وارد کنید:\n\n```md\n<<< @/filepath\n```\n\nاین دستور [highlight کردن خط](#line-highlighting-in-code-blocks) را نیز پشتیبانی می‌کند:\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**ورودی**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**فایل کد**\n\n<<< @/snippets/snippet.js\n\n**خروجی**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip نکته\nمقدار `@` با ریشه منبع مطابقت دارد. به‌طور پیش‌فرض، این ریشه پروژه ویت‌پرس است، مگر اینکه `srcDir` پیکربندی شده باشد. به‌طور جایگزینی، می‌توانید از مسیرهای نسبی وارد کنید:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\nهمچنین می‌توانید [ناحیه VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) را برای اضافه کردن قسمت مربوطه فایل کد استفاده کنید. می‌توانید نام ناحیه سفارشی را پس از `#` به دنبال مسیر فایل تعیین کنید:\n\n**ورودی**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**فایل کد**\n\n<<< @/snippets/snippet-with-region.js\n\n**خروجی**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\nهمچنین می‌توانید زبان را داخل آکولادها (`{}`) مشخص کنید:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- با highlight خطوط: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- با شماره‌گذاری خطوط: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nاین قابلیت مفید است اگر زبان منبع نمی‌تواند از پسوند فایل استنتاج شود.\n\n\n### گروه‌های کد {#code-groups}\n\nمی‌توانید چندین بلوک کد را به این شکل گروه‌بندی کنید:\n\n**ورودی**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**خروجی**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nهمچنین می‌توانید [قطعات کد](#import-code-snippets) را در گروه‌های کد وارد کنید:\n\n**ورودی**\n\n```md\n::: code-group\n\n<!-- به طور پیش‌فرض نام فایل به عنوان عنوان استفاده می‌شود -->\n\n<<< @/snippets/snippet.js\n\n<!-- می‌توانید یک عنوان سفارشی نیز ارائه دهید -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [قطعه با منطقه]\n:::\n```\n\n**خروجی**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [قطعه با منطقه]\n:::\n\n## ادغام فایل‌های Markdown {#markdown-file-inclusion}\n\nمی‌توانید یک فایل Markdown را در یک فایل Markdown دیگر، حتی در صورت وجود تو در تو، وارد کنید.\n\n::: tip نکته\nمی‌توانید مسیر Markdown را با `@` پیش‌فرض کنید. این به عنوان ریشه منبع عمل می‌کند. به طور پیش‌فرض، ریشه پروژه ویت‌پرس است، مگر اینکه `srcDir` پیکربندی شده باشد.\n:::\n\nبه عنوان مثال، می‌توانید یک فایل Markdown نسبی را با استفاده از این کد وارد کنید:\n\n**ورودی**\n\n```md\n# مستندات\n\n## مبانی\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**قسمت فایل** (`parts/basics.md`)\n\n```md\nبعضی موارد مربوط به شروع کار.\n\n### پیکربندی\n\nمی‌توان با استفاده از `.foorc.json` ایجاد شد.\n```\n\n**کد معادل**\n\n```md\n# مستندات\n\n## مبانی\n\nبعضی موارد مربوط به شروع کار.\n\n### پیکربندی\n\nمی‌توان با استفاده از `.foorc.json` ایجاد شد.\n```\n\nهمچنین از انتخاب یک محدوده خطی پشتیبانی می‌کند:\n\n**ورودی**\n\n```md\n# مستندات\n\n## مبانی\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**قسمت فایل** (`parts/basics.md`)\n\n```md\nبعضی موارد مربوط به شروع کار.\n\n### پیکربندی\n\nمی‌توان با استفاده از `.foorc.json` ایجاد شد.\n```\n\n**کد معادل**\n\n```md\n# مستندات\n\n## مبانی\n\n### پیکربندی\n\nمی‌توان با استفاده از `.foorc.json` ایجاد شد.\n```\n\nقالب محدوده خطی می‌تواند شامل `{3,}`, `{,10}`, `{1,10}` باشد.\n\nهمچنین می‌توانید از [ناحیه VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) برای اضافه کردن بخش متناظر فایل کد استفاده کنید. می‌توانید پس از `#` نام ناحیه سفارشی را پس از مسیر فایل دنبال کنید:\n\n**ورودی**\n\n```md\n# مستندات\n\n## مبانی\n\n<!--@@include: ./parts/basics.md#basic-usage{,2}-->\n<!--@@include: ./parts/basics.md#basic-usage{5,}-->\n```\n\n**قسمت فایل** (`parts/basics.md`)\n\n```md\n<!-- #region basic-usage -->\n## استفاده خط 1\n\n## استفاده خط 2\n\n## استفاده خط 3\n<!-- #endregion basic-usage -->\n```\n\n**کد معادل**\n\n```md\n# مستندات\n\n## مبانی\n\n## استفاده خط 1\n\n## استفاده خط 3\n```\n\n::: warning هشدار\nتوجه داشته باشید که این اقدام منجر به خطا نمی‌شود اگر فایل شما وجود نداشته باشد. بنابراین، در استفاده از این ویژگی، مطمئن شوید که محتوا به درستی نمایش داده می‌شود.\n:::\n\n## معادلات ریاضی {#math-equations}\n\nدر حال حاضر این گزینه اختیاری است. برای فعال‌سازی آن، باید `markdown-it-mathjax3` را نصب کرده و `markdown.math` را در فایل پیکربندی خود به `true` تنظیم کنید:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**ورودی**\n\n```md\nوقتی $a \\ne 0$ است، دو حل برای $(ax^2 + bx + c = 0)$ وجود دارد و آن‌ها عبارتند از\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**معادلات مکسول**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | تنوع $\\vec{\\mathbf{B}}$ صفر است                                                      |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl $\\vec{\\mathbf{E}}$ نسبت به نرخ تغییر $\\vec{\\mathbf{B}}$ نسبی است              |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _چیست؟_                                                                               |\n```\n\n**خروجی**\n\nوقتی $a \\ne 0$ است، دو حل برای $(ax^2 + bx + c = 0)$\n\nوجود دارد و آن‌ها عبارتند از\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**معادلات مکسول**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | تنوع $\\vec{\\mathbf{B}}$ صفر است                                                      |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl $\\vec{\\mathbf{E}}$ نسبت به نرخ تغییر $\\vec{\\mathbf{B}}$ نسبی است              |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _چیست؟_                                                                               |\n\n## بارگذاری lazy تصویر {#image-lazy-loading}\n\nمی‌توانید بارگذاری تنبلی را برای هر تصویر اضافه شده از طریق Markdown با تنظیم `lazyLoading` به `true` در فایل پیکربندی فعال کنید:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // بارگذاری تنبلی تصویر به طور پیش‌فرض غیرفعال است\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## پیکربندی پیشرفته {#advanced-configuration}\n\nویت‌پرس از [markdown-it](https://github.com/markdown-it/markdown-it) به عنوان نمایشگر Markdown استفاده می‌کند. اکثر افزونه‌های فوق را با استفاده از افزونه‌های سفارشی پیاده‌سازی کرده‌ایم. می‌توانید نمونه‌ای بیشتر از نمونه `markdown-it` را با استفاده از گزینه `markdown` در `.vitepress/config.js` سفارشی‌سازی کنید:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // گزینه‌های markdown-it-anchor\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // گزینه‌های @mdit-vue/plugin-toc\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // استفاده از افزونه‌های markdown-it بیشتر!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\nبرای دیدن لیست کامل خصوصیات قابل تنظیم، به [مرجع تنظیمات: پیکربندی برنامه](../reference/site-config#markdown) مراجعه کنید.\n"
  },
  {
    "path": "docs/fa/guide/migration-from-vitepress-0.md",
    "content": "# مهاجرت از ویت‌پرس 0.x\n\nاگر از نسخه 0.x ویت‌پرس می‌آیید، تغییرات قابل توجهی به دلیل ویژگی‌ها و بهبودهای جدید وجود دارد. لطفاً این راهنما را دنبال کنید تا ببینید چگونه برنامه خود را به ویت‌پرس جدیدتر منتقل کنید.\n\n## پیکربندی برنامه\n\n- ویژگی بین‌المللی‌سازی هنوز اجرا نشده است.\n\n## پیکربندی تم\n\n- گزینه `sidebar` ساختار خود را تغییر داده است.\n  - کلید `children` حالا به نام `items` نامیده می‌شود.\n  - در حال حاضر ممکن است مورد بالادستی حاوی `link` نباشد. ما قصد داریم این گزینه را بازگردانیم.\n- `repo`، `repoLabel`، `docsDir`، `docsBranch`، `editLinks`، `editLinkText` به منظور API انعطاف‌پذیرتر حذف شده‌اند.\n  - برای اضافه کردن لینک GitHub با آیکون به نوار ناوبری، از ویژگی [پیوندهای اجتماعی](../reference/default-theme-nav#navigation-links) استفاده کنید.\n  - برای اضافه کردن ویژگی \"ویرایش این صفحه\"، از ویژگی [پیوند ویرایش](../reference/default-theme-edit-link) استفاده کنید.\n- گزینه `lastUpdated` حالا به `config.lastUpdated` و `themeConfig.lastUpdatedText` تقسیم شده است.\n- `carbonAds.carbon` به `carbonAds.code` تغییر کرده است.\n\n## پیکربندی Frontmatter\n\n- گزینه `home: true` به `layout: home` تغییر کرده است. همچنین، تنظیمات مربوط به صفحه اصلی بسیار تغییر کرده‌اند تا ویژگی‌های اضافی را ارائه دهند. برای جزئیات بیشتر، [راهنمای صفحه اصلی](../reference/default-theme-home-page) را ببینید.\n- گزینه `footer` به [`themeConfig.footer`](../reference/default-theme-config#footer) منتقل شده است.\n"
  },
  {
    "path": "docs/fa/guide/migration-from-vuepress.md",
    "content": "# مهاجرت از VuePress\n\n## پیکربندی\n\n### نوار کناری\n\nنوار کناری دیگر به طور خودکار از frontmatter پر نمی‌شود. شما می‌توانید [frontmatter را خودتان بخوانید](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) تا نوار کناری به طور پویا پر شود. ابزارهای [اضافی برای این منظور](https://github.com/vuejs/vitepress/issues/96) ممکن است در آینده ارائه شود.\n\n## Markdown\n\n### تصاویر\n\nبرخلاف VuePress، ویت‌پرس وقتی شما از تصویر استاتیک استفاده می‌کنید، [`base`](./asset-handling#base-url) پیکربندی شما را به طور خودکار مدیریت می‌کند.\n\nبنابراین، اکنون می‌توانید تصاویر را بدون استفاده از تگ `img` نمایش دهید.\n\n```diff\n- <img :src=\"$withBase('/foo.png')\" alt=\"foo\">\n+ ![foo](/foo.png)\n```\n\n::: warning\nبرای تصاویر پویا، همچنان نیاز به استفاده از `withBase` به طوری که در [راهنمای Base URL](./asset-handling#base-url) نشان داده شده است، دارید.\n:::\n\nاز عبارت `!<img.*withBase\\('(.*)'\\).*alt=\"([^\"]*)\".*>` برای جستجو و جایگزینی با `![$2]($1)` استفاده کنید تا تمام تصاویر را با سینتکس `![](...)` جایگزین کنید.\n\n---\n\nادامه دارد...\n"
  },
  {
    "path": "docs/fa/guide/mpa-mode.md",
    "content": "# حالت MPA <Badge type=\"warning\" text=\"آزمایشی\" /> {#mpa-mode}\n\nحالت MPA (برنامه چند صفحه) می‌تواند از طریق خط فرمان با `vitepress build --mpa` فعال شود، یا از طریق تنظیمات با گزینه `mpa: true`.\n\nدر حالت MPA، همه صفحات به طور پیش‌فرض بدون هیچ جاوااسکریپتی رندر می‌شوند. به همین دلیل، سایت تولیدی احتمالاً امتیاز بهتری از ابزارهای آزمایشی در اولین بازدید دریافت خواهد کرد.\n\nبا این حال، به دلیل عدم وجود مسیریابی SPA، لینک‌های متقاطع به بازنشانی کامل صفحه منتهی می‌شوند. ناوبری پس از بارگیری در حالت MPA حساسیت به همان اندازه با حالت SPA نخواهد داشت.\n\nهمچنین توجه داشته باشید که عدم وجود JS به طور پیش‌فرض به این معنی است که شما اساساً Vue را به عنوان یک زبان قالب‌بندی سمت سرور استفاده می‌کنید. هیچ کنترل کننده رویدادی در مرورگر اضافه نمی‌شود، بنابراین هیچ تعاملی وجود نخواهد داشت. برای بارگیری JS سمت کلاینت، شما باید از تگ خاص `<script client>` استفاده کنید:\n\n```html\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('JavaScript سمت کلاینت!')\n})\n</script>\n\n# سلام\n```\n\n`<script client>` یک ویژگی تنها برای ویت‌پرس است، نه یک ویژگی Vue. این در هر دو فایل `.md` و `.vue` کار می‌کند، اما فقط در حالت MPA. اسکریپت‌های کلاینت در تمام اجزای تم با هم بسته می‌شوند، در حالی که اسکریپت کلاینت برای یک صفحه خاص، فقط برای آن صفحه تقسیم می‌شود.\n\nتوجه داشته باشید که `<script client>` به عنوان **کد مؤلفه مؤلفه Vue** ارزیابی نمی‌شود: به عنوان یک ماژول جاوااسکریپت معمولی پردازش می‌شود. به همین دلیل، حالت MPA فقط باید در صورتی استفاده شود که سایت شما به تعامل کمینه‌ای از جانب کلاینت نیاز دارد.\n"
  },
  {
    "path": "docs/fa/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# مسیریابی {#routing}\n\n## مسیریابی مبتنی بر فایل {#file-based-routing}\n\nویت‌پرس از مسیریابی مبتنی بر فایل استفاده می‌کند که به این معنی است که صفحات HTML تولید شده از ساختار دایرکتوری فایل‌های Markdown منبع نقشه‌بندی می‌شوند. به عنوان مثال، با توجه به ساختار دایرکتوری زیر:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\nصفحات HTML تولید شده به شرح زیر خواهد بود:\n\n```\nindex.md                  -->  /index.html (قابل دسترس به عنوان /)\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html (قابل دسترس به عنوان /guide/)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\nاین صفحات HTML نهایی می‌توانند بر روی هر سرور وبی که قادر به ارائه فایل‌های ایستا است، میزبانی شوند.\n\n## ریشه و دایرکتوری منبع {#root-and-source-directory}\n\nدر ساختار فایل پروژه ویت‌پرس، دو مفهوم مهم وجود دارد: **ریشه پروژه** و **دایرکتوری منبع**.\n\n### ریشه پروژه {#project-root}\n\nریشه پروژه جایی است که ویت‌پرس سعی می‌کند برای دایرکتوری ویژه `.vitepress` را بررسی کند. دایرکتوری `.vitepress` مکانی رزرو شده برای فایل پیکربندی، حافظه نهان سرور توسعه، خروجی ساخت، و کد سفارشی‌سازی موضوع اختیاری ویت‌پرس است.\n\nزمانی که شما دستور `vitepress dev` یا `vitepress build` را از خط فرمان اجرا می‌کنید، ویت‌پرس از دایرکتوری کاری فعلی به عنوان ریشه پروژه استفاده می‌کند. برای مشخص کردن یک زیردایرکتوری به عنوان ریشه، باید مسیر نسبی را به دستور ارسال کنید. به عنوان مثال، اگر پروژه ویت‌پرس شما در `./docs` قرار دارد، باید دستور `vitepress dev docs` را اجرا کنید:\n\n```\n.\n├─ docs                    # ریشه پروژه\n│  ├─ .vitepress           # دایرکتوری پیکربندی\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nاین عمل به نتیجه زیر منجر می‌شود:\n\n```\ndocs/index.md            -->  /index.html (قابل دسترس به عنوان /)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### دایرکتوری منبع {#source-directory}\n\nدایرکتوری منبع جایی است که فایل‌های منبع Markdown شما قرار می‌گیرند. به طور پیش‌فرض، این همانند ریشه پروژه است. با این حال، شما می‌توانید آن را از طریق گزینه [`srcDir`](../reference/site-config#srcdir) پیکربندی کنید.\n\nگزینه `srcDir` نسبت به ریشه پروژه حل می‌شود. به عنوان مثال، با `srcDir: 'src'`، ساختار فایل شما به این صورت خواهد بود:\n\n```\n.                          # ریشه پروژه\n├─ .vitepress              # دایرکتوری پیکربندی\n└─ src                     # دایرکتوری منبع\n   ├─ getting-started.md\n   └─ index.md\n```\n\nنتیجه نقشه‌بندی منبع به HTML:\n\n```\nsrc/index.md            -->  /index.html (قابل دسترس به عنوان /)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## لینک‌دهی بین صفحات {#linking-between-pages}\n\nمی‌توانید هنگام لینک‌دهی بین صفحات از مسیرهای نسبی و مطلق استفاده کنید. توجه داشته باشید که با اینکه هر دو پسوند `.md` و `.html` کار می‌کنند، بهتر است که پسوندها را حذف کنید تا ویت‌پرس بتواند URL‌های نهایی را بر اساس پیکربندی شما تولید کند.\n\n```md\n<!-- درست -->\n[شروع کار](./getting-started)\n[شروع کار](../guide/getting-started)\n\n<!-- نادرست -->\n[شروع کار](./getting-started.md)\n[شروع کار](./getting-started.html)\n```\n\nجهت آشنایی بیشتر با لینک‌دهی به منابع مانند تصاویر به [مدیریت منابع](./asset-handling) مراجعه کنید.\n\n### لینک‌دهی به صفحات غیر ویت‌پرس {#linking-to-non-vitepress-pages}\n\nاگر می‌خواهید به یک صفحه در وب‌سایت خود لینک دهید که توسط ویت‌پرس تولید نشده است، باید یا از URL کامل (باز می‌شود در یک تب جدید) استفاده کنید، یا هدف را به طور صریح مشخص کنید:\n\n**ورودی**\n\n```md\n[لینک به pure.html](/pure.html){target=\"_self\"}\n```\n\n**خروجی**\n\n[لینک به pure.html](/pure.html){target=\"_self\"}\n\n::: tip توجه\n\nدر لینک‌های Markdown، `base` به طور خودکار به URL پیشوند داده می‌شود. این بدان معنی است که اگر می‌خواهید به صفحه‌ای خارج از پایه خود لینک دهید، باید چیزی شبیه `../../pure.html` را در لینک استفاده کنید (توسط مرورگر نسبت به صفحه فعلی حل می‌شود).\n\nدر غیر این صورت، می‌توانید به طور مستقیم از anchor tag syntax استفاده کنید:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">لینک به pure.html</a>\n```\n\n:::\n\n## تولید URLهای تمیز {#generating-clean-urls}\n\n::: warning نیازمندی پشتیبانی سرور\n\nبرای ارائه URL‌های تمیز با ویت‌پرس، نیاز به پشتیبانی سمت سرور وجود دارد.\n\n:::\n\nبه طور پیش‌فرض، ویت‌پرس لینک‌های ورودی را به URL‌هایی با پسوند `.html` حل می‌کند. با این حال، برخی از کاربران ممکن است از URL‌های \"تمیز\" بدون پسوند `.html` استفاده کنند - به عنوان مثال، `example.com/path` به جای `example.com/path.html`.\n\nبرخی از سرورها یا پلتفرم‌های میزبانی (مانند Netlify، Vercel، GitHub Pages) امکان این را فراهم می‌کنند که یک URL مانند `/foo` به `/foo.html` نگاشت شود اگر موجود باشد، بدون انتقال:\n\n- Netlify و GitHub Pages این را به طور پیش‌فرض پشتیبانی می‌کنند.\n- Vercel نیاز به فعال‌سازی [`cleanUrls` در `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls) دارد.\n\nاگر این ویژگی برای شما در دسترس است، می‌توانید از گزینه پیکربندی خود ویت‌پرس به نام [`cleanUrls`](../reference/site-config#cleanurls) استفاده کنید تا:\n\n- لینک‌های ورودی بین صفحات بدون پسوند `.html` تولید شوند.\n- اگر مسیر کنونی با `.html` ختم شود، مسیریاب به صورت تغییر مسیر کلاینت به مسیر بدون پسوند انجام می‌دهد.\n\nاگر امکان پیکربندی سرور شما برای این پشتیبانی وجود نداشته باشد، شما باید به صورت دستی به ساختار دایرکتوری زیر رجوع کنید:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## بازنویسی مسیر {#route-rewrites}\n\nمی‌توانید نقشه‌بندی بین ساختار دایرکتوری منبع و صفحات تولید شده را سفارشی‌سازی کنید. این ویژگی وقتی مفید است که یک ساختار پروژه پیچیده داشته باشید. به عنوان مثال، فرض کنید یک مونورپو با چند بسته دارید و می‌خواهید مستندات را همراه با فایل‌های منبع قرار دهید مانند این:\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ pkg-a-code.ts\n│  │      └─ pkg-a-docs.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ pkg-b-code.ts\n│         └─ pkg-b-docs.md\n```\n\nو می‌خواهید صفحات ویت‌پرس به این صورت تولید شوند:\n\n```\npackages/pkg-a/src/pkg-a-docs.md  -->  /pkg-a/index.html\npackages/pkg-b/src/pkg-b-docs.md  -->  /pkg-b/index.html\n```\n\nمی‌توانید این کار را با پیکربندی گزینه [`rewrites`](../reference/site-config#rewrites) مانند زیر انجام دهید:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',\n    'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'\n  }\n}\n```\n\nگزینه `rewrites` همچنین پارامترهای مسیر پویایی را پشتیبانی می‌کند. در مثال بالا، اگر تعداد بسیاری از بسته‌ها داشته باشید، لیست کردن همه مسیرها به شکل زیر ممکن است طولانی باشد. با توجه به اینکه همه دارای ساختار فایل یکسان هستند، می‌توانید پیکربندی را به این صورت ساده‌تر کنید:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/(.*)': ':pkg/index.md'\n  }\n}\n```\n\nمسیرهای بازنویسی با استفاده از بسته `path-to-regexp` ترجمه می‌شوند - برای جزئیات بیشتر به [مستندات آن](https://github.com/pillarjs/path-to-regexp#parameters) مراجعه کنید.\n\n::: warning لینک‌های نسبی با بازنویسی\n\nزمانی که بازنویسی‌ها فعال باشند، **لینک‌های نسبی باید بر اساس مسیرهای بازنویسی باشند**. به عنوان مثال، برای ایجاد یک لینک نسبی از `packages/pkg-a/src/pkg-a-code.md` به `packages/pkg-b/src/pkg-b-code.md`، باید از مورد زیر استفاده کنید:\n\n```md\n[لینک به PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## مسیرهای پویا {#dynamic-routes}\n\nمی‌توانید صفحات زیادی را با استفاده از یک فایل Markdown و داده‌های پویا تولید کنید. به عنوان مثال، می‌توانید یک فایل `packages/[pkg].md` ایجاد کنید که برای هر بسته در یک پروژه، یک صفحه متناظر تولید می‌کند. در اینجا، بخش `[pkg]` یک پارامتر مسیر است که هر صفحه را از دیگران تمایز می‌دهد.\n\n### فایل بارگیری مسیرها {#paths-loader-file}\n\nاز آنجایی که ویت‌پرس یک موتور سایت ایستا است، مسیرهای ممکن باید در زمان ساخت تعیین شوند. بنابراین، یک صفحه مسیر پویا باید همراه با یک **فایل بارگیری مسیرها** همراه باشد. برای `packages/[pkg].md`، به `packages/[pkg].paths.js` (همچنین `.ts` پشتیبانی می‌شود) نیاز داریم:\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # قالب مسیر\n   └─ [pkg].paths.js   # فایل بارگیری\n\n مسیرها\n```\n\nفایل بارگیری باید یک شیء با یک متد `paths` به عنوان export پیش‌فرض ارائه دهد. متد `paths` باید آرایه‌ای از اشیاء با خصوصیت `params` را برگرداند. هر یک از این اشیاء یک صفحه متناظر را ایجاد می‌کنند.\n\nبا توجه به آرایه `paths` زیر:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\nصفحات HTML تولید شده به شرح زیر خواهد بود:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### چندین پارامتر {#multiple-params}\n\nیک مسیر پویا می‌تواند شامل چندین پارامتر باشد:\n\n**ساختار فایل**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**بارگیری مسیرها**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**خروجی**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### تولید پویای مسیرها {#dynamically-generating-paths}\n\nماژول بارگیری مسیر در Node.js اجرا می‌شود و تنها در زمان ساخت اجرا می‌شود. شما می‌توانید آرایه‌ی مسیرها را با استفاده از هر داده‌ای، سطحی یا از راه دور، به صورت پویا تولید کنید.\n\nتولید مسیرها از فایل‌های محلی:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\nتولید مسیرها از داده‌های از راه دور:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### دسترسی به پارامترها در صفحه {#accessing-params-in-page}\n\nشما می‌توانید از پارامترها برای انتقال داده‌های اضافی به هر صفحه استفاده کنید. فایل مسیر Markdown می‌تواند از پارامترهای صفحه کنونی در عبارات Vue با استفاده از خاصیت `$params` global استفاده کند:\n\n```md\n- نام بسته: {{ $params.pkg }}\n- نسخه: {{ $params.version }}\n```\n\nهمچنین می‌توانید به پارامترهای کنونی صفحه از طریق [`useData`](../reference/runtime-api#usedata) runtime API دسترسی داشته باشید. این در هر دو فایل Markdown و کامپوننت‌های Vue در دسترس است:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params یک Vue ref است\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### نمایش محتوای خام {#rendering-raw-content}\n\nپارامترهای ارسال شده به صفحه در بارگذاری JavaScript کلاینت سریال می‌شوند، بنابراین باید از ارسال داده‌های سنگین در پارامترها خودداری کنید، برای مثال محتوای خام Markdown یا HTML از یک CMS از راه دور.\n\nبه جای اینکه می‌توانید محتوای چنین محتوایی را در هر صفحه با استفاده از خاصیت `content` روی هر شیء مسیر ارسال کنید:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // Markdown یا HTML خام\n      }\n    })\n  }\n}\n```\n\nسپس، از دستورات ویژه‌ی زیر برای نمایش محتوا به عنوان بخشی از فایل Markdown استفاده کنید:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/fa/guide/sitemap-generation.md",
    "content": "# جنریت کردن Sitemap {#sitemap-generation}\n\nویت‌پرس با پشتیبانی بیرونی برای تولید فایل `sitemap.xml` برای سایت شما ارائه می‌شود. برای فعال‌سازی آن، موارد زیر را به فایل `.vitepress/config.js` خود اضافه کنید:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\nبرای داشتن تگ‌های `<lastmod>` در فایل `sitemap.xml` خود، می‌توانید گزینه [`lastUpdated`](../reference/default-theme-last-updated) را فعال کنید.\n\n## گزینه‌ها {#options}\n\nپشتیبانی از sitemap توسط ماژول [`sitemap`](https://www.npmjs.com/package/sitemap) ارائه شده است. می‌توانید هر گزینه‌ای که توسط این ماژول پشتیبانی می‌شود را به گزینه `sitemap` در فایل پیکربندی خود منتقل کنید. این گزینه‌ها به طور مستقیم به سازنده `SitemapStream` منتقل می‌شوند. برای جزئیات بیشتر به [مستندات sitemap](https://www.npmjs.com/package/sitemap#options-you-can-pass) مراجعه کنید. مثال:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\nاگر از `base` در پیکربندی خود استفاده می‌کنید، باید آن را به گزینه `hostname` اضافه کنید:\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## هوک `transformItems` {#transformitems-hook}\n\nمی‌توانید از هوک `sitemap.transformItems` برای اصلاح موارد sitemap قبل از نوشتن آن‌ها به فایل `sitemap.xml` استفاده کنید. این هوک با یک آرایه از موارد sitemap فراخوانی می‌شود و انتظار دارد که یک آرایه از موارد sitemap بازگردانده شود. مثال:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // اضافه کردن موارد جدید یا اصلاح/فیلتر کردن موارد موجود\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/fa/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# تطابق SSR {#ssr-compatibility}\n\nویت‌پرس، با استفاده از قابلیت‌های رندرینگ سمت سرور (SSR) ارائه شده توسط Vue، اپلیکیشن را در Node.js در هنگام ساخت تولیدی پیش از رندر می‌کند. این بدان معناست که کلیه کدهای سفارشی در اجزای تم به تطابق SSR وابسته هستند.\n\n[بخش SSR در مستندات رسمی Vue](https://vuejs.org/guide/scaling-up/ssr.html) بیشتر در مورد SSR، ارتباط بین SSR / SSG و نکات متداول در نوشتن کد‌های سازگار با SSR توضیح می‌دهد. قانون عمده این است که فقط در `beforeMount` یا `mounted` هوک‌های اجزای Vue از API‌های مرورگر / DOM استفاده کنید.\n\n## `<ClientOnly>` {#clientonly}\n\nاگر از اجزا یا دموهایی استفاده می‌کنید که سازگاری با SSR ندارند (برای مثال حاوی دستورالعمل‌های سفارشی هستند)، می‌توانید آن‌ها را درون کامپوننت داخلی `<ClientOnly>` قرار دهید:\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## کتابخانه‌هایی که در هنگام وارد کردن به API مرورگر دسترسی دارند {#libraries-that-access-browser-api-on-import}\n\nبعضی از کتابخانه‌ها یا اجزا در هنگام وارد کردن به API‌های مرورگر **دسترسی دارند**. برای استفاده از کدی که فرض می‌کند محیطی مرورگر در هنگام وارد کردن وجود دارد، باید آن‌ها را به صورت پویا وارد کنید.\n\n### وارد کردن در هوک Mounted {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // استفاده از کد\n  })\n})\n</script>\n```\n\n### وارد کردن شرطی {#conditional-import}\n\nمی‌توانید همچنین وابستگی را با استفاده از `import.meta.env.SSR` (قسمتی از [متغیرهای env Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)) به شرط وارد کنید:\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // استفاده از کد\n  })\n}\n```\n\nاز آنجا که `Theme.enhanceApp` می‌تواند async باشد، می‌توانید به صورت شرطی پلاگین‌های Vue را که دسترسی به API‌های مرورگر را هنگام وارد کردن دارند، وارد و ثبت کنید:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nاگر از TypeScript استفاده می‌کنید:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent` {#defineclientcomponent}\n\nویت‌پرس یک کمک‌کننده راحتی برای وارد کردن کامپوننت‌های Vue که هنگام وارد کردن به API‌های مرورگر دسترسی دارند فراهم می‌کند.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nهمچنین می‌توانید props/children/slots را به کامپوننت مقصد منتقل کنید:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // آرگومان‌ها به h() منتقل می‌شوند - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'اسلات پیش‌فرض',\n      foo: () => h('div', 'فو')\n      bar: () => [h('span', 'یک'), h('span', 'دو')]\n    }\n  ],\n\n  // تابع بازخورد بعد از بارگذاری کامپوننت، می‌تواند async باشد\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nکامپوننت مقصد فقط در هوک Mounted کامپوننت پوشش وارد می‌شود.\n"
  },
  {
    "path": "docs/fa/guide/using-vue.md",
    "content": "# استفاده از Vue در Markdown  {#using-vue-in-markdown}\n\nدر ویت‌پرس، هر فایل Markdown به HTML تبدیل شده و سپس به عنوان یک [کامپوننت فایل تکی Vue](https://vuejs.org/guide/scaling-up/sfc.html) پردازش می‌شود. این بدان معنی است که شما می‌توانید از هر ویژگی Vue در داخل Markdown استفاده کنید، شامل قالب‌بندی پویا، استفاده از کامپوننت‌های Vue، یا منطق کامپوننت Vue دلخواه در داخل صفحه با افزودن تگ `<script>`.\n\nمهم است که ویت‌پرس از کامپایلر Vue برای به‌طور خودکار شناسایی و بهینه‌سازی اجزای ثابت محتوای Markdown استفاده می‌کند. محتویات استاتیک به صورت یکنواخت به عنوان placeholder nodes بهینه‌سازی شده و از بارگذاری اولیه در JavaScript صفحه مستثنی می‌شوند. همچنین، در فرآیند hydration سمت کلاینت نیز نادیده گرفته می‌شوند. به طور خلاصه، شما فقط برای اجزای پویا در هر صفحه هزینه می‌پردازید.\n\n::: tip سازگاری با SSR\nهمه استفاده‌های Vue باید با سازگاری SSR همخوانی داشته باشند. برای جزئیات و راه‌حل‌های متداول، به [سازگاری با SSR](./ssr-compat) مراجعه کنید.\n:::\n\n## قالب‌بندی {#templating}\n\n### درون‌یابی(Interpolation) {#interpolation}\n\nهر فایل Markdown ابتدا به HTML تبدیل شده و سپس به عنوان یک کامپوننت Vue به خط لوله فرآیند Vite ارسال می‌شود. این بدان معنی است که می‌توانید از درون‌یابی به سبک Vue در متن استفاده کنید:\n\n**ورودی**\n\n```md\n{{ 1 + 1 }}\n```\n\n**خروجی**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n#### دستورالعمل‌ها {#directives}\n\nدستورالعمل‌ها نیز کار می‌کنند (توجه داشته باشید که طراحی، HTML خام همچنین معتبر است):\n\n**ورودی**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**خروجی**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` و `<style>` {#script-and-style}\n\nتگ‌های `<script>` و `<style>` در سطح ریشه در فایل‌های Markdown همانند کارکرد آنها در SFC Vue کار می‌کنند، شامل `<script setup>`، `<style module>`، و غیره. تفاوت اصلی در اینجا این است که هیچ تگ `<template>` وجود ندارد: تمام محتویات سطح ریشه دیگر Markdown است. همچنین توجه داشته باشید که همه تگ‌ها باید **پس از** frontmatter قرار گیرند:\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## محتوای Markdown\n\nتعداد: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">افزایش</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning اجتناب از `<style scoped>` در Markdown\nدر استفاده از Markdown باید توجه داشت که `<style scoped>` نیازمند افزودن ویژگی‌های خاص به هر عنصر در صفحه فعلی است که باعث بزرگ شدن قابل‌ملاحظه اندازه صفحه می‌شود. هنگام نیاز به قالب‌بندی محلی محدود، استفاده از `<style module>` توصیه می‌شود.\n:::\n\nهمچنین شما به دسترسی به API‌های runtime ویت‌پرس مانند [`useData` helper](../reference/runtime-api#usedata) دارید که امکان دسترسی به metadata صفحه فعلی را فراهم می‌کند:\n\n**ورودی**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**خروجی**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"Using Vue in Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## استفاده از کامپوننت‌ها {#using-components}\n\nشما می‌توانید کامپوننت‌های Vue را مستقیماً در فایل‌های Markdown وارد و استفاده کنید.\n\n### وارد کردن در Markdown  {#importing-in-markdown}\n\nاگر یک کامپوننت تنها توسط چند صفحه استفاده می‌شود، توصیه می‌شود آنها را به صراحت در جایی که استفاده می‌شوند وارد کنید. این کار امکان تقسیم کد مناسب را فراهم می‌کند و فقط هنگام نمایش صفحات مربوطه بارگذاری می‌شوند:\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# مستندات\n\nاین یک فایل .md با استفاده از یک کامپوننت اختصاصی است\n\n<CustomComponent />\n\n## مستندات بیشتر\n\n...\n```\n\n### ثبت کامپوننت‌ها به صورت Global {#registering-components-globally}\n\nاگر یک کامپوننت بر روی اکثر صفحات استفاده می‌شود، می‌توانید آنها را به صورت global با سفارشی‌سازی نمونه برنامه Vue ثبت کنید. برای مثال، بخش مربوطه را در [گسترش تم پیش‌فرض](./extending-default-theme#registering-global-components) بررسی کنید.\n\n::: warning مهم\nاطمینان حاصل کنید که نام یک کامپوننت سفارشی حاوی خط فاصله دارد یا به صورت PascalCase است. در غیر این صورت، به عنوان یک\n\nعنصر داخلی تلقی می‌شود و درون یک تگ `<p>` قرار داده خواهد شد که باعث عدم هم‌سانی‌سازی hydration می‌شود چون `<p>` اجازه قرار دادن عناصر بلوک داخل آن را نمی‌دهد.\n:::\n\n### استفاده از کامپوننت‌ها در سربرگ‌ها <ComponentInHeader />  {#using-components-in-headers}\n\nشما می‌توانید کامپوننت‌های Vue را در سربرگ‌ها استفاده کنید، اما تفاوت بین دو نحوه نگارش زیر را توجه کنید:\n\n| Markdown                                                | HTML خروجی                               | سربرگ تجزیه شده |\n| ------------------------------------------------------- | ----------------------------------------- | ------------- |\n| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre>     | `<h1>text <Tag/></h1>`                    | `text`        |\n| <pre v-pre><code> # text \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>` |\n\nHTML که توسط `<code>` محصور شده باشد به عنوان آن نمایش داده خواهد شد؛ تنها HTML که **محصور نشده باشد** توسط Vue تجزیه خواهد شد.\n\n::: tip نکته\nخروجی HTML توسط [Markdown-it](https://github.com/Markdown-it/Markdown-it) انجام می‌شود، در حالی که سربرگ‌های تجزیه شده توسط ویت‌پرس انجام می‌شود (و برای هر دو نوار کناری و عنوان سند استفاده می‌شود).\n:::\n\n## Escaping {#escaping}\n\nشما می‌توانید درون‌یابی‌های Vue را با محصور کردن آنها در یک `<span>` یا عناصر دیگر با دستورالعمل `v-pre` فرار کنید:\n\n**ورودی**\n\n```md\nThis <span v-pre>{{ will be displayed as-is }}</span>\n```\n\n**خروجی**\n\n<div class=\"escape-demo\">\n  <p>This <span v-pre>{{ will be displayed as-is }}</span></p>\n</div>\n\nبه طور جایگزین، می‌توانید کل پاراگراف را در یک ظرف سفارشی `v-pre` محصور کنید:\n\n```md\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n```\n\n**خروجی**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n\n</div>\n\n## غیرفعال کردن در بلوک‌های کد {#unescape-in-code-blocks}\n\nبه طور پیش‌فرض، تمام بلوک‌های کد با حصار `v-pre` به صورت خودکار محصور می‌شوند، بنابراین هیچ نحوه درون‌یابی Vue در داخل آنها پردازش نمی‌شود. برای فعال کردن درون‌یابی به سبک Vue در داخل حصارها، می‌توانید زبان را با پسوند `-vue` اضافه کنید، به عنوان مثال `js-vue`:\n\n**ورودی**\n\n````md\n```js-vue\nHello {{ 1 + 1 }}\n```\n````\n\n**خروجی**\n\n```js-vue\nHello {{ 1 + 1 }}\n```\n\nتوجه داشته باشید که این ممکن است باعث جلوگیری از نمایش صحیح برخی نشانه‌ها در هایلایتینگ نحوه زبان شود.\n\n## استفاده از پیش‌پردازنده‌های CSS {#using-css-pre-processors}\n\nویت‌پرس از [پشتیبانی داخلی](https://vitejs.dev/guide/features.html#css-pre-processors) برای پیش‌پردازنده‌های CSS مانند فایل‌های `.scss`، `.sass`، `.less`، `.styl` و `.stylus` پشتیبانی می‌کند. برای استفاده از آنها نیازی به نصب پلاگین‌های خاص Vite نیست، اما خود پیش‌پردازنده مربوطه باید نصب شده باشد:\n\n```\n# .scss و .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl و .stylus\nnpm install -D stylus\n```\n\nسپس می‌توانید در Markdown و کامپوننت‌های تم:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## استفاده از Teleport {#using-teleports}\n\nدر حال حاضر ویت‌پرس پشتیبانی از SSG برای teleport به body را دارد. برای اهداف دیگر، می‌توانید آنها را درون کامپوننت `<ClientOnly>` یا نشانه تله‌پورت به مکان مناسب در HTML صفحه نهایی خود از طریق [هوک postRender](../reference/site-config#postrender) درج کنید.\n\n<ModalDemo />\n\n::: details جزئیات\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n"
  },
  {
    "path": "docs/fa/guide/what-is-vitepress.md",
    "content": "# ویت‌پرس چیست؟ {#what-is-vitepress}\n\nویت‌پرس یک [تولید کننده سایت ایستا](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) است که برای ساخت وب‌سایت‌های سریع و محتوا محور طراحی شده است. به طور خلاصه، ویت‌پرس محتوای منبع شما که به زبان [Markdown](https://en.wikipedia.org/wiki/Markdown) نوشته شده است را گرفته، یک تم بر روی آن اعمال می‌کند و صفحات HTML ایستا تولید می‌کند که به راحتی در هر جایی قابل استقرار هستند.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nفقط می‌خواهید آن را امتحان کنید؟ به [شروع سریع](./getting-started) بروید.\n\n</div>\n\n## موارد استفاده {#use-cases}\n\n- **مستندسازی**\n\n  ویت‌پرس با یک تم پیش‌فرض طراحی شده برای مستندات فنی ارائه می‌شود. این صفحه‌ای که اکنون در حال خواندن آن هستید و همچنین مستندات [Vite](https://vitejs.dev/)، [Rollup](https://rollupjs.org/)، [Pinia](https://pinia.vuejs.org/)، [VueUse](https://vueuse.org/)، [Vitest](https://vitest.dev/)، [D3](https://d3js.org/)، [UnoCSS](https://unocss.dev/)، [Iconify](https://iconify.design/) و [بسیاری دیگر](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code) با استفاده از ویت‌پرس ساخته شده‌اند.\n\n  [مستندات رسمی Vue.js](https://vuejs.org/) نیز بر پایه ویت‌پرس ساخته شده است، اما از یک تم سفارشی که بین چندین ترجمه مشترک است استفاده می‌کند.\n\n- **وبلاگ‌ها، نمونه کارها و سایت‌های بازاریابی**\n\n  ویت‌پرس از [تم‌های کاملاً سفارشی](./custom-theme) پشتیبانی می‌کند، با تجربه توسعه مشابه یک برنامه استاندارد Vite + Vue. با ساختن بر روی Vite، این امکان وجود دارد که مستقیماً از پلاگین‌های Vite از اکوسیستم غنی آن استفاده کنید. علاوه بر این، ویت‌پرس API‌های انعطاف‌پذیری برای [بارگذاری داده](./data-loading) (محلی یا از راه دور) و [تولید پویا مسیرها](./routing#dynamic-routes) ارائه می‌دهد. شما می‌توانید تقریباً هر چیزی را بسازید به شرطی که داده‌ها در زمان ساخت تعیین شوند.\n\n  وبلاگ رسمی [Vue.js](https://blog.vuejs.org/) یک وبلاگ ساده است که صفحه فهرست خود را بر اساس محتوای محلی تولید می‌کند.\n\n## تجربه توسعه دهنده {#developer-experience}\n\nویت‌پرس هدف ارائه یک تجربه عالی برای توسعه دهنده (DX) هنگام کار با محتوای Markdown را دارد.\n\n- **[قدرت گرفته از Vite:](https://vitejs.dev/)** شروع سرور فوری، با بازتاب ویرایش‌ها به صورت آنی (<100ms) بدون بارگذاری مجدد صفحه.\n\n- **[افزونه‌های داخلی Markdown:](./markdown)** استفاده از Frontmatter، جداول، syntax highlighting... هرچه که بخواهید. ویت‌پرس به ویژه ویژگی‌های پیشرفته زیادی برای کار با بلوک‌های کد فراهم می‌کند، که آن را برای مستندات فنی بسیار مناسب می‌کند.\n\n- **[Markdown بهبود یافته با Vue:](./using-vue)** هر صفحه Markdown نیز یک [کامپوننت تک فایل Vue](https://vuejs.org/guide/scaling-up/sfc.html) است، به لطف سازگاری ۱۰۰٪ سینتکسی قالب Vue با HTML. شما می‌توانید از ویژگی‌های قالب‌بندی Vue یا کامپوننت‌های وارد شده Vue برای ایجاد تعامل در محتوای ایستا خود استفاده کنید.\n\n## عملکرد {#performance}\n\nبر خلاف بسیاری از SSG‌های سنتی که هر ناوبری منجر به بارگذاری کامل صفحه می‌شود، یک وب‌سایت تولید شده توسط ویت‌پرس در بازدید اولیه HTML ایستا را سرو می‌کند، اما برای ناوبری‌های بعدی در سایت به یک [برنامه تک صفحه‌ای](https://en.wikipedia.org/wiki/Single-page_application) (SPA) تبدیل می‌شود. به نظر ما، این مدل برای عملکرد بهترین تعادل را فراهم می‌کند:\n\n- **بارگذاری اولیه سریع**\n\n  بازدید اولیه از هر صفحه، HTML پیش‌پردازش شده ایستا را برای سرعت بارگذاری سریع و بهینه‌سازی SEO سرو می‌کند. سپس صفحه یک بسته JavaScript را بارگذاری می‌کند که صفحه را به یک SPA Vue تبدیل می‌کند (\"hydration\"). بر خلاف فرضیات رایج که hydration برای SPA کند است، این فرآیند در واقع بسیار سریع است به لطف عملکرد خام Vue 3 و بهینه‌سازی‌های کامپایلر. در [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F)، سایت‌های معمولی ویت‌پرس حتی در دستگاه‌های موبایل پایین‌رده با شبکه کند به امتیازهای عملکردی تقریباً کامل دست می‌یابند.\n\n- **ناوبری سریع پس از بارگذاری**\n\n  مهم‌تر از آن، مدل SPA منجر به تجربه کاربری بهتر **پس از** بارگذاری اولیه می‌شود. ناوبری‌های بعدی در سایت دیگر باعث بارگذاری کامل صفحه نمی‌شوند. در عوض، محتوای صفحه ورودی بارگذاری و به صورت پویا به‌روزرسانی می‌شود. ویت‌پرس همچنین به صورت خودکار تکه‌های صفحه را برای لینک‌هایی که در viewport هستند پیش‌بارگذاری (pre-fetch) می‌کند. در بیشتر موارد، ناوبری پس از بارگذاری به صورت آنی احساس می‌شود.\n\n- **تعامل بدون جریمه**\n\n  برای اینکه بتوانید بخش‌های پویا Vue جاسازی شده در داخل Markdown ایستا را hydrated کنید، هر صفحه Markdown به عنوان یک کامپوننت Vue پردازش و به JavaScript کامپایل می‌شود. این ممکن است غیر بهینه به نظر برسد، اما کامپایلر Vue به اندازه کافی هوشمند است که بخش‌های ایستا و پویا را جدا کند، هزینه hydration و اندازه محموله را به حداقل برساند. برای بارگذاری اولیه صفحه، بخش‌های ایستا به صورت خودکار از محموله JavaScript حذف می‌شوند و در حین hydration نادیده گرفته می‌شوند.\n\n## درباره VuePress چه؟ {#what-about-vuepress}\n\nویت‌پرس جانشین معنوی VuePress است. VuePress اصلی بر پایه Vue 2 و webpack بود. با Vue 3 و Vite در هسته، ویت‌پرس تجربه توسعه بهتر، عملکرد تولید بهتر، تم پیش‌فرض کامل‌تر و API سفارشی‌سازی انعطاف‌پذیرتری ارائه می‌دهد.\n\nتفاوت API بین ویت‌پرس و VuePress عمدتاً در زمینه تم‌سازی و سفارشی‌سازی است. اگر از VuePress 1 با تم پیش‌فرض استفاده می‌کنید، باید مهاجرت به ویت‌پرس نسبتاً ساده باشد.\n\nهمچنین تلاش‌هایی برای VuePress 2 انجام شده است، که از Vue 3 و Vite با سازگاری بیشتر با VuePress 1 پشتیبانی می‌کند. با این حال، نگهداری دو SSG به صورت موازی پایدار نیست، بنابراین تیم Vue تصمیم گرفته است که در دراز مدت بر روی ویت‌پرس به عنوان SSG اصلی توصیه شده تمرکز کند.\n"
  },
  {
    "path": "docs/fa/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: ویت‌پرس\n  text: سازنده سایت‌های ایستا به کمک Vite و Vue\n  tagline: تبدیل Markdown به مستندات زیبا در چند دقیقه\n  actions:\n    - theme: brand\n      text: ویت‌پرس چیست؟\n      link: fa/guide/what-is-vitepress\n    - theme: alt\n      text: شروع سریع\n      link: fa/guide/getting-started\n    - theme: alt\n      text: گیت‌هاب\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: ویت‌پرس\n\nfeatures:\n  - icon: 📝\n    title: تمرکز روی محتوا\n    details: ایجاد سایت‌های مستند‌سازی زیبا بدون زحمت و فقط با Markdown\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: لذت از تجربه توسعه با Vite\n    details: شروع فوری سرور، به‌روزرسانی‌های سریع و استفاده از افزونه‌های اکوسیستم Vite\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: شخصی‌سازی با Vue\n    details: استفاده مستقیم از syntax و کامپوننت‌های Vue در Markdown، یا ایجاد تم‌های شخصی به کمک Vue\n  - icon: 🚀\n    title: ارسال سایت های سریع\n    details: بارگذاری اولیه سریع با HTML ایستا، ناوبری سریع پس از بارگیری با مسیریابی سمت کلاینت\n---\n"
  },
  {
    "path": "docs/fa/reference/cli.md",
    "content": "# رابط خط فرمان {#command-line-interface}\n\n## `vitepress dev` {#vitepress-dev}\n\nشروع سرور توسعه ویت‌پرس با استفاده از دایرکتوری مشخص به عنوان ریشه. به طور پیش‌فرض از دایرکتوری فعلی استفاده می‌شود. دستور `dev` همچنین می‌تواند حذف شود زمانی که در دایرکتوری فعلی اجرا می‌شود.\n\n### استفاده {#usage}\n\n```sh\n# شروع در دایرکتوری فعلی، بدون `dev`\nvitepress\n\n# شروع در زیردایرکتوری\nvitepress dev [root]\n```\n\n### گزینه‌ها {#options}\n\n| گزینه          | توضیحات                                                         |\n| --------------- | ----------------------------------------------------------------- |\n| `--open [path]` | باز کردن مرورگر در زمان راه‌اندازی (`boolean \\| string`)       |\n| `--port <port>` | تعیین پورت (`number`)                                           |\n| `--base <path>` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`)                        |\n| `--cors`        | فعال‌سازی CORS                                                   |\n| `--strictPort`  | خروج در صورت استفاده از پورت مشخص شده (`boolean`)              |\n| `--force`       | اجبار به نادیده گرفتن حافظه پنهان و بازسازی (`boolean`)       |\n\n## `vitepress build` {#vitepress-build}\n\nساخت سایت ویت‌پرس برای تولید نهایی.\n\n### استفاده {#usage-1}\n\n```sh\nvitepress build [root]\n```\n\n### گزینه‌ها {#options-1}\n\n| گزینه                         | توضیحات                                                                                                          |\n| ------------------------------ | ---------------------------------------------------------------------------------------------------------------- |\n| `--mpa` (آزمایشی)             | ساخت در حالت [MPA](../guide/mpa-mode) بدون هیدراسیون سمت مشتری (`boolean`)                                      |\n| `--base <path>`                | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`)                                                                       |\n| `--target <target>`            | هدف ترنسپایل (پیش‌فرض: `\"modules\"`) (`string`)                                                                 |\n| `--outDir <dir>`               | دایرکتوری خروجی نسبت به **cwd** (پیش‌فرض: `<root>/.vitepress/dist`) (`string`)                                |\n| `--assetsInlineLimit <number>` | آستانه تبدیل پایه ۶۴ استاتیک به بایت (پیش‌فرض: `4096`) (`number`)                                             |\n\n## `vitepress preview` {#vitepress-preview}\n\nپیش‌نمایش محلی برای ساخت تولیدی را نمایش دهید.\n\n### استفاده {#usage-2}\n\n```sh\nvitepress preview [root]\n```\n\n### گزینه‌ها {#options-2}\n\n| گزینه          | توضیحات                                |\n| --------------- | ---------------------------------------- |\n| `--base <path>` | مسیر پایه عمومی (پیش‌فرض: `/`) (`string`) |\n| `--port <port>` | تعیین پورت (`number`)                   |\n\n## `vitepress init` {#vitepress-init}\n\nشروع [جادوگر راه‌اندازی](../guide/getting-started#setup-wizard) در دایرکتوری فعلی.\n\n### استفاده {#usage-3} \n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-badge.md",
    "content": "# نشان {#badge}\n\nبرچسب به شما امکان می‌دهد وضعیت‌های مختلفی را به سربرگ‌های خود اضافه کنید. به عنوان مثال، می‌تواند مفید باشد تا نوع بخش را مشخص کنید یا نسخه‌های پشتیبانی شده را نشان دهید.\n\n## استفاده {#usage}\n\nشما می‌توانید از کامپوننت `Badge` که به صورت جهانی در دسترس است، استفاده کنید.\n\n```html\n### عنوان <Badge type=\"info\" text=\"پیش‌فرض\" />\n### عنوان <Badge type=\"tip\" text=\"^1.9.0\" />\n### عنوان <Badge type=\"warning\" text=\"بتا\" />\n### عنوان <Badge type=\"danger\" text=\"هشدار\" />\n```\n\nکد بالا به صورت زیر نمایش داده می‌شود:\n\n### عنوان <Badge type=\"info\" text=\"پیش‌فرض\" /> {#title}\n\n### عنوان <Badge type=\"tip\" text=\"^1.9.0\" /> {#title-1}\n\n### عنوان <Badge type=\"warning\" text=\"بتا\" /> {#title-2}\n\n### عنوان <Badge type=\"danger\" text=\"هشدار\" /> {#title-3}\n\n## ارائه دادن محتوای دلخواه {#custom-children}\n\n`<Badge>` می‌پذیرد `children` که در برچسب نمایش داده خواهد شد.\n\n```html\n### عنوان <Badge type=\"info\">عنصر سفارشی</Badge>\n```\n\n### عنوان <Badge type=\"info\">عنصر سفارشی</Badge>\n\n## سفارشی‌سازی رنگ نوع {#customize-type-color}\n\nشما می‌توانید استایل برچسب‌ها را با دوباره‌نویسی متغیرهای css سفارشی کنید. مقادیر پیش‌فرض به شرح زیر هستند:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>` {#badge-1}\n\nکامپوننت `<Badge>` پراپ‌های زیر را می‌پذیرد:\n\n```ts\ninterface Props {\n  // وقتی `<slot>` ارسال می‌شود، این مقدار نادیده گرفته می‌شود.\n  text?: string\n\n  // پیش‌فرض به `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-carbon-ads.md",
    "content": "# تبلیغات Carbon {#carbon-ads}\n\nویت‌پرس پشتیبانی داخلی برای [Carbon Ads](https://www.carbonads.net/) را دارد. با تعریف مشخصات تبلیغات Carbon در تنظیمات، ویت‌پرس تبلیغات را در صفحه نمایش می‌دهد.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\nاین مقادیر برای فراخوانی اسکریپت CDN Carbon به شکل زیر استفاده می‌شوند.\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nبرای یادگیری بیشتر درباره پیکربندی تبلیغات Carbon، لطفاً به [وب‌سایت Carbon Ads](https://www.carbonads.net/) مراجعه کنید.\n"
  },
  {
    "path": "docs/fa/reference/default-theme-config.md",
    "content": "# پیکربندی پیش‌فرض تم {#default-theme-config}\n\nپیکربندی تم به شما امکان می‌دهد تا تم خود را سفارشی کنید. شما می‌توانید پیکربندی تم را از طریق گزینه `themeConfig` در فایل پیکربندی تعریف کنید:\n\n```ts\nexport default {\n  lang: 'en-US',\n  title: 'ویت‌پرس',\n  description: 'Vite & Vue powered static site generator.',\n\n  // پیکربندی‌های مربوط به تم.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**گزینه‌های مستند شده در این صفحه تنها برای تم پیش‌فرض اعمال می‌شوند.** تم‌های مختلف انتظار دارند که پیکربندی تم متفاوتی داشته باشند. در هنگام استفاده از یک تم سفارشی، شیء پیکربندی تم به تم منتقل می‌شود تا تم بتواند بر اساس آن رفتار شرطی را تعریف کند.\n\n## i18nRouting {#i18nrouting}\n\n- نوع: `boolean`\n\nتغییر زبان به `zh` باعث تغییر URL از `/foo` (یا `/en/foo/`) به `/zh/foo` می‌شود. شما می‌توانید این رفتار را با تنظیم `themeConfig.i18nRouting` به `false` غیرفعال کنید.\n\n## logo {#logo}\n\n- نوع: `ThemeableImage`\n\nفایل لوگو برای نمایش در نوار ناوبری، به سمت راست قبل از عنوان سایت. یک رشته مسیر یا یک شیء برای تنظیم لوگو متفاوت برای حالت نوری/تاریک قبول می‌کند.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- نوع: `string | false`\n\nشما می‌توانید این مورد را سفارشی کنید تا عنوان سایت پیش‌فرض (`title` در پیکربندی برنامه) را در ناوبری جایگزین کنید. هنگامی که به `false` تنظیم می‌شود، عنوان در ناوبری غیرفعال می‌شود. این قابلیت مفید است زمانی که شما لوگو دارید که حاوی متن عنوان سایت است.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hello World'\n  }\n}\n```\n\n## nav\n\n- نوع: `NavItem`\n\nپیکربندی برای موارد منوی ناوبری. جزئیات بیشتر در [تم پیش‌فرض: ناوبری](./default-theme-nav#navigation-links).\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'راهنما', link: '/guide' },\n      {\n        text: 'منوی کشویی',\n        items: [\n          { text: 'مورد الف', link: '/item-1' },\n          { text: 'مورد ب', link: '/item-2' },\n          { text: 'مورد ج', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- نوع: `Sidebar`\n\nپیکربندی برای موارد منوی نوار کناری. جزئیات بیشتر در [تم پیش‌فرض: نوار کناری](./default-theme-sidebar).\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'راهنما',\n        items: [\n          { text: 'معرفی', link: '/introduction' },\n          { text: 'شروع کار', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n}\n\nexport type SidebarItem = {\n  /**\n   * برچسب متنی مورد.\n   */\n  text?: string\n\n  /**\n   * لینک مورد.\n   */\n  link?: string\n\n  /**\n   * فرزندان مورد.\n   */\n  items?: SidebarItem[]\n\n  /**\n   * اگر مشخص نشده باشد، گروه قابل جمع‌شدن نیست.\n   *\n   * اگر `true` باشد، گروه قابل جمع‌شدن است و به طور پیش‌فرض جمع شده است\n   *\n   * اگر `false` باشد، گروه قابل جمع‌شدن است اما به طور پیش‌فرض باز شده است\n   */\n  collapsed?: boolean\n\n  /**\n   * مسیر پایه برای موارد فرزند.\n   */\n  base?: string\n\n  /**\n   * سفارشی‌سازی متنی که در پا صفحه قبلی/بعدی نمایش داده می‌شود.\n   */\n  docFooterText?: string\n\n  rel?: string\n  target?: string\n}\n```\n\n## aside\n\n- نوع: `boolean | 'left'`\n- پیش‌فرض: `true`\n- می‌تواند به صورت خودکار برای هر صفحه از طریق [frontmatter](./frontmatter-config#aside) بازنویسی شود.\n\nتنظیم این مقدار به `false` از رندر کردن کانتینر اطراف خودداری می‌کند.\\\nتنظیم این مقدار به `true` کانتینر اطراف را به راست رندر می‌کند.\\\nتنظیم این مقدار به `left` کانتینر اطراف را به چپ رندر می‌کند.\n\nاگر می‌خواهید آن را برای تمام نمایه‌گرها غیرفعال کنید، به جای آن باید از `outline: false` استفاده کنید.\n\n## outline\n\n- نوع: `Outline | Outline['level'] | false`\n- می‌تواند به صورت خودکار برای هر صفحه از طریق [frontmatter](./frontmatter-config#outline) بازنویسی شود.\n\nتنظیم این مقدار به `false` از\n\nرندر کردن کانتینر آوند خودداری می‌کند. به این رابط مراجعه کنید تا جزئیات بیشتری را بدانید:\n\n```ts\ninterface Outline {\n  /**\n   * سطوح سرفصل‌هایی که در آوند نمایش داده خواهند شد.\n   * یک عدد تک را به این معنا است که تنها سرفصل‌های آن سطح نمایش داده می‌شوند.\n   * اگر یک دوتایی گذر داده شود، عدد اول سطح حداقل و عدد دوم سطح حداکثر است.\n   * `'deep'` مانند `[2، 6]` است، که به معنای همه سرفصل‌ها از `<h2>` تا `<h6>` است.\n   *\n   * @default 2\n   */\n  level?: number | [number، number] | 'deep'\n\n  /**\n   * عنوانی که باید در آوند نمایش داده شود.\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- نوع: `SocialLink[]`\n\nمی‌توانید این گزینه را تعریف کنید تا لینک‌های حساب اجتماعی خود را با آیکون‌ها در ناوبری نمایش دهید.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // شما همچنین می‌توانید آیکون‌های سفارشی را با ارسال SVG به عنوان رشته اضافه کنید:\n      {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // شما همچنین می‌توانید برچسب سفارشی را برای دسترسی (اختیاری اما توصیه می‌شود) شامل کنید:\n        ariaLabel: 'لینک جذاب'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: SocialLinkIcon\n  link: string\n  ariaLabel?: string\n}\n\ntype SocialLinkIcon =\n  | 'discord'\n  | 'facebook'\n  | 'github'\n  | 'instagram'\n  | 'linkedin'\n  | 'mastodon'\n  | 'npm'\n  | 'slack'\n  | 'twitter'\n  | 'x'\n  | 'youtube'\n  | { svg: string }\n```\n\n## footer\n\n- نوع: `Footer`\n- می‌تواند به صورت خودکار برای هر صفحه از طریق [frontmatter](./frontmatter-config#footer) بازنویسی شود.\n\nپیکربندی پا. شما می‌توانید پیام یا متن حق کپی را در پا اضافه کنید، با این حال، فقط زمانی نمایش داده می‌شود که صفحه شامل نوار کناری نباشد. این به دلایل طراحی است.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'منتشر شده تحت مجوز MIT.',\n      copyright: 'حق نشر © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- نوع: `EditLink`\n- می‌تواند به صورت خودکار برای هر صفحه از طریق [frontmatter](./frontmatter-config#editlink) بازنویسی شود.\n\nپیوند ویرایش به شما امکان می‌دهد که یک لینک به ویرایش صفحه را در خدمات مدیریت گیت مانند GitHub یا GitLab نمایش دهید. برای جزئیات بیشتر به [تم پیش‌فرض: لینک ویرایش](./default-theme-edit-link) مراجعه کنید.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'ویرایش این صفحه در GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- نوع: `LastUpdatedOptions`\n\nامکانات سفارشی‌سازی برای متن به‌روز شده و فرمت تاریخ.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'به‌روزرسانی شده در',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'آخرین به‌روزرسانی'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- نوع: `AlgoliaSearch`\n\nیک گزینه برای پشتیبانی از جستجو در سایت مستندات خود با استفاده از [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). بیشتر در [تم پیش‌فرض: جستجو](./default-theme-search) بیاموزید.\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\nگزینه‌های کامل را [اینجا](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) مشاهده کنید.\n\n## carbonAds {#carbon-ads}\n\n- نوع: `CarbonAdsOptions`\n\nیک گزینه برای نمایش [Carbon Ads](https://www.carbonads.net/).\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\nبیشتر در [تم پیش‌فرض: Carbon Ads](./default-theme-carbon-ads) بیاموزید.\n\n## docFooter\n\n- نوع: `DocFooter`\n\nمی‌تواند برای سفارشی‌سازی متنی که در بالای لینک‌های قبلی و بعدی نمایش داده می‌شود استفاده شود. مفید است اگر مستندات خود را به زبانی غیر از انگلیسی نوشته باشید. همچنین می‌تواند برای غیرفعال کردن لینک‌های قبلی/بعدی به صورت جهانی استفاده شود. اگر می‌خواهید لینک‌های قبلی/بعدی را به صورت انتخابی فعال\n\n/غیرفعال کنید، می‌توانید از [frontmatter](./default-theme-prev-next-links) استفاده کنید.\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'صفحه قبلی',\n      next: 'صفحه بعدی'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- نوع: `string`\n- پیش‌فرض: `ظاهر`\n\nمی‌تواند برای سفارشی‌سازی برچسب سوئیچ حالت تاریک استفاده شود. این برچسب تنها در نمای تلفن همراه نمایش داده می‌شود.\n\n## lightModeSwitchTitle\n\n- نوع: `string`\n- پیش‌فرض: `تغییر به تم روشن`\n\nمی‌تواند برای سفارشی‌سازی عنوان سوئیچ حالت روشن که در بالا حاشیه دار می‌شود، استفاده شود.\n\n## darkModeSwitchTitle\n\n- نوع: `string`\n- پیش‌فرض: `تغییر به تم تاریک`\n\nمی‌تواند برای سفارشی‌سازی عنوان سوئیچ حالت تاریک که در بالا حاشیه دار می‌شود، استفاده شود.\n\n## sidebarMenuLabel\n\n- نوع: `string`\n- پیش‌فرض: `منو`\n\nمی‌تواند برای سفارشی‌سازی برچسب منوی نوار کناری استفاده شود. این برچسب تنها در نمای تلفن همراه نمایش داده می‌شود.\n\n## returnToTopLabel\n\n- نوع: `string`\n- پیش‌فرض: `بازگشت به بالا`\n\nمی‌تواند برای سفارشی‌سازی برچسب دکمه بازگشت به بالا استفاده شود. این برچسب تنها در نمای تلفن همراه نمایش داده می‌شود.\n\n## langMenuLabel\n\n- نوع: `string`\n- پیش‌فرض: `تغییر زبان`\n\nمی‌تواند برای سفارشی‌سازی برچسب aria- توگل زبان در ناوبری استفاده شود. این فقط در صورت استفاده از [i18n](../guide/i18n) استفاده می‌شود.\n\n## externalLinkIcon\n\n- نوع: `boolean`\n- پیش‌فرض: `false`\n\nآیا باید نمایش آیکون لینک خارجی کنار لینک‌های خارجی در مارک‌داون باشد.\n"
  },
  {
    "path": "docs/fa/reference/default-theme-edit-link.md",
    "content": "# پیوند ویرایش {#edit-link}\n\n## پیکربندی سطح سایت {#site-level-config}\n\nپیوند ویرایش به شما این امکان را می‌دهد که یک پیوند به صفحه ویرایش را در خدمات مدیریت گیت مانند GitHub یا GitLab نمایش دهید. برای فعال‌سازی آن، گزینه `themeConfig.editLink` را به پیکربندی خود اضافه کنید.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\nگزینه `pattern` ساختار URL را برای پیوند تعیین می‌کند و `:path` با مسیر صفحه جایگزین خواهد شد.\n\nهمچنین می‌توانید یک تابع خالص ارائه دهید که `PageData` را به عنوان آرگومان دریافت کرده و رشته URL را برمی‌گرداند.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nاین تابع نباید اثر جانبی داشته باشد و هیچ چیز خارج از دامنه خود را دسترسی ندهد، زیرا که در مرورگر سریالیزه و اجرا خواهد شد.\n\nبه طور پیش‌فرض، این عبارت \"ویرایش این صفحه\" را در پایین صفحه مستندات اضافه می‌کند. می‌توانید این متن را با تعریف گزینه `text` سفارشی‌سازی کنید.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'ویرایش این صفحه در GitHub'\n    }\n  }\n}\n```\n\n## پیکربندی Frontmatter {#frontmatter-config}\n\nمی‌توانید این امکان را برای هر صفحه با استفاده از گزینه `editLink` در frontmatter غیرفعال کنید:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-footer.md",
    "content": "# پاورقی {#footer}\n\nوقتی `themeConfig.footer` حاضر باشد، ویت‌پرس پاورقی جهانی را در پایین صفحه نمایش می‌دهد.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // پیام نمایش داده شده درست قبل از حق نسخه.\n  message?: string\n\n  // متن حق نسخه واقعی.\n  copyright?: string\n}\n```\n\nپیکربندی بالا همچنین از رشته‌های HTML پشتیبانی می‌کند. بنابراین، به عنوان مثال، اگر می‌خواهید متن پاورقی دارای برخی از لینک‌ها باشد، می‌توانید پیکربندی را به شکل زیر تنظیم کنید:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">MIT License</a>.',\n      copyright: 'Copyright © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning هشدار\nتنها عناصر مستقیم می‌توانند در `message` و `copyright` استفاده شوند زیرا در داخل یک عنصر `<p>` رندر می‌شوند. اگر می‌خواهید عناصر بلوکی را اضافه کنید، در نظر داشته باشید که به جای این، از [اسلات `layout-bottom`](../guide/extending-default-theme#layout-slots) استفاده کنید.\n:::\n\nتوجه داشته باشید که پاورقی نمایش داده نمی‌شود زمانی که [نوار کناری](./default-theme-sidebar) قابل مشاهده باشد.\n\n## پیکربندی Frontmatter {#frontmatter-config}\n\nاین می‌تواند برای هر صفحه با استفاده از گزینه `footer` در frontmatter غیرفعال شود:\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-home-page.md",
    "content": "# صفحه اصلی {#home-page}\n\nقالب پیش‌فرض ویت‌پرس یک طرح صفحه اصلی فراهم می‌کند که می‌توانید آن را همچنین در [صفحه اصلی این سایت](../) مشاهده کنید. شما می‌توانید آن را در هر یک از صفحات خود با تعیین `layout: home` در [frontmatter](./frontmatter-config) استفاده کنید.\n\n```yaml\n---\nlayout: home\n---\n```\n\nاما این گزینه به تنهایی خیلی کاربردی نخواهد بود. شما می‌توانید با اضافه کردن بخش‌های \"قالب‌های پیش‌فرض\" مختلف، چندین بخش متفاوت را به صفحه اصلی اضافه کنید مانند `hero` و `features`.\n\n## بخش Hero {#hero-section}\n\nبخش Hero در بالای صفحه اصلی قرار دارد. در ادامه می‌توانید نحوه پیکربندی بخش Hero را ببینید.\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: ویت‌پرس\n  text: Vite & Vue powered static site generator.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: ویت‌پرس\n  actions:\n    - theme: brand\n      text: Get Started\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: View on GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // رشته نمایش داده شده در بالای `text`. همراه با رنگ برند و انتظار می‌رود که کوتاه باشد، مانند نام محصول.\n  name?: string\n\n  // متن اصلی بخش Hero. این به عنوان تگ `h1` تعریف می‌شود.\n  text: string\n\n  // تگ‌لاین نمایش داده شده زیر `text`.\n  tagline?: string\n\n  // تصویر که در کنار ناحیه متن و تگ‌لاین نمایش داده می‌شود.\n  image?: ThemeableImage\n\n  // دکمه‌های اقدام برای نمایش در بخش Hero صفحه اصلی.\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // رنگ تم دکمه. به طور پیش‌فرض `brand` است.\n  theme?: 'brand' | 'alt'\n\n  // برچسب دکمه.\n  text: string\n\n  // مقصد لینک دکمه.\n  link: string\n\n  // ویژگی هدف لینک.\n  target?: string\n\n  // ویژگی rel لینک.\n  rel?: string\n}\n```\n\n### سفارشی‌سازی رنگ نام {#customizing-the-name-color}\n\nویت‌پرس از رنگ برند (`--vp-c-brand-1`) برای `name` استفاده می‌کند. با این حال، شما می‌توانید این رنگ را با جایگذاری متغیر `--vp-home-hero-name-color` سفارشی کنید.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nهمچنین می‌توانید با ترکیب `--vp-home-hero-name-background`، رنگ گرادیانت `name` را تعیین کنید.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## {#features-section} بخش ویژگی‌ها\n\nدر بخش ویژگی‌ها، می‌توانید هر تعدادی ویژگی که مایلید پس از بخش Hero نمایش دهید، لیست کنید. برای پیکربندی آن، گزینه `features` را به frontmatter ارسال کنید.\n\nمی‌توانید برای هر ویژگی آیکونی ارائه دهید که می‌تواند یک ایموجی یا هر نوع تصویر دیگری باشد. زمانی که آیکون پیکربندی شده یک تصویر است (svg، png، jpeg...). باید آیکون را با عرض و ارتفاع مناسب ارائه دهید. شما همچنین می‌توانید توضیحات، اندازه داخلی آن و نسخه‌های آن برای تم تاریک و روشن را ارائه دهید هنگام لزوم.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: ساده و کم حجم، همیشه\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: ویژگی جالب دیگر\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: ویژگی جالب دیگر\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // نمایش آیکون در هر جعبه ویژگی.\n  icon?: FeatureIcon\n\n  // عنوان ویژگی.\n  title: string\n\n  // جزئیات ویژگی.\n  details: string\n\n  // لینک زمانی که بر روی جزئیات کلیک می‌کنید. لینک می‌تواند داخلی یا خارجی باشد.\n  //\n  // به عنوان مثال: `guide/reference/default-theme-home-page` یا `https://example.com`\n  link?: string\n\n  // متن لینکی که داخل جزئیات کامپوننت نمایش داده می‌شود. بهتر است با گزینه `link` استفاده شود.\n  //\n  // به عنوان مثال: `بیشتر بدانید`، `صفحه بازدید` و غیره.\n  linkText?: string\n\n  // ویژگی rel لینک برای گزینه `link`.\n  //\n  // به عنوان مثال: `external`\n  rel?: string\n\n  // ویژگی target لینک برای گزینه `link`.\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## محتوای Markdown {#markdown-content}\n\nمی‌توانید محتوای اضافی را به صفحه اصلی سایت خود اضافه کنید فقط با افزودن Markdown زیر تقسیم‌کننده `---` در پایین frontmatter.\n\n````md\n---\nlayout: home\n\nhero:\n  name\n\n: ویت‌پرس\n  text: Vite & Vue powered static site generator.\n---\n\n## شروع کردن\n\nمی‌توانید بلافاصله با استفاده از `npx` از ویت‌پرس شروع کنید!\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n\n::: info اطلاعات\nویت‌پرس همیشه استایل اضافی محتوای صفحه `layout: home` را خودکار نمی‌کند. برای بازگشت به رفتار قدیمی، می‌توانید `markdownStyles: false` را به frontmatter اضافه کنید.\n:::\n"
  },
  {
    "path": "docs/fa/reference/default-theme-last-updated.md",
    "content": "# آخرین بروزرسانی {#last-updated}\n\nزمان به روزرسانی آخرین محتوا در گوشه پایین سمت راست صفحه نمایش داده خواهد شد. برای فعال‌سازی آن، گزینه `lastUpdated` را به پیکربندی خود اضافه کنید.\n\n::: tip نکته\nبرای دیدن زمان به‌روزرسانی، باید فایل Markdown را commit کنید.\n:::\n\n## پیکربندی سطح سایت {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## پیکربندی Frontmatter {#frontmatter-config}\n\nمی‌توانید این امکان را برای هر صفحه با استفاده از گزینه `lastUpdated` در frontmatter غیرفعال کنید:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nهمچنین به [پیکربندی پیش‌فرض: آخرین بروزرسانی](./default-theme-config#lastupdated) مراجعه کنید تا اطلاعات بیشتری دریافت کنید. هر مقدار حقیقی در سطح تم از ویژگی را فعال خواهد کرد مگر آنکه به صورت صریح در سطح سایت یا صفحه غیرفعال شود.\n"
  },
  {
    "path": "docs/fa/reference/default-theme-layout.md",
    "content": "# طرح بندی {#layout}\n\nمی‌توانید طرح صفحه را با تنظیم گزینه `layout` در [frontmatter](./frontmatter-config) صفحه انتخاب کنید. سه گزینه طرح وجود دارد، `doc`، `page` و `home`. اگر هیچ چیز مشخص نشده باشد، صفحه به عنوان صفحه `doc` در نظر گرفته می‌شود.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## طرح Doc {#doc-layout}\n\nگزینه `doc` طرح پیش‌فرض است و تمام محتوای Markdown را به \"نمایشگاه\" درست می‌کند. این با پوشاندن کل محتوا در داخل کلاس css `vp-doc` کار می‌کند و استایل‌های لازم را بر روی عناصر زیرش اعمال می‌کند.\n\nتقریباً همه عناصر عمومی مانند `p` یا `h2` استایل‌های خاصی دارند. بنابراین، به یاد داشته باشید که اگر HTML سفارشی‌ای درون محتوای Markdown اضافه کنید، این استایل‌ها روی آن‌ها هم اعمال خواهند شد.\n\nاین طرح ویژگی‌های خاص مستندسازی زیر را فراهم می‌کند. این ویژگی‌ها فقط در این طرح فعال هستند.\n\n- پیوند ویرایش\n- پیوند قبلی و بعدی\n- ساختار\n- [تبلیغات Carbon](./default-theme-carbon-ads)\n\n## طرح Page {#page-layout}\n\nگزینه `page` به عنوان \"صفحه خالی\" در نظر گرفته می‌شود. Markdown همچنان تجزیه و تحلیل می‌شود و تمامی [توسعه‌های Markdown](../guide/markdown) به عنوان طرح `doc` کار می‌کنند، اما هیچ استایل پیش‌فرضی به آن اعمال نمی‌شود.\n\nطرح صفحه به شما این امکان را می‌دهد که همه چیز را به دلخواه خود شخصی‌سازی کنید بدون این که طرح ویت‌پرس بر روی مارک‌آپ تاثیر بگذارد. این کار بسیار مفید است زمانی که می‌خواهید صفحه سفارشی خود را ایجاد کنید.\n\nتوجه داشته باشید که حتی در این طرح، نوار کناری نیز نمایش داده می‌شود اگر صفحه دارای پیکربندی نوار کناری مطابق باشد.\n\n## طرح Home  {#home-layout}\n\nگزینه `home` صفحه \"خانه\" قالب‌بندی می‌کند. در این طرح، می‌توانید گزینه‌های اضافی مانند `hero` و `features` را برای دلخواه‌سازی محتوا تنظیم کنید. لطفاً [صفحه پیش‌فرض: صفحه خانه](./default-theme-home-page) را برای اطلاعات بیشتر مشاهده کنید.\n\n## بدون طرح {#no-layout}\n\nاگر نمی‌خواهید هیچ طرحی داشته باشید، می‌توانید با گذراندن `layout: false` از frontmatter، از این گزینه استفاده کنید. این گزینه مفید است اگر صفحهٔ نخستی کاملاً قابل تنظیم (بدون هیچ نوار کناری، نوار ناوبری یا پاورقی به صورت پیش‌فرض) را می‌خواهید.\n\n## طرح سفارشی {#custom-layout}\n\nهمچنین می‌توانید از یک طرح سفارشی استفاده کنید:\n\n```md\n---\nlayout: foo\n---\n```\n\nاین دستور به دنبال یک کامپوننت به نام `foo` ثبت شده در محیط است. به عنوان مثال، می‌توانید کامپوننت خود را به صورت گلوبال در `.vitepress/theme/index.ts` ثبت کنید:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-nav.md",
    "content": "# ناوبری {#nav}\n\nناوبری نوار ناوبری است که در بالای صفحه نمایش داده می‌شود و شامل عنوان سایت، لینک‌های منوی جهانی، و غیره می‌باشد.\n\n## عنوان سایت و لوگو {#site-title-and-logo}\n\nبه طور پیش‌فرض، ناو نام سایت را با ارجاع به مقدار [`config.title`](./site-config#title) نمایش می‌دهد. اگر می‌خواهید تغییر دهید که چه چیزی در ناو نمایش داده شود، می‌توانید متن سفارشی را در گزینه `themeConfig.siteTitle` تعریف کنید.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'عنوان سفارشی من'\n  }\n}\n```\n\nاگر برای سایت خود لوگو دارید، می‌توانید آن را با ارسال مسیر تصویر نمایش دهید. شما باید لوگو را در دایرکتوری `public` قرار داده و مسیر مطلق آن را تعریف کنید.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nهنگام افزودن یک لوگو، آن به همراه عنوان سایت نمایش داده می‌شود. اگر لوگوی شما همه چیزی است که نیاز دارید و اگر می‌خواهید متن عنوان سایت را پنهان کنید، گزینه `siteTitle` را برابر با `false` قرار دهید.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nهمچنین می‌توانید به عنوان لوگو یک شیء را نیز ارسال کنید اگر می‌خواهید ویژگی `alt` را اضافه کنید یا آن را بر اساس حالت تاریک / روشن سفارشی‌سازی کنید. برای جزئیات بیشتر به [`themeConfig.logo`](./default-theme-config#logo) مراجعه کنید.\n\n## لینک‌های ناوبری {#navigation-links}\n\nشما می‌توانید گزینه `themeConfig.nav` را تعریف کنید تا لینک‌ها را به ناوبری خود اضافه کنید.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'راهنما', link: '/guide' },\n      { text: 'پیکربندی', link: '/config' },\n      { text: 'تغییرات', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` متن واقعی است که در ناوبری نمایش داده می‌شود و `link` لینکی است که هنگام کلیک بر روی متن به آن ناوبری می‌شود. برای لینک، مسیر را به صورت واقعی بدون پیشوند `.md` تنظیم کنید و همیشه با `/` شروع کنید.\n\n`link` همچنین می‌تواند تابعی باشد که [`PageData`](./runtime-api#usedata) را به عنوان آرگومان بپذیرد و مسیر را برگرداند.\n\nلینک‌های ناوبری همچنین می‌توانند منوهای کشویی باشند. برای این کار، کلید `items` را در گزینه لینک تنظیم کنید.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'راهنما', link: '/guide' },\n      {\n        text: 'منوی کشویی',\n        items: [\n          { text: 'مورد الف', link: '/item-1' },\n          { text: 'مورد ب', link: '/item-2' },\n          { text: 'مورد ج', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nلطفا توجه داشته باشید که عنوان منوی کشویی (`منوی کشویی` در مثال بالا) نمی‌تواند خاصیت `link` داشته باشد زیرا این دکمه برای باز کردن صفحه گفتگوی کشویی می‌شود.\n\nهمچنین می‌توانید بخش‌هایی را نیز به موارد منوی کشویی با ارسال موارد بیشتر تو در تو اضافه کنید.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'راهنما', link: '/guide' },\n      {\n        text: 'منوی کشویی',\n        items: [\n          {\n            // عنوان بخش\n            text: 'عنوان بخش A',\n            items: [\n              { text: 'آیتم A بخش A', link: '...' },\n              { text: 'آیتم B بخش B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'منوی کشویی',\n        items: [\n          {\n            // شما همچنین می‌توانید عنوان را حذف کنید.\n            items: [\n              { text: 'آیتم A بخش A', link: '...' },\n              { text: 'آیتم B بخش B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### سفارشی‌سازی وضعیت \"فعال\" لینک {#customize-link-s-active-state}\n\nموارد منوی ناوبری زمانی که صفحه فعلی زیر مسیر مطابقت دارد، مشخص می‌شوند. اگر می‌خواهید مسیر مطابقت را سفارشی کنید، ویژگی `activeMatch` و regex را به عنوان مقدار رشته تعریف کنید.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // این لینک وضعیت فعال را در زمانی که کاربر در مسیر `/config/` است، دریافت می‌کند.\n      {\n        text: 'راهنما',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning هشدار\n`activeMatch` انتظار می‌رود که به عنوان یک رشته regex باشد، اما شما باید آن را به عنوان یک رشته تعریف کنید. ما نمی‌توانیم از شیء RegExp واقعی اینجا استفاده کنیم زیرا در زمان ساخت غیر قابل سریالیز کردن است.\n:::\n\n### سفارشی‌سازی ویژگی‌های \"target\" و \"rel\" لینک {#customize-link-s-target-and-rel-attributes}\n\nبه طور پیش‌فرض، ویت‌پرس به طور خودکار ویژگی‌های\n\n`target` و `rel` را بر اساس اینکه لینک یک لینک خارجی است یا خیر، تعیین می‌کند. اما اگر می‌خواهید، شما همچنین می‌توانید آن‌ها را سفارشی کنید.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'کالای معاملاتی',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## لینک‌های اجتماعی {#social-links}\n\nبه [`socialLinks`](./default-theme-config#sociallinks) مراجعه کنید.\n\n## اجزای سفارشی\n\nمی‌توانید اجزای سفارشی را در نوار ناوبری با استفاده از گزینه `component` اضافه کنید. کلید `component` باید نام مؤلفه Vue باشد و باید به صورت جهانی با استفاده از [Theme.enhanceApp](../guide/custom-theme#theme-interface) ثبت شود.\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'منوی من',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // پارامترهای اختیاری برای ارسال به مؤلفه\n            props: {\n              title: 'مؤلفه سفارشی من'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\nسپس، شما باید مؤلفه را به صورت جهانی ثبت کنید:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\nاجزای شما در نوار ناوبری نمایش داده خواهد شد. ویت‌پرس ویژگی‌های اضافی زیر را به مؤلفه ارائه می‌دهد:\n\n- `screenMenu`: یک بولین اختیاری که نشان می‌دهد آیا مؤلفه در منوی ناوبری تلفن همراه است یا خیر\n\nمی‌توانید یک نمونه را در آزمایش‌های e2e [اینجا](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress) بررسی کنید.\n"
  },
  {
    "path": "docs/fa/reference/default-theme-prev-next-links.md",
    "content": "# پیوندهای قبلی و بعدی {#prev-next-links}\n\nشما می‌توانید متن و پیوند برای صفحات قبلی و بعدی را سفارشی‌سازی کنید (نمایش داده شده در پایین صفحه مستندات). این مفید است اگر می‌خواهید متن دیگری را در این قسمت نمایش دهید که با آنچه در نوار کناری دارید، متفاوت باشد. همچنین، ممکن است مفید باشد که فوتر را غیرفعال کنید یا به یک صفحه لینک کنید که در نوار کناری شما وجود ندارد.\n\n## prev\n\n- نوع: `string | false | { text?: string; link?: string }`\n\n- جزئیات:\n\n  مشخص می‌کند متن/لینکی که برای لینک به صفحه قبلی نمایش داده خواهد شد. اگر این را در frontmatter تنظیم نکنید، متن/لینک از تنظیمات نوار کناری استخراج خواهد شد.\n\n- مثال‌ها:\n\n  - برای فقط سفارشی‌سازی متن:\n\n    ```yaml\n    ---\n    prev: 'شروع کنید | مارک‌داون'\n    ---\n    ```\n\n  - برای سفارشی‌سازی هم متن و هم لینک:\n\n    ```yaml\n    ---\n    prev:\n      text: 'مارک‌داون'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - برای مخفی کردن صفحه قبلی:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\nمشابه `prev` اما برای صفحه بعدی.\n"
  },
  {
    "path": "docs/fa/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# جستجو {#search}\n\n## جستجوی محلی {#local-search}\n\nویت‌پرس از جستجوی متن کامل نامتقارن با استفاده از یک فهرست در مرورگر با تشکر از [minisearch](https://github.com/lucaong/minisearch/) پشتیبانی می‌کند. برای فعال‌سازی این ویژگی، کافی است گزینه `themeConfig.search.provider` را به `'local'` در فایل `.vitepress/config.ts` خود تنظیم کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\nنمونه نتیجه:\n\n![تصویر نمایشی از مودال جستجو](/search.png)\n\nهمچنین، می‌توانید از [Algolia DocSearch](#algolia-search) یا برخی افزونه‌های جامعه‌ای مانند <https://www.npmjs.com/package/vitepress-plugin-search> یا <https://www.npmjs.com/package/vitepress-plugin-pagefind> استفاده کنید.\n\n### بین‌المللی‌سازی {#local-search-i18n}\n\nمی‌توانید با استفاده از تنظیماتی مانند این برای جستجوی چندزبانه استفاده کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          fa: { // اگر می خواهید زبان پیش فرض را ترجمه کنید، این را `root` قرار دهید\n            translations: {\n              button: {\n                buttonText: 'جستجو',\n                buttonAriaLabel: 'جستجو'\n              },\n              modal: {\n                displayDetails: 'نمایش فهرست کامل',\n                resetButtonTitle: 'بازنشانی جستجو',\n                backButtonTitle: 'بستن جستجو',\n                noResultsText: 'نتیجه ای یافت نشد',\n                footer: {\n                  selectText: 'انتخاب',\n                  selectKeyAriaLabel: 'Enter',\n                  navigateText: 'پیمایش',\n                  navigateUpKeyAriaLabel: 'فلش بالا',\n                  navigateDownKeyAriaLabel: 'فلش پایین',\n                  closeText: 'بستن',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### گزینه‌های miniSearch {#minisearch-options}\n\nمی‌توانید MiniSearch را به این صورت پیکربندی کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nبرای کسب اطلاعات بیشتر به [اسناد MiniSearch](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html) مراجعه کنید.\n\n### سفارشی‌سازی رندر محتوا {#custom-content-renderer}\n\nمی‌توانید تابع استفاده شده برای رندر محتوای Markdown قبل از فهرست‌بندی آن را سفارشی‌سازی کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // رشته HTML را برمی گرداند\n        }\n      }\n    }\n  }\n})\n```\n\nاین تابع از داده‌های سایت سمت کلاینت پاک خواهد شد، بنابراین شما می‌توانید از API‌های Node.js در آن استفاده کنید.\n\n#### مثال: استثنای صفحات از جستجو {#example-excluding-pages-from-search}\n\nمی‌توانید با اضافه کردن `search: false` به frontmatter صفحه، صفحات را از جستجو استثنا دهید. به طور جایگزین:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning توجه\nدر صورت ارائه تابع `_render` سفارشی، باید خودتان بررسی کنید که آیا frontmatter `search: false` را مدیریت می‌کند یا خیر. همچنین، شی env قبل از فراخوانی `md.renderAsync` کاملاً پر نمی‌شود، بنابراین هر بررسی‌ای روی ویژگی‌های اختیاری env مانند `frontmatter` باید بعد از آن انجام شود.\n:::\n\n#### مثال: تبدیل محتوا - افزودن لینک‌های صفحه {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## جستجوی Algolia {#algolia-search}\n\nویت‌پرس از جستجو در سایت مستندات شما با استفاده از [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) پشتیبانی می‌کند. به راهنمای شروع کار آن‌ها مراجعه کنید. در فایل `.vitepress/config.ts` شما نیاز دارید که حداقل موارد زیر را فراهم کنید تا کار کند:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### بین‌المللی‌سازی {#algolia-search-i18n}\n\nمی‌توانید با استفاده از تنظیماتی مانند این برای جستجوی چندزبانه استفاده کنید:\n\n<details>\n<summary>برای باز کردن کلیک کنید</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\nبرای اطلاعات بیشتر به [مستندات رسمی Algolia](https://docsearch.algolia.com/docs/api#translations) مراجعه کنید. برای شروع سریع‌تر، می‌توانید ترجمه‌های استفاده‌شده در این سایت را از [مخزن GitHub ما](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code) کپی کنید.\n\n### پشتیبانی Algolia Ask AI {#ask-ai}\n\nبرای فعال‌سازی **Ask AI** کافی است گزینه `askAi` را اضافه کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"شناسه-دستیار-شما\"\n        // یا\n        askAi: {\n          // حداقل باید assistantId دریافت شده از Algolia را ارائه کنید\n          assistantId: 'XXXYYY',\n          // بازنویسی های اختیاری — اگر حذف شوند، مقادیر appId/apiKey/indexName سطح بالا دوباره استفاده می شوند\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning نکته\nاگر فقط به جستجوی کلمات کلیدی نیاز دارید، `askAi` را اضافه نکنید.\n:::\n\n### پنل کناری Ask AI {#ask-ai-side-panel}\n\nDocSearch v4.5+ از **پنل کناری Ask AI** اختیاری پشتیبانی می‌کند. وقتی فعال باشد، به طور پیش‌فرض می‌توان آن را با **Ctrl/Cmd+I** باز کرد. [مرجع API پنل کناری](https://docsearch.algolia.com/docs/sidepanel/api-reference) شامل لیست کامل گزینه‌ها است.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // آینه API @docsearch/sidepanel-js SidepanelProps\n            panel: {\n              variant: 'floating', // یا 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nاگر نیاز به غیرفعال کردن میانبر صفحه‌کلید دارید، از گزینه `keyboardShortcuts` پنل کناری استفاده کنید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### حالت (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nمی‌توانید به صورت اختیاری نحوه ادغام جستجوی کلمات کلیدی و Ask AI در VitePress را کنترل کنید:\n\n- `mode: 'auto'` (پیش‌فرض): وقتی جستجوی کلمات کلیدی پیکربندی شده باشد `hybrid` را استنباط می‌کند، در غیر این صورت وقتی پنل کناری Ask AI پیکربندی شده باشد `sidePanel` را استنباط می‌کند.\n- `mode: 'sidePanel'`: فقط پنل کناری را اعمال می‌کند (دکمه جستجوی کلمات کلیدی را پنهان می‌کند).\n- `mode: 'hybrid'`: مودال جستجوی کلمات کلیدی + پنل کناری Ask AI را فعال می‌کند (نیاز به پیکربندی جستجوی کلمات کلیدی دارد).\n- `mode: 'modal'`: Ask AI را درون مودال DocSearch نگه می‌دارد (حتی اگر پنل کناری را پیکربندی کرده باشید).\n\n#### فقط Ask AI (بدون جستجوی کلمات کلیدی) {#ask-ai-only}\n\nاگر می‌خواهید **فقط پنل کناری Ask AI** را استفاده کنید، می‌توانید پیکربندی جستجوی کلمات کلیدی سطح بالا را حذف کرده و اعتبارنامه‌ها را در `askAi` ارائه دهید:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### پیکربندی Crawler {#crawler-config}\n\nدر اینجا یک پیکربندی نمونه بر اساس آنچه که این سایت استفاده می‌کند آمده است:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/fa/reference/default-theme-sidebar.md",
    "content": "# نوار کناری {#sidebar}\n\nنوار کناری بلوک اصلی ناوبری برای مستندات شما است. شما می‌توانید منوی نوار کناری را در [`themeConfig.sidebar`](./default-theme-config#sidebar) پیکربندی کنید.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'راهنما',\n        items: [\n          { text: 'مقدمه', link: '/introduction' },\n          { text: 'شروع کردن', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## مبانی {#the-basics}\n\nساده‌ترین فرم منوی نوار کناری ارسال یک آرایه تکی از لینک‌هاست. آیتم سطح اول \"بخش\" نوار کناری را تعریف می‌کند. باید شامل `text` باشد که عنوان بخش است و `items` که لینک‌های واقعی ناوبری هستند.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'عنوان بخش A',\n        items: [\n          { text: 'آیتم A', link: '/item-a' },\n          { text: 'آیتم B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'عنوان بخش B',\n        items: [\n          { text: 'آیتم C', link: '/item-c' },\n          { text: 'آیتم D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\nهر `link` باید مسیر به فایل واقعی را با `/` آغاز کند. اگر شما `/` را به انتهای لینک اضافه کنید، صفحه `index.md` دایرکتوری متناظر را نمایش می‌دهد.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'راهنما',\n        items: [\n          // این صفحه `/guide/index.md` را نمایش می‌دهد.\n          { text: 'مقدمه', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nشما می‌توانید آیتم‌های نوار کناری را تا عمق ۶ سطح تعویض کنید که از سطح ریشه شمارش می‌شود. توجه داشته باشید که عمق بیشتر از ۶ سطح از آیتم‌های تو در تو نادیده گرفته می‌شود و در نوار کناری نمایش داده نمی‌شود.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'سطح ۱',\n        items: [\n          {\n            text: 'سطح ۲',\n            items: [\n              {\n                text: 'سطح ۳',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## نوارهای کناری چندگانه {#multiple-sidebars}\n\nمی‌توانید بسته به مسیر صفحه، نوار کناری مختلفی را نمایش دهید. به عنوان مثال، همانطور که در این سایت نشان داده شده است، ممکن است بخواهید برای مستندات خود بخش‌های جداگانه مانند صفحه \"راهنما\" و صفحه \"پیکربندی\" را ایجاد کنید.\n\nبرای این کار، ابتدا صفحات خود را در دایرکتوری‌های مختلف برای هر بخش مورد نظر خود سازماندهی کنید:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nسپس، پیکربندی خود را برای تعریف نوار کناری برای هر بخش تعیین کنید. در این موارد، شما باید به جای یک آرایه، یک شیء را ارسال کنید.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // این نوار کناری نمایش داده می‌شود زمانی که کاربر در دایرکتوری `guide` است.\n      '/guide/': [\n        {\n          text: 'راهنما',\n          items: [\n            { text: 'فهرست', link: '/guide/' },\n            { text: 'یک', link: '/guide/one' },\n            { text: 'دو', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // این نوار کناری نمایش داده می‌شود زمانی که کاربر در دایرکتوری `config` است.\n      '/config/': [\n        {\n          text: 'پیکربندی',\n          items: [\n            { text: 'فهرست', link: '/config/' },\n            { text: 'سه', link: '/config/three' },\n            { text: 'چهار', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## گروه‌های نوار کناری قابل جمع و جور {#collapsible-sidebar-groups}\n\nبا اضافه کردن گزینه `collapsed` به گروه نوار کناری، دکمه جداگانه‌ای برای پنهان کردن/نمایش هر بخش نمایش داده می‌شود.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'عنوان بخش A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\nتمام بخش‌ها به طور پیش‌فرض \"باز\" هستند. اگر می‌خواهید آن‌ها را در بارگذاری اولیه صفحه \"بسته\" کنید، گزینه `collapsed` را به `true` تنظیم کنید.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'عنوان بخش A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/fa/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Developer',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# صفحه تیم {#team-page}\n\nاگر می‌خواهید تیم خود را معرفی کنید، می‌توانید از کامپوننت‌های تیم برای ساخت صفحه تیم استفاده کنید. دو راه برای استفاده از این کامپوننت‌ها وجود دارد. یکی اینکه آنها را در صفحه مستندات قرار دهید و دیگری اینکه یک صفحه کامل تیم ایجاد کنید.\n\n## نمایش اعضای تیم در یک صفحه {#show-team-members-in-a-page}\n\nمی‌توانید از کامپوننت `<VPTeamMembers>` که از `vitepress/theme` قابل دسترسی است، برای نمایش لیست اعضای تیم در هر صفحه‌ای استفاده کنید.\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# تیم ما\n\nبا سلام به تیم فوق‌العاده‌ی ما خوش آمدید.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\nبالا به صورت عنصری با شکل کارتی اعضای تیم را نمایش می‌دهد. باید به شکل زیر نمایش داده شود.\n\n<VPTeamMembers size=\"small\" :members />\n\nکامپوننت `<VPTeamMembers>` دارای دو اندازه مختلف، `small` و `medium` است. معمولاً اندازه `small` برای استفاده در صفحات مستندات مناسب‌تر است. همچنین می‌توانید ویژگی‌های بیشتری برای هر عضو اضافه کنید مانند \"توضیحات\" یا \"دکمه حامی\". جهت کسب اطلاعات بیشتر به [`<VPTeamMembers>`](#vpteammembers) مراجعه کنید.\n\nقرار دادن اعضای تیم در صفحه مستندات برای تیم‌های کوچک مناسب است که ایجاد یک صفحه کامل تیم ممکن است بیش از حد باشد یا معرفی اعضا به عنوان مرجع در زمینه مستندات.\n\nاگر تعداد اعضا بسیار زیاد است یا به سادگی می‌خواهید بیشتر فضا برای نمایش اعضای تیم داشته باشید، در نظر بگیرید [ایجاد یک صفحه کامل تیم](#create-a-full-team-page).\n\n## ایجاد یک صفحه کامل تیم {#create-a-full-team-page}\n\nبجای اضافه کردن اعضای تیم به صفحه مستندات، می‌توانید یک صفحه کامل تیم را ایجاد کنید، مشابه اینکه چگونه می‌توانید یک [صفحه خانگی سفارشی](./default-theme-home-page) ایجاد کنید.\n\nبرای ایجاد یک صفحه تیم، ابتدا یک فایل md جدید بسازید. نام فایل مهم نیست، اما در اینجا آن را `team.md` می‌نامیم. در این فایل، گزینه `layout: page` را در فرانت‌ماتر تنظیم کنید، سپس می‌توانید ساختار صفحه خود را با استفاده از کامپوننت‌های `TeamPage` ایجاد کنید.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      تیم ما\n    </template>\n    <template #lead>\n      توسعه ویت‌پرس توسط تیمی بین‌المللی راهنمایی می‌شود، برخی از اعضا که انتخاب کرده‌اند تا در زیر نمایش داده شوند.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\nدر ایجاد یک صفحه کامل تیم، به یاد داشته باشید که همهٔ کامپوننت‌ها را با کامپوننت `<VPTeamPage>` بپوشانید. این کامپوننت تضمین می‌کند که همهٔ کامپوننت‌های مرتبط با تیم در ساختار طراحی مناسبی مانند فضاهای خالی قرار می‌گیرند.\n\nکامپوننت `<VPPageTitle>` بخش عنوان صفحه را اضافه می‌کند. عنوان به عنوان `<h1>` نمایش داده می‌شود. از اسلات‌های `#title` و `#lead` برای مستندسازی در مورد تیم خود استفاده کنید.\n\n`<VPMembers>` به عنوان زمانی که در یک صفحه مستند استفاده می‌شود، کار می‌کند. این لیست اعضا را نمایش می‌دهد.\n\n### اضافه کردن بخش‌ها برای تقسیم اعضای تیم {#add-sections-to-divide-team-members}\n\nمی‌توانید بخش‌ها را به صفحه تیم اضافه کنید. به عنوان مثال، ممکن است اعضای مختلف تیمی مانند اعضای تیم اصلی و شرکای اجتماعی داشته باشید. شما می‌توانید این اعضا را به بخش‌ها تقسیم کنید تا نقش هر گروه بهتر توضیح داده شود.\n\nبرای این کار، کامپوننت `<VPTeamPageSection>` را به فایل `team.md` اضافه کنید که قبلاً ایجاد کردیم.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>تیم ما</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>شرکای تجاری</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\nکامپوننت `<VPTeamPageSection>` می‌تواند همچون کامپوننت `VPTeamPageTitle` دارای اسلات‌های `#title` و `#lead` باشد و همچنین اسلات `#members` را برای نمایش اعضای تیم پذیرفته است.\n\nبه یاد داشته باشید که کامپوننت `<VPTeamMembers>` را درون اسلات `#members` قرار دهید.\n\n## `<VPTeamMembers>` {#vpteammembers}\n\nکامپوننت `<VPTeamMembers>` لیست داده‌شده از اعضا را نمایش می‌دهد.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // اندازه هر عضو. پیش‌فرض به `medium`.\n  size?: 'small' | 'medium'\n\n  // لیست اعضا برای نمایش.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // تصویر آواتار برای عضو.\n  avatar: string\n\n  // نام عضو.\n  name: string\n\n  // عنوانی که زیر نام عضو نمایش داده خواهد شد.\n  // برای مثال، توسعه‌دهنده، مهندس نرم‌افزار و غیره.\n  title?: string\n\n  // سازمانی که عضو به آن تعلق دارد.\n  org?: string\n\n  // پیوند URL برای سازمان.\n  orgLink?: string\n\n  // توضیحات برای عضو.\n  desc?: string\n\n  // پیوندهای اجتماعی. برای مثال، GitHub، Twitter و غیره. می‌توانید شیء پیوندهای اجتماعی را در اینجا ارسال کنید.\n  // مشاهده: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // URL برای صفحه حامی برای عضو.\n  sponsor?: string\n\n  // متن برای لینک حامی. پیش‌فرض به 'حمایت‌کننده'.\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>` {#vpteampage}\n\nکامپوننت ریشه هنگام ایجاد یک صفحه کامل تیم. فقط یک اسلات را قبول می‌کند. این همه کامپوننت‌های مربوط به تیم را استایل می‌کند.\n\n## `<VPTeamPageTitle>` {#vpteampagetitle}\n\nبخش \"عنوان\" صفحه را اضافه می‌کند. بهترین استفاده را در ابتدایی‌ترین جای زیر `<VPTeamPage>` داشته باشد. این اسلات‌های `#title` و `#lead` را قبول می‌کند.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      تیم ما\n    </template>\n    <template #lead>\n      توسعه ویت‌پرس توسط تیمی بین‌المللی راهنمایی می‌شود، برخی از اعضا که انتخاب کرده‌اند تا در زیر نمایش داده شوند.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>` {#vpteampagesection}\n\nیک \"بخش\" را درون صفحه تیم ایجاد می‌کند. اسلات‌های `#title`، `#lead` و `#members` را قبول می‌کند. می‌توانید هر تعداد بخش را درون `<VPTeamPage>` اضافه کنید.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>شرکای تجاری</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/fa/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# تنظیمات Frontmatter {#frontmatter-config}\n\nFrontmatter امکان پیکربندی بر اساس صفحه را فراهم می‌کند. در هر فایل markdown، شما می‌توانید از تنظیمات frontmatter برای بازنویسی تنظیمات سطح سایت یا تم استفاده کنید. همچنین، تنظیماتی وجود دارند که فقط می‌توانید آن‌ها را در frontmatter تعریف کنید.\n\nنمونه استفاده:\n\n```md\n---\ntitle: مستندات با ویت‌پرس\neditLink: true\n---\n```\n\nشما می‌توانید به داده‌های frontmatter از طریق `$frontmatter` در بیانیه‌های Vue دسترسی داشته باشید:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- نوع: `string`\n\nعنوان صفحه. همانطور که در [config.title](./site-config#title) است، این تنظیمات سطح سایت را بازنویسی می‌کند.\n\n```yaml\n---\ntitle: ویت‌پرس\n---\n```\n\n## titleTemplate\n\n- نوع: `string | boolean`\n\nپسوند برای عنوان. همانطور که در [config.titleTemplate](./site-config#titletemplate) است، این تنظیمات سطح سایت را بازنویسی می‌کند.\n\n```yaml\n---\ntitle: ویت‌پرس\ntitleTemplate: Vite & Vue powered static site generator\n---\n```\n\n## description\n\n- نوع: `string`\n\nتوضیحات صفحه. همانطور که در [config.description](./site-config#description) است، این تنظیمات سطح سایت را بازنویسی می‌کند.\n\n```yaml\n---\ndescription: ویت‌پرس\n---\n```\n\n## head\n\n- نوع: `HeadConfig[]`\n\nتگ‌های head اضافی برای درج در صفحه فعلی. پس از تگ‌های head تزریق شده توسط تنظیمات سطح سایت، این تنظیمات درج می‌شوند.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## فقط برای تم پیش‌فرض {#default-theme-only}\n\nگزینه‌های frontmatter زیر فقط زمانی قابل استفاده هستند که از تم پیش‌فرض استفاده می‌کنید.\n\n### layout\n\n- نوع: `doc | home | page`\n- پیش‌فرض: `doc`\n\nتعیین چیدمان صفحه.\n\n- `doc` - این چیدمان استایل‌های مستندات پیش‌فرض را به محتوای markdown اعمال می‌کند.\n- `home` - چیدمان ویژه برای \"صفحه اصلی\". شما می‌توانید گزینه‌های اضافی مانند `hero` و `features` را اضافه کنید تا به سرعت یک صفحه نخست زیبا ایجاد کنید.\n- `page` - مشابه `doc` عمل می‌کند اما هیچ استایلی به محتوا اعمال نمی‌شود. مفید است زمانی که می‌خواهید یک صفحه کاملاً سفارشی ایجاد کنید.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"فقط برای صفحه اصلی\" /> {#hero}\n\nتعیین محتویات بخش hero صفحه اصلی هنگامی که `layout` به `home` تنظیم شده است. جزئیات بیشتر در [تم پیش‌فرض: صفحه اصلی](./default-theme-home-page).\n\n### features <Badge type=\"info\" text=\"فقط برای صفحه اصلی\" /> {#features}\n\nتعیین مواردی که در بخش ویژگی‌ها باید نمایش داده شوند هنگامی که `layout` به `home` تنظیم شده است. جزئیات بیشتر در [تم پیش‌فرض: صفحه اصلی](./default-theme-home-page).\n\n### navbar\n\n- نوع: `boolean`\n- پیش‌فرض: `true`\n\nآیا باید [نوار ناوبری](./default-theme-nav) نمایش داده شود یا خیر؟\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- نوع: `boolean`\n- پیش‌فرض: `true`\n\nآیا باید [نوار کناری](./default-theme-sidebar) نمایش داده شود یا خیر؟\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- نوع: `boolean | 'left'`\n- پیش‌فرض: `true`\n\nتعیین مکان کامپوننت aside در چیدمان `doc`.\n\n- اگر این مقدار را به `false` تنظیم کنید، اجرای کانتینر aside جلوگیری می‌کند.\n- اگر این مقدار را به `true` تنظیم کنید، aside به راست اجرا می‌شود.\n- اگر این مقدار را به `'left'` تنظیم کنید، aside به چپ اجرا می‌شود.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- نوع: `number | [number, number] | 'deep' | false`\n- پیش‌فرض: `2`\n\nسطوح سرفصل‌های مورد نمایش برای صفحه. همانطور که در [config.themeConfig.outline.level](./default-theme-config#outline) است، این مقدار سطح مجموعه سایت را بازنویسی می‌کند.\n\n### lastUpdated\n\n- نوع: `boolean | Date`\n- پیش‌فرض: `true`\n\nآیا متن [آخرین به‌روزرسانی](./default-theme-last-updated) را در پاورقی صفحه فعلی نمایش دهد یا خیر؟ اگر تاریخ و زمان مشخص شده باشد، به جای زمان اصلاح شده git نمایش داده می‌شود.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- نوع: `boolean`\n- پیش‌فرض: `true`\n\nآیا [پیوند ویرایش](./default-theme-edit-link) را در پاورقی صفحه فعلی نمایش دهد یا خیر؟\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- نوع: `boolean`\n- پیش‌فرض: `true`\n\nآیا [پاورقی](./default-theme-footer) را\n\nنمایش دهد یا خیر؟\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- نوع: `string`\n\nافزودن نام کلاس اضافی به یک صفحه خاص.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nسپس می‌توانید استایل‌های این صفحه خاص را در فایل `.vitepress/theme/custom.css` سفارشی کنید:\n\n```css\n.custom-page-class {\n    /* استایل‌های مخصوص صفحه */\n}\n```\n"
  },
  {
    "path": "docs/fa/reference/runtime-api.md",
    "content": "# API زمان اجرا {#runtime-api}\n\nویت‌پرس چندین API داخلی را ارائه می‌دهد تا به شما امکان دسترسی به داده‌های برنامه را بدهد. همچنین، ویت‌پرس با چندین کامپوننت داخلی همراه است که می‌توانید به صورت جهانی از آن‌ها استفاده کنید.\n\nمتدهای کمکی به صورت جهانی از `vitepress` قابل وارد کردن هستند و معمولاً در کامپوننت‌های Vue سفارشی تم استفاده می‌شوند. با این حال، آن‌ها همچنین در صفحات `.md` قابل استفاده هستند زیرا فایل‌های markdown به [کامپوننت‌های فایل تکی](https://vuejs.org/guide/scaling-up/sfc.html) Vue ترجمه می‌شوند.\n\nمتدهایی که با `use*` آغاز می‌شوند نشان می‌دهند که این یک تابع [API ترکیبی Vue 3](https://vuejs.org/guide/introduction.html#composition-api) (\"Composable\") است که فقط می‌تواند در `setup()` یا `<script setup>` استفاده شود.\n\n## `useData` <Badge type=\"info\" text=\"composable\" /> {#usedata}\n\nداده‌های خاص به صفحه را برمی‌گرداند. شیء برگشتی این نوع را دارد:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * Metadata سطح سایت\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig از .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Metadata سطح صفحه\n   */\n  page: Ref<PageData>\n  /**\n   * Frontmatter صفحه\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * پارامترهای مسیر دینامیک\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  /**\n   * مکان فعلی hash\n   */\n  hash: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**مثال:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" /> {#useroute}\n\nشیء مسیر فعلی را با این نوع برمی‌گرداند:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" /> {#userouter}\n\nنمونه راوتر ویت‌پرس را برمی‌گرداند تا بتوانید به صورت برنامه‌ریزی‌شده به صفحه دیگری ناوبری کنید.\n\n```ts\ninterface Router {\n  /**\n   * Route فعلی\n   */\n  route: Route\n  /**\n   * به URL جدید ناوبری کنید.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * قبل از تغییر مسیر فراخوانی می‌شود. برای لغو ناوبری `false` را برگردانید.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * قبل از بارگذاری مؤلفه صفحه فراخوانی می‌شود (پس از به‌روزرسانی وضعیت تاریخچه). برای لغو ناوبری `false` را برگردانید.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * پس از تغییر مسیر فراخوانی می‌شود.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" /> {#withbase}\n\n- **نوع**: `(path: string) => string`\n\nپایه [پیکربندی‌شده](./site-config#base) را به یک مسیر URL داده شده اضافه می‌کند. همچنین به [آدرس پایه](../guide/asset-handling#base-url) مراجعه کنید.\n\n## `<Content />` <Badge type=\"info\" text=\"component\" /> {#content}\n\nکامپوننت `<Content />` محتوای markdown را نمایش می‌دهد. مفید است [هنگام ایجاد تم شخصی شما](../guide/custom-theme).\n\n```vue\n<template>\n  <h1>چیدمان شخصی!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" /> {#clientonly}\n\nکامپوننت `<ClientOnly />` فقط اسلات خود را در سمت مشتری رندر می‌کند.\n\nچون برنامه‌های ویت‌پرس هنگام ایجاد از سمت سرور در Node.js رندر می‌شوند، هر استفاده از Vue باید به الزامات کد یکپارچه دنیا پاسخ دهد. به طور خلاصه، اطمینان حاصل کنید که فقط در قالب hooks `beforeMount` یا `mounted` به API‌های Browser / DOM دسترسی دارید.\n\nاگر از کامپوننت‌هایی استفاده یا نمایش دهنده‌هایی که با SSR سازگار نیستند (مانند دستورالعمل‌های سفارشی) استفاده می‌کنید، می‌توانید آن‌ها را داخل کامپوننت `ClientOnly` قرار دهید.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- مرتبط: [سازگاری با SSR](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" /> {#frontmatter}\n\nدر بیانیه‌های Vue، به صورت مستقیم به [داده‌های frontmatter](../guide/frontmatter) صفحه فعلی دسترسی پیدا کنید.\n\n```md\n---\ntitle: سلام\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" /> {#params}\n\nدر بیانیه‌های Vue، به صورت مستقیم به [پارامترهای مسیر دینامیک](../guide/routing#dynamic-routes) صفحه فعلی دسترسی پیدا کنید.\n\n```md\n- نام بسته: {{ $params.pkg }}\n- نسخه: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/fa/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# تنظیمات سایت {#site-config}\n\nتنظیمات سایت جایی است که می‌توانید تنظیمات جهانی سایت را تعریف کنید. گزینه‌های تنظیمات برنامه شامل تنظیماتی است که برای هر سایت ویت‌پرس اعمال می‌شود، صرف نظر از اینکه از چه تمی استفاده می‌کند. برای مثال، دایرکتوری پایه یا عنوان سایت.\n\n## مروری کلی {#overview}\n\n### رفع تنظیمات {#config-resolution}\n\nفایل تنظیمات همیشه از `<root>/.vitepress/config.[ext]` رفع می‌شود، جایی که `<root>` ریشه پروژه ویت‌پرس شما است و `[ext]` یکی از پسوندهای فایل پشتیبانی شده است. تایپ‌اسکریپت به طور پیش‌فرض پشتیبانی می‌شود. پسوندهای پشتیبانی شده شامل `.js`, `.ts`, `.mjs` و `.mts` هستند.\n\nتوصیه می‌شود از سینتکس ماژول‌های ES در فایل‌های تنظیمات استفاده کنید. فایل تنظیمات باید به طور پیش‌فرض یک شیء صادر کند:\n\n```ts\nexport default {\n  // گزینه‌های تنظیمات سطح برنامه\n  lang: 'en-US',\n  title: 'ویت‌پرس',\n  description: 'مولد سایت استاتیک توسط Vite & Vue.',\n  ...\n}\n```\n\n::: details تنظیمات پویا (غیرهمزمان)\n\nاگر نیاز دارید به طور پویا تنظیمات را تولید کنید، می‌توانید یک تابع صادر کنید. به عنوان مثال:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // گزینه‌های تنظیمات سطح برنامه\n    lang: 'en-US',\n    title: 'ویت‌پرس',\n    description: 'مولد سایت استاتیک توسط Vite & Vue.',\n\n    // گزینه‌های تنظیمات سطح تم\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nهمچنین می‌توانید از `await` سطح بالا استفاده کنید. به عنوان مثال:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // گزینه‌های تنظیمات سطح برنامه\n  lang: 'en-US',\n  title: 'ویت‌پرس',\n  description: 'مولد سایت استاتیک توسط Vite & Vue.',\n\n  // گزینه‌های تنظیمات سطح تم\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### هوشمندی تنظیمات {#config-intellisense}\n\nاستفاده از تابع `defineConfig` هوشمندی تایپ‌اسکریپت را برای گزینه‌های تنظیمات فراهم می‌کند. فرض کنید IDE شما از آن پشتیبانی می‌کند، این باید هم در جاوااسکریپت و هم تایپ‌اسکریپت کار کند.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### تنظیمات تایپ‌شده تم {#typed-theme-config}\n\nبه طور پیش‌فرض، تابع `defineConfig` انتظار دارد نوع تنظیمات تم از تم پیش‌فرض باشد:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // نوع `DefaultTheme.Config`\n  }\n})\n```\n\nاگر از تم سفارشی استفاده می‌کنید و می‌خواهید بررسی نوع برای تنظیمات تم داشته باشید، باید به جای آن از `defineConfigWithTheme` استفاده کنید و نوع تنظیمات تم سفارشی خود را از طریق یک آرگومان جنریک منتقل کنید:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // نوع `ThemeConfig`\n  }\n})\n```\n\n### تنظیمات Vite, Vue و Markdown {#vite-vue-markdown-config}\n\n- **Vite**\n\n  شما می‌توانید نمونه پایه Vite را با استفاده از گزینه [vite](#vite) در تنظیمات ویت‌پرس خود پیکربندی کنید. نیازی به ایجاد فایل تنظیمات Vite جداگانه نیست.\n\n- **Vue**\n\n  ویت‌پرس از قبل پلاگین رسمی Vue برای Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)) را شامل می‌شود. شما می‌توانید گزینه‌های آن را با استفاده از گزینه [vue](#vue) در تنظیمات ویت‌پرس خود پیکربندی کنید.\n\n- **Markdown**\n\n  شما می‌توانید نمونه پایه [Markdown-It](https://github.com/markdown-it/markdown-it) را با استفاده از گزینه [markdown](#markdown) در تنظیمات ویت‌پرس خود پیکربندی کنید.\n\n## متاداده‌های سایت {#site-metadata}\n\n### عنوان {#title}\n\n- نوع: `string`\n- پیش‌فرض: `ویت‌پرس`\n- می‌تواند به ازای هر صفحه از طریق [frontmatter](./frontmatter-config#title) جایگزین شود.\n\nعنوان سایت. هنگامی که از تم پیش‌فرض استفاده می‌کنید، این در نوار ناوبری نمایش داده می‌شود.\n\nهمچنین به عنوان پسوند پیش‌فرض برای تمام عناوین صفحات فردی استفاده می‌شود، مگر اینکه [`titleTemplate`](#titletemplate) تعریف شده باشد. عنوان نهایی صفحه‌ای به محتوای متنی اولین هدر `<h1>` آن صفحه ترکیب می‌شود با `title` جهانی به عنوان پسوند. به عنوان مثال با تنظیمات زیر و محتوای صفحه:\n\n```ts\nexport default {\n  title: 'سایت فوق‌العاده من'\n}\n```\n\n```md\n# سلام\n```\n\nعنوان صفحه خواهد بود `سلام | سایت فوق‌العاده من`.\n\n### قالب عنوان  {##titletemplate}\n\n- نوع: `string | boolean`\n- می‌تواند به ازای هر صفحه از طریق [frontmatter](./frontmatter-config#titletemplate) جایگزین شود.\n\nاجازه می‌دهد پسوند عنوان هر صفحه یا کل عنوان را سفارشی کنید. به عنوان مثال:\n\n```ts\nexport default {\n  title: 'سایت فوق‌العاده من',\n  titleTemplate: 'پسوند سفارشی'\n}\n```\n\n```md\n# سلام\n```\n\nعنوان صفحه خواهد بود `سلام | پسوند سفارشی`.\n\nبرای سفارشی کردن کامل نحوه نمایش عنوان، می‌توانید از نماد `:title` در `titleTemplate` استفاده کنید:\n\n```ts\nexport default {\n  titleTemplate: ':title - پسوند سفارشی'\n}\n```\n\nاینجا `:title` با متن استنباط شده از اولین هدر `<h1>` صفحه جایگزین می‌شود. عنوان صفحه مثال قبلی خواهد بود `سلام - پسوند سفارشی`.\n\nاین گزینه می‌تواند به `false` تنظیم شود تا پسوندهای عنوان غیرفعال شوند.\n\n### توضیحات {#description}\n\n- نوع: `string`\n- پیش‌فرض: `یک سایت ویت‌پرس`\n- می‌تواند به ازای هر صفحه از طریق [frontmatter](./frontmatter-config#description) جایگزین شود.\n\nتوضیحات برای سایت. این به عنوان یک تگ `<meta>` در HTML صفحه رندر خواهد شد.\n\n```ts\nexport default {\n  description: 'یک سایت ویت‌پرس'\n}\n```\n\n### head\n\n- نوع: `HeadConfig[]`\n- پیش‌فرض: `[]`\n- می‌تواند به ازای هر صفحه از طریق [frontmatter](./frontmatter-config#head) افزوده شود.\n\nعناصر اضافی برای رندر در تگ `<head>` در HTML صفحه. تگ‌های افزوده شده توسط کاربر قبل از بسته شدن تگ `head`، پس از تگ‌های ویت‌پرس رندر می‌شوند.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### مثال: اضافه کردن یک favicon {#example-adding-a-favicon}\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // favicon.ico را در دایرکتوری عمومی قرار دهید، اگر base تنظیم شده است، از /base/favicon.ico استفاده کنید.\n\n/* رندر خواهد شد:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### مثال: اضافه کردن فونت‌های گوگل {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* رندر خواهد شد:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### مثال: ثبت یک سرویس ورکر {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* رندر خواهد شد\n\n:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### مثال: استفاده از گوگل آنالیتیکس {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* رندر خواهد شد:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### زبان {#lang}\n\n- نوع: `string`\n- پیش‌فرض: `en-US`\n\nویژگی زبان برای سایت. این به عنوان یک تگ `<html lang=\"en-US\">` در HTML صفحه رندر خواهد شد.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### پایه {#base}\n\n- نوع: `string`\n- پیش‌فرض: `/`\n\nآدرس پایه‌ای که سایت در آن مستقر خواهد شد. اگر قصد دارید سایت خود را در یک مسیر فرعی مستقر کنید، باید این تنظیم را انجام دهید، به عنوان مثال، صفحات GitHub. اگر قصد دارید سایت خود را در `https://foo.github.io/bar/` مستقر کنید، باید پایه را به `'/bar/'` تنظیم کنید. این باید همیشه با یک اسلش شروع و پایان یابد.\n\nپایه به طور خودکار به تمام آدرس‌های URL که با / شروع می‌شوند در سایر گزینه‌ها اضافه می‌شود، بنابراین فقط باید آن را یک بار مشخص کنید.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## مسیریابی {#routing}\n\n### cleanUrls\n\n- نوع: `boolean`\n- پیش‌فرض: `false`\n\nوقتی تنظیم شود به `true`، ویت‌پرس `.html` انتهایی را از URL ها حذف می‌کند. همچنین ببینید [تولید URLهای تمیز](../guide/routing#generating-clean-urls).\n\n::: warning هشدار نیاز به پشتیبانی سرور\nفعال کردن این ممکن است نیاز به پیکربندی اضافی در پلتفرم میزبان شما داشته باشد. برای اینکه کار کند، سرور شما باید بتواند `/foo.html` را زمانی که `/foo` بازدید می‌شود **بدون ریدایرکت** سرو کند.\n:::\n\n### rewrites\n\n- نوع: `Record<string, string>`\n\nتعریف نقشه‌برداری‌های سفارشی دایرکتوری <-> URL. جزئیات بیشتر را در [مسیریابی: بازنویسی مسیرها](../guide/routing#route-rewrites) ببینید.\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## ساخت {#build}\n\n### srcDir\n\n- نوع: `string`\n- پیش‌فرض: `.`\n\nدایرکتوری که صفحات مارک‌داون شما در آن ذخیره شده‌اند، نسبت به ریشه پروژه. همچنین ببینید [دایرکتوری ریشه و منبع](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- نوع: `string`\n- پیش‌فرض: `undefined`\n\nیک [الگوی glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) برای تطبیق فایل‌های مارک‌داون که باید به عنوان محتوای منبع حذف شوند.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- نوع: `string`\n- پیش‌فرض: `./.vitepress/dist`\n\nمکان خروجی ساخت برای سایت، نسبت به [ریشه پروژه](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- نوع: `string`\n- پیش‌فرض: `assets`\n\nدایرکتوری برای قرار دادن دارایی‌های تولید شده را مشخص کنید. مسیر باید داخل [`outDir`](#outdir) باشد و نسبت به آن حل شود.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- نوع: `string`\n- پیش‌فرض: `./.vitepress/cache`\n\nدایرکتوری برای فایل‌های کش، نسبت به [ریشه پروژه](../guide/routing#root-and-source-directory). همچنین ببینید: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- نوع: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- پیش‌فرض: `false`\n\nزمانی که به `true` تنظیم شود، ویت‌پرس به دلیل لینک‌های مرده ساخت‌ها را شکست نخواهد داد.\n\nوقتی به `'localhostLinks'` تنظیم شود، ساخت بر روی لینک‌های مرده شکست خواهد خورد، اما لینک‌های `localhost` بررسی نخواهند شد.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\nهمچنین می‌تواند یک آرایه از رشته‌های URL دقیق، الگوهای رگکس، یا توابع فیلتر سفارشی باشد.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // نادیده گرفتن URL دقیق \"/playground\"\n    '/playground',\n    // نادیده گرفتن همه لینک‌های localhost\n    /^https?:\\/\\/localhost/,\n    // نادیده گرفتن همه لینک‌های شامل \"/repl/\"\"\n    /\\/repl\\//,\n    // تابع سفارشی، نادیده گرفتن همه لینک‌های شامل \"ignore\"\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"experimental\" /> {#metachunk}\n\n- نوع: `boolean`\n- پیش‌فرض: `false`\n\nزمانی که به `true` تنظیم شود، فراداده‌های صفحات را به یک قسمت جداگانه جاوااسکریپت استخراج می‌کند به جای درون‌گذاری آن در HTML اولیه. این کار باعث کاهش بار HTML هر صفحه می‌شود و فراداده‌های صفحات قابل کش شدن می‌شود، که منجر به کاهش پهنای باند سرور می‌شود وقتی که صفحات زیادی در سایت دارید.\n\n### mpa <Badge type=\"warning\" text=\"experimental\" /> {#mpa}\n\n- نوع: `boolean`\n- پیش‌فرض: `false`\n\nزمانی که به `true` تنظیم شود، اپلیکیشن تولید شده در [حالت MPA](../guide/mpa-mode) ساخته خواهد شد. حالت MPA به طور پیش‌فرض 0 کیلوبایت جاوااسکریپت ارسال می‌کند، به هزینه غیرفعال کردن ناوبری سمت کاربر و نیاز به opt-in صریح برای تعامل.\n\n## تم‌سازی {#theming}\n\n### appearance\n\n- نوع: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`\n- پیش‌فرض: `true`\n\nآیا حالت تاریک فعال شود یا نه (با اضافه کردن کلاس `.dark` به عنصر `<html>`).\n\n- اگر گزینه به `true` تنظیم شود، تم پیش‌فرض با توجه به طرح رنگ مورد نظر کاربر تعیین می‌شود.\n- اگر گزینه به `dark` تنظیم شود، تم به صورت پیش‌فرض تاریک خواهد بود، مگر اینکه کاربر آن را به صورت دستی تغییر دهد.\n- اگر گزینه به `false` تنظیم شود، کاربران قادر به تغییر تم نخواهند بود.\n- اگر گزینه به `force-dark` تنظیم شود، تم همیشه تاریک خواهد بود و کاربران نمی‌توانند آن را تغییر دهند.\n- اگر گزینه به `force-auto` تنظیم شود، تم همیشه با توجه به طرح رنگ مورد نظر کاربر تعیین می‌شود و کاربران نمی‌توانند آن را تغییر دهند.\n\nاین گزینه یک اسکریپت داخلی تزریق می‌کند که تنظیمات کاربران را از حافظه محلی با استفاده از کلید `vitepress-theme-appearance` بازیابی می‌کند. این اطمینان حاصل می‌شود که کلاس `.dark` قبل از رندر شدن صفحه اعمال می‌شود تا از پرش جلوگیری شود.\n\n`appearance.initialValue` فقط می‌تواند `dark` یا `undefined` باشد. Refs یا getters پشتیبانی نمی‌شوند.\n\n### lastUpdated\n\n- نوع: `boolean`\n- پیش‌فرض: `false`\n\nآیا زمان آخرین به‌روزرسانی برای هر صفحه با استفاده از Git دریافت شود. این زمان در داده‌های هر صفحه گنجانده خواهد شد و از طریق [`useData`](./runtime-api#usedata) قابل دسترسی خواهد بود.\n\nوقتی از تم پیش‌فرض استفاده می‌کنید، فعال کردن این گزینه زمان آخرین به‌روزرسانی هر صفحه را نمایش می‌دهد. می‌توانید متن را از طریق گزینه [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) سفارشی کنید.\n\n## سفارشی‌سازی {#customization}\n\n### markdown\n\n- نوع: `MarkdownOption`\n\nگزینه‌های پارسر مارک‌داون را تنظیم کنید. ویت‌پرس از [Markdown-it](https://github.com/markdown-it/markdown-it) به عنوان پارسر استفاده می‌کند و [Shiki](https://github.com/shikijs/shiki) را برای برجسته‌سازی نحو زبان استفاده می‌کند. در داخل این گزینه، می‌توانید گزینه‌های مختلف مرتبط با مارک‌داون را بر اساس نیازهای خود ارسال کنید.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\nبرای مشاهده اعلامیه نوع و jsdocs برای همه گزینه‌های موجود، [type declaration and jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) را بررسی کنید.\n\n### vite\n\n- نوع: `import('vite').UserConfig`\n\nپیکربندی خام [Vite Config](https://vitejs.dev/config/) را به سرور توسعه داخلی / بسته‌بند Vite ارسال کنید.\n\n```js\nexport default {\n  vite: {\n    // گزینه‌های پیکربندی Vite\n  }\n}\n```\n\n### vue\n\n- نوع: `import('@vitejs/plugin-vue').Options`\n\nگزینه‌های خام [`@vitejs/plugin-vue` options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) را به نمونه افزونه داخلی ارسال کنید.\n\n```js\nexport default {\n  vue: {\n    // گزینه‌های @vitejs/plugin-vue\n  }\n}\n```\n\n## قلاب‌های ساخت {#build-hooks}\n\nقلاب‌های ساخت ویت‌پرس به شما امکان اضافه کردن عملکرد و رفتارهای جدید به وب‌سایت خود را می‌دهند:\n\n- نقشه سایت\n- شاخص‌بندی جستجو\n- PWA\n- Teleports\n\n### buildEnd\n\n- نوع: `(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd` یک قلاب CLI ساخت است، که بعد از اتمام ساخت (SSG) اجرا می‌شود اما قبل از خروج از فرآیند CLI ویت‌پرس.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender\n\n- نوع: `(context: SSGContext) => Awaitable<SSGContext | void>`\n\n`postRender` یک قلاب ساخت است که زمانی که رندر SSG انجام شد، فراخوانی می‌شود. این امکان را به شما می‌دهد که محتوای teleports را در حین SSG مدیریت کنید.\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead\n\n- نوع: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` یک قلاب ساخت است که برای تغییر head قبل از تولید هر صفحه استفاده می‌شود. این امکان را به شما می‌دهد که ورودی‌های head اضافه کنید که نمی‌توانند به صورت استاتیک به تنظیمات ویت‌پرس اضافه شوند. شما فقط باید ورودی‌های اضافی را برگردانید، آنها به صورت خودکار با موارد موجود ترکیب می‌شوند.\n\n::: warning هشدار\nهیچ‌چیزی را در داخل `context` تغییر ندهید.\n:::\n\n```ts\nexport default {\n  async transform\n\nHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // به عنوان مثال index.md (نسبت به srcDir)\n  assets: string[] // همه دارایی‌های غیر js/css به عنوان URL عمومی کاملاً حل شده\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nتوجه داشته باشید که این قلاب فقط زمانی که سایت به صورت استاتیک تولید می‌شود فراخوانی می‌شود. در زمان توسعه فراخوانی نمی‌شود. اگر نیاز به اضافه کردن ورودی‌های head دینامیک در زمان توسعه دارید، می‌توانید به جای آن از قلاب [`transformPageData`](#transformpagedata) استفاده کنید:\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `ویت‌پرس`\n            : `${pageData.title} | ویت‌پرس`\n      }\n    ])\n  }\n}\n```\n\n#### مثال: اضافه کردن یک canonical URL `<link>` {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n\n- نوع: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml` یک قلاب ساخت است که برای تغییر محتوای هر صفحه قبل از ذخیره به دیسک استفاده می‌شود.\n\n::: warning هشدار\nهیچ‌چیزی را در داخل `context` تغییر ندهید. همچنین، تغییر محتوای html ممکن است باعث مشکلات هیدراتاسیون در زمان اجرا شود.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n\n- نوع: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` یک قلاب است که برای تغییر `pageData` هر صفحه استفاده می‌شود. شما می‌توانید `pageData` را به صورت مستقیم تغییر دهید یا مقادیر تغییر یافته را برگردانید که به داده‌های صفحه ادغام خواهند شد.\n\n::: warning هشدار\nهیچ‌چیزی را در داخل `context` تغییر ندهید و دقت کنید که این ممکن است بر عملکرد سرور توسعه تاثیر بگذارد، به ویژه اگر در این قلاب درخواست‌های شبکه یا محاسبات سنگین (مانند تولید تصاویر) داشته باشید. می‌توانید برای منطق شرطی بررسی کنید `process.env.NODE_ENV === 'production'`.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // یا داده‌ها را برای ادغام برگردانید\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/ja/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Vite と Vue による静的サイトジェネレーター',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/ja/guide/': { base: '/ja/guide/', items: sidebarGuide() },\n      '/ja/reference/': { base: '/ja/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'GitHub でこのページを編集'\n    },\n\n    footer: {\n      message: 'MIT ライセンスの下で公開されています。',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'ガイド',\n      link: '/ja/guide/what-is-vitepress',\n      activeMatch: '/guide/'\n    },\n    {\n      text: 'リファレンス',\n      link: '/ja/reference/site-config',\n      activeMatch: '/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/'\n        },\n        {\n          text: '更新履歴',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'コントリビュート方法',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '導入',\n      collapsed: false,\n      items: [\n        { text: 'VitePress とは？', link: 'what-is-vitepress' },\n        { text: 'はじめに', link: 'getting-started' },\n        { text: 'ルーティング', link: 'routing' },\n        { text: 'デプロイ', link: 'deploy' }\n      ]\n    },\n    {\n      text: '執筆',\n      collapsed: false,\n      items: [\n        { text: 'Markdown 拡張', link: 'markdown' },\n        { text: 'アセットの取り扱い', link: 'asset-handling' },\n        { text: 'フロントマター', link: 'frontmatter' },\n        { text: 'Markdown で Vue を使う', link: 'using-vue' },\n        { text: '多言語対応', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'カスタマイズ',\n      collapsed: false,\n      items: [\n        { text: 'カスタムテーマを使う', link: 'custom-theme' },\n        {\n          text: 'デフォルトテーマの拡張',\n          link: 'extending-default-theme'\n        },\n        { text: 'ビルド時のデータ読み込み', link: 'data-loading' },\n        { text: 'SSR 互換性', link: 'ssr-compat' },\n        { text: 'CMS との接続', link: 'cms' }\n      ]\n    },\n    {\n      text: '実験的機能',\n      collapsed: false,\n      items: [\n        { text: 'MPA モード', link: 'mpa-mode' },\n        { text: 'サイトマップ生成', link: 'sitemap-generation' }\n      ]\n    },\n    {\n      text: '設定 & API リファレンス',\n      base: '/ja/reference/',\n      link: 'site-config'\n    }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'リファレンス',\n      items: [\n        { text: 'サイト設定', link: 'site-config' },\n        { text: 'Frontmatter 設定', link: 'frontmatter-config' },\n        { text: 'ランタイム API', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: 'デフォルトテーマ',\n          base: '/ja/reference/default-theme-',\n          items: [\n            { text: '概要', link: 'config' },\n            { text: 'ナビゲーション', link: 'nav' },\n            { text: 'サイドバー', link: 'sidebar' },\n            { text: 'ホームページ', link: 'home-page' },\n            { text: 'フッター', link: 'footer' },\n            { text: 'レイアウト', link: 'layout' },\n            { text: 'バッジ', link: 'badge' },\n            { text: 'チームページ', link: 'team-page' },\n            { text: '前 / 次 リンク', link: 'prev-next-links' },\n            { text: '編集リンク', link: 'edit-link' },\n            { text: '最終更新日時', link: 'last-updated' },\n            { text: '検索', link: 'search' },\n            { text: 'Carbon 広告', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: '検索',\n        buttonAriaLabel: '検索'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: 'クリア',\n          clearButtonAriaLabel: 'クエリをクリア',\n          closeButtonText: '閉じる',\n          closeButtonAriaLabel: '閉じる',\n          placeholderText: 'ドキュメントを検索するか Ask AI に質問',\n          placeholderTextAskAi: '別の質問をする...',\n          placeholderTextAskAiStreaming: '回答中...',\n          searchInputLabel: '検索',\n          backToKeywordSearchButtonText: 'キーワード検索に戻る',\n          backToKeywordSearchButtonAriaLabel: 'キーワード検索に戻る',\n          newConversationPlaceholder: '質問する',\n          conversationHistoryTitle: '自分の会話履歴',\n          startNewConversationText: '新しい会話を開始',\n          viewConversationHistoryText: '会話履歴',\n          threadDepthErrorPlaceholder: '会話上限に達しました'\n        },\n        newConversation: {\n          newConversationTitle: '今日はどのようにお手伝いできますか？',\n          newConversationDescription:\n            'ドキュメントを検索して、設定ガイド、機能の詳細、トラブルシューティングのヒントをすばやく見つけるお手伝いをします。'\n        },\n        footer: {\n          selectText: '選択',\n          submitQuestionText: '質問を送信',\n          selectKeyAriaLabel: 'Enter キー',\n          navigateText: '移動',\n          navigateUpKeyAriaLabel: '上矢印',\n          navigateDownKeyAriaLabel: '下矢印',\n          closeText: '閉じる',\n          backToSearchText: '検索に戻る',\n          closeKeyAriaLabel: 'Escape キー',\n          poweredByText: '提供'\n        },\n        errorScreen: {\n          titleText: '結果を取得できませんでした',\n          helpText: 'ネットワーク接続を確認してください。'\n        },\n        startScreen: {\n          recentSearchesTitle: '最近',\n          noRecentSearchesText: '最近の検索はありません',\n          saveRecentSearchButtonTitle: 'この検索を保存',\n          removeRecentSearchButtonTitle: '履歴からこの検索を削除',\n          favoriteSearchesTitle: 'お気に入り',\n          removeFavoriteSearchButtonTitle: 'お気に入りからこの検索を削除',\n          recentConversationsTitle: '最近の会話',\n          removeRecentConversationButtonTitle: '履歴からこの会話を削除'\n        },\n        noResultsScreen: {\n          noResultsText: '次の検索結果はありません',\n          suggestedQueryText: '次を検索してみてください',\n          reportMissingResultsText:\n            'この検索には結果があるべきだと思いますか？',\n          reportMissingResultsLinkText: 'お知らせください。'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'AI に質問：',\n          noResultsAskAiPlaceholder:\n            'ドキュメントに見つかりませんでしたか？ Ask AI に相談：'\n        },\n        askAiScreen: {\n          disclaimerText:\n            '回答は AI により生成され、誤りが含まれる場合があります。内容をご確認ください。',\n          relatedSourcesText: '関連ソース',\n          thinkingText: '考え中...',\n          copyButtonText: 'コピー',\n          copyButtonCopiedText: 'コピーしました！',\n          copyButtonTitle: 'コピー',\n          likeButtonTitle: 'いいね',\n          dislikeButtonTitle: 'よくないね',\n          thanksForFeedbackText: 'フィードバックありがとうございます！',\n          preToolCallText: '検索中...',\n          duringToolCallText: '検索中...',\n          afterToolCallText: '検索しました',\n          stoppedStreamingText: 'この応答を停止しました',\n          errorTitleText: 'チャットエラー',\n          threadDepthExceededMessage:\n            '回答の正確性を保つため、この会話は終了しました。',\n          startNewConversationButtonText: '新しい会話を開始'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'AI に質問',\n            buttonAriaLabel: 'AI に質問'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'AI に質問',\n              conversationHistoryTitle: '自分の会話履歴',\n              newConversationText: '新しい会話を開始',\n              viewConversationHistoryText: '会話履歴'\n            },\n            promptForm: {\n              promptPlaceholderText: '質問する',\n              promptAnsweringText: '回答中...',\n              promptAskAnotherQuestionText: '別の質問をする',\n              promptDisclaimerText:\n                '回答は AI により生成され、誤りが含まれる場合があります。',\n              promptLabelText: 'Enterで送信、Shift+Enterで改行。',\n              promptAriaLabelText: 'プロンプト入力'\n            },\n            conversationScreen: {\n              preToolCallText: '検索中...',\n              searchingText: '検索中...',\n              toolCallResultText: '検索しました',\n              conversationDisclaimer:\n                '回答は AI により生成され、誤りが含まれる場合があります。内容をご確認ください。',\n              reasoningText: '推論中...',\n              thinkingText: '考え中...',\n              relatedSourcesText: '関連ソース',\n              stoppedStreamingText: 'この応答を停止しました',\n              copyButtonText: 'コピー',\n              copyButtonCopiedText: 'コピーしました！',\n              likeButtonTitle: 'いいね',\n              dislikeButtonTitle: 'よくないね',\n              thanksForFeedbackText: 'フィードバックありがとうございます！',\n              errorTitleText: 'チャットエラー'\n            },\n            newConversationScreen: {\n              titleText: '今日はどのようにお手伝いできますか？',\n              introductionText:\n                'ドキュメントを検索して、設定ガイド、機能の詳細、トラブルシューティングのヒントをすばやく見つけるお手伝いをします。'\n            },\n            logo: {\n              poweredByText: '提供'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/ja/guide/asset-handling.md",
    "content": "# アセットの取り扱い {#asset-handling}\n\n## 静的アセットの参照 {#referencing-static-assets}\n\nすべての Markdown ファイルは Vue コンポーネントにコンパイルされ、[Vite](https://vitejs.dev/guide/assets.html) によって処理されます。Markdown 内では、相対 URL を使ってアセットを参照することが **推奨されます**。\n\n```md\n![画像](./image.png)\n```\n\nMarkdown ファイル内、テーマの `*.vue` コンポーネント内、スタイルや通常の `.css` ファイル内でも、アセットはプロジェクトルートを基準とした絶対パス、またはファイルシステムを基準とした相対パスで参照できます。後者は Vite、Vue CLI、あるいは webpack の `file-loader` を使ったことがある場合に慣れ親しんだ挙動です。\n\n一般的な画像、メディア、フォントファイルタイプは自動的にアセットとして検出され、含まれます。\n\n::: tip リンクされたファイルはアセットとして扱われません\nMarkdown ファイル内のリンクで参照された PDF やその他のドキュメントは、自動的にアセットとして扱われません。これらのリンクファイルにアクセスできるようにするには、手動でプロジェクトの [`public`](#the-public-directory) ディレクトリに配置する必要があります。\n:::\n\n絶対パスを含むすべての参照されたアセットは、プロダクションビルド時にハッシュ化されたファイル名で出力ディレクトリにコピーされます。参照されないアセットはコピーされません。4kb 未満の画像アセットは base64 としてインライン化されます（これは [`vite`](../reference/site-config#vite) 設定オプションで変更可能です）。\n\nすべての **静的な** パス参照（絶対パスを含む）は、作業ディレクトリの構造を基準にする必要があります。\n\n## Public ディレクトリ {#the-public-directory}\n\nMarkdown やテーマコンポーネントで直接参照されない静的アセットを提供する必要がある場合や、特定のファイルをオリジナルのファイル名のまま提供したい場合があります。  \n例えば `robots.txt`、favicon、PWA 用アイコンなどです。\n\nこれらのファイルは [ソースディレクトリ](./routing#source-directory) 配下の `public` ディレクトリに配置できます。たとえばプロジェクトルートが `./docs` で、デフォルトのソースディレクトリを使用している場合、`public` ディレクトリは `./docs/public` になります。\n\n`public` に配置されたアセットは、出力ディレクトリのルートにそのままコピーされます。\n\nなお、`public` 内のファイルはルート絶対パスで参照する必要があります。例えば `public/icon.png` は常に `/icon.png` として参照しなければなりません。\n\n## ベース URL {#base-url}\n\nサイトをルート以外の URL にデプロイする場合、`.vitepress/config.js` で `base` オプションを設定する必要があります。  \n例えば `https://foo.github.io/bar/` にデプロイする場合、`base` は `'/bar/'` と設定します（必ずスラッシュで開始・終了する必要があります）。\n\nすべての静的アセットパスは `base` 設定値に応じて自動的に調整されます。  \n例えば Markdown 内で `public` 配下のアセットを絶対参照した場合：\n\n```md\n![画像](/image-inside-public.png)\n```\n\nこの場合は `base` の設定値を変更しても、参照を修正する必要はありません。\n\nただし、テーマコンポーネントで動的にアセットをリンクする場合（例：テーマ設定値に基づいた画像の `src`）は注意が必要です。\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nこの場合は、VitePress が提供する [`withBase` ヘルパー](../reference/runtime-api#withbase) でパスをラップすることを推奨します。\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/ja/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# CMS との接続 {#connecting-to-a-cms}\n\n## 全体のワークフロー {#general-workflow}\n\nVitePress を CMS と接続する際は、主に [動的ルーティング](./routing#dynamic-routes) を中心に考えることになります。先にその仕組みを理解しておいてください。\n\nCMS ごとに動作が異なるため、ここでは各自の環境に合わせて調整できる汎用的なワークフローのみを示します。\n\n1. CMS が認証を必要とする場合は、API トークンを格納するための `.env` を作成し、次のように読み込みます。\n\n   ```js\n   // posts/[id].paths.js\n   import { loadEnv } from 'vitepress'\n\n   const env = loadEnv('', process.cwd())\n   ```\n\n2. CMS から必要なデータを取得し、適切なパスデータの形式に整形します。\n\n   ```js\n   export default {\n     async paths() {\n       // 必要に応じて各 CMS のクライアントライブラリを使用\n       const data = await (await fetch('https://my-cms-api', {\n         headers: {\n           // 必要ならトークン\n         }\n       })).json()\n\n       return data.map((entry) => {\n         return {\n           params: { id: entry.id, /* title, authors, date など */ },\n           content: entry.content\n         }\n       })\n     }\n   }\n   ```\n\n3. ページ内でコンテンツをレンダリングします。\n\n   ```md\n   # {{ $params.title }}\n\n   - {{ $params.date }} に {{ $params.author }} が作成\n\n   <!-- @content -->\n   ```\n\n## 連携ガイドの募集 {#integration-guides}\n\n特定の CMS と VitePress の連携ガイドを書かれた方は、下部の「Edit this page」リンクからぜひ投稿してください！\n"
  },
  {
    "path": "docs/ja/guide/custom-theme.md",
    "content": "# カスタムテーマを使う {#using-a-custom-theme}\n\n## テーマの解決 {#theme-resolving}\n\nカスタムテーマを有効にするには、`.vitepress/theme/index.js` または `.vitepress/theme/index.ts` ファイル（「テーマエントリファイル」）を作成します。\n\n```\n.\n├─ docs                # プロジェクトルート\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # テーマエントリ\n│  │  └─ config.js     # 設定ファイル\n│  └─ index.md\n└─ package.json\n```\n\nVitePress はテーマエントリファイルを検出すると、常にデフォルトテーマではなくカスタムテーマを使用します。ただし、[デフォルトテーマを拡張](./extending-default-theme) してその上で高度なカスタマイズを行うことも可能です。\n\n## テーマインターフェース {#theme-interface}\n\nVitePress のカスタムテーマは次のインターフェースを持つオブジェクトとして定義されます。\n\n```ts\ninterface Theme {\n  /**\n   * すべてのページに適用されるルートレイアウトコンポーネント\n   * @required\n   */\n  Layout: Component\n  /**\n   * Vue アプリインスタンスを拡張\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * 別のテーマを拡張し、そのテーマの `enhanceApp` を先に実行\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // Vue アプリインスタンス\n  router: Router // VitePress のルーターインスタンス\n  siteData: Ref<SiteData> // サイト全体のメタデータ\n}\n```\n\nテーマエントリファイルでは、このテーマをデフォルトエクスポートとして公開します。\n\n```js [.vitepress/theme/index.js]\n// テーマエントリでは Vue ファイルを直接インポートできます\n// VitePress は @vitejs/plugin-vue をあらかじめ設定済みです\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nデフォルトエクスポートはカスタムテーマにおける唯一の契約であり、必須なのは `Layout` プロパティだけです。つまり、VitePress のテーマは単一の Vue コンポーネントでも成り立ちます。\n\nレイアウトコンポーネントの内部は通常の Vite + Vue 3 アプリケーションと同じように動作します。なお、テーマは [SSR 対応](./ssr-compat) である必要があります。\n\n## レイアウトの構築 {#building-a-layout}\n\n最も基本的なレイアウトコンポーネントには [`<Content />`](../reference/runtime-api#content) コンポーネントを含める必要があります。\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Custom Layout!</h1>\n\n  <!-- この部分に markdown コンテンツが描画されます -->\n  <Content />\n</template>\n```\n\n上記のレイアウトは、すべてのページの Markdown を単純に HTML として描画します。最初の改善点として 404 エラー処理を追加できます。\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n<h1>Custom Layout!</h1>\n\n<div v-if=\"page.isNotFound\">\n  Custom 404 page!\n</div>\n<Content v-else />\n</template>\n```\n\n[`useData()`](../reference/runtime-api#usedata) ヘルパーを使うと、条件によってレイアウトを切り替えるために必要なすべてのランタイムデータを取得できます。アクセスできるデータのひとつにフロントマターがあります。これを利用すると、ページごとにレイアウトを制御できます。例えば、ユーザーが特別なホームページレイアウトを使いたい場合は以下のように記述します。\n\n```md\n---\nlayout: home\n---\n```\n\nテーマ側を次のように調整します。\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n<h1>Custom Layout!</h1>\n\n<div v-if=\"page.isNotFound\">\n  Custom 404 page!\n</div>\n<div v-if=\"frontmatter.layout === 'home'\">\n  Custom home page!\n</div>\n<Content v-else />\n</template>\n```\n\nもちろんレイアウトをさらにコンポーネントに分割することもできます。\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n<h1>Custom Layout!</h1>\n\n<NotFound v-if=\"page.isNotFound\" />\n<Home v-if=\"frontmatter.layout === 'home'\" />\n<Page v-else /> <!-- <Page /> が <Content /> を描画 -->\n</template>\n```\n\n利用可能なすべての機能は [Runtime API リファレンス](../reference/runtime-api) を参照してください。さらに [ビルド時データ読み込み](./data-loading) を活用すれば、ブログ記事一覧ページのようなデータ駆動型のレイアウトも実現できます。\n\n## カスタムテーマの配布 {#distributing-a-custom-theme}\n\n最も簡単な配布方法は [GitHub のテンプレートリポジトリ](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository) として提供することです。\n\nnpm パッケージとして配布する場合は、次の手順を踏みます。\n\n1. パッケージエントリでテーマオブジェクトをデフォルトエクスポートとして公開する。\n2. 必要であればテーマ設定の型定義を `ThemeConfig` として公開する。\n3. テーマが VitePress 設定の調整を必要とする場合は、パッケージのサブパス（例：`my-theme/config`）としてその設定を公開し、ユーザーが拡張できるようにする。\n4. 設定ファイルやフロントマターを通じて、テーマ設定オプションを文書化する。\n5. テーマの利用方法を明確に説明する（以下を参照）。\n\n## カスタムテーマの利用 {#consuming-a-custom-theme}\n\n外部テーマを利用するには、カスタムテーマエントリからインポートして再エクスポートします。\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nテーマを拡張する必要がある場合:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nテーマが特別な VitePress 設定を必要とする場合は、設定ファイルも拡張する必要があります。\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // 必要に応じてテーマの基本設定を拡張\n  extends: baseConfig\n}\n```\n\nテーマがテーマ設定用の型を提供している場合:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // 型は `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/ja/guide/data-loading.md",
    "content": "# ビルド時のデータの読み込み {#build-time-data-loading}\n\nVitePress には **データローダー (data loaders)** という機能があり、任意のデータを読み込み、ページやコンポーネントからインポートすることができます。データの読み込みは **ビルド時のみ** 実行され、最終的な JavaScript バンドルには JSON としてシリアライズされたデータが含まれます。\n\nデータローダーはリモートデータの取得や、ローカルファイルに基づいたメタデータの生成に利用できます。たとえば、ローカルの API ページをすべて解析して API エントリのインデックスを自動生成するといったことが可能です。\n\n## 基本的な使い方 {#basic-usage}\n\nデータローダーファイルは `.data.js` または `.data.ts` で終わる必要があります。ファイルは `load()` メソッドを持つオブジェクトをデフォルトエクスポートします。\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\nローダーモジュールは Node.js 上でのみ評価されるため、Node API や npm 依存関係を自由に利用できます。\n\nその後、このファイルから `.md` ページや `.vue` コンポーネントで `data` という名前のエクスポートを使ってデータをインポートできます。\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\n出力:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\nデータローダー自体は `data` を直接エクスポートしていないことに気づくでしょう。これは VitePress が裏側で `load()` を呼び出し、その結果を暗黙的に `data` として公開しているためです。\n\nローダーが非同期でも動作します。\n\n```js\nexport default {\n  async load() {\n    // リモートデータを取得\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## ローカルファイルからのデータ {#data-from-local-files}\n\nローカルファイルに基づいたデータを生成する必要がある場合は、データローダー内で `watch` オプションを使用し、ファイルの変更をホットリロードに反映させることが推奨されます。\n\n`watch` では [glob パターン](https://github.com/mrmlnc/fast-glob#pattern-syntax) を利用して複数ファイルをマッチさせることができ、パターンはローダーファイルからの相対パスで指定できます。`load()` 関数にはマッチしたファイルの絶対パスが渡されます。\n\n以下は CSV ファイルを読み込み [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) を使って JSON に変換する例です。このコードはビルド時にのみ実行されるため、CSV パーサーがクライアントに送られることはありません。\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\nコンテンツ中心のサイトを構築する場合、ブログ記事や API ページなどを一覧表示する「アーカイブ」や「インデックス」ページが必要になることがよくあります。これはデータローダー API を使って直接実装できますが、あまりにも一般的なケースなので VitePress では `createContentLoader` というヘルパーが用意されています。\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* options */)\n```\n\nこのヘルパーは [ソースディレクトリ](./routing#source-directory) からの相対 glob パターンを受け取り、`{ watch, load }` を返すデータローダーオブジェクトを生成します。これをデータローダーファイルのデフォルトエクスポートにできます。開発時のパフォーマンスを向上させるために、ファイルの更新時刻に基づくキャッシュも行われます。\n\nこのローダーは Markdown ファイルにのみ対応し、それ以外のファイルは無視されます。\n\n読み込まれるデータは `ContentData[]` 型の配列です。\n\n```ts\ninterface ContentData {\n  url: string // ページのマッピング URL（例: /posts/hello.html）\n  frontmatter: Record<string, any> // ページのフロントマター\n\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nデフォルトでは `url` と `frontmatter` のみが提供されます。これは読み込まれたデータがクライアントバンドルに JSON としてインライン化されるため、サイズに注意する必要があるためです。\n\n以下はデータを使って最小限のブログインデックスページを構築する例です。\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>All Blog Posts</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>by {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### オプション {#options}\n\nデフォルトデータが要件に合わない場合は、オプションで変換処理を追加できます。\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // 生の markdown ソースを含める？\n  render: true,     // レンダリングされた HTML を含める？\n  excerpt: true,    // 抜粋を含める？\n\n  transform(rawData) {\n    return rawData\n      .sort((a, b) => {\n        return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n      })\n      .map((page) => {\n        page.src     // 生の markdown ソース\n        page.html    // レンダリングされた HTML\n        page.excerpt // 抜粋 HTML（最初の `---` までの内容）\n        return {/* ... */}\n      })\n  }\n})\n```\n\n[Vue.js ブログ](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts) での使用例も参考になります。\n\n`createContentLoader` API は [ビルドフック](../reference/site-config#build-hooks) 内でも利用可能です。\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // メタデータを基にファイルを生成（例: RSS フィード）\n  }\n}\n```\n\n**型定義**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  includeSrc?: boolean\n  render?: boolean\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## 型付きデータローダー {#typed-data-loaders}\n\nTypeScript を使用する場合は、ローダーと `data` エクスポートを型付けできます。\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // データ型\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## 設定情報の取得 {#configuration}\n\nローダー内で設定情報を取得するには次のようにします。\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/ja/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# VitePress サイトをデプロイする {#deploy-your-vitepress-site}\n\n以下のガイドは、次の前提に基づいています。\n\n- VitePress のサイトはプロジェクトの `docs` ディレクトリ内にある。\n- デフォルトのビルド出力ディレクトリ（`.vitepress/dist`）を使用している。\n- VitePress はプロジェクトのローカル依存としてインストールされており、`package.json` に次のスクリプトが設定されている。\n\n```json [package.json]\n{\n  \"scripts\": {\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  }\n}\n```\n\n## ローカルでビルドしてテストする {#build-and-test-locally}\n\n1. 次のコマンドでドキュメントをビルドします。\n\n   ```sh\n    $ npm run docs:build\n   ```\n\n2. ビルド後、次のコマンドでローカルプレビューします。\n\n   ```sh\n    $ npm run docs:preview\n   ```\n\n   `preview` コマンドはローカルの静的 Web サーバーを起動し、出力ディレクトリ `.vitepress/dist` を `http://localhost:4173` で配信します。プロダクションへプッシュする前に見た目を確認できます。\n\n3. `--port` 引数でサーバーのポートを設定できます。\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   これで `docs:preview` は `http://localhost:8080` でサーバーを起動します。\n\n## 公開ベースパスの設定 {#setting-a-public-base-path}\n\nデフォルトでは、サイトはドメインのルートパス（`/`）にデプロイされることを想定しています。サイトをサブパス、例：`https://mywebsite.com/blog/` で配信する場合は、VitePress の設定で [`base`](../reference/site-config#base) オプションを `'/blog/'` に設定してください。\n\n**例:** GitHub（または GitLab）Pages に `user.github.io/repo/` としてデプロイするなら、`base` を `/repo/` に設定します。\n\n## HTTP キャッシュヘッダー {#http-cache-headers}\n\n本番サーバーの HTTP ヘッダーを制御できる場合は、`cache-control` ヘッダーを設定して、再訪時のパフォーマンスを向上させましょう。\n\n本番ビルドでは静的アセット（JavaScript、CSS、`public` 以外のインポートアセット）にハッシュ付きファイル名が使用されます。ブラウザの開発者ツールのネットワークタブで本番プレビューを確認すると、`app.4f283b18.js` のようなファイルが見られます。\n\nこの `4f283b18` ハッシュはファイル内容から生成されます。同じハッシュの URL は同じ内容を必ず返し、内容が変われば URL も変わります。したがって、これらのファイルには最も強いキャッシュヘッダーを安全に適用できます。これらのファイルは出力ディレクトリ内の `assets/` 配下に配置されるため、次のヘッダーを設定できます。\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Netlify の `_headers` ファイル例\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\n注：`_headers` ファイルは [public ディレクトリ](./asset-handling#the-public-directory) に配置します（この例では `docs/public/_headers`）。そうすると、ビルド出力にそのままコピーされます。\n\n[Netlify のカスタムヘッダードキュメント](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details `vercel.json` による Vercel 設定例\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n注：`vercel.json` は **リポジトリのルート** に配置してください。\n\n[Vercel のヘッダー設定ドキュメント](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## プラットフォーム別ガイド {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\n新しいプロジェクトを作成し、ダッシュボードで次の設定に変更します。\n\n- **Build Command:** `npm run docs:build`\n- **Output Directory:** `docs/.vitepress/dist`\n- **Node Version:** `20`（以上）\n\n::: warning\nHTML の _Auto Minify_ のようなオプションを有効にしないでください。Vue にとって意味のあるコメントが出力から削除され、削除されるとハイドレーションの不整合エラーが発生する可能性があります。\n:::\n\n### GitHub Pages\n\n1. プロジェクトの `.github/workflows` ディレクトリに `deploy.yml` を作成し、以下の内容を記述します。\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Sample workflow for building and deploying a VitePress site to GitHub Pages\n   #\n   name: Deploy VitePress site to Pages\n\n   on:\n     # Runs on pushes targeting the `main` branch. Change this to `master` if you're\n     # using the `master` branch as the default branch.\n     push:\n       branches: [main]\n\n     # Allows you to run this workflow manually from the Actions tab\n     workflow_dispatch:\n\n   # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n   # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Build job\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # Not needed if lastUpdated is not enabled\n         # - uses: pnpm/action-setup@v4 # Uncomment this block if you're using pnpm\n         #   with:\n         #     version: 9 # Not needed if you've set \"packageManager\" in package.json\n         # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # or pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # or pnpm install / yarn install / bun install\n         - name: Build with VitePress\n           run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Deployment job\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   VitePress の `base` オプションが正しく設定されていることを確認してください。詳細は [公開ベースパスの設定](#公開ベースパスの設定) を参照してください。\n   :::\n\n2. リポジトリ設定の「Pages」メニューで、「Build and deployment > Source」を「GitHub Actions」に設定します。\n\n3. 変更を `main` ブランチにプッシュし、GitHub Actions の完了を待ちます。設定に応じて、サイトは `https://<username>.github.io/[repository]/` または `https://<custom-domain>/` にデプロイされます。以後、`main` へのプッシュごとに自動デプロイされます。\n\n### GitLab Pages\n\n1. VitePress の設定で `outDir` を `../public` に設定します。`https://<username>.gitlab.io/<repository>/` にデプロイする場合は `base` を `'/<repository>/'` に設定します。カスタムドメイン、ユーザー／グループページ、または GitLab の「Use unique domain」を有効にしている場合は `base` は不要です。\n\n2. プロジェクトのルートに `.gitlab-ci.yml` を作成して、以下を追加します。これにより、コンテンツを更新するたびにサイトがビルド・デプロイされます。\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Uncomment this if you're using small docker images like alpine and have lastUpdated enabled\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. [公式ドキュメント](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration) に従います。\n\n2. 設定ファイルで次の値を指定します（`api_location` のように不要なものは削除）。\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\n[CloudRay](https://cloudray.io/) でのデプロイ方法は [こちらの手順](https://cloudray.io/articles/how-to-deploy-vitepress-site) を参照してください。\n\n### Firebase\n\n1. プロジェクトのルートに `firebase.json` と `.firebaserc` を作成します。\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. `npm run docs:build` の後、次のコマンドでデプロイします。\n\n   ```sh\n    firebase deploy\n   ```\n\n### Heroku\n\n1. [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) のドキュメントとガイドに従います。\n\n2. プロジェクトのルートに `static.json` を作成し、以下を記述します。\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\n[Hostinger](https://www.hostinger.com/web-apps-hosting) を使用して VitePress プロジェクトをデプロイするには、こちらの [手順](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/) に従ってください。ビルド設定の構成では、フレームワークに VitePress を選択し、ルートディレクトリを `./docs` に調整してください。\n\n### Kinsta\n\n[VitePress](https://kinsta.com/static-site-hosting/) を [こちらの手順](https://kinsta.com/docs/vitepress-static-site-example/) に従ってデプロイできます。\n\n### Stormkit\n\n[VitePress プロジェクトを Stormkit にデプロイ](https://stormkit.io/blog/how-to-deploy-vitepress) する手順を参照してください。\n\n### Surge\n\n1. `npm run docs:build` の後、次のコマンドでデプロイします。\n\n   ```sh\n    npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\n以下は Nginx サーバーブロックの設定例です。一般的なテキスト系アセットの gzip 圧縮、VitePress サイトの静的ファイル配信における適切なキャッシュヘッダー、そして `cleanUrls: true` のハンドリングを含みます。\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # content location\n        root /app;\n\n        # exact matches -> reverse clean urls -> folders -> not found\n        try_files $uri $uri.html $uri/ =404;\n\n        # non existent pages\n        error_page 404 /404.html;\n\n        # a folder without index.html raises 403 in this setup\n        error_page 403 /404.html;\n\n        # adjust caching headers\n        # files in the assets folder have hashes filenames\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nこの設定は、ビルド済みの VitePress サイトがサーバー上の `/app` ディレクトリに配置されていることを想定しています。サイトのファイルが別の場所にある場合は、`root` ディレクティブを適宜変更してください。\n\n::: warning index.html をデフォルトにしない\n`try_files` の解決先を、他の Vue アプリのように index.html にフォールバックさせないでください。不正なページ状態になります。\n:::\n\n詳細は [公式 nginx ドキュメント](https://nginx.org/en/docs/)、Issue [#2837](https://github.com/vuejs/vitepress/discussions/2837)、[#3235](https://github.com/vuejs/vitepress/issues/3235)、および Mehdi Merah 氏の [ブログ記事](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) を参照してください。\n"
  },
  {
    "path": "docs/ja/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# デフォルトテーマの拡張 {#extending-the-default-theme}\n\nVitePress のデフォルトテーマはドキュメント向けに最適化されており、カスタマイズ可能です。利用できるオプションの一覧は [デフォルトテーマの概要](../reference/default-theme-config) を参照してください。\n\nしかし、設定だけでは不十分なケースもあります。例えば:\n\n1. CSS のスタイルを微調整したい\n2. グローバルコンポーネントの登録など、Vue アプリインスタンスを変更したい\n3. レイアウトのスロット経由でテーマに独自コンテンツを挿入したい\n\nこれらの高度なカスタマイズには、デフォルトテーマを「拡張」するカスタムテーマを使用する必要があります。\n\n::: tip\n先に [カスタムテーマの使用](./custom-theme) を読み、カスタムテーマの仕組みを理解してから進めてください。\n:::\n\n## CSS のカスタマイズ {#customizing-css}\n\nデフォルトテーマの CSS は、ルートレベルの CSS 変数をオーバーライドすることでカスタマイズできます。\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\n上書き可能な [デフォルトテーマの CSS 変数](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) を参照してください。\n\n## フォントを変更する {#using-different-fonts}\n\nVitePress はデフォルトフォントとして [Inter](https://rsms.me/inter/) を使用し、ビルド出力にフォントを含めます。プロダクションでは自動でプリロードもされます。しかし、別のメインフォントを使いたい場合には望ましくないことがあります。\n\nInter をビルド出力に含めたくない場合は、`vitepress/theme-without-fonts` からテーマをインポートします。\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* 通常テキスト用フォント */\n  --vp-font-family-mono: /* コード用フォント */\n}\n```\n\n::: warning\n[Team Page](../reference/default-theme-team-page) などのオプションコンポーネントを使う場合も、必ず `vitepress/theme-without-fonts` からインポートしてください。\n:::\n\nフォントが `@font-face` で参照されるローカルファイルの場合、アセットとして処理され、ハッシュ付きファイル名で `.vitepress/dist/assets` に出力されます。このファイルをプリロードするには、[transformHead](../reference/site-config#transformhead) ビルドフックを使います。\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // 使うフォントに合わせて正規表現を調整\n    const myFontFile = assets.find((file) =>\n      /font-name\\.[\\w-]+\\.woff2/.test(file)\n    )\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## グローバルコンポーネントの登録 {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 独自のグローバルコンポーネントを登録\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nTypeScript を使う場合:\n\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 独自のグローバルコンポーネントを登録\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nVite を使っているため、Vite の [glob import 機能](https://vitejs.dev/guide/features.html#glob-import) を利用してディレクトリ内のコンポーネントを自動登録することもできます。\n\n## レイアウトスロット {#layout-slots}\n\nデフォルトテーマの `<Layout/>` コンポーネントには、ページ内の特定の位置にコンテンツを挿入するためのスロットがいくつか用意されています。以下は、アウトラインの前にコンポーネントを挿入する例です。\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // スロットを注入するラッパーコンポーネントで Layout を上書き\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      My custom sidebar top content\n    </template>\n  </Layout>\n</template>\n```\n\nレンダーファンクションを使う方法もあります。\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nデフォルトテーマレイアウトで利用可能なスロットの一覧:\n\n- フロントマターで `layout: 'doc'`（デフォルト）を有効にしているとき:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- フロントマターで `layout: 'home'` を有効にしているとき:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- フロントマターで `layout: 'page'` を有効にしているとき:\n  - `page-top`\n  - `page-bottom`\n- 404（Not Found）ページ:\n  - `not-found`\n- 常に利用可能:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## View Transitions API の利用\n\n### 外観切り替え時（ライト/ダーク） {#on-appearance-toggle}\n\nカラーモード切り替え時にカスタムトランジションを提供するよう、デフォルトテーマを拡張できます。例:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\n結果（**注意！**：点滅や急な動き、明るい光を含みます）:\n\n<details>\n<summary>デモ</summary>\n\n![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)\n\n</details>\n\n詳細は [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) を参照してください。\n\n### ルート遷移時 {#on-route-change}\n\n近日公開。\n\n## 内部コンポーネントの置き換え {#overriding-internal-components}\n\nVite の [エイリアス](https://vitejs.dev/config/shared-options.html#resolve-alias) を使って、デフォルトテーマのコンポーネントを独自のものに置き換えられます。\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./theme/components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\n正確なコンポーネント名は [ソースコード](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components) を参照してください。内部コンポーネントであるため、マイナーリリース間で名称が更新される可能性があります。\n"
  },
  {
    "path": "docs/ja/guide/frontmatter.md",
    "content": "# フロントマター {#frontmatter}\n\n## 使い方 {#usage}\n\nVitePress はすべての Markdown ファイルで YAML フロントマターをサポートしており、[gray-matter](https://github.com/jonschlinkert/gray-matter) で解析します。フロントマターは Markdown ファイルの先頭（`<script>` タグを含むあらゆる要素より前）に配置し、三本のハイフンで囲まれた **有効な YAML** 形式で記述します。例:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\nサイトやデフォルトテーマの多くの設定オプションには、フロントマター上で対応するオプションがあります。フロントマターを使うことで、**そのページに限って** 特定の振る舞いを上書きできます。詳細は [Frontmatter Config Reference](../reference/frontmatter-config) を参照してください。\n\nまた、独自のカスタムフロントマターデータを定義し、ページ上の動的な Vue 式で利用することもできます。\n\n## フロントマターデータへのアクセス {#accessing-frontmatter-data}\n\nフロントマターデータは特別なグローバル変数 `$frontmatter` で参照できます。\n\nMarkdown ファイル内での使用例:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nGuide content\n```\n\n[`useData()`](../reference/runtime-api#usedata) ヘルパーを使えば、`<script setup>` 内からも現在のページのフロントマターデータにアクセスできます。\n\n## 代替フロントマター形式 {#alternative-frontmatter-formats}\n\nVitePress は JSON フロントマター構文もサポートしています。中括弧で開始・終了する形式です。\n\n```md\n---\n{\n  \"title\": \"Blogging Like a Hacker\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/ja/guide/getting-started.md",
    "content": "# はじめに {#getting-started}\n\n## オンラインで試す {#try-it-online}\n\n[VitePress](https://vitepress.new) をブラウザ上で直接試すことができます。\n\n## インストール {#installation}\n\n### 前提条件 {#prerequisites}\n\n- [Node.js](https://nodejs.org/) バージョン 20 以上\n- VitePress をコマンドラインインターフェース (CLI) で操作するためのターミナル\n- [Markdown](https://en.wikipedia.org/wiki/Markdown) 構文に対応したテキストエディタ\n  - 推奨: [VSCode](https://code.visualstudio.com/) と [公式 Vue 拡張](https://marketplace.visualstudio.com/items?itemName=Vue.volar)\n\nVitePress は単独でも利用できますし、既存プロジェクトに組み込むことも可能です。いずれの場合も以下でインストールできます。\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip 注意\nVitePress は ESM 専用パッケージです。`require()` を使ってインポートせず、最も近い `package.json` に `\"type\": \"module\"` を含めるか、`.vitepress/config.js` を `.mjs` / `.mts` に変更してください。詳しくは [Vite のトラブルシューティングガイド](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) を参照してください。また、非同期 CJS コンテキスト内では `await import('vitepress')` を使用できます。\n:::\n\n### セットアップウィザード {#setup-wizard}\n\nVitePress にはコマンドラインのセットアップウィザードが付属しており、基本的なプロジェクトを簡単に作成できます。インストール後、以下のコマンドでウィザードを起動します。\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nいくつかの簡単な質問が表示されます。\n\n<<< @/snippets/init.ansi\n\n::: tip Vue をピア依存関係に\nVue コンポーネントや API を使ったカスタマイズを行う場合は、明示的に `vue` を依存関係としてインストールしてください。\n:::\n\n## ファイル構成 {#file-structure}\n\nスタンドアロンの VitePress サイトを構築する場合は、現在のディレクトリ (`./`) にサイトを作成できます。しかし、既存プロジェクトに VitePress を追加する場合は、他のソースコードと分離するために `./docs` などのサブディレクトリに作成することをおすすめします。\n\n例えば `./docs` に VitePress プロジェクトを作成した場合、生成されるファイル構成は以下のようになります。\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\n`docs` ディレクトリが VitePress サイトの **プロジェクトルート** とみなされます。`.vitepress` ディレクトリは VitePress の設定ファイル、開発サーバーのキャッシュ、ビルド出力、テーマのカスタマイズコードなどに予約されています。\n\n::: tip\nデフォルトでは開発サーバーのキャッシュは `.vitepress/cache` に、本番ビルド出力は `.vitepress/dist` に保存されます。Git を使用している場合は `.gitignore` に追加してください。これらの場所は [設定](../reference/site-config#outdir) で変更可能です。\n:::\n\n### 設定ファイル {#the-config-file}\n\n設定ファイル (`.vitepress/config.js`) では、VitePress サイトのさまざまな動作をカスタマイズできます。最も基本的なオプションはサイトのタイトルと説明です。\n\n```js [.vitepress/config.js]\nexport default {\n  // サイトレベルのオプション\n  title: 'VitePress',\n  description: 'Just playing around.',\n\n  themeConfig: {\n    // テーマレベルのオプション\n  }\n}\n```\n\nテーマの動作は `themeConfig` オプションで設定できます。利用可能なすべての設定オプションは [Config Reference](../reference/site-config) を参照してください。\n\n### ソースファイル {#source-files}\n\n`.vitepress` ディレクトリ外の Markdown ファイルは **ソースファイル** とみなされます。\n\nVitePress は **ファイルベースのルーティング** を採用しています。各 `.md` ファイルは同じパスを持つ `.html` ファイルにコンパイルされます。例えば `index.md` は `index.html` にコンパイルされ、サイトのルート `/` で表示されます。\n\nVitePress にはクリーン URL の生成、パスの書き換え、動的なページ生成といった機能もあります。これらは [ルーティングガイド](./routing) で解説します。\n\n## 実行してみる {#up-and-running}\n\nセットアッププロセスで許可した場合、以下の npm スクリプトが `package.json` に追加されています。\n\n```json [package.json]\n {\n   ...\n   \"scripts\": {\n     \"docs:dev\": \"vitepress dev docs\",\n     \"docs:build\": \"vitepress build docs\",\n     \"docs:preview\": \"vitepress preview docs\"\n   },\n   ...\n }\n```\n\n`docs:dev` スクリプトを実行すると、即時ホットリロード対応のローカル開発サーバーが起動します。次のコマンドで実行します。\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nnpm スクリプトではなく、直接 VitePress を実行することもできます。\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nその他のコマンドラインの使い方は [CLI リファレンス](../reference/cli) に記載されています。\n\n開発サーバーは `http://localhost:5173` で動作します。ブラウザでこの URL にアクセスすると、新しいサイトが確認できます。\n\n## 次のステップ {#what-s-next}\n\n- Markdown ファイルがどのように HTML にマッピングされるかを理解するには、[ルーティングガイド](./routing) を読みましょう。\n\n- ページ内でできること（Markdown コンテンツの記述や Vue コンポーネントの利用など）を知るには、ガイドの「Writing」セクションを参照してください。まずは [Markdown 拡張](./markdown) を学ぶのがおすすめです。\n\n- デフォルトドキュメントテーマの機能を知りたい場合は、[Default Theme Config Reference](../reference/default-theme-config) を確認してください。\n\n- サイトの見た目をさらにカスタマイズしたい場合は、[デフォルトテーマの拡張](./extending-default-theme) や [カスタムテーマの構築](./custom-theme) を検討してください。\n\n- ドキュメントサイトが形になったら、必ず [デプロイガイド](./deploy) を読んでください。\n"
  },
  {
    "path": "docs/ja/guide/i18n.md",
    "content": "# 多言語対応 {#internationalization}\n\n組み込みの i18n 機能を使うには、次のようなディレクトリ構成を作成します。\n\n```\n docs/\n ├─ es/\n │  ├─ foo.md\n ├─ fr/\n │  ├─ foo.md\n ├─ foo.md\n```\n\n次に `docs/.vitepress/config.ts` で設定します。\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // 共有のプロパティやトップレベル設定...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    fr: {\n      label: 'French',\n      lang: 'fr', // 省略可。最終的に html タグの `lang` 属性として付与されます\n      link: '/fr/guide' // デフォルトは /fr/。ナビバーの言語メニューに表示。外部 URL でも可\n\n      // ロケール固有のその他のプロパティ...\n    }\n  }\n})\n```\n\n各ロケール（root を含む）ごとに、次のプロパティを上書きできます。\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // 既存の head とマージ。重複する meta タグは自動的に除去\n  themeConfig?: ThemeConfig // シャローにマージ。共通項目はトップレベルの themeConfig に置けます\n}\n```\n\nデフォルトテーマのプレースホルダ文言のカスタマイズについては [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) を参照してください。`themeConfig.algolia` や `themeConfig.carbonAds` をロケール単位で上書きしないでください。多言語検索の利用は [Algolia ドキュメント](../reference/default-theme-search#i18n) を参照。\n\n**プロ向けヒント:** 設定ファイルは `docs/.vitepress/config/index.ts` に置くこともできます。ロケールごとに設定ファイルを作成して、`index.ts` でマージ・エクスポートすると整理しやすくなります。\n\n## ロケールごとにディレクトリを分ける {#separate-directory-for-each-locale}\n\n次のような構成でも問題ありません。\n\n```\n docs/\n ├─ en/\n │  ├─ foo.md\n ├─ es/\n │  ├─ foo.md\n ├─ fr/\n    ├─ foo.md\n```\n\nただし、VitePress はデフォルトで `/` から `/en/` へのリダイレクトを行いません。これにはサーバー側の設定が必要です。たとえば Netlify では、`docs/public/_redirects` に次のようなファイルを追加できます。\n\n```\n /*  /es/:splat  302  Language=es\n /*  /fr/:splat  302  Language=fr\n /*  /en/:splat  302\n```\n\n**プロ向けヒント:** 上記の方法を使う場合、`nf_lang` クッキーでユーザーの言語選択を保持できます。\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## RTL サポート（実験的）{#rtl-support-experimental}\n\nRTL をサポートするには、設定で `dir: 'rtl'` を指定し、<https://github.com/MohammadYounes/rtlcss>、<https://github.com/vkalinichev/postcss-rtl>、または <https://github.com/elchininet/postcss-rtlcss> のような RTLCSS 系の PostCSS プラグインを使用してください。CSS の詳細度の問題を避けるため、PostCSS プラグインでは `:where([dir=\"ltr\"])` と `:where([dir=\"rtl\"])` を接頭辞として使うよう設定してください。\n"
  },
  {
    "path": "docs/ja/guide/markdown.md",
    "content": "# Markdown 拡張 {#markdown-extensions}\n\nVitePress には組み込みの Markdown 拡張機能が用意されています。\n\n## 見出しアンカー {#header-anchors}\n\n見出しには自動的にアンカーリンクが付与されます。アンカーのレンダリングは `markdown.anchor` オプションで設定できます。\n\n### カスタムアンカー {#custom-anchors}\n\n自動生成ではなく任意のアンカーを指定したい場合は、見出しの末尾にサフィックスを追加します。\n\n```md\n# カスタムアンカーを使う {#my-anchor}\n```\n\nこれにより、デフォルトの `#using-custom-anchors` ではなく `#my-anchor` でその見出しにリンクできます。\n\n## リンク {#links}\n\n内部リンクと外部リンクは特別に処理されます。\n\n### 内部リンク {#internal-links}\n\n内部リンクは SPA ナビゲーションのためにルーターリンクへ変換されます。また、各サブディレクトリにある `index.md` は自動的に `index.html` に変換され、URL は対応する `/` になります。\n\n次のようなディレクトリ構成があるとします。\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nそして、現在編集中のファイルが `foo/one.md` の場合:\n\n```md\n[Home](/) <!-- ルートの index.md に移動 -->\n[foo](/foo/) <!-- ディレクトリ foo の index.html に移動 -->\n[foo の見出し](./#heading) <!-- foo の index ファイル内の見出しへアンカー -->\n[bar - three](../bar/three) <!-- 拡張子は省略可能 -->\n[bar - three](../bar/three.md) <!-- .md を付けても OK -->\n[bar - four](../bar/four.html) <!-- .html を付けても OK -->\n```\n\n### ページサフィックス {#page-suffix}\n\nページと内部リンクはデフォルトで `.html` サフィックス付きで生成されます。\n\n### 外部リンク {#external-links}\n\n外部リンクには自動的に `target=\"_blank\" rel=\"noreferrer\"` が付与されます。\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## フロントマター {#frontmatter}\n\n[YAML フロントマター](https://jekyllrb.com/docs/front-matter/) をそのままサポートしています。\n\n```yaml\n---\ntitle: ハッカーのようにブログを書く\nlang: ja-JP\n---\n```\n\nこのデータはページ内や、カスタム／テーマコンポーネントからも利用できます。詳しくは [Frontmatter](../reference/frontmatter-config) を参照してください。\n\n## GitHub 風テーブル {#github-style-tables}\n\n**入力**\n\n```md\n| テーブル |    は     | クール |\n| -------- | :-------: | -----: |\n| 3列目は  |  右寄せ   |  $1600 |\n| 2列目は  |   中央    |    $12 |\n| シマ模様 | neat です |     $1 |\n```\n\n**出力**\n\n| テーブル |    は    | クール |\n| -------- | :------: | -----: |\n| 3列目は  |  右寄せ  | \\$1600 |\n| 2列目は  |   中央   |   \\$12 |\n| シマ模様 | neatです |    \\$1 |\n\n## 絵文字 :tada: {#emoji}\n\n**入力**\n\n```\n:tada: :100:\n```\n\n**出力**\n\n:tada: :100:\n\nすべての絵文字の [一覧はこちら](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs)。\n\n## 目次 {#table-of-contents}\n\n**入力**\n\n```\n[[toc]]\n```\n\n**出力**\n\n[[toc]]\n\nTOC のレンダリングは `markdown.toc` オプションで設定できます。\n\n## カスタムコンテナ {#custom-containers}\n\nタイプ、タイトル、内容を指定してカスタムコンテナを定義できます。\n\n### デフォルトタイトル {#default-title}\n\n**入力**\n\n```md\n::: info\nこれは情報ボックスです。\n:::\n\n::: tip\nこれはヒントです。\n:::\n\n::: warning\nこれは警告です。\n:::\n\n::: danger\nこれは危険の警告です。\n:::\n\n::: details\nこれは詳細ブロックです。\n:::\n```\n\n**出力**\n\n::: info\nこれは情報ボックスです。\n:::\n\n::: tip\nこれはヒントです。\n:::\n\n::: warning\nこれは警告です。\n:::\n\n::: danger\nこれは危険の警告です。\n:::\n\n::: details\nこれは詳細ブロックです。\n:::\n\n### カスタムタイトル {#custom-title}\n\nコンテナの「タイプ」の直後に文字列を追加することで、タイトルをカスタマイズできます。\n\n**入力**\n\n````md\n::: danger 停止\n危険地帯。先に進まないでください。\n:::\n\n::: details クリックしてコードを表示/非表示\n```js\nconsole.log('こんにちは、VitePress!')\n```\n:::\n````\n\n**出力**\n\n::: danger 停止\n危険地帯。先に進まないでください。\n:::\n\n::: details クリックしてコードを表示/非表示\n```js\nconsole.log('こんにちは、VitePress!')\n```\n:::\n\nまた、英語以外で執筆する場合などは、サイト設定に以下を追加してタイトル文字列をグローバルに上書きできます。\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: 'ヒント',\n      warningLabel: '警告',\n      dangerLabel: '危険',\n      infoLabel: '情報',\n      detailsLabel: '詳細'\n    }\n  }\n  // ...\n})\n```\n\n### 追加属性 {#additional-attributes}\n\nカスタムコンテナには追加の属性を付与できます。この機能には [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) を使用しており、ほぼすべての Markdown 要素でサポートされます。たとえば `open` 属性を付けると、details ブロックをデフォルトで開いた状態にできます。\n\n**入力**\n\n````md\n::: details クリックしてコードを表示/非表示 {open}\n```js\nconsole.log('こんにちは、VitePress!')\n```\n:::\n````\n\n**出力**\n\n::: details クリックしてコードを表示/非表示 {open}\n```js\nconsole.log('こんにちは、VitePress!')\n```\n:::\n\n### `raw`\n\nこれは、VitePress でのスタイルやルーターの衝突を防ぐための特別なコンテナです。コンポーネントライブラリのドキュメント化に特に有用です。より強力な分離が必要であれば、[whyframe](https://whyframe.dev/docs/integrations/vitepress) も検討してください。\n\n**構文**\n\n```md\n::: raw\nWraps in a `<div class=\"vp-raw\">`\n:::\n```\n\n`vp-raw` クラスは要素に直接付与することも可能です。スタイルの分離は現在オプトインです。\n\n- お好みのパッケージマネージャで `postcss` をインストールします:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- `docs/postcss.config.mjs` を作成し、次を追加します:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  オプションは次のように渡せます:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // 既定は [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## GitHub 形式のアラート {#github-flavored-alerts}\n\nVitePress は [GitHub 形式のアラート](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) をコールアウトとしてレンダリングできます。表示は [カスタムコンテナ](#custom-containers) と同様です。\n\n**入力**\n\n```md\n> [!NOTE]\n> 流し読みでも目に留めてほしい情報を強調します。\n\n> [!TIP]\n> 成功の手助けとなる任意の情報です。\n\n> [!IMPORTANT]\n> 成功に必須の重要情報です。\n\n> [!WARNING]\n> 危険性があるため即時の注意が必要な重要情報です。\n\n> [!CAUTION]\n> 行動による望ましくない結果の可能性です。\n```\n\n**出力**\n\n> [!NOTE]\n> 流し読みでも目に留めてほしい情報を強調します。\n\n> [!TIP]\n> 成功の手助けとなる任意の情報です。\n\n> [!IMPORTANT]\n> 成功に必須の重要情報です。\n\n> [!WARNING]\n> 危険性があるため即時の注意が必要な重要情報です。\n\n> [!CAUTION]\n> 行動による望ましくない結果の可能性です。\n\n## コードブロックのシンタックスハイライト {#syntax-highlighting-in-code-blocks}\n\nVitePress は [Shiki](https://github.com/shikijs/shiki) を使って、Markdown のコードブロックに色付きのシンタックスハイライトを適用します。Shiki は多くのプログラミング言語をサポートしています。コードブロックの先頭のバッククォートに有効な言語エイリアスを付けるだけで利用できます。\n\n**入力**\n\n````md\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````md\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**出力**\n\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\n有効な言語の [一覧](https://shiki.style/languages) は Shiki のリポジトリで確認できます。\n\nまた、シンタックスハイライトのテーマ変更、言語エイリアスの設定、言語ラベルのカスタマイズなどはアプリ設定の [`markdown` オプション](../reference/site-config#markdown) で行えます。\n\n## コードブロックの行ハイライト {#line-highlighting-in-code-blocks}\n\n**入力**\n\n````md\n```js{4}\nexport default {\n  data() {\n    return {\n      msg: 'ハイライト！'\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js{4}\nexport default {\n  data() {\n    return {\n      msg: 'ハイライト！'\n    }\n  }\n}\n```\n\n単一行だけでなく、複数の単一行や範囲、あるいはその組み合わせも指定できます:\n\n- 行範囲の例: `{5-8}`, `{3-10}`, `{10-17}`\n- 複数の単一行: `{4,7,9}`\n- 行範囲＋単一行: `{4,7-13,16,23-27,40}`\n\n**入力**\n\n````md\n```js{1,4,6-8}\nexport default { // Highlighted\n  data() {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js{1,4,6-8}\nexport default { // Highlighted\n  data() {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n\n代替案として、`// [!code highlight]` コメントを使って行内を直接ハイライトできます。\n\n**入力**\n\n````md\n```js\nexport default {\n  data() {\n    return {\n      msg: 'ハイライト！' // [!code highlight]\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'ハイライト！' // [!code highlight]\n    }\n  }\n}\n```\n\n## コードブロックでのフォーカス {#focus-in-code-blocks}\n\n`// [!code focus]` コメントを行に付けると、その行にフォーカスし、他の部分がぼかされます。\n\nまた、`// [!code focus:<lines>]` を使ってフォーカスする行数を指定することもできます。\n\n**入力**\n\n````md\n```js\nexport default {\n  data() {\n    return {\n      msg: 'フォーカス！' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'フォーカス！' // [!code focus]\n    }\n  }\n}\n```\n\n## コードブロックのカラー差分表示 {#colored-diffs-in-code-blocks}\n\n`// [!code --]` または `// [!code ++]` コメントを行に付けると、その行に差分（削除/追加）スタイルを適用できます。コードブロックの色付けは維持されます。\n\n**入力**\n\n````md\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Removed' // [!!code --]\n      msg: 'Added' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Removed' // [!code --]\n      msg: 'Added' // [!code ++]\n    }\n  }\n}\n```\n\n## コードブロック内のエラー/警告表示 {#errors-and-warnings-in-code-blocks}\n\n行に `// [!code warning]` または `// [!code error]` コメントを付けると、その行が対応する色で表示されます。\n\n**入力**\n\n````md\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!!code error]\n      msg: 'Warning' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**出力**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!code error]\n      msg: 'Warning' // [!code warning]\n    }\n  }\n}\n```\n\n## 行番号 {#line-numbers}\n\n設定で、各コードブロックに行番号を表示できます：\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\n詳しくは [`markdown` オプション](../reference/site-config#markdown) を参照してください。\n\n設定値を上書きするために、フェンス付きコードブロックに `:line-numbers` / `:no-line-numbers` マークを付与できます。\n\nまた、`:line-numbers` の後ろに `=` を付けて開始行番号を指定できます。例：`:line-numbers=2` は行番号が `2` から始まることを意味します。\n\n**入力**\n\n````md\n```ts {1}\n// 既定では line-numbers は無効\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// line-numbers が有効\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// line-numbers が有効で、2 から開始\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n````\n\n**出力**\n\n```ts {1}\n// 既定では line-numbers は無効\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// line-numbers が有効\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// line-numbers が有効で、2 から開始\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n\n## コードスニペットのインポート {#import-code-snippets}\n\n既存ファイルから、次の構文でコードスニペットをインポートできます：\n\n```md\n<<< @/filepath\n```\n\nまた、[行のハイライト](#line-highlighting-in-code-blocks)にも対応しています：\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**入力**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**コードファイル**\n\n<<< @/snippets/snippet.js\n\n**出力**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\n`@` の値はソースルートを表します。既定では VitePress プロジェクトのルートですが、`srcDir` を設定している場合はその値になります。代替として、相対パスからのインポートも可能です：\n\n```md\n<<< ../snippets/snippet.js\n```\n:::\n\nまた、[VS Code のリージョン](https://code.visualstudio.com/docs/editor/codebasics#_folding)を利用して、コードファイルの該当部分のみを取り込むことができます。ファイルパスの後ろに `#` を付けてカスタムリージョン名を指定します：\n\n**入力**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**コードファイル**\n\n<<< @/snippets/snippet-with-region.js\n\n**出力**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\n中括弧（`{}`）の中で言語を指定することもできます：\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- 行のハイライト付き: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- 行番号付き: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nこれは、ファイル拡張子からソース言語を推論できない場合に有用です。\n\n## コードグループ {#code-groups}\n\n複数のコードブロックを、次のようにグループ化できます。\n\n**入力**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**出力**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nコードグループ内でも [スニペットのインポート](#import-code-snippets) が可能です：\n\n**入力**\n\n```md\n::: code-group\n\n<!-- 既定ではファイル名がタイトルとして使われます -->\n\n<<< @/snippets/snippet.js\n\n<!-- カスタムタイトルも指定できます -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [リージョン付きスニペット]\n\n:::\n```\n\n**出力**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [リージョン付きスニペット]\n\n:::\n\n## Markdown ファイルのインクルード {#markdown-file-inclusion}\n\nある Markdown ファイルの中に、別の Markdown ファイルを取り込めます（入れ子も可能）。\n\n::: tip\nMarkdown パスの先頭に `@` を付けることもでき、その場合はソースルートとして扱われます。既定では VitePress プロジェクトのルートですが、`srcDir` を設定している場合はその値になります。\n:::\n\n例えば、相対パスの Markdown ファイルを次のように取り込めます。\n\n**入力**\n\n```md\n# ドキュメント\n\n## 基本\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**パートファイル**（`parts/basics.md`）\n\n```md\nはじめに知っておきたいこと。\n\n### 設定\n\n`.foorc.json` を使用して作成できます。\n```\n\n**等価なコード**\n\n```md\n# ドキュメント\n\n## 基本\n\nはじめに知っておきたいこと。\n\n### 設定\n\n`.foorc.json` を使用して作成できます。\n```\n\n行範囲の選択にも対応しています。\n\n**入力**\n\n```md:line-numbers\n# ドキュメント\n\n## 基本\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**パートファイル**（`parts/basics.md`）\n\n```md:line-numbers\nはじめに知っておきたいこと。\n\n### 設定\n\n`.foorc.json` を使って作成できます。\n```\n\n**等価なコード**\n\n```md:line-numbers\n# ドキュメント\n\n## 基本\n\n### 設定\n\n`.foorc.json` を使って作成できます。\n```\n\n選択できる行範囲の書式は、`{3,}`、`{,10}`、`{1,10}` のいずれかです。\n\n[VS Code のリージョン](https://code.visualstudio.com/docs/editor/codebasics#_folding)を使って、コードファイルの該当部分だけを取り込むこともできます。ファイルパスの後ろに `#` を付けて、カスタムリージョン名を指定します。\n\n**入力**\n\n```md:line-numbers\n# ドキュメント\n\n## 基本\n\n<!--@@include: ./parts/basics.md#basic-usage{,2}-->\n<!--@@include: ./parts/basics.md#basic-usage{5,}-->\n```\n\n**パートファイル**（`parts/basics.md`）\n\n```md:line-numbers\n<!-- #region basic-usage -->\n## 使用例 1\n\n## 使用例 2\n\n## 使用例 3\n<!-- #endregion basic-usage -->\n```\n\n**等価なコード**\n\n```md:line-numbers\n# ドキュメント\n\n## 基本\n\n## 使用例 1\n\n## 使用例 3\n```\n\n::: warning\nファイルが存在しない場合でもエラーは発生しません。したがって、この機能を使う際は、期待どおりに内容がレンダリングされているか必ず確認してください。\n:::\n\nVS Code のリージョンの代わりに、ヘッダーアンカーを使ってファイル内の特定セクションだけを取り込むこともできます。たとえば、Markdown ファイルに次のようなヘッダーがある場合：\n\n```md\n## ベースのセクション\n\nここに本文。\n\n### サブセクション\n\nここに本文（サブ）。\n\n## 別のセクション\n\n`ベースのセクション` の外側の内容。\n```\n\n`ベースのセクション` を次のように取り込めます：\n\n```md\n## 拡張セクション\n\n<!--@@include: ./parts/basics.md#my-base-section-->\n```\n\n**等価なコード**\n\n```md\n## 拡張セクション\n\nここに本文。\n\n### サブセクション\n\nここに本文（サブ）。\n```\n\nここで `my-base-section` は見出し要素から生成される ID です。推測しづらい場合は、パートファイルをブラウザで開いて見出しのアンカー（ホバー時に見出しの左に表示される `#` 記号）をクリックし、URL バーで ID を確認してください。あるいはブラウザの開発者ツールで要素を検査して確認できます。別案として、パートファイル側で明示的に ID を指定できます：\n\n```md\n## ベースのセクション {#custom-id}\n```\n\nそして次のように取り込みます：\n\n```md\n<!--@@include: ./parts/basics.md#custom-id-->\n```\n\n## 数式 {#math-equations}\n\nこの機能はオプトインです。利用するには `markdown-it-mathjax3` をインストールし、設定ファイルで `markdown.math` を `true` に設定します。\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**入力**\n\n```md\nもし $a \\ne 0$ のとき、$(ax^2 + bx + c = 0)$ の解は 2 つ存在し、次式で与えられます\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**マクスウェル方程式:**\n\n| 方程式                                                                                                                                                                    | 説明                                                                           |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | 磁束密度 $\\vec{\\mathbf{B}}$ の発散は 0                                         |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | 電場 $\\vec{\\mathbf{E}}$ の回転は、磁束密度 $\\vec{\\mathbf{B}}$ の時間変化に比例 |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _え？_                                                                         |\n```\n\n**出力**\n\nもし $a \\ne 0$ のとき、$(ax^2 + bx + c = 0)$ の解は 2 つ存在し、次式で与えられます\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**マクスウェル方程式:**\n\n| 方程式                                                                                                                                                                    | 説明                                                                           |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | 磁束密度 $\\vec{\\mathbf{B}}$ の発散は 0                                         |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | 電場 $\\vec{\\mathbf{E}}$ の回転は、磁束密度 $\\vec{\\mathbf{B}}$ の時間変化に比例 |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _え？_                                                                         |\n\n## 画像の遅延読み込み {#image-lazy-loading}\n\nMarkdown で追加した各画像に対して遅延読み込みを有効化するには、設定ファイルで `lazyLoading` を `true` にします：\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // 既定では画像の遅延読み込みは無効\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## 高度な設定 {#advanced-configuration}\n\nVitePress は Markdown レンダラーとして [markdown-it](https://github.com/markdown-it/markdown-it) を使用しています。上記の多くの拡張はカスタムプラグインとして実装されています。`.vitepress/config.js` の `markdown` オプションを使って、`markdown-it` のインスタンスをさらにカスタマイズできます。\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // markdown-it-anchor のオプション\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // @mdit-vue/plugin-toc のオプション\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // markdown-it のプラグインをもっと使えます！\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\n設定可能なプロパティの完全な一覧は、[設定リファレンス: アプリ設定](../reference/site-config#markdown) を参照してください。\n"
  },
  {
    "path": "docs/ja/guide/mpa-mode.md",
    "content": "# MPA モード <Badge type=\"warning\" text=\"experimental\" /> {#mpa-mode}\n\nMPA（Multi-Page Application）モードは、コマンドラインの `vitepress build --mpa`、または設定で `mpa: true` を指定することで有効化できます。\n\nMPA モードでは、既定で **あらゆるページが JavaScript を含まずに** レンダリングされます。結果として、本番サイトは監査ツールにおける初回訪問のパフォーマンススコアが向上しやすくなります。\n\n一方、SPA のナビゲーションがないため、ページ間リンクはフルリロードになります。読み込み後のページ遷移は、SPA モードのような即時性はありません。\n\nまた、「既定で JS なし」ということは、実質的に Vue をサーバーサイドのテンプレート言語としてのみ使うことを意味します。ブラウザ側ではイベントハンドラがアタッチされないため、インタラクティブ性はありません。クライアントサイドの JavaScript を読み込むには、特別な `<script client>` タグを使用します：\n\n```md\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('client side JavaScript!')\n})\n</script>\n\n# Hello\n```\n\n`<script client>` は VitePress 固有の機能であり、Vue の機能ではありません。`.md` と `.vue` の両方で動作しますが、**MPA モード時のみ** 有効です。テーマコンポーネント内のクライアントスクリプトはひとつにバンドルされ、特定ページ専用のクライアントスクリプトはそのページごとに分割されます。\n\nなお、`<script client>` は **Vue コンポーネントのコードとしては評価されません**。プレーンな JavaScript モジュールとして処理されます。このため、MPA モードはクライアント側のインタラクションを極力最小限に抑えたいサイトにのみ使用するのが適しています。\n"
  },
  {
    "path": "docs/ja/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# ルーティング {#routing}\n\n## ファイルベースのルーティング {#file-based-routing}\n\nVitePress はファイルベースのルーティングを採用しており、生成される HTML はソースの Markdown ファイルのディレクトリ構造に対応します。例えば、次のディレクトリ構造があるとします：\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\n生成される HTML は次のとおりです：\n\n```\nindex.md                  -->  /index.html （/ でアクセス可能）\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html （/guide/ でアクセス可能）\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\n生成された HTML は、静的ファイルを配信できる任意の Web サーバーでホストできます。\n\n## ルートディレクトリとソースディレクトリ {#root-and-source-directories}\n\nVitePress プロジェクトのファイル構成には重要な概念が 2 つあります：**プロジェクトルート** と **ソースディレクトリ** です。\n\n### プロジェクトルート {#project-root}\n\nプロジェクトルートは、VitePress が特別なディレクトリである `.vitepress` を探しにいく場所です。`.vitepress` ディレクトリは、VitePress の設定ファイル、開発サーバーのキャッシュ、ビルド出力、任意のテーマカスタマイズコードのための予約場所です。\n\nコマンドラインから `vitepress dev` や `vitepress build` を実行すると、VitePress は現在の作業ディレクトリをプロジェクトルートとして使用します。サブディレクトリをルートとして指定したい場合は、コマンドに相対パスを渡します。例えば、VitePress プロジェクトが `./docs` にある場合、`vitepress dev docs` を実行します：\n\n```\n.\n├─ docs                    # プロジェクトルート\n│  ├─ .vitepress           # 設定ディレクトリ\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nこれにより、ソースから HTML へのマッピングは次のようになります：\n\n```\ndocs/index.md            -->  /index.html （/ でアクセス可能）\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### ソースディレクトリ {#source-directory}\n\nソースディレクトリは、Markdown のソースファイルを置く場所です。既定ではプロジェクトルートと同じです。ただし、[`srcDir`](../reference/site-config#srcdir) 設定オプションで変更できます。\n\n`srcDir` はプロジェクトルートからの相対パスで解決されます。例えば `srcDir: 'src'` の場合、ファイル構成は次のようになります：\n\n```\n.                          # プロジェクトルート\n├─ .vitepress              # 設定ディレクトリ\n└─ src                     # ソースディレクトリ\n   ├─ getting-started.md\n   └─ index.md\n```\n\nソースから HTML へのマッピングは次のとおりです：\n\n```\nsrc/index.md            -->  /index.html （/ でアクセス可能）\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## ページ間リンク {#linking-between-pages}\n\nページ間のリンクには、絶対パスと相対パスのどちらも使用できます。`.md` と `.html` の拡張子はどちらも機能しますが、最終的な URL を設定に応じて VitePress が生成できるよう、**拡張子は省略する** のがベストプラクティスです。\n\n```md\n<!-- 良い例 -->\n[はじめに](./getting-started)\n[はじめに](../guide/getting-started)\n\n<!-- 悪い例 -->\n[はじめに](./getting-started.md)\n[はじめに](./getting-started.html)\n```\n\n画像などのアセットへのリンクについては、[アセットの取り扱い](./asset-handling) を参照してください。\n\n### VitePress 管理外のページへのリンク {#linking-to-non-vitepress-pages}\n\nサイト内で VitePress が生成していないページへリンクしたい場合は、フル URL（新しいタブで開く）を使うか、明示的にターゲットを指定します。\n\n**入力**\n\n```md\n[pure.html へのリンク](/pure.html){target=\"_self\"}\n```\n\n**出力**\n\n[pure.html へのリンク](/pure.html){target=\"_self\"}\n\n::: tip 注意\n\nMarkdown のリンクでは、`base` が自動的に URL の先頭に付与されます。つまり、`base` の外にあるページへリンクしたい場合は、ブラウザの相対解決に従って `../../pure.html` のように書く必要があります。\n\nあるいは、アンカータグの構文を直接使うこともできます：\n\n```md\n<a href=\"/pure.html\" target=\"_self\">pure.html へのリンク</a>\n```\n:::\n\n## クリーン URL の生成 {#generating-clean-urls}\n\n::: warning サーバー側の対応が必要\nVitePress でクリーン URL を提供するには、サーバー側のサポートが必要です。\n:::\n\n既定では、VitePress は内部リンクを `.html` で終わる URL に解決します。しかし、`.html` を含まない「クリーン URL」（例：`example.com/path`）を好む場合もあります。\n\n一部のサーバーやホスティング（例：Netlify、Vercel、GitHub Pages）は、リダイレクトなしに `/foo` を `/foo.html` にマッピングできます。\n\n- Netlify と GitHub Pages はデフォルトで対応しています。\n- Vercel は [`vercel.json` の `cleanUrls` オプション](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls) を有効にする必要があります。\n\nこの機能が利用可能であれば、VitePress 側の [`cleanUrls`](../reference/site-config#cleanurls) 設定も有効化してください。これにより：\n\n- ページ間の内部リンクが `.html` 拡張子なしで生成されます。\n- 現在のパスが `.html` で終わっている場合、拡張子なしのパスへクライアントサイドのリダイレクトを行います。\n\nもしサーバーをそのように設定できない場合は、次のようなディレクトリ構造に手動でする必要があります：\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## ルートのリライト {#route-rewrites}\n\nソースディレクトリ構造と生成ページのマッピングをカスタマイズできます。これは複雑なプロジェクト構成で有用です。例えば、複数パッケージを持つモノレポで、ソースファイルと並べてドキュメントを配置したい場合：\n\n```\n.\n└─ packages\n   ├─ pkg-a\n   │  └─ src\n   │     ├─ foo.md\n   │     └─ index.md\n   └─ pkg-b\n      └─ src\n         ├─ bar.md\n         └─ index.md\n```\n\n生成したいページが次のような場合：\n\n```\npackages/pkg-a/src/index.md  -->  /pkg-a/index.html\npackages/pkg-a/src/foo.md    -->  /pkg-a/foo.html\npackages/pkg-b/src/index.md  -->  /pkg-b/index.html\npackages/pkg-b/src/bar.md    -->  /pkg-b/bar.html\n```\n\n[`rewrites`](../reference/site-config#rewrites) オプションを次のように設定します：\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/index.md': 'pkg-a/index.md',\n    'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',\n    'packages/pkg-b/src/index.md': 'pkg-b/index.md',\n    'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'\n  }\n}\n```\n\n`rewrites` は動的なルートパラメータにも対応しています。上記の例で多くのパッケージがある場合、同じ構造なら次のように簡略化できます：\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/:slug*': ':pkg/:slug*'\n  }\n}\n```\n\nリライトのパスは `path-to-regexp` パッケージでコンパイルされます。高度な構文は[ドキュメント](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters)を参照してください。\n\n`rewrites` は、元のパスを受け取って新しいパスを返す **関数** として定義することもできます：\n\n```ts\nexport default {\n  rewrites(id) {\n    return id.replace(/^packages\\/([^/]+)\\/src\\//, '$1/')\n  }\n}\n```\n\n::: warning リライト時の相対リンク\n\nリライトを有効にした場合、**相対リンクはリライト後のパスに基づいて** 記述してください。例えば、`packages/pkg-a/src/pkg-a-code.md` から `packages/pkg-b/src/pkg-b-code.md` への相対リンクを作るには、次のように書きます：\n\n```md\n[PKG B へのリンク](../pkg-b/pkg-b-code)\n```\n:::\n\n## 動的ルート {#dynamic-routes}\n\nひとつの Markdown ファイルと動的データから多数のページを生成できます。例えば、`packages/[pkg].md` を作成して、プロジェクト内の各パッケージに対応するページを生成できます。ここで `[pkg]` セグメントは、それぞれのページを区別する **ルートパラメータ** です。\n\n### パスローダーファイル {#path-loader-files}\n\nVitePress は静的サイトジェネレーターなので、生成可能なページパスはビルド時に確定している必要があります。したがって、動的ルートページには **パスローダーファイル** が **必須** です。`packages/[pkg].md` に対しては `packages/[pkg].paths.js`（`.ts` も可）が必要です：\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # ルートテンプレート\n   └─ [pkg].paths.js   # ルートのパスローダー\n```\n\nパスローダーは、`paths` メソッドを持つオブジェクトをデフォルトエクスポートします。`paths` は `params` プロパティを持つオブジェクトの配列を返します。各オブジェクトが 1 ページに対応します。\n\n例えば次の `paths` 配列を返すと：\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' } },\n      { params: { pkg: 'bar' } }\n    ]\n  }\n}\n```\n\n生成される HTML は次のようになります：\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### 複数パラメータ {#multiple-params}\n\n動的ルートに複数のパラメータを含めることもできます。\n\n**ファイル構成**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**パスローダー**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' } },\n    { params: { pkg: 'foo', version: '2.0.0' } },\n    { params: { pkg: 'bar', version: '1.0.0' } },\n    { params: { pkg: 'bar', version: '2.0.0' } }\n  ]\n}\n```\n\n**出力**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### パスを動的に生成する {#dynamically-generating-paths}\n\nパスローダーモジュールは Node.js 上で実行され、ビルド時にのみ評価されます。ローカルまたはリモートの任意のデータから、動的に配列を生成できます。\n\nローカルファイルから生成する例：\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n      return { params: { pkg } }\n    })\n  }\n}\n```\n\nリモートデータから生成する例：\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### ページ内でパラメータにアクセスする {#accessing-params-in-page}\n\n各ページへ追加データを渡すために、パラメータを利用できます。Markdown のルートファイルでは、Vue 式内で `$params` グローバルプロパティから現在ページのパラメータにアクセスできます：\n\n```md\n- パッケージ名: {{ $params.pkg }}\n- バージョン: {{ $params.version }}\n```\n\n[`useData`](../reference/runtime-api#usedata) ランタイム API からも、現在ページのパラメータにアクセスできます（Markdown と Vue コンポーネントの両方で利用可能）：\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params は Vue の ref\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### 生コンテンツのレンダリング {#rendering-raw-content}\n\nページに渡したパラメータはクライアント JavaScript のペイロードにシリアライズされます。そのため、リモート CMS から取得した生の Markdown や HTML など、重いデータをパラメータに含めるのは避けてください。\n\n代わりに、各パスオブジェクトの `content` プロパティでコンテンツを渡せます：\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // 生の Markdown または HTML\n      }\n    })\n  }\n}\n```\n\nそのうえで、Markdown ファイル内で次の特別な構文を使って、そのコンテンツを埋め込みます：\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/ja/guide/sitemap-generation.md",
    "content": "# サイトマップ生成 {#sitemap-generation}\n\nVitePress には、サイト用の `sitemap.xml` を生成する機能が標準で用意されています。有効化するには、`.vitepress/config.js` に次を追加します。\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\n`siteamp.xml` に `<lastmod>` タグを含めるには、[`lastUpdated`](../reference/default-theme-last-updated) オプションを有効にします。\n\n## オプション {#options}\n\nサイトマップ生成は [`sitemap`](https://www.npmjs.com/package/sitemap) モジュールで行われます。設定ファイルの `sitemap` に、このモジュールがサポートする任意のオプションを渡せます。指定した値はそのまま `SitemapStream` コンストラクタに渡されます。詳しくは [`sitemap` のドキュメント](https://www.npmjs.com/package/sitemap#options-you-can-pass) を参照してください。例：\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\n設定で `base` を使っている場合は、`hostname` にもそれを付与してください：\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## `transformItems` フック {#transformitems-hook}\n\n`siteamp.xml` に書き出す直前にサイトマップ項目を加工するには、`sitemap.transformItems` フックを使います。このフックはサイトマップ項目の配列を受け取り、配列を返す必要があります。例：\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // 既存項目の追加・変更・フィルタリングが可能\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ja/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# SSR 互換性 {#ssr-compatibility}\n\nVitePress は本番ビルド時に、Node.js 上で Vue のサーバーサイドレンダリング（SSR）機能を使ってアプリを事前レンダリングします。つまり、テーマコンポーネント内のすべてのカスタムコードは SSR 互換性の対象になります。\n\n[公式 Vue ドキュメントの SSR セクション](https://vuejs.org/guide/scaling-up/ssr.html)では、SSR とは何か、SSR と SSG の関係、そして SSR に優しいコードを書く際の一般的な注意点が解説されています。経験則としては、**ブラウザ / DOM API へのアクセスは Vue コンポーネントの `beforeMount` または `mounted` フック内に限定** するのが安全です。\n\n## `<ClientOnly>` {#clientonly}\n\nSSR に適さないコンポーネント（例：カスタムディレクティブを含むなど）を使用・デモする場合は、組み込みの `<ClientOnly>` コンポーネントでラップできます。\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## インポート時に Browser API にアクセスするライブラリ {#libraries-that-access-browser-api-on-import}\n\n一部のコンポーネントやライブラリは **インポート時に** ブラウザ API にアクセスします。インポート時にブラウザ環境を前提とするコードを使うには、動的インポートが必要です。\n\n### mounted フック内でのインポート {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // ここでコードを利用\n  })\n})\n</script>\n```\n\n### 条件付きインポート {#conditional-import}\n\n[`import.meta.env.SSR`](https://vitejs.dev/guide/env-and-mode.html#env-variables) フラグ（Vite の環境変数の一部）を使って、依存関係を条件付きでインポートすることもできます。\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // ここでコードを利用\n  })\n}\n```\n\n[`Theme.enhanceApp`](./custom-theme#theme-interface) は非同期にできるため、**インポート時に Browser API に触れる Vue プラグイン** を条件付きでインポート・登録できます。\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nTypeScript を使う場合：\n\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress は、**インポート時に Browser API にアクセスする Vue コンポーネント** を読み込むためのユーティリティを提供します。\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nターゲットコンポーネントに props / children / slots を渡すこともできます。\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // 引数は h() に渡されます - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'default slot',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'one'), h('span', 'two')]\n    }\n  ],\n\n  // コンポーネント読み込み後のコールバック（非同期可）\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nターゲットコンポーネントは、ラッパーコンポーネントの mounted フックで初めてインポートされます。\n"
  },
  {
    "path": "docs/ja/guide/using-vue.md",
    "content": "# MarkdownでVueを使う {#using-vue-in-markdown}\n\nVitePress では、各 Markdown ファイルはまず HTML にコンパイルされ、その後 [Vue の単一ファイルコンポーネント（SFC）](https://vuejs.org/guide/scaling-up/sfc.html) として処理されます。つまり、Markdown 内で Vue のあらゆる機能が使えます。動的テンプレート、Vue コンポーネントの利用、`<script>` タグを追加してページ内ロジックを書くことも可能です。\n\nなお、VitePress は Vue のコンパイラを利用して、Markdown コンテンツの**純粋に静的な部分**を自動検出・最適化します。静的コンテンツは単一のプレースホルダノードに最適化され、初回訪問時の JavaScript ペイロードから除外されます。クライアント側のハイドレーションでもスキップされます。要するに、そのページで**動的な部分に対してだけ**コストを支払うことになります。\n\n::: tip SSR 互換性\nVue の使用は SSR 互換である必要があります。詳細と一般的な回避策は [SSR 互換性](./ssr-compat) を参照してください。\n:::\n\n## テンプレート記法 {#templating}\n\n### 補間 {#interpolation}\n\n各 Markdown は最初に HTML にコンパイルされ、その後 Vite の処理パイプラインで Vue コンポーネントとして扱われます。つまり、テキスト内で Vue 風の補間が使えます。\n\n**入力**\n\n```md\n{{ 1 + 1 }}\n```\n\n**出力**\n\n <div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### ディレクティブ {#directives}\n\nディレクティブも動作します（設計上、生の HTML は Markdown でも有効です）。\n\n**入力**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**出力**\n\n <div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` と `<style>` {#script-and-style}\n\nMarkdown ファイルのルート直下に置く `<script>` と `<style>` タグは、Vue の SFC と同様に動作します（`<script setup>` や `<style module>` などを含む）。大きな違いは `<template>` タグが無い点で、その他のルート直下のコンテンツは Markdown になることです。すべてのタグはフロントマターの**後**に配置してください。\n\n```md\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## Markdown コンテンツ\n\n現在の値: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Increment</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning Markdown での `<style scoped>` は避ける\nMarkdown で `<style scoped>` を使うと、そのページ内のすべての要素に特殊な属性を付与する必要があり、ページサイズが大きく膨らみます。ページ単位でローカルスコープが必要な場合は `<style module>` を推奨します。\n:::\n\nVitePress のランタイム API（例：現在ページのメタデータにアクセスできる [`useData` ヘルパー](../reference/runtime-api#usedata)）も利用できます。\n\n**入力**\n\n```md\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**出力**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"Using Vue in Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## コンポーネントの利用 {#using-components}\n\nMarkdown ファイルで、Vue コンポーネントを直接インポートして使用できます。\n\n### Markdown 内でのインポート {#importing-in-markdown}\n\n特定のページでしか使わないコンポーネントは、そのページで明示的にインポートするのがおすすめです。これにより適切にコード分割され、該当ページでのみ読み込まれます。\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# ドキュメント\n\nこれはカスタムコンポーネントを使う .md です\n\n<CustomComponent />\n\n## 続き\n\n...\n```\n\n### グローバル登録 {#registering-components-globally}\n\nほとんどのページで使うコンポーネントは、Vue アプリインスタンスをカスタマイズしてグローバル登録できます。例は [デフォルトテーマの拡張](./extending-default-theme#registering-global-components) を参照してください。\n\n::: warning 重要\nカスタムコンポーネント名にはハイフンを含めるか、PascalCase を使用してください。そうでない場合、インライン要素として解釈されて `<p>` タグ内にラップされ、ブロック要素が入れられないためハイドレーション不整合を引き起こします。\n:::\n\n### 見出し内でのコンポーネント利用 <ComponentInHeader /> {#using-components-in-headers}\n\n見出し内で Vue コンポーネントを使うこともできますが、次の書き方の違いに注意してください。\n\n| Markdown                                                | 出力 HTML                                 | 解析される見出し |\n| ------------------------------------------------------- | ----------------------------------------- | ---------------- |\n| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre>     | `<h1>text <Tag/></h1>`                    | `text`           |\n| <pre v-pre><code> # text \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>`    |\n\n`<code>` に包まれた HTML はそのまま表示されます。包まれて**いない** HTML だけが Vue によってパースされます。\n\n::: tip\n出力 HTML の生成は [Markdown-it](https://github.com/Markdown-it/Markdown-it) が担当し、見出しの解析は VitePress が担当します（サイドバーやドキュメントタイトルに利用）。\n:::\n\n## エスケープ {#escaping}\n\n`v-pre` ディレクティブを付けた `<span>` などでラップすることで、Vue の補間をエスケープできます。\n\n**入力**\n\n```md\nThis <span v-pre>{{ will be displayed as-is }}</span>\n```\n\n**出力**\n\n <div class=\"escape-demo\">\n   <p>This <span v-pre>{{ will be displayed as-is }}</span></p>\n </div>\n\n段落全体を `v-pre` のカスタムコンテナで囲む方法もあります。\n\n```md\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n```\n\n**出力**\n\n <div class=\"escape-demo\">\n\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n\n </div>\n\n## コードブロック内でのアンエスケープ {#unescape-in-code-blocks}\n\n既定では、フェンス付きコードブロックは自動で `v-pre` が付与され、Vue の構文は処理されません。フェンス内で Vue 風の補間を有効にするには、言語に `-vue` サフィックスを付けます（例：`js-vue`）。\n\n**入力**\n\n````md\n```js-vue\nHello {{ 1 + 1 }}\n```\n````\n\n**出力**\n\n```js-vue\nHello {{ 1 + 1 }}\n```\n\nこの方法では、一部のトークンが正しくシンタックスハイライトされない場合があります。\n\n## CSS プリプロセッサの利用 {#using-css-pre-processors}\n\nVitePress は CSS プリプロセッサ（`.scss`、`.sass`、`.less`、`.styl`、`.stylus`）を[標準サポート](https://vitejs.dev/guide/features.html#css-pre-processors)しています。Vite 固有のプラグインは不要ですが、各プリプロセッサ本体のインストールは必要です。\n\n```\n# .scss / .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl / .stylus\nnpm install -D stylus\n```\n\nその後、Markdown やテーマコンポーネントで次のように使えます。\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## Teleport の利用 {#using-teleports}\n\n現時点で VitePress は、SSG における Teleport を **body** へのみサポートしています。その他のターゲットへ Teleport したい場合は、組み込みの `<ClientOnly>` でラップするか、[`postRender` フック](../reference/site-config#postrender)で最終ページ HTML の適切な位置に Teleport のマークアップを注入してください。\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n\n## VS Code の IntelliSense サポート {#vs-code-intellisense-support}\n\n<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->\n\nVue は [Vue - Official VS Code plugin](https://marketplace.visualstudio.com/items?itemName=Vue.volar) により、標準で IntelliSense を提供します。ただし `.md` ファイルでも有効にするには、設定ファイルをいくつか調整する必要があります。\n\n1. tsconfig/jsconfig の `include` と `vueCompilerOptions.vitePressExtensions` に `.md` パターンを追加します。\n\n::: code-group\n```json [tsconfig.json]\n{\n  \"include\": [\n    \"docs/**/*.ts\",\n    \"docs/**/*.vue\",\n    \"docs/**/*.md\"\n  ],\n  \"vueCompilerOptions\": {\n    \"vitePressExtensions\": [\".md\"]\n  }\n}\n```\n:::\n\n2. VS Code の設定で、`vue.server.includeLanguages` に `markdown` を追加します。\n\n::: code-group\n```json [.vscode/settings.json]\n{\n  \"vue.server.includeLanguages\": [\"vue\", \"markdown\"]\n}\n```\n:::\n"
  },
  {
    "path": "docs/ja/guide/what-is-vitepress.md",
    "content": "# VitePress とは？ {#what-is-vitepress}\n\nVitePress は、高速でコンテンツ中心の Web サイトを構築するための [静的サイトジェネレーター（SSG）](https://en.wikipedia.org/wiki/Static_site_generator) です。要するに、VitePress は [Markdown](https://en.wikipedia.org/wiki/Markdown) で書かれたソースコンテンツにテーマを適用し、どこにでも簡単にデプロイできる静的 HTML ページを生成します。\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nまずは試してみたい？ [クイックスタート](./getting-started) へどうぞ。\n\n</div>\n\n## ユースケース {#use-cases}\n\n- **ドキュメント**\n\n  VitePress には技術ドキュメント向けに設計されたデフォルトテーマが同梱されています。今あなたが読んでいるこのページのほか、[Vite](https://vitejs.dev/)、[Rollup](https://rollupjs.org/)、[Pinia](https://pinia.vuejs.org/)、[VueUse](https://vueuse.org/)、[Vitest](https://vitest.dev/)、[D3](https://d3js.org/)、[UnoCSS](https://unocss.dev/)、[Iconify](https://iconify.design/) など、[まだまだたくさん](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code)のドキュメントサイトで使われています。\n\n  [公式の Vue.js ドキュメント](https://vuejs.org/) も VitePress をベースにしています（複数言語で共有されるカスタムテーマを使用）。\n\n- **ブログ／ポートフォリオ／マーケティングサイト**\n\n  VitePress は [フルカスタムテーマ](./custom-theme) をサポートし、標準的な Vite + Vue アプリ同様の開発体験を提供します。Vite 上に構築されているため、豊富なエコシステムから Vite プラグインを直接活用できます。さらに、[データの読み込み](./data-loading)（ローカル／リモート）や [ルートの動的生成](./routing#dynamic-routes) のための柔軟な API も提供します。ビルド時にデータが確定できる限り、ほとんど何でも構築できます。\n\n  公式の [Vue.js ブログ](https://blog.vuejs.org/) は、ローカルコンテンツに基づいてインデックスページを生成するシンプルなブログです。\n\n## 開発体験 {#developer-experience}\n\nVitePress は、Markdown コンテンツを扱う際の優れた開発体験（DX）を目指しています。\n\n- **[Vite 駆動](https://vitejs.dev/)**：即時サーバー起動、編集はページリロードなしで常に瞬時（<100ms）に反映。\n\n- **[ビルトインの Markdown 拡張](./markdown)**：Frontmatter、表、シンタックスハイライト…必要なものはひと通り。特にコードブロック周りの機能が充実しており、高度な技術ドキュメントに最適です。\n\n- **[Vue 拡張 Markdown](./using-vue)**：各 Markdown ページは Vue の [単一ファイルコンポーネント（SFC）](https://vuejs.org/guide/scaling-up/sfc.html) としても機能します。HTML と 100% 互換な Vue テンプレートを活かし、Vue のテンプレート機能やインポートしたコンポーネントで静的コンテンツにインタラクションを埋め込めます。\n\n## パフォーマンス {#performance}\n\n多くの従来型 SSG と異なり、VitePress で生成されたサイトは **初回訪問では静的 HTML** を返し、その後のサイト内ナビゲーションは [シングルページアプリケーション（SPA）](https://en.wikipedia.org/wiki/Single-page_application) として動作します。これはパフォーマンス面で最適なバランスだと考えています。\n\n- **初期ロードが速い**\n\n  どのページへの初回訪問でも、静的な事前レンダリング HTML が配信され、高速な読み込みと最適な SEO を実現します。続いて JavaScript バンドルが読み込まれ、ページが Vue の SPA に「ハイドレート」されます。SPA のハイドレーションは遅いという通説に反し、Vue 3 の素のパフォーマンスとコンパイラ最適化により非常に高速です。[PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F) でも、VitePress サイトは低速回線のローエンド端末でもほぼ満点のスコアを達成できます。\n\n- **読み込み後のナビゲーションが速い**\n\n  さらに重要なのは、初回ロード**後**の体験が向上することです。サイト内の以降の移動ではフルリロードは発生せず、遷移先のコンテンツを取得して動的に更新します。VitePress はビューポート内のリンクに対してページチャンクを自動プリフェッチするため、ほとんどの場合で遷移は「即時」に感じられます。\n\n- **インタラクションのペナルティなし**\n\n  静的 Markdown に埋め込まれた動的な Vue 部分をハイドレートできるよう、各 Markdown ページは Vue コンポーネントとして処理され JavaScript にコンパイルされます。一見非効率に思えますが、Vue コンパイラは静的部分と動的部分を賢く分離し、ハイドレーションのコストとペイロードを最小化します。初回ロードでは静的部分は自動的に JS ペイロードから除外され、ハイドレーションでもスキップされます。\n\n## VuePress はどうなるの？ {#what-about-vuepress}\n\nVitePress は VuePress 1 の精神的後継です。元の VuePress 1 は Vue 2 と webpack をベースとしていました。VitePress は内部に Vue 3 と Vite を採用し、開発体験・本番性能・完成度の高いデフォルトテーマ・より柔軟なカスタマイズ API を提供します。\n\nVitePress と VuePress 1 の API の違いは主にテーマやカスタマイズ周りにあります。VuePress 1 でデフォルトテーマを使っている場合は、比較的容易に移行できます。\n\n2 つの SSG を並行して維持するのは現実的ではないため、Vue チームは長期的に VitePress を推奨 SSG とする方針に集中しています。現在、VuePress 1 は非推奨となり、VuePress 2 は今後の開発・保守を VuePress コミュニティチームに委ねています。\n"
  },
  {
    "path": "docs/ja/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue をベースにした静的サイトジェネレーター\n  tagline: Markdown から美しいドキュメントを数分で\n  actions:\n    - theme: brand\n      text: VitePress とは？\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: クイックスタート\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: コンテンツに集中\n    details: Markdown だけで、美しいドキュメントサイトを簡単に作成できます。\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Vite の開発体験を享受\n    details: 即時サーバー起動、超高速ホットリロード、そして Vite エコシステムのプラグイン活用。\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Vue でカスタマイズ\n    details: Markdown 内で直接 Vue 構文やコンポーネントを利用したり、Vue で独自テーマを構築できます。\n  - icon: 🚀\n    title: 高速サイトを公開\n    details: 静的 HTML による高速初期ロードと、クライアントサイドルーティングによる快適なページ遷移。\n---\n"
  },
  {
    "path": "docs/ja/reference/cli.md",
    "content": "# コマンドラインインターフェイス {#command-line-interface}\n\n## `vitepress dev`\n\n指定したディレクトリをルートとして VitePress の開発サーバーを起動します。既定はカレントディレクトリです。カレントディレクトリで実行する場合、`dev` コマンドは省略できます。\n\n### 使い方 {#usage}\n\n```sh\n# カレントディレクトリで起動（`dev` を省略）\nvitepress\n\n# サブディレクトリで起動\nvitepress dev [root]\n```\n\n### オプション {#options}\n\n| オプション      | 説明                                                  |\n| --------------- | ----------------------------------------------------- |\n| `--open [path]` | 起動時にブラウザを開く（`boolean \\| string`）         |\n| `--port <port>` | ポート番号を指定（`number`）                          |\n| `--base <path>` | 公開時のベースパス（既定: `/`）（`string`）           |\n| `--cors`        | CORS を有効化                                         |\n| `--strictPort`  | 指定ポートが使用中なら終了（`boolean`）               |\n| `--force`       | 最適化時にキャッシュを無視して再バンドル（`boolean`） |\n\n## `vitepress build`\n\n本番用に VitePress サイトをビルドします。\n\n### 使い方 {#usage-1}\n\n```sh\nvitepress build [root]\n```\n\n### オプション {#options-1}\n\n| オプション                     | 説明                                                                                       |\n| ------------------------------ | ------------------------------------------------------------------------------------------ |\n| `--mpa`（実験的）              | クライアント側ハイドレーションなしの [MPA モード](../guide/mpa-mode) でビルド（`boolean`） |\n| `--base <path>`                | 公開時のベースパス（既定: `/`）（`string`）                                                |\n| `--target <target>`            | トランスパイルターゲット（既定: `\"modules\"`）（`string`）                                  |\n| `--outDir <dir>`               | 出力先ディレクトリ（**cwd** からの相対）（既定: `<root>/.vitepress/dist`）（`string`）     |\n| `--assetsInlineLimit <number>` | 静的アセットを base64 インライン化する閾値（バイト）（既定: `4096`）（`number`）           |\n\n## `vitepress preview`\n\n本番ビルドをローカルでプレビューします。\n\n### 使い方 {#usage-2}\n\n```sh\nvitepress preview [root]\n```\n\n### オプション {#options-2}\n\n| オプション      | 説明                                        |\n| --------------- | ------------------------------------------- |\n| `--base <path>` | 公開時のベースパス（既定: `/`）（`string`） |\n| `--port <port>` | ポート番号を指定（`number`）                |\n\n## `vitepress init`\n\nカレントディレクトリで [セットアップウィザード](../guide/getting-started#setup-wizard) を起動します。\n\n### 使い方 {#usage-3}\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-badge.md",
    "content": "# バッジ {#badge}\n\nバッジを使うと、見出しにステータスを追加できます。たとえば、そのセクションの種類や対応バージョンを示すのに便利です。\n\n## 使い方 {#usage}\n\nグローバルに利用可能な `Badge` コンポーネントを使用します。\n\n```md\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n```\n\n上記のコードは次のように表示されます：\n\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n\n## 子要素のカスタマイズ {#custom-children}\n\n`<Badge>` は子要素（`children`）を受け取り、バッジ内に表示できます。\n\n```md\n### Title <Badge type=\"info\">custom element</Badge>\n```\n\n### Title <Badge type=\"info\">custom element</Badge>\n\n## 種類ごとの色をカスタマイズ {#customize-type-color}\n\nCSS 変数を上書きすることで、バッジのスタイルをカスタマイズできます。以下はデフォルト値です：\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\n`<Badge>` コンポーネントは次の props を受け取ります。\n\n```ts\ninterface Props {\n  // `<slot>` が渡された場合、この値は無視されます。\n  text?: string\n\n  // 既定値は `tip`。\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-carbon-ads.md",
    "content": "# Carbon 広告 {#carbon-ads}\n\nVitePress は [Carbon Ads](https://www.carbonads.net/) をネイティブにサポートしています。設定で Carbon Ads の認証情報を定義すると、ページ上に広告が表示されます。\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\nこれらの値は、次のように Carbon の CDN スクリプトを呼び出すために使用されます。\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nCarbon Ads の設定について詳しくは、[Carbon Ads のウェブサイト](https://www.carbonads.net/)を参照してください。\n"
  },
  {
    "path": "docs/ja/reference/default-theme-config.md",
    "content": "# デフォルトテーマの設定 {#default-theme-config}\n\nテーマ設定では、テーマのカスタマイズができます。設定ファイルの `themeConfig` オプションで定義します。\n\n```ts\nexport default {\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // テーマ関連の設定\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**このページで説明するオプションは、デフォルトテーマにのみ適用されます。** テーマによって期待する設定は異なります。カスタムテーマを使用する場合、ここで定義したテーマ設定オブジェクトはテーマへ渡され、テーマ側がそれに基づいて条件付きの挙動を定義できます。\n\n## i18nRouting\n\n- 型: `boolean`\n\nロケールを `zh` のように切り替えると、URL は `/foo`（または `/en/foo/`）から `/zh/foo` に変わります。`themeConfig.i18nRouting` を `false` に設定すると、この挙動を無効化できます。\n\n## logo\n\n- 型: `ThemeableImage`\n\nサイトタイトルの直前に、ナビゲーションバーに表示されるロゴ。パス文字列、またはライト／ダークモードで異なるロゴを設定するオブジェクトを受け取ります。\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- 型: `string | false`\n\nナビゲーション内の既定サイトタイトル（アプリ設定の `title`）を置き換えます。`false` の場合、ナビのタイトルを非表示にします。ロゴ自体にサイト名が含まれている場合に便利です。\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hello World'\n  }\n}\n```\n\n## nav\n\n- 型: `NavItem`\n\nナビゲーションメニューの設定。[デフォルトテーマ: ナビ](./default-theme-nav#navigation-links) を参照してください。\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- 型: `Sidebar`\n\nサイドバーメニューの設定。[デフォルトテーマ: サイドバー](./default-theme-sidebar) を参照してください。\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n}\n\nexport type SidebarItem = {\n  /**\n   * 項目のテキストラベル\n   */\n  text?: string\n\n  /**\n   * 項目のリンク\n   */\n  link?: string\n\n  /**\n   * 子項目\n   */\n  items?: SidebarItem[]\n\n  /**\n   * 指定しない場合、グループは折りたたみ不可。\n   *\n   * `true` なら折りたたみ可能でデフォルト折りたたみ\n   *\n   * `false` なら折りたたみ可能だがデフォルト展開\n   */\n  collapsed?: boolean\n\n  /**\n   * 子項目のベースパス\n   */\n  base?: string\n\n  /**\n   * 前／次リンクのフッターに表示するテキストをカスタマイズ\n   */\n  docFooterText?: string\n\n  rel?: string\n  target?: string\n}\n```\n\n## aside\n\n- 型: `boolean | 'left'`\n- 既定値: `true`\n- ページごとに [frontmatter](./frontmatter-config#aside) で上書き可能\n\n`false` でサイドコンテナの描画を無効化。\\\n`true` で右側に表示。\\\n`left` で左側に表示。\n\nすべてのビューポートで無効にしたい場合は、代わりに `outline: false` を使用してください。\n\n## outline\n\n- 型: `Outline | Outline['level'] | false`\n- レベルはページごとに [frontmatter](./frontmatter-config#outline) で上書き可能\n\n`false` でアウトラインコンテナの描画を無効化。詳細は以下を参照：\n\n```ts\ninterface Outline {\n  /**\n   * アウトラインに表示する見出しレベル\n   * 単一の数値なら、そのレベルのみ表示\n   * タプルなら最小レベルと最大レベル\n   * `'deep'` は `[2, 6]` と同じ（`<h2>` 〜 `<h6>` を表示）\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * アウトラインに表示するタイトル\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- 型: `SocialLink[]`\n\nナビゲーションにアイコン付きのソーシャルリンクを表示します。\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      // simple-icons (https://simpleicons.org/) の任意のアイコンを指定可能\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // SVG 文字列を渡してカスタムアイコンも可\n      {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // アクセシビリティ向けにカスタムラベルも指定可（推奨）\n        ariaLabel: 'cool link'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- 型: `Footer`\n- ページごとに [frontmatter](./frontmatter-config#footer) で上書き可能\n\nフッター設定。メッセージや著作権表示を追加できますが、ページにサイドバーがある場合はデザイン上表示されません。\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- 型: `EditLink`\n- ページごとに [frontmatter](./frontmatter-config#editlink) で上書き可能\n\n「このページを編集」リンクを表示します（GitHub/GitLab など）。詳細は [デフォルトテーマ: 編集リンク](./default-theme-edit-link) を参照。\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- 型: `LastUpdatedOptions`\n\n最終更新の文言と日付フォーマットをカスタマイズします。\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Updated at',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- 型: `AlgoliaSearch`\n\n[Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) によるサイト内検索の設定。[デフォルトテーマ: 検索](./default-theme-search) を参照。\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\n完全なオプションは[こちら](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)。\n\n## carbonAds {#carbon-ads}\n\n- 型: `CarbonAdsOptions`\n\n[Carbon Ads](https://www.carbonads.net/) を表示します。\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\n詳細は [デフォルトテーマ: Carbon Ads](./default-theme-carbon-ads) を参照。\n\n## docFooter\n\n- 型: `DocFooter`\n\n前／次リンクの上に表示される文言をカスタマイズします。英語以外のドキュメントで便利。前／次リンク自体をグローバルに無効化することも可能。ページごとに切り替えたい場合は [frontmatter](./default-theme-prev-next-links) を使用します。\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Pagina prior',\n      next: 'Proxima pagina'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- 型: `string`\n- 既定値: `Appearance`\n\nダークモード切替スイッチのラベル（モバイル表示のみ）をカスタマイズします。\n\n## lightModeSwitchTitle\n\n- 型: `string`\n- 既定値: `Switch to light theme`\n\nホバー時に表示されるライトモード切替のタイトルをカスタマイズします。\n\n## darkModeSwitchTitle\n\n- 型: `string`\n- 既定値: `Switch to dark theme`\n\nホバー時に表示されるダークモード切替のタイトルをカスタマイズします。\n\n## sidebarMenuLabel\n\n- 型: `string`\n- 既定値: `Menu`\n\nサイドバーメニューのラベル（モバイル表示のみ）をカスタマイズします。\n\n## returnToTopLabel\n\n- 型: `string`\n- 既定値: `Return to top`\n\nトップに戻るボタンのラベル（モバイル表示のみ）をカスタマイズします。\n\n## langMenuLabel\n\n- 型: `string`\n- 既定値: `Change language`\n\nナビバーの言語切替ボタンの aria-label をカスタマイズします。[i18n](../guide/i18n) を使う場合に有効です。\n\n## skipToContentLabel\n\n- 型: `string`\n- 既定値: `Skip to content`\n\nコンテンツへスキップリンクのラベルをカスタマイズします。キーボード操作時に表示されます。\n\n## externalLinkIcon\n\n- 型: `boolean`\n- 既定値: `false`\n\nMarkdown 内の外部リンクの横に外部リンクアイコンを表示するかどうか。\n\n## `useLayout` <Badge type=\"info\" text=\"composable\" />\n\nレイアウト関連のデータを返します。返り値の型は次のとおりです。\n\n```ts\ninterface {\n  isHome: ComputedRef<boolean>\n\n  sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>\n  sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>\n  hasSidebar: ComputedRef<boolean>\n  isSidebarEnabled: ComputedRef<boolean>\n\n  hasAside: ComputedRef<boolean>\n  leftAside: ComputedRef<boolean>\n\n  headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>\n  hasLocalNav: ComputedRef<boolean>\n}\n```\n\n**例:**\n\n```vue\n<script setup>\nimport { useLayout } from 'vitepress/theme'\n\nconst { hasSidebar } = useLayout()\n</script>\n\n<template>\n  <div v-if=\"hasSidebar\">サイドバーがあるときだけ表示</div>\n</template>\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-edit-link.md",
    "content": "# 編集リンク {#edit-link}\n\n## サイトレベルの設定 {#site-level-config}\n\n編集リンクは、GitHub や GitLab などの Git 管理サービスでそのページを編集できるリンクを表示します。有効化するには、設定に `themeConfig.editLink` オプションを追加します。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\n`pattern` オプションはリンクの URL 構造を定義します。`:path` はページパスに置き換えられます。\n\nまた、引数に [`PageData`](./runtime-api#usedata) を受け取り、URL 文字列を返す純粋関数を指定することもできます。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nこの関数はブラウザでシリアライズされ実行されるため、副作用を持たず、スコープ外のものへアクセスしないでください。\n\n既定では、ドキュメント下部に「Edit this page」というリンクテキストが表示されます。`text` オプションでこの文言をカスタマイズできます。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'GitHub でこのページを編集'\n    }\n  }\n}\n```\n\n## フロントマターでの設定 {#frontmatter-config}\n\nページごとに無効化するには、フロントマターで `editLink` オプションを使用します。\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-footer.md",
    "content": "# フッター {#footer}\n\n`themeConfig.footer` を設定すると、ページ下部にグローバルフッターが表示されます。\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // 著作権表示の直前に表示されるメッセージ\n  message?: string\n\n  // 実際の著作権表記\n  copyright?: string\n}\n```\n\n上記の設定は HTML 文字列にも対応しています。たとえば、フッター内のテキストにリンクを含めたい場合は、次のように設定できます。\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">MIT License</a>.',\n      copyright: 'Copyright © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning\n`message` と `copyright` は `<p>` 要素内にレンダリングされるため、\n使用できるのはインライン要素のみです。ブロック要素を追加したい場合は、\n[`layout-bottom`](../guide/extending-default-theme#layout-slots) スロットの利用を検討してください。\n:::\n\nなお、[SideBar](./default-theme-sidebar) が表示されている場合はフッターは表示されません。\n\n## フロントマターでの設定 {#frontmatter-config}\n\nページ単位で無効化するには、フロントマターの `footer` オプションを使用します。\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-home-page.md",
    "content": "# ホームページ {#home-page}\n\nVitePress のデフォルトテーマにはホームページ用レイアウトが用意されています（[このサイトのトップページ](../) でも使われています）。[フロントマター](./frontmatter-config) に `layout: home` を指定すれば、任意のページで利用できます。\n\n```yaml\n---\nlayout: home\n---\n```\n\nただし、この指定だけでは多くのことは起きません。`hero` や `features` などの追加オプションを設定して、ホームページにあらかじめ用意された複数の「セクション」を配置できます。\n\n## ヒーローセクション {#hero-section}\n\nヒーローセクションはホームページの最上部に表示されます。設定例は次のとおりです。\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n  tagline: 概要テキスト...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: はじめる\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: GitHub で見る\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // `text` の上に表示される短い文字列。ブランドカラーで表示。\n  // 製品名のような短い文言を想定。\n  name?: string\n\n  // ヒーローセクションのメインテキスト。`h1` として出力。\n  text: string\n\n  // `text` の下に表示されるタグライン。\n  tagline?: string\n\n  // テキストとタグラインの横に表示する画像。\n  image?: ThemeableImage\n\n  // ヒーローに表示するアクションボタン。\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // ボタンのカラーテーマ。既定は `brand`。\n  theme?: 'brand' | 'alt'\n\n  // ボタンのラベル。\n  text: string\n\n  // ボタンのリンク先。\n  link: string\n\n  // a 要素の target 属性。\n  target?: string\n\n  // a 要素の rel 属性。\n  rel?: string\n}\n```\n\n### name の色をカスタマイズする {#customizing-the-name-color}\n\n`name` にはブランドカラー（`--vp-c-brand-1`）が使われますが、`--vp-home-hero-name-color` 変数を上書きして色を変更できます。\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nさらに、`--vp-home-hero-name-background` を組み合わせると、`name` にグラデーションを適用できます。\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## フィーチャーセクション {#features-section}\n\nフィーチャーセクションでは、ヒーロー直下に任意の数の機能説明を並べられます。フロントマターに `features` オプションを指定して設定します。\n\n各フィーチャーにはアイコン（絵文字または画像）を指定できます。アイコンが画像（svg, png, jpeg など）の場合は、**適切な幅・高さ** を指定してください。必要に応じて説明テキストや実サイズ、ライト／ダーク用の差し替えも指定できます。\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: いつでもシンプル＆ミニマル\n    details: 概要テキスト...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: もうひとつの便利機能\n    details: 概要テキスト...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: さらに別の機能\n    details: 概要テキスト...\n---\n```\n\n```ts\ninterface Feature {\n  // 各フィーチャーボックスに表示するアイコン。\n  icon?: FeatureIcon\n\n  // フィーチャーのタイトル。\n  title: string\n\n  // フィーチャーの詳細説明。\n  details: string\n\n  // フィーチャーをクリックしたときのリンク（内部・外部どちらも可）。\n  //\n  // 例: `guide/reference/default-theme-home-page` や `https://example.com`\n  link?: string\n\n  // フィーチャー内に表示するリンクテキスト。\n  // `link` と併用するのが最適。\n  //\n  // 例: `Learn more`, `Visit page` など\n  linkText?: string\n\n  // `link` 用の rel 属性。\n  //\n  // 例: `external`\n  rel?: string\n\n  // `link` 用の target 属性。\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## Markdown コンテンツ {#markdown-content}\n\n`---` で区切るフロントマターの下に Markdown を書くだけで、ホームページに追加コンテンツを表示できます。\n\n````md\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n---\n\n## はじめに\n\n`npx` を使えば、すぐに VitePress を始められます！\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n"
  },
  {
    "path": "docs/ja/reference/default-theme-last-updated.md",
    "content": "# 最終更新日時 {#last-updated}\n\nページ右下に、コンテンツの最終更新時刻を表示できます。有効化するには、設定に `lastUpdated` オプションを追加します。\n\n::: info\nVitePress は各ファイルの **直近の Git コミットのタイムスタンプ** を用いて「最終更新」を表示します。これを有効にするには、対象の Markdown ファイルが Git にコミットされている必要があります。\n\n内部的には、各ファイルに対して `git log -1 --pretty=\"%ai\"` を実行してタイムスタンプを取得します。すべてのページで同じ更新時刻が表示される場合、（CI 環境でよくある）**浅いクローン（shallow clone）** により Git の履歴が取得できていない可能性があります。\n\n**GitHub Actions** での修正例は次のとおりです。\n\n```yaml{4}\n- name: Checkout\n  uses: actions/checkout@v5\n  with:\n    fetch-depth: 0\n```\n\n他の CI/CD プラットフォームでも同様の設定が用意されています。\n\nもしそのようなオプションが使えない場合は、`package.json` のビルドスクリプトで手動フェッチを前置してください。\n\n```json\n\"docs:build\": \"git fetch --unshallow && vitepress build docs\"\n```\n:::\n\n## サイトレベルの設定 {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## フロントマターでの設定 {#frontmatter-config}\n\nページ単位で無効化するには、フロントマターで `lastUpdated` を指定します。\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nより詳しくは [デフォルトテーマ: 最終更新](./default-theme-config#lastupdated) を参照してください。テーマレベルで truthy な値を設定すると、サイトまたはページで明示的に無効化しない限り、この機能は有効になります。\n"
  },
  {
    "path": "docs/ja/reference/default-theme-layout.md",
    "content": "# レイアウト {#layout}\n\nページの [フロントマター](./frontmatter-config) の `layout` オプションでページのレイアウトを選択できます。利用可能なレイアウトは `doc`、`page`、`home` の 3 種類です。何も指定しない場合は `doc` として扱われます。\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## Doc レイアウト {#doc-layout}\n\n`doc` は既定のレイアウトで、Markdown 全体を「ドキュメント」風にスタイリングします。コンテンツ全体を `vp-doc` という CSS クラスでラップし、その配下の要素にスタイルを適用します。\n\n`p` や `h2` などほぼすべての汎用要素に特別なスタイルが当たります。そのため、Markdown 内にカスタム HTML を追加した場合も、これらのスタイルの影響を受ける点に注意してください。\n\nまた、以下のようなドキュメント特有の機能も提供します。これらはこのレイアウトでのみ有効になります。\n\n- 編集リンク（Edit Link）\n- 前後リンク（Prev / Next Link）\n- アウトライン（Outline）\n- [Carbon 広告](./default-theme-carbon-ads)\n\n## Page レイアウト {#page-layout}\n\n`page` は「ブランクページ」として扱われます。Markdown はパースされ、[Markdown 拡張](../guide/markdown) も `doc` と同様に機能しますが、既定のスタイルは適用されません。\n\nこのレイアウトでは、VitePress テーマにマークアップを干渉させず、すべてを自分でスタイルできます。独自のカスタムページを作成したい場合に便利です。\n\nなお、このレイアウトでも、ページがサイドバー設定に一致する場合はサイドバーが表示されます。\n\n## Home レイアウト {#home-layout}\n\n`home` はテンプレート化された「ホームページ」を生成します。このレイアウトでは、`hero` や `features` などの追加オプションでコンテンツをさらにカスタマイズできます。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照してください。\n\n## レイアウトなし {#no-layout}\n\nレイアウトを一切適用したくない場合は、フロントマターで `layout: false` を指定します。これは（既定でサイドバー／ナビバー／フッターなしの）完全にカスタマイズ可能なランディングページを作りたい場合に役立ちます。\n\n## カスタムレイアウト {#custom-layout}\n\nカスタムレイアウトを使用することもできます。\n\n```md\n---\nlayout: foo\n---\n```\n\nこれは、コンテキストに登録された `foo` という名前のコンポーネントを探します。たとえば、`.vitepress/theme/index.ts` でグローバル登録できます。\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-nav.md",
    "content": "# ナビゲーション {#nav}\n\nナビはページ上部に表示されるナビゲーションバーです。サイトタイトル、グローバルメニューリンクなどを含みます。\n\n## サイトタイトルとロゴ {#site-title-and-logo}\n\n既定では、ナビには [`config.title`](./site-config#title) の値が表示されます。ナビに表示する文字列を変更したい場合は、`themeConfig.siteTitle` にカスタム文字列を指定します。\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'My Custom Title'\n  }\n}\n```\n\nサイトのロゴがある場合は、画像へのパスを渡すと表示できます。ロゴは `public` 直下に配置し、絶対パスで指定してください。\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nロゴを追加すると、サイトタイトルと並んで表示されます。ロゴだけを表示したい場合は、`siteTitle` を `false` に設定してタイトル文字列を非表示にできます。\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nダーク／ライトモードでロゴを切り替えたり、`alt` 属性を付けたい場合は、ロゴにオブジェクトを渡すこともできます。詳細は [`themeConfig.logo`](./default-theme-config#logo) を参照してください。\n\n## ナビゲーションリンク {#navigation-links}\n\n`themeConfig.nav` オプションでナビにリンクを追加できます。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      { text: 'Config', link: '/config' },\n      { text: 'Changelog', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` はナビに表示される文字列、`link` はクリック時に遷移するリンクです。内部リンクは `.md` 拡張子を付けず、必ず `/` で始めるようにしてください。\n\n`link` には、[`PageData`](./runtime-api#usedata) を受け取ってパスを返す関数を指定することもできます。\n\nナビリンクはドロップダウンメニューにもできます。リンクオプションに `items` を設定してください。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nなお、ドロップダウンのタイトル（上の例の `Dropdown Menu`）には `link` は設定できません。ドロップダウンを開くボタンになるためです。\n\nさらに、ドロップダウン内を「セクション」に分けることもできます（入れ子の `items` を使います）。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // セクションのタイトル\n            text: 'Section A Title',\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // タイトルは省略することも可能\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### リンクの「アクティブ」状態をカスタマイズ {#customize-link-s-active-state}\n\n現在のページが特定のパス配下にあるとき、該当するナビ項目がハイライトされます。一致させるパスをカスタマイズしたい場合は、`activeMatch` に **正規表現文字列** を指定します。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // ユーザーが `/config/` 配下にいるときにアクティブになる\n      {\n        text: 'Guide',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch` は正規表現 **オブジェクト** ではなく、**文字列** で指定してください。ビルド時のシリアライズの都合で `RegExp` は使用できません。\n:::\n\n### リンクの `target` と `rel` をカスタマイズ {#customize-link-s-target-and-rel-attributes}\n\n既定では、リンクが外部かどうかに応じて VitePress が `target` と `rel` を自動設定します。必要であれば明示的に指定することもできます。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Merchandise',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## ソーシャルリン� {#social-links}\n\n[`socialLinks`](./default-theme-config#sociallinks) を参照してください。\n\n## カスタムコンポーネント {#custom-components}\n\n`component` オプションを使って、ナビゲーションバーにカスタムコンポーネントを配置できます。`component` には Vue コンポーネント名を指定し、[Theme.enhanceApp](../guide/custom-theme#theme-interface) で **グローバル登録** しておく必要があります。\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'My Menu',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // コンポーネントに渡す任意の props\n            props: {\n              title: 'My Custom Component'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\n次に、コンポーネントをグローバル登録します。\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\nコンポーネントはナビゲーションバー内にレンダリングされます。VitePress は次の追加 props をコンポーネントに提供します。\n\n- `screenMenu`: モバイルのナビメニュー内にあるかどうかを示す任意の boolean\n\ne2e テスト内の例は[こちら](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress)を参照してください。\n"
  },
  {
    "path": "docs/ja/reference/default-theme-prev-next-links.md",
    "content": "# 前／次リンク {#prev-next-links}\n\nドキュメントのフッターに表示される「前のページ」「次のページ」のテキストとリンクをカスタマイズできます。サイドバーに表示しているタイトルとは別の文言を使いたい場合や、フッターを無効化したり、サイドバーに含まれていないページへリンクしたい場合に便利です。\n\n## prev\n\n- 型: `string | false | { text?: string; link?: string }`\n\n- 詳細:\n\n  前のページへのリンクに表示するテキスト／リンクを指定します。フロントマターで設定しない場合は、サイドバー設定から自動推測されます。\n\n- 例:\n\n  - テキストだけをカスタマイズ:\n\n    ```yaml\n    ---\n    prev: 'Get Started | Markdown'\n    ---\n    ```\n\n  - テキストとリンクの両方をカスタマイズ:\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - 前のページを非表示にする:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\n`prev` と同様ですが、次のページ用の設定です。\n"
  },
  {
    "path": "docs/ja/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# 検索 {#search}\n\n## ローカル検索 {#local-search}\n\nVitePress は、[minisearch](https://github.com/lucaong/minisearch/) によるブラウザ内インデックスを使った曖昧一致の全文検索をサポートします。有効化するには、`.vitepress/config.ts` で `themeConfig.search.provider` を `'local'` に設定します。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\n表示例:\n\n![screenshot of the search modal](/search.png)\n\n代わりに [Algolia DocSearch](#algolia-search) や、次のコミュニティ製プラグインを使うこともできます。\n\n- <https://www.npmjs.com/package/vitepress-plugin-search>\n- <https://www.npmjs.com/package/vitepress-plugin-pagefind>\n- <https://www.npmjs.com/package/@orama/plugin-vitepress>\n- <https://www.npmjs.com/package/vitepress-plugin-typesense>\n\n### i18n {#local-search-i18n}\n\n多言語検索を行う設定例です。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          ja: { // 既定ロケールを翻訳する場合は `root` にしてください\n            translations: {\n              button: {\n                buttonText: '検索',\n                buttonAriaLabel: '検索'\n              },\n              modal: {\n                displayDetails: '詳細一覧を表示',\n                resetButtonTitle: '検索をリセット',\n                backButtonTitle: '検索を閉じる',\n                noResultsText: '結果が見つかりません',\n                footer: {\n                  selectText: '選択',\n                  selectKeyAriaLabel: 'Enter',\n                  navigateText: '移動',\n                  navigateUpKeyAriaLabel: '上矢印',\n                  navigateDownKeyAriaLabel: '下矢印',\n                  closeText: '閉じる',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### miniSearch のオプション {#minisearch-options}\n\nMiniSearch の設定例です。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n詳しくは [MiniSearch のドキュメント](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html) を参照してください。\n\n### コンテンツレンダラーのカスタマイズ {#custom-content-renderer}\n\nインデックス前に Markdown コンテンツをレンダリングする関数をカスタマイズできます。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // HTML 文字列を返す\n        }\n      }\n    }\n  }\n})\n```\n\nこの関数はクライアント側のサイトデータからは除外されるため、Node.js の API を使用できます。\n\n#### 例: 検索対象からページを除外する {#example-excluding-pages-from-search}\n\nフロントマターに `search: false` を追加すると、そのページを検索対象から除外できます。あるいは次のようにもできます。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 注意\nカスタムの `_render` 関数を提供する場合、`search: false` の処理は自分で行う必要があります。また、`env` は `md.renderAsync` の呼び出し前には完全ではないため、`frontmatter` などの任意プロパティのチェックはその後に行ってください。\n:::\n\n#### 例: コンテンツの変換 — 見出しアンカーを追加 {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Algolia 検索 {#algolia-search}\n\nVitePress は [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) によるサイト検索をサポートします。導入は公式のガイドを参照してください。`.vitepress/config.ts` では最低限次の設定が必要です。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\n多言語検索の設定例です。\n\n<details>\n<summary>クリックして展開</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\n詳しくは[公式 Algolia ドキュメント](https://docsearch.algolia.com/docs/api#translations)を参照してください。すぐに始めるには、このサイトで使っている翻訳を[GitHub リポジトリ](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code)からコピーすることもできます。\n\n### Algolia Ask AI のサポート {#ask-ai}\n\n**Ask AI** を有効にするには、`options` 内に `askAi` オプション（またはその一部）を指定します。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"あなたのアシスタントID\"\n        // または\n        askAi: {\n          // 最低限、Algolia から受け取った assistantId を指定する必要があります\n          assistantId: 'XXXYYY',\n          // 任意の上書き — 省略した場合は上位の appId/apiKey/indexName を再利用\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 注意\nキーワード検索を既定にして Ask AI を使わない場合は、`askAi` を指定しないでください。\n:::\n\n### Ask AI サイドパネル {#ask-ai-side-panel}\n\nDocSearch v4.5+ はオプションの **Ask AI サイドパネル**をサポートしています。有効にすると、デフォルトで **Ctrl/Cmd+I** で開くことができます。[サイドパネル API リファレンス](https://docsearch.algolia.com/docs/sidepanel/api-reference)にオプションの完全なリストがあります。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // @docsearch/sidepanel-js SidepanelProps API をミラー\n            panel: {\n              variant: 'floating', // または 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nキーボードショートカットを無効にする必要がある場合は、サイドパネルの `keyboardShortcuts` オプションを使用してください：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### モード (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nVitePress がキーワード検索と Ask AI を統合する方法をオプションで制御できます：\n\n- `mode: 'auto'`（デフォルト）：キーワード検索が設定されている場合は `hybrid` を推論し、それ以外の場合は Ask AI サイドパネルが設定されている場合は `sidePanel` を推論します。\n- `mode: 'sidePanel'`：サイドパネルのみを強制（キーワード検索ボタンを非表示）。\n- `mode: 'hybrid'`：キーワード検索モーダル + Ask AI サイドパネルを有効化（キーワード検索設定が必要）。\n- `mode: 'modal'`：Ask AI を DocSearch モーダル内に保持（サイドパネルを設定した場合でも）。\n\n#### Ask AI のみ（キーワード検索なし） {#ask-ai-only}\n\n**Ask AI サイドパネルのみ**を使用する場合は、トップレベルのキーワード検索設定を省略し、`askAi` の下に認証情報を提供できます：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### クローラー設定 {#crawler-config}\n\nこのサイトで使用している設定を元にした例です。\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/ja/reference/default-theme-sidebar.md",
    "content": "# サイドバー {#sidebar}\n\nサイドバーはドキュメントの主要なナビゲーションブロックです。[`themeConfig.sidebar`](./default-theme-config#sidebar) でメニューを設定できます。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 基本 {#the-basics}\n\n最もシンプルな構成は、リンクの配列を 1 つ渡す方法です。第 1 階層のアイテムがサイドバーの「セクション」を表します。各セクションは `text`（セクションのタイトル）と、実際のナビゲーションリンクである `items` を持ちます。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        items: [\n          { text: 'Item A', link: '/item-a' },\n          { text: 'Item B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Section Title B',\n        items: [\n          { text: 'Item C', link: '/item-c' },\n          { text: 'Item D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n各 `link` は `/` で始まる実ファイルへのパスを指定します。リンクの末尾を `/` で終わらせると、対応するディレクトリの `index.md` が表示されます。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          // `/guide/index.md` を表示\n          { text: 'Introduction', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nサイドバーのアイテムは、ルートから数えて最大 6 階層まで入れ子にできます。7 階層以上は無視され、表示されません。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Level 1',\n        items: [\n          {\n            text: 'Level 2',\n            items: [\n              {\n                text: 'Level 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 複数のサイドバー {#multiple-sidebars}\n\nページのパスに応じて異なるサイドバーを表示できます。たとえば、このサイトのように「Guide」セクションと「Config」セクションでナビゲーションを分けたい場合に便利です。\n\nまず、対象のセクションごとにディレクトリを分けてページを配置します。\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\n次に、各セクション用のサイドバーを設定します。この場合、配列ではなくオブジェクトを渡します。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // ユーザーが `guide` ディレクトリ配下にいるときに表示\n      '/guide/': [\n        {\n          text: 'Guide',\n          items: [\n            { text: 'Index', link: '/guide/' },\n            { text: 'One', link: '/guide/one' },\n            { text: 'Two', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // ユーザーが `config` ディレクトリ配下にいるときに表示\n      '/config/': [\n        {\n          text: 'Config',\n          items: [\n            { text: 'Index', link: '/config/' },\n            { text: 'Three', link: '/config/three' },\n            { text: 'Four', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## 折りたたみ可能なサイドバーグループ {#collapsible-sidebar-groups}\n\nサイドバーグループに `collapsed` オプションを追加すると、各セクションの開閉トグルが表示されます。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\n既定ではすべてのセクションが「開いた」状態です。初回表示時に「閉じた」状態にしたい場合は、`collapsed` を `true` に設定します。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/ja/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Developer',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# チームページ {#team-page}\n\nチームを紹介したい場合は、Team コンポーネント群を使ってチームページを構成できます。使い方は 2 通りあり、ドキュメントページに埋め込む方法と、専用のチームページを作成する方法があります。\n\n## ページ内にメンバー一覧を表示する {#show-team-members-in-a-page}\n\n任意のページでチームメンバーの一覧を表示するには、`vitepress/theme` からエクスポートされている `<VPTeamMembers>` コンポーネントを使用します。\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# 私たちのチーム\n\n私たちの素晴らしいチームを紹介します。\n\n<VPTeamMembers size=\"small\" :members />\n```\n\n上記のように、カード風の要素でメンバーが表示されます。下図のような見た目になります。\n\n<VPTeamMembers size=\"small\" :members />\n\n`<VPTeamMembers>` コンポーネントには `small` と `medium` の 2 種類のサイズがあります。好みによりますが、ドキュメントページ内で使う場合は `small` が馴染みやすいことが多いでしょう。各メンバーに「説明文」や「スポンサー」ボタンなど、追加のプロパティを付けることもできます。詳細は [`<VPTeamMembers>`](#vpteammembers) を参照してください。\n\n小規模なチームで専用ページまでは不要な場合や、文脈上の参考として一部のメンバーのみを紹介したい場合は、ドキュメントページへ埋め込む方法が適しています。\n\nメンバーが多い場合や、より広いスペースで紹介したい場合は、[専用のチームページを作成する](#専用のチームページを作成する) ことを検討してください。\n\n## 専用のチームページを作成する {#create-a-full-team-page}\n\nドキュメントページにメンバーを追加する代わりに、カスタムの [ホームページ](./default-theme-home-page) と同様、専用のチームページを作成することもできます。\n\nまず新しい md ファイルを作成します。ファイル名は任意ですが、ここでは `team.md` とします。このファイルでフロントマターに `layout: page` を設定し、その後 `TeamPage` コンポーネント群を使ってページを構成します。\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      私たちのチーム\n    </template>\n    <template #lead>\n      VitePress の開発は国際的なチームによって主導されています。\n      その一部を以下に紹介します。\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\n専用のチームページを作る際は、必ずすべてのチーム関連コンポーネントを `<VPTeamPage>` でラップしてください。レイアウトや余白などが適切に適用されます。\n\n`<VPPageTitle>` はページタイトルのセクションを追加します。タイトルは `<h1>` 見出しになります。`#title` と `#lead` スロットでチームについて説明を書きましょう。\n\n`<VPMembers>` はドキュメントページで使う場合と同様に、メンバー一覧を表示します。\n\n### セクションを追加してメンバーを分ける {#add-sections-to-divide-team-members}\n\nチームページに「セクション」を追加できます。たとえば、コアメンバーとコミュニティパートナーなど、役割ごとにメンバーを分けて説明しやすくできます。\n\nそのためには、先ほど作成した `team.md` に `<VPTeamPageSection>` コンポーネントを追加します。\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>私たちのチーム</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>パートナー</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\n`<VPTeamPageSection>` は `VPTeamPageTitle` と同様に `#title` と `#lead` のスロットを持ち、さらにメンバー表示用の `#members` スロットを備えます。\n\n`#members` スロット内に `<VPTeamMembers>` を配置するのを忘れないでください。\n\n## `<VPTeamMembers>`\n\n`<VPTeamMembers>` コンポーネントは、与えられたメンバー配列を表示します。\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // 各メンバーカードのサイズ。既定は `medium`。\n  size?: 'small' | 'medium'\n\n  // 表示するメンバー一覧。\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // メンバーのアバター画像\n  avatar: string\n\n  // メンバー名\n  name: string\n\n  // 名前の下に表示する肩書き（例: Developer, Software Engineer など）\n  title?: string\n\n  // 所属組織名\n  org?: string\n\n  // 所属組織への URL\n  orgLink?: string\n\n  // メンバーの説明\n  desc?: string\n\n  // ソーシャルリンク（例: GitHub, Twitter など）\n  // Social Links オブジェクトを渡せます。\n  // 参照: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // メンバーのスポンサー用 URL\n  sponsor?: string\n\n  // スポンサーボタンのテキスト。既定は 'Sponsor'\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\n専用のチームページを作成する際のルートコンポーネントです。単一のスロットのみを受け取り、渡されたチーム関連コンポーネント全体に適切なスタイルを適用します。\n\n## `<VPTeamPageTitle>`\n\nページの「タイトル」セクションを追加します。`<VPTeamPage>` の直下に置くのが最適です。`#title` と `#lead` のスロットを受け取ります。\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      私たちのチーム\n    </template>\n    <template #lead>\n      VitePress の開発は国際的なチームによって主導されています。\n      その一部を以下に紹介します。\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\nチームページ内に「セクション」を作成します。`#title`、`#lead`、`#members` の各スロットを受け取ります。`<VPTeamPage>` の中に必要な数だけ追加できます。\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>パートナー</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/ja/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# フロントマター設定 {#frontmatter-config}\n\nフロントマターはページ単位の設定を可能にします。各 Markdown ファイルで、サイト全体やテーマレベルの設定を上書きできます。フロントマターでしか定義できない項目もあります。\n\n使用例:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\nVue の式内では、グローバル `$frontmatter` を介してフロントマターデータにアクセスできます。\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- 型: `string`\n\nページのタイトルです。[config.title](./site-config#title) と同じ意味で、サイトレベルの設定を上書きします。\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- 型: `string | boolean`\n\nタイトルのサフィックスです。[config.titleTemplate](./site-config#titletemplate) と同じ意味で、サイトレベルの設定を上書きします。\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Vite & Vue powered static site generator\n---\n```\n\n## description\n\n- 型: `string`\n\nページの説明です。[config.description](./site-config#description) と同じ意味で、サイトレベルの設定を上書きします。\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- 型: `HeadConfig[]`\n\n現在のページに追加で挿入する `<head>` タグを指定します。サイトレベル設定で挿入されたタグの後に追加されます。\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## デフォルトテーマ専用 {#default-theme-only}\n\n以下のフロントマター項目は、デフォルトテーマ使用時にのみ適用されます。\n\n### layout\n\n- 型: `doc | home | page`\n- 既定値: `doc`\n\nページのレイアウトを決めます。\n\n- `doc` — Markdown コンテンツにドキュメント向けの既定スタイルを適用します。\n- `home` — 「ホームページ」用の特別なレイアウト。`hero` や `features` を追加指定して、ランディングページを素早く構築できます。\n- `page` — `doc` と似ていますが、コンテンツにスタイルを適用しません。完全にカスタムなページを作りたい場合に便利です。\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"home ページ専用\" />\n\n`layout: home` のときのヒーローセクションの内容を定義します。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照。\n\n### features <Badge type=\"info\" text=\"home ページ専用\" />\n\n`layout: home` のときのフィーチャーセクションに表示する項目を定義します。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照。\n\n### navbar\n\n- 型: `boolean`\n- 既定値: `true`\n\n[ナビゲーションバー](./default-theme-nav) を表示するかどうか。\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- 型: `boolean`\n- 既定値: `true`\n\n[サイドバー](./default-theme-sidebar) を表示するかどうか。\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- 型: `boolean | 'left'`\n- 既定値: `true`\n\n`doc` レイアウトでの aside コンポーネントの位置を定義します。\n\nこの値を `false` にすると aside コンテナを表示しません。\\\n`true` にすると右側に表示します。\\\n`'left'` にすると左側に表示します。\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- 型: `number | [number, number] | 'deep' | false`\n- 既定値: `2`\n\nページのアウトラインに表示する見出しレベルです。[config.themeConfig.outline.level](./default-theme-config#outline) と同じ意味で、サイトレベルの設定を上書きします。\n\n```yaml\n---\noutline: [2, 4]\n---\n```\n\n### lastUpdated\n\n- 型: `boolean | Date`\n- 既定値: `true`\n\n現在のページのフッターに[最終更新](./default-theme-last-updated)を表示するかどうか。日時を指定した場合は、その日時が Git の最終更新時刻の代わりに表示されます。\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- 型: `boolean`\n- 既定値: `true`\n\n現在のページのフッターに[編集リンク](./default-theme-edit-link)を表示するかどうか。\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- 型: `boolean`\n- 既定値: `true`\n\n[フッター](./default-theme-footer) を表示するかどうか。\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- 型: `string`\n\n特定のページに追加のクラス名を付与します。\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nその後、`.vitepress/theme/custom.css` でこのページ専用のスタイルを記述できます。\n\n```css\n.custom-page-class {\n  /* ページ固有のスタイル */\n}\n```\n\n### isHome\n\n- 型: `boolean`\n\nデフォルトテーマは通常、`frontmatter.layout === 'home'` のチェックに基づいてホームページかどうかを判断します。\\\nカスタムレイアウトでホームページ用の要素を強制的に表示したい場合に便利です。\n\n```yaml\n---\nisHome: true\n---\n```\n"
  },
  {
    "path": "docs/ja/reference/runtime-api.md",
    "content": "# ランタイム API {#runtime-api}\n\nVitePress には、アプリのデータへアクセスするための組み込み API がいくつか用意されています。さらに、グローバルに使用できる組み込みコンポーネントも提供されています。\n\nヘルパーメソッドは `vitepress` からグローバルインポートでき、主にカスタムテーマの Vue コンポーネントで使われます。Markdown ファイルは Vue の [Single File Component](https://vuejs.org/guide/scaling-up/sfc.html) にコンパイルされるため、`.md` ファイル内でも使用できます。\n\n`use*` で始まるメソッドは [Vue 3 Composition API](https://vuejs.org/guide/introduction.html#composition-api) の関数（Composable）で、`setup()` または `<script setup>` の中でのみ使用できます。\n\n## `useData` <Badge type=\"info\" text=\"composable\" />\n\nページ固有のデータを返します。戻り値の型は次のとおりです。\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * サイト全体のメタデータ\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * .vitepress/config.js の themeConfig\n   */\n  theme: Ref<T>\n  /**\n   * ページ単位のメタデータ\n   */\n  page: Ref<PageData>\n  /**\n   * ページのフロントマター\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * 動的ルートのパラメータ\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  /**\n   * 現在の location hash\n   */\n  hash: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**使用例:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" />\n\n現在のルートオブジェクトを返します。型は次のとおりです。\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" />\n\nVitePress のルーターインスタンスを返し、プログラムで別ページへ遷移できます。\n\n```ts\ninterface Router {\n  /**\n   * 現在のルート\n   */\n  route: Route\n  /**\n   * 新しい URL へ遷移\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * ルートが変わる前に呼ばれる。`false` を返すと遷移をキャンセル\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * ページコンポーネントが読み込まれる前（履歴が更新された後）に呼ばれる。\n   * `false` を返すと遷移をキャンセル\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * ページコンポーネントが読み込まれた後（更新前）に呼ばれる\n   */\n  onAfterPageLoad?: (to: string) => Awaitable<void>\n  /**\n   * ルートが変わった後に呼ばれる\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" />\n\n- **型**: `(path: string) => string`\n\n設定された [`base`](./site-config#base) を指定の URL パスに付与します。[Base URL](../guide/asset-handling#base-url) も参照。\n\n## `<Content />` <Badge type=\"info\" text=\"component\" />\n\nレンダリング済みの Markdown コンテンツを表示します。［独自テーマの作成時］(../guide/custom-theme) に便利です。\n\n```vue\n<template>\n  <h1>Custom Layout!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" />\n\nスロット内容をクライアント側でのみレンダリングします。\n\nVitePress アプリは静的ビルド時に Node.js 上でサーバーレンダリングされるため、Vue の使用はユニバーサルコードの要件に従う必要があります。要するに、ブラウザ／DOM API へのアクセスは beforeMount / mounted フック内に限定してください。\n\nSSR 非対応（例: カスタムディレクティブを含む）なコンポーネントを使用・デモする場合は、`ClientOnly` でラップできます。\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- 関連: [SSR 互換性](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" />\n\nVue の式内で現在ページの [フロントマター](../guide/frontmatter) に直接アクセスします。\n\n```md\n---\ntitle: Hello\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" />\n\nVue の式内で現在ページの [動的ルートのパラメータ](../guide/routing#dynamic-routes) に直接アクセスします。\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/ja/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# サイト設定 {#site-config}\n\nサイト設定では、サイト全体のグローバル設定を定義します。アプリ設定オプションは、使用するテーマに関係なく、すべての VitePress サイトに適用されます。たとえば、ベースディレクトリやサイトのタイトルなどです。\n\n## 概要 {#overview}\n\n### 設定ファイルの解決 {#config-resolution}\n\n設定ファイルは常に `<root>/.vitepress/config.[ext]` から解決されます。`<root>` は VitePress の[プロジェクトルート](../guide/routing#root-and-source-directory)で、`[ext]` にはサポートされる拡張子が入ります。TypeScript はそのまま使えます。サポートされる拡張子は `.js`、`.ts`、`.mjs`、`.mts` です。\n\n設定ファイルでは ES Modules 構文の使用を推奨します。設定オブジェクトをデフォルトエクスポートしてください。\n\n```ts\nexport default {\n  // アプリレベルの設定\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n  ...\n}\n```\n\n::: details 動的（非同期）設定\n\n設定を動的に生成する必要がある場合は、関数をデフォルトエクスポートすることもできます。例:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // アプリレベル設定\n    lang: 'en-US',\n    title: 'VitePress',\n    description: 'Vite & Vue powered static site generator.',\n\n    // テーマレベル設定\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nトップレベル `await` も使用できます。例:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // アプリレベル設定\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // テーマレベル設定\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### 設定のインテリセンス {#config-intellisense}\n\n`defineConfig` ヘルパーを使うと、TypeScript による補完が効きます。対応 IDE であれば、JavaScript と TypeScript のどちらでも動作します。\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### 型付きのテーマ設定 {#typed-theme-config}\n\nデフォルトでは、`defineConfig` はデフォルトテーマのテーマ設定型を想定します。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // 型は `DefaultTheme.Config`\n  }\n})\n```\n\nカスタムテーマを使用しており、そのテーマ設定に型チェックを効かせたい場合は、代わりに `defineConfigWithTheme` を使い、ジェネリクスでカスタムテーマの設定型を渡してください。\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // 型は `ThemeConfig`\n  }\n})\n```\n\n### Vite・Vue・Markdown の設定 {#vite-vue-markdown-config}\n\n- **Vite**\n\n  Vite の設定は VitePress 設定の [vite](#vite) オプションで行えます。別途 Vite の設定ファイルを作る必要はありません。\n\n- **Vue**\n\n  VitePress には公式の Vue プラグイン（[@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)）が同梱されています。オプションは VitePress 設定の [vue](#vue) から指定できます。\n\n- **Markdown**\n\n  既定の [Markdown-It](https://github.com/markdown-it/markdown-it) インスタンスは、VitePress 設定の [markdown](#markdown) オプションでカスタマイズできます。\n\n## サイトメタデータ {#site-metadata}\n\n### title\n\n- 型: `string`\n- 既定値: `VitePress`\n- ページ単位での上書き: [frontmatter](./frontmatter-config#title)\n\nサイトのタイトル。デフォルトテーマではナビバーに表示されます。\n\n[`titleTemplate`](#titletemplate) を定義していない場合、個々のページタイトルの既定のサフィックスとしても使われます。各ページの最終タイトルは、そのページの最初の `<h1>` 見出しのテキストに、グローバルの `title` をサフィックスとして結合したものになります。次の設定とページ内容の例:\n\n```ts\nexport default {\n  title: 'My Awesome Site'\n}\n```\n\n```md\n# Hello\n```\n\nこのページのタイトルは `Hello | My Awesome Site` になります。\n\n### titleTemplate\n\n- 型: `string | boolean`\n- ページ単位での上書き: [frontmatter](./frontmatter-config#titletemplate)\n\n各ページタイトルのサフィックス、またはタイトル全体のカスタマイズができます。例:\n\n```ts\nexport default {\n  title: 'My Awesome Site',\n  titleTemplate: 'Custom Suffix'\n}\n```\n\n```md\n# Hello\n```\n\nこのページのタイトルは `Hello | Custom Suffix` になります。\n\nタイトルの描画方法を完全にカスタマイズするには、`titleTemplate` 内で `:title` シンボルを使います。\n\n```ts\nexport default {\n  titleTemplate: ':title - Custom Suffix'\n}\n```\n\nここで `:title` はページ先頭の `<h1>` から推論されたテキストに置き換えられます。先ほどの例では `Hello - Custom Suffix` になります。\n\n`false` を設定するとタイトルのサフィックスを無効にできます。\n\n### description\n\n- 型: `string`\n- 既定値: `A VitePress site`\n- ページ単位での上書き: [frontmatter](./frontmatter-config#description)\n\nサイトの説明。ページの HTML に `<meta>` タグとして出力されます。\n\n```ts\nexport default {\n  description: 'A VitePress site'\n}\n```\n\n### head\n\n- 型: `HeadConfig[]`\n- 既定値: `[]`\n- ページ単位での追加: [frontmatter](./frontmatter-config#head)\n\nページ HTML の `<head>` に追加で出力する要素。ユーザーが追加したタグは、VitePress のタグの後、`</head>` の直前にレンダリングされます。\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### 例: favicon を追加 {#example-adding-a-favicon}\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // favicon.ico は public に配置。base を設定している場合は /base/favicon.ico を利用\n\n/* 出力結果:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### 例: Google Fonts を追加 {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* 出力結果:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### 例: Service Worker を登録 {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* 出力結果:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### 例: Google Analytics を使用 {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* 出力結果:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- 型: `string`\n- 既定値: `en-US`\n\nサイトの言語属性。ページ HTML の `<html lang=\"en-US\">` として出力されます。\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- 型: `string`\n- 既定値: `/`\n\nサイトをデプロイするベース URL。GitHub Pages などサブパス配下にデプロイする場合に設定が必要です。たとえば `https://foo.github.io/bar/` にデプロイする場合、`base` は `'/bar/'` にします。先頭と末尾は必ずスラッシュにしてください。\n\n`/` で始まる他のオプション内の URL には、この `base` が自動的に付与されます。1 回設定すれば十分です。\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## ルーティング {#routing}\n\n### cleanUrls\n\n- 型: `boolean`\n- 既定値: `false`\n\n`true` にすると、URL の末尾の `.html` を削除します。あわせて [クリーン URL の生成](../guide/routing#generating-clean-urls) も参照してください。\n\n::: warning サーバ設定が必要\nホスティング環境によっては追加の設定が必要です。`/foo` へのアクセス時に **リダイレクトなしで** `/foo.html` を返せるサーバ設定が必要です。\n:::\n\n### rewrites\n\n- 型: `Record<string, string>`\n\nディレクトリと URL のカスタム対応を定義します。詳しくは [ルーティング: ルートのリライト](../guide/routing#route-rewrites) を参照。\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## ビルド {#build}\n\n### srcDir\n\n- 型: `string`\n- 既定値: `.`\n\nMarkdown ページを置くディレクトリ（プロジェクトルートからの相対パス）。[ルートとソースディレクトリ](../guide/routing#root-and-source-directory) も参照。\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- 型: `string[]`\n- 既定値: `undefined`\n\nソースとして除外したい Markdown ファイルにマッチする [glob パターン](https://github.com/mrmlnc/fast-glob#pattern-syntax)。\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- 型: `string`\n- 既定値: `./.vitepress/dist`\n\nビルド出力先（[プロジェクトルート](../guide/routing#root-and-source-directory) からの相対パス）。\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- 型: `string`\n- 既定値: `assets`\n\n生成されるアセットを配置するサブディレクトリ名。パスは [`outDir`](#outdir) の内部で、相対解決されます。\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- 型: `string`\n- 既定値: `./.vitepress/cache`\n\nキャッシュファイル用ディレクトリ（[プロジェクトルート](../guide/routing#root-and-source-directory) からの相対パス）。参考: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir)\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- 型: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- 既定値: `false`\n\n`true` にすると、デッドリンクがあってもビルド失敗にしません。\n\n`'localhostLinks'` にすると、`localhost` へのリンクはチェック対象外にしつつ、その他のデッドリンクではビルドを失敗させます。\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\n正確な URL 文字列、正規表現、カスタムフィルタ関数の配列として指定することもできます。\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // 正確に \"/playground\" を無視\n    '/playground',\n    // すべての localhost リンクを無視\n    /^https?:\\/\\/localhost/,\n    // パスに \"/repl/\" を含むリンクを無視\n    /\\/repl\\//,\n    // カスタム関数: \"ignore\" を含むリンクを無視\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"experimental\" />\n\n- 型: `boolean`\n- 既定値: `false`\n\n`true` にすると、各ページのメタデータを初期 HTML にインラインせず、別の JavaScript チャンクに抽出します。これにより各ページの HTML ペイロードが小さくなり、メタデータをキャッシュ可能にすることで、多数のページがあるサイトでサーバ帯域を削減できます。\n\n### mpa <Badge type=\"warning\" text=\"experimental\" />\n\n- 型: `boolean`\n- 既定値: `false`\n\n`true` にすると、本番アプリは [MPA モード](../guide/mpa-mode) でビルドされます。MPA モードは既定でクライアント JavaScript を 0kb で配信する代わりに、クライアントサイドのナビゲーションを無効にし、相互作用には明示的な opt-in が必要です。\n\n## テーマ関連 {#theming}\n\n### appearance\n\n- 型: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`\n- 既定値: `true`\n\nダークモードを有効にするか（`<html>` に `.dark` クラスを付与）。\n\n- `true` の場合、ユーザーの環境設定に従います。\n- `dark` の場合、ユーザーが切り替えない限りダークを既定にします。\n- `false` の場合、ユーザーはテーマを切り替えできません。\n- `'force-dark'` の場合、常にダークで固定（切替不可）。\n- `'force-auto'` の場合、常にユーザーの環境設定に従い（切替不可）。\n\nこのオプションは、ローカルストレージの `vitepress-theme-appearance` から設定を復元するインラインスクリプトを挿入します。これにより、ページ描画前に `.dark` クラスを適用してフリッカを防ぎます。\n\n`appearance.initialValue` は `'dark' | undefined` のみサポート。Ref や getter は使えません。\n\n### lastUpdated\n\n- 型: `boolean`\n- 既定値: `false`\n\nGit を使って各ページの最終更新時刻を取得します。タイムスタンプは各ページのデータに含まれ、[`useData`](./runtime-api#usedata) から参照できます。\n\nデフォルトテーマ使用時にこのオプションを有効にすると、各ページの最終更新時刻が表示されます。テキストは [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) でカスタマイズ可能です。\n\n## カスタマイズ {#customization}\n\n### markdown\n\n- 型: `MarkdownOption`\n\nMarkdown パーサの設定。VitePress はパーサに [Markdown-it](https://github.com/markdown-it/markdown-it)、構文ハイライトに [Shiki](https://github.com/shikijs/shiki) を使用しています。必要に応じて Markdown 関連の各種オプションを指定できます。\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\n利用可能なオプションは [型定義と JSDoc](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) を参照してください。\n\n### vite\n\n- 型: `import('vite').UserConfig`\n\n内部の Vite 開発サーバ／バンドラへ生の [Vite Config](https://vitejs.dev/config/) を渡します。\n\n```js\nexport default {\n  vite: {\n    // Vite の設定\n  }\n}\n```\n\n### vue\n\n- 型: `import('@vitejs/plugin-vue').Options`\n\n内部の `@vitejs/plugin-vue` インスタンスへオプションをそのまま渡します。\n\n```js\nexport default {\n  vue: {\n    // @vitejs/plugin-vue のオプション\n  }\n}\n```\n\n## ビルドフック {#build-hooks}\n\nVitePress のビルドフックを使うと、サイトに機能や振る舞いを追加できます。\n\n- サイトマップ\n- 検索インデックス\n- PWA\n- Teleport\n\n### buildEnd\n\n- 型: `(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd` はビルド CLI フックです。ビルド（SSG）が完了した後、VitePress CLI プロセスが終了する前に実行されます。\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender\n\n- 型: `(context: SSGContext) => Awaitable<SSGContext | void>`\n\n`postRender` は SSG のレンダリング完了時に呼ばれるビルドフックです。SSG 中の teleport コンテンツの処理に利用できます。\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead\n\n- 型: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` は、各ページを生成する前に head を変換するためのビルドフックです。設定ファイルでは静的に追加できない head 要素を追加できます。追加分のみ返せば、既存のものと自動でマージされます。\n\n::: warning\n`context` 内の値は変更しないでください。\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // 例: index.md（srcDir からの相対）\n  assets: string[] // 解決済みの公開 URL（非 js/css アセット）\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nこのフックは静的サイト生成時のみ呼ばれ、開発中には呼ばれません。開発中に動的な head 要素を追加したい場合は、代わりに [`transformPageData`](#transformpagedata) を使用できます。\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `VitePress`\n            : `${pageData.title} | VitePress`\n      }\n    ])\n  }\n}\n```\n\n#### 例: 正規 URL の `<link>` を追加 {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n\n- 型: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml` は、各ページの内容をディスクへ保存する前に変換するためのビルドフックです。\n\n::: warning\n`context` 内の値は変更しないでください。また、HTML を変更すると実行時のハイドレーション問題を引き起こす可能性があります。\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n\n- 型: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` は各ページの `pageData` を変換するためのフックです。`pageData` を直接変更するか、変更値を返してマージさせることができます。\n\n::: warning\n`context` 内の値は変更しないでください。ネットワークリクエストや重い計算（画像生成など）を行うと開発サーバのパフォーマンスに影響します。`process.env.NODE_ENV === 'production'` を用いた条件分岐を検討してください。\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // あるいはマージ用の値を返す\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/ko/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Vite 및 Vue 기반 정적 사이트 생성기.',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/ko/guide/': { base: '/ko/guide/', items: sidebarGuide() },\n      '/ko/reference/': { base: '/ko/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: '이 페이지 편집 제안하기'\n    },\n\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    },\n\n    docFooter: {\n      prev: '이전',\n      next: '다음'\n    },\n\n    outline: {\n      label: '이 페이지 목차'\n    },\n\n    lastUpdated: {\n      text: '업데이트 날짜'\n    },\n\n    notFound: {\n      title: '페이지를 찾을 수 없습니다',\n      quote:\n        '방향을 바꾸지 않고 계속 찾다 보면 결국 당신이 가고 있는 곳에 도달할 수도 있습니다.',\n      linkLabel: '홈으로 가기',\n      linkText: '집으로 데려가줘'\n    },\n\n    langMenuLabel: '언어 변경',\n    returnToTopLabel: '맨 위로 돌아가기',\n    sidebarMenuLabel: '사이드바 메뉴',\n    darkModeSwitchLabel: '다크 모드',\n    lightModeSwitchTitle: '라이트 모드로 변경',\n    darkModeSwitchTitle: '다크 모드로 변경',\n    skipToContentLabel: '본문으로 건너뛰기'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: '가이드',\n      link: '/ko/guide/what-is-vitepress',\n      activeMatch: '/ko/guide/'\n    },\n    {\n      text: '레퍼런스',\n      link: '/ko/reference/site-config',\n      activeMatch: '/ko/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/ko/'\n        },\n        {\n          text: '변경 로그',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: '기여',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '소개',\n      collapsed: false,\n      items: [\n        {\n          text: 'VitePress란 무엇인가?',\n          link: 'what-is-vitepress'\n        },\n        {\n          text: '시작하기',\n          link: 'getting-started'\n        },\n        {\n          text: '라우팅',\n          link: 'routing'\n        },\n        {\n          text: '배포하기',\n          link: 'deploy'\n        }\n      ]\n    },\n    {\n      text: '글쓰기',\n      collapsed: false,\n      items: [\n        {\n          text: '마크다운 확장 기능',\n          link: 'markdown'\n        },\n        {\n          text: '에셋 핸들링',\n          link: 'asset-handling'\n        },\n        {\n          text: '전문(Front-matter)',\n          link: 'frontmatter'\n        },\n        {\n          text: '마크다운에서 Vue 사용하기',\n          link: 'using-vue'\n        },\n        {\n          text: 'i18n',\n          link: 'i18n'\n        }\n      ]\n    },\n    {\n      text: '커스텀',\n      collapsed: false,\n      items: [\n        {\n          text: '커스텀 테마 사용하기',\n          link: 'custom-theme'\n        },\n        {\n          text: '기본 테마 확장하기',\n          link: 'extending-default-theme'\n        },\n        {\n          text: '빌드할 때 데이터 로딩하기',\n          link: 'data-loading'\n        },\n        {\n          text: 'SSR 호환성',\n          link: 'ssr-compat'\n        },\n        {\n          text: 'CMS 연결하기',\n          link: 'cms'\n        }\n      ]\n    },\n    {\n      text: '실험적인',\n      collapsed: false,\n      items: [\n        {\n          text: 'MPA 모드',\n          link: 'mpa-mode'\n        },\n        {\n          text: '사이트맵 생성',\n          link: 'sitemap-generation'\n        }\n      ]\n    },\n    {\n      text: '구성 & API 레퍼런스',\n      base: '/ko/reference/',\n      link: 'site-config'\n    }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '레퍼런스',\n      items: [\n        { text: '사이트 구성', link: 'site-config' },\n        { text: '전문(front-matter) 구성', link: 'frontmatter-config' },\n        { text: '런타임 API', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: '기본 테마',\n          base: '/ko/reference/default-theme-',\n          items: [\n            { text: '개요', link: 'config' },\n            { text: '네비게이션 바', link: 'nav' },\n            { text: '사이드바', link: 'sidebar' },\n            { text: '홈 페이지', link: 'home-page' },\n            { text: '푸터', link: 'footer' },\n            { text: '레이아웃', link: 'layout' },\n            { text: '배지(badge)', link: 'badge' },\n            { text: '팀 페이지', link: 'team-page' },\n            { text: '이전/다음 링크', link: 'prev-next-links' },\n            { text: '편집 링크', link: 'edit-link' },\n            { text: '마지막 업데이트 날짜', link: 'last-updated' },\n            { text: '검색', link: 'search' },\n            { text: '카본 광고', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: '검색',\n        buttonAriaLabel: '검색'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: '지우기',\n          clearButtonAriaLabel: '검색어 지우기',\n          closeButtonText: '닫기',\n          closeButtonAriaLabel: '닫기',\n          placeholderText: '문서를 검색하거나 Ask AI에 질문',\n          placeholderTextAskAi: '다른 질문하기...',\n          placeholderTextAskAiStreaming: '답변 중...',\n          searchInputLabel: '검색',\n          backToKeywordSearchButtonText: '키워드 검색으로 돌아가기',\n          backToKeywordSearchButtonAriaLabel: '키워드 검색으로 돌아가기',\n          newConversationPlaceholder: '질문하기',\n          conversationHistoryTitle: '내 대화 기록',\n          startNewConversationText: '새 대화 시작',\n          viewConversationHistoryText: '대화 기록',\n          threadDepthErrorPlaceholder: '대화 한도에 도달했습니다'\n        },\n        newConversation: {\n          newConversationTitle: '오늘 무엇을 도와드릴까요?',\n          newConversationDescription:\n            '문서를 검색해 설정 가이드, 기능 설명, 문제 해결 팁을 빠르게 찾아드립니다.'\n        },\n        footer: {\n          selectText: '선택',\n          submitQuestionText: '질문 제출',\n          selectKeyAriaLabel: 'Enter 키',\n          navigateText: '이동',\n          navigateUpKeyAriaLabel: '위 화살표',\n          navigateDownKeyAriaLabel: '아래 화살표',\n          closeText: '닫기',\n          backToSearchText: '검색으로 돌아가기',\n          closeKeyAriaLabel: 'Escape 키',\n          poweredByText: '제공'\n        },\n        errorScreen: {\n          titleText: '결과를 불러올 수 없습니다',\n          helpText: '네트워크 연결을 확인해 주세요.'\n        },\n        startScreen: {\n          recentSearchesTitle: '최근',\n          noRecentSearchesText: '최근 검색이 없습니다',\n          saveRecentSearchButtonTitle: '이 검색 저장',\n          removeRecentSearchButtonTitle: '기록에서 이 검색 제거',\n          favoriteSearchesTitle: '즐겨찾기',\n          removeFavoriteSearchButtonTitle: '즐겨찾기에서 이 검색 제거',\n          recentConversationsTitle: '최근 대화',\n          removeRecentConversationButtonTitle: '기록에서 이 대화 제거'\n        },\n        noResultsScreen: {\n          noResultsText: '다음에 대한 결과를 찾을 수 없습니다',\n          suggestedQueryText: '다음을 검색해 보세요',\n          reportMissingResultsText: '이 검색은 결과가 있어야 하나요?',\n          reportMissingResultsLinkText: '알려주세요.'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'AI에게 묻기: ',\n          noResultsAskAiPlaceholder: '문서에서 찾지 못했나요? Ask AI에 문의: '\n        },\n        askAiScreen: {\n          disclaimerText:\n            '답변은 AI가 생성하며 오류가 있을 수 있습니다. 확인해 주세요.',\n          relatedSourcesText: '관련 출처',\n          thinkingText: '생각 중...',\n          copyButtonText: '복사',\n          copyButtonCopiedText: '복사됨!',\n          copyButtonTitle: '복사',\n          likeButtonTitle: '좋아요',\n          dislikeButtonTitle: '싫어요',\n          thanksForFeedbackText: '피드백 감사합니다!',\n          preToolCallText: '검색 중...',\n          duringToolCallText: '검색 중...',\n          afterToolCallText: '검색함',\n          stoppedStreamingText: '이 응답을 중지했습니다',\n          errorTitleText: '채팅 오류',\n          threadDepthExceededMessage:\n            '정확성을 유지하기 위해 이 대화는 종료되었습니다.',\n          startNewConversationButtonText: '새 대화 시작'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'AI에게 묻기',\n            buttonAriaLabel: 'AI에게 묻기'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'AI에게 묻기',\n              conversationHistoryTitle: '내 대화 기록',\n              newConversationText: '새 대화 시작',\n              viewConversationHistoryText: '대화 기록'\n            },\n            promptForm: {\n              promptPlaceholderText: '질문하기',\n              promptAnsweringText: '답변 중...',\n              promptAskAnotherQuestionText: '다른 질문하기',\n              promptDisclaimerText:\n                '답변은 AI가 생성하며 오류가 있을 수 있습니다.',\n              promptLabelText: 'Enter로 전송, Shift+Enter로 줄바꿈.',\n              promptAriaLabelText: '프롬프트 입력'\n            },\n            conversationScreen: {\n              preToolCallText: '검색 중...',\n              searchingText: '검색 중...',\n              toolCallResultText: '검색함',\n              conversationDisclaimer:\n                '답변은 AI가 생성하며 오류가 있을 수 있습니다. 확인해 주세요.',\n              reasoningText: '추론 중...',\n              thinkingText: '생각 중...',\n              relatedSourcesText: '관련 출처',\n              stoppedStreamingText: '이 응답을 중지했습니다',\n              copyButtonText: '복사',\n              copyButtonCopiedText: '복사됨!',\n              likeButtonTitle: '좋아요',\n              dislikeButtonTitle: '싫어요',\n              thanksForFeedbackText: '피드백 감사합니다!',\n              errorTitleText: '채팅 오류'\n            },\n            newConversationScreen: {\n              titleText: '오늘 무엇을 도와드릴까요?',\n              introductionText:\n                '문서를 검색해 설정 가이드, 기능 설명, 문제 해결 팁을 빠르게 찾아드립니다.'\n            },\n            logo: {\n              poweredByText: '제공'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/ko/guide/asset-handling.md",
    "content": "# 에셋 핸들링 {#asset-handling}\n\n## 정적 에셋 참조하기 {#referencing-static-assets}\n\n모든 마크다운 파일은 Vue 컴포넌트로 컴파일되어 [Vite](https://vitejs.dev/guide/assets.html)에 의해 처리됩니다. 모든 에셋은 상대 URL을 사용하여 참조할 수 있으며, **참조해야 합니다**:\n\n```md\n![이미지](./image.png)\n```\n\n마크다운 파일에서 정적 에셋을 참조할 수 있으며, 테마 내의 `*.vue` 컴포넌트, 스타일 및 일반 `.css` 파일을 절대 경로(프로젝트 루트를 기준으로) 또는 상대 경로(파일 시스템을 기준으로)를 사용하여 참조할 수 있습니다. 후자는 Vite, Vue CLI 또는 webpack의 `file-loader` 동작과 유사합니다.\n\n일반적인 이미지, 미디어 및 글꼴 파일 형식은 자동으로 에셋으로 감지되어 포함됩니다.\n\n::: tip 링크를 통해 참조된 파일은 에셋으로 처리되지 않습니다\n마크다운 파일 내에서 링크로 참조된 PDF 또는 기타 문서는 자동으로 에셋으로 처리되지 않습니다. 링크된 파일을 접근 가능하게 하려면 프로젝트의 [`public`](#the-public-directory) 디렉토리에 수동으로 배치해야 합니다.\n:::\n\n절대 경로를 사용하는 에셋을 포함하여 모든 참조된 에셋은 프로덕션 빌드에서 해시된 파일 이름으로 출력 디렉토리에 복사됩니다. 참조되지 않은 에셋은 복사되지 않습니다. 4kb보다 작은 이미지 에셋은 base64로 인라인됩니다. 이는 [`vite`](../reference/site-config#vite) 구성 옵션을 통해 구성할 수 있습니다.\n\n모든 **정적** 경로 참조는 절대 경로를 포함하여 작업 디렉토리 구조를 기반으로 해야 합니다.\n\n## Public 디렉터리 {#the-public-directory}\n\n때때로 마크다운이나 테마 컴포넌트에서 직접 참조되지 않는 정적 에셋을 제공해야 하거나 특정 파일을 원래 파일 이름으로 제공하고 싶을 때가 있습니다. 이러한 파일의 예로는 `robots.txt`, 파비콘, PWA 아이콘 등이 있습니다.\n\n이 파일들은 [소스 디렉토리](./routing#source-directory) 아래의 `public` 디렉토리에 놓을 수 있습니다. 예를 들어 프로젝트 루트가 `./docs`이고 기본 소스 디렉토리 위치를 사용 중인 경우, `public` 디렉토리는 `./docs/public`이 됩니다.\n\n`public`에 배치된 에셋은 출력 디렉토리의 루트로 그대로 복사됩니다.\n\n`public`에 배치된 파일은 루트 절대 경로를 사용하여 참조해야 한다는 점에 유의하세요. 예를 들어, `public/icon.png`는 소스 코드에서 항상 `/icon.png`로 참조되어야 합니다.\n\n## Base URL {#base-url}\n\n사이트가 루트 URL이 아닌 곳에 배포된 경우, `.vitepress/config.js`에서 `base` 옵션을 설정해야 합니다. 예를 들어, 사이트를 `https://foo.github.io/bar/`에 배포하려는 경우 `base`는 `'/bar/'`로 설정해야 합니다(항상 슬래시로 시작하고 끝나야 합니다).\n\n모든 정적 에셋 경로는 다른 `base` 구성 값에 맞게 자동으로 처리됩니다. 예를 들어, 마크다운에서 `public` 하위의 에셋에 대한 절대 참조가 있는 경우:\n\n```md\n![이미지](/image-inside-public.png)\n```\n\n이 경우 `base` 구성 값을 변경할 때 **업데이트할 필요가 없습니다**.\n\n그러나 테마 구성 값을 기반으로 `src`가 설정된 이미지와 같이 동적으로 에셋에 링크하는 테마 컴포넌트를 작성하는 경우:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\n이 경우 VitePress에서 제공하는 [`withBase` 헬퍼](../reference/runtime-api#withbase)로 경로를 감싸는 것이 좋습니다:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/ko/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# CMS에 연결하기 {#connecting-to-a-cms}\n\n## 일반적인 워크플로우 {#general-workflow}\n\nVitePress를 CMS에 연결하는 것은 주로 [동적 라우트](./routing#dynamic-routes)를 중심으로 이루어질 것입니다. 진행하기 전에 작동 방식을 이해해야 합니다.\n\n각 CMS가 다르게 작동하므로, 여기서는 특정 상황에 맞게 조정해야 하는 일반적인 워크플로우만 제공할 수 있습니다.\n\n1. CMS가 인증을 요구하는 경우, `.env` 파일을 생성하여 API 토큰을 저장하고 다음과 같이 로드하세요:\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. CMS에서 필요한 데이터를 가져와 적절한 경로 데이터로 형식을 지정하세요:\n\n    ```js\n    export default {\n      async paths() {\n        // 필요한 경우 해당 CMS 클라이언트 라이브러리 사용\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // 필요한 경우 토큰을 사용\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* 제목, 저자, 날짜 등 */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. 페이지의 컨텐츠를 렌더링하세요:\n\n    ```md\n    # {{ $params.title }}\n\n    - 작성자: {{ $params.author }}, 작성일: {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## 통합 가이드 {#integration-guides}\n\nVitePress를 특정 CMS와 통합하는 방법에 대한 가이드를 작성한 경우 아래의 \"이 페이지 편집 제안하기\" 링크를 클릭하여 여기에 제출하세요!\n"
  },
  {
    "path": "docs/ko/guide/custom-theme.md",
    "content": "# 커스텀 테마 사용하기 {#using-a-custom-theme}\n\n## 테마 사용법 {#theme-resolving}\n\n`.vitepress/theme/index.js` 또는 `.vitepress/theme/index.ts` 파일(\"테마 엔트리 파일\")을 생성하여 커스텀 테마를 활성화할 수 있습니다:\n\n```\n.\n├─ docs                # 프로젝트 루트\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # 테마 엔트리\n│  │  └─ config.js     # 구성 파일\n│  └─ index.md\n└─ package.json\n```\n\nVitePress는 테마 엔트리 파일이 존재를 감지하면 기본 테마 대신 커스텀 테마를 사용합니다. 아니면 [기본 테마 확장하기](./extending-default-theme)를 통해 이를 기반으로 고급 커스터마이징을 수행할 수 있습니다.\n\n## 테마 인터페이스 {#theme-interface}\n\nVitePress 커스텀 테마는 아래와 같은 인터페이스 객체로 정의됩니다:\n\n```ts\ninterface Theme {\n  /**\n   * 모든 페이지의 루트 레이아웃 컴포넌트\n   * @required\n   */\n  Layout: Component\n  /**\n   * Vue 애플리케이션 인스턴스 추가조작 (의역: \"enhance → 추가조작\")\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * 현재 `enhanceApp`를 호출하기 전, 다른 테마를 먼저 확장\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // Vue 애플리케이션 인스턴스\n  router: Router // VitePress 라우터 인스턴스\n  siteData: Ref<SiteData> // 사이트 수준 메타데이터\n}\n```\n\n테마 엔트리 파일은 테마(Theme 객체)를 \"export default\" 해야 합니다:\n\n```js [.vitepress/theme/index.js]\n\n// 테마 엔트리에서 Vue 파일을 직접 \"import\" 할 수 있습니다.\n// VitePress는 @vitejs/plugin-vue가 사전 구성되어 있습니다.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\n\"export default\"는 커스텀 테마를 설정하는 유일한 방법이며, `Layout` 프로퍼티만 필수입니다. 따라서 기술적으로 VitePress 테마는 단일 Vue 컴포넌트처럼 간단할 수 있습니다.\n\n레이아웃 컴포넌트 내부에서는 일반적인 Vite + Vue 3 애플리케이션처럼 동작합니다. 또한 테마가 [SSR 호환](./ssr-compat)이 되어야 합니다.\n\n## 레이아웃 만들기 {#building-a-layout}\n\n가장 기본적인 레이아웃 컴포넌트는 [`<Content />`](../reference/runtime-api#content) 컴포넌트가 포함되어야 합니다:\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Custom Layout!</h1>\n\n  <!-- 마크다운 내용은 여기에 렌더링됩니다 -->\n  <Content />\n</template>\n```\n\n위의 레이아웃은 각 페이지의 마크다운을 HTML로 렌더링합니다. 첫 번째로 개선 사항은 404 에러를 처리하는 것입니다:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <Content v-else />\n</template>\n```\n\n[`useData()`](../reference/runtime-api#usedata) 헬퍼는 다양한 레이아웃을 조건부로 렌더링하는 데 필요한 모든 런타임 데이터를 제공합니다. 접근할 수 있는 다른 데이터 중 하나는 현재 페이지의 전문(front-matter)입니다. 이를 활용하여 각 페이지에 맞게 레이아웃을 제어할 수 있습니다. 예를 들어 특정 페이지에서 홈 페이지 레이아웃을 사용하도록 지정할 수 있습니다:\n\n```md\n---\nlayout: home\n---\n```\n\n그리고 이를 처리하도록 테마를 조정할 수 있습니다:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Custom home page!\n  </div>\n  <Content v-else />\n</template>\n```\n\n물론 레이아웃을 더 많은 컴포넌트로 나눌 수 있습니다:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> 는 <Content /> 를 렌더링합니다 -->\n</template>\n```\n\n테마 컴포넌트에서 사용할 수 있는 모든 항목에 대해서는 [런타임 API 레퍼런스](../reference/runtime-api)를 참고하세요. 또한 [빌드할 때 데이터 로딩하기](./data-loading)를 활용하여 데이터 기반의 레이아웃을 생성할 수 있습니다. 예를 들어 현재 프로젝트의 모든 블로그 게시물을 나열하는 페이지를 만들 수 있습니다.\n\n## 사용자 정의 테마 배포하기 {#distributing-a-custom-theme}\n\n커스텀 테마를 배포하는 가장 쉬운 방법은 [GitHub 템플릿 리포지토리](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository)로 제공하는 것입니다.\n\n테마를 npm 패키지로 배포하려면 다음 단계를 따라야 합니다:\n\n1. 패키지 엔트리에서 테마 객체를 \"export default\" 합니다.\n\n2. 해당되는 경우, 테마 구성 타입 정의를 `ThemeConfig`로 \"export\" 합니다.\n\n3. 테마에서 VitePress 구성을 조정해야 하는 경우, 사용자가 확장할 수 있도록 패키지 하위 경로(예: `my-theme/config`)에 해당 구성을 \"export\" 합니다.\n\n4. 테마 구성 옵션을 문서화합니다 (구성 파일과 전문 둘 다).\n\n5. 테마를 사용하는 방법에 대한 명확한 지침을 제공합니다 (아래 참조).\n\n## 커스텀 테마 사용하기 {#consuming-a-custom-theme}\n\n외부 테마를 사용하려면, 커스텀 테마 엔트리에서 테마를 \"import\" 후 다시 \"export\"합니다:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\n테마를 확장해야 하는 경우:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\n테마가 특별한 VitePress 구성을 요구하는 경우, 해당 구성을 (외부 커스텀 테마를 사용하는 자신의) 구성 파일에서도 확장해야 합니다:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // 필요한 경우 테마 기본 구성 확장\n  extends: baseConfig\n}\n```\n\n마지막으로 테마가 테마 구성에 대한 타입을 제공하는 경우:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // 타입은 `ThemeConfig`입니다.\n  }\n})\n```\n"
  },
  {
    "path": "docs/ko/guide/data-loading.md",
    "content": "# 빌드할 때 데이터 로딩하기 {#build-time-data-loading}\n\nVitePress는 페이지나 컴포넌트에서 임의의 데이터를 로드하고 이를 가져올 수 있는 **데이터 로더** 기능을 제공합니다. 데이터 로딩은 **빌드할 때에만** 실행되며, 결과적으로 생성된 데이터는 최종 JavaScript 번들에 JSON으로 직렬화됩니다.\n\n데이터 로더는 원격 데이터를 가져오거나 로컬 파일을 기반으로 메타데이터를 생성하는 데 사용할 수 있습니다. 예를 들어, 데이터 로더를 사용하여 모든 로컬 API 페이지를 파싱하고 모든 API 항목의 색인을 자동으로 생성할 수 있습니다.\n\n## 기본 사용법 {#basic-usage}\n\n데이터 로더 파일은 반드시 `.data.js` 또는 `.data.ts`로 끝나야 합니다. 이 파일은 `load()` 메서드를 가진 객체를 \"export default\" 해야 합니다:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\n로더 모듈은 Node.js에서만 평가되므로, 필요한 경우 Node API와 npm 종속성을 \"import\" 할 수 있습니다.\n\n그런 다음 `.md` 페이지와 `.vue` 컴포넌트에서 `data`라는 이름으로 \"export\" 한 데이터를 이 파일에서 \"import\" 할 수 있습니다:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\n출력:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\n데이터 로더 자체가 `data`를 \"export\" 하지 않는다는 점에 주목하십시오. VitePress가 백그라운드에서 `load()` 메서드를 호출하고 결과를 암묵적으로 `data`라는 이름으로 \"export\" 하기 때문입니다.\n\n이 방법은 로더가 비동기적이어도 작동합니다:\n\n```js\nexport default {\n  async load() {\n    // 원격 데이터 가져오기\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## 로컬 파일에서 데이터 가져오기 {#data-from-local-files}\n\n로컬 파일을 기반으로 데이터를 생성해야 할 때는 데이터 로더에서 `watch` 옵션을 사용해야 합니다. 이 옵션을 사용하면 이러한 파일에 변경이 있을 때 핫 업데이트를 트리거할 수 있습니다.\n\n`watch` 옵션은 또한 여러 파일을 매칭하는 [glob 패턴](https://github.com/mrmlnc/fast-glob#pattern-syntax)을 사용할 수 있어서 편리합니다. 패턴은 로더 파일 자체에 상대적일 수 있으며, `load()` 함수는 매칭된 파일을 절대 경로로 받게 됩니다.\n\n다음 예제는 CSV 파일을 로드하고 이를 [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/)를 사용하여 JSON으로 변환하는 방법을 보여줍니다. 이 파일은 빌드할 때에만 실행되므로 CSV 파서를 클라이언트로 전송하지 않습니다!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles는 매칭된 파일의 절대 경로 배열 입니다.\n    // 테마 레이아웃에서 목록을 렌더링하는 데 사용할 수 있는\n    // 블로그 포스트 메타데이터 배열을 생성합니다.\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\n콘텐츠가 많은 사이트를 구축할 때, 종종 \"아카이브\" 또는 \"인덱스\" 페이지를 만들어야 합니다. 이 페이지는 콘텐츠 모음에 있는 모든 항목(예: 블로그 게시물, API 페이지)을 나열하는 페이지입니다. 데이터 로더 API를 직접 사용하여 이를 구현할 수 있지만, VitePress는 이러한 일반적인 사용 사례를 간소화하기 위해 `createContentLoader` 헬퍼를 제공합니다:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* options */)\n```\n\n이 헬퍼는 [소스 디렉터리](./routing#source-directory)를 기준으로 glob 패턴을 허용하고 데이터 로드 파일에서 \"default export\"로 사용할 수 있는 `{ watch, load }` 데이터 로더 객체를 반환합니다. 또한 파일 수정 타임스탬프를 기반으로 캐싱을 구현하여 개발 성능을 향상시킵니다.\n\n참고로 로더는 마크다운 파일에서만 작동하며, 매칭되는 마크다운이 아닌 파일은 건너뜁니다.\n\n로드된 데이터는 `ContentData[]` 타입의 배열입니다:\n\n```ts\ninterface ContentData {\n  // 페이지에 매핑된 URL입니다. 예: /posts/hello.html (base는 포함하지 않음)\n  // 수동으로 반복하거나 커스텀 `transform`을 사용하여 경로를 정규화.\n  url: string\n  // 페이지의 전문(front-matter) 데이터\n  frontmatter: Record<string, any>\n\n  // 다음은 관련 옵션이 활성화된 경우에만 나타납니다.\n  // 아래에서 이에 대해 논의할 것입니다.\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\n기본적으로 `url`과 `frontmatter`만 제공됩니다. 이는 로드된 데이터가 클라이언트 번들에 JSON으로 인라인되기 때문에 크기에 주의해야 합니다. 다음은 데이터를 사용하여 최소한의 블로그 인덱스 페이지를 구축하는 예입니다:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>All Blog Posts</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>by {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### 옵션 {#options}\n\n기본 데이터가 모든 요구 사항에 충족하지 않을 수 있습니다. 옵션을 사용하여 데이터를 변환할 수 있습니다:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // 원시 마크다운 소스를 포함할까요?\n  render: true,     // 렌더링된 전체 페이지 HTML을 포함할까요?\n  excerpt: true,    // 발췌문을 포함할까요?\n  transform(rawData) {\n    // 필요에 따라 원시 데이터를 매핑, 정렬 또는 필터링.\n    // 최종 결과를 클라이언트에 전달.\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // 원시 마크다운 소스\n      page.html    // 렌더링된 전체 페이지 HTML\n      page.excerpt // 렌더링된 발췌문 HTML (첫 번째 `---` 위에 있는 내용)\n      return {/* ... */}\n    })\n  }\n})\n```\n\n[Vue.js 블로그](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts)에서 어떻게 사용되었는지 확인해보세요.\n\n`createContentLoader` API는 [빌드 훅](../reference/site-config#build-hooks) 내에서도 사용할 수 있습니다:\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // 포스트 메타데이터를 기반으로 파일 생성하기, 예: RSS 피드\n    // 게시물 메타데이터를 기반으로 파일 생성, 예: RSS 피드\n  }\n}\n```\n\n**타입**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * src를 포함할까요?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * src를 HTML로 렌더링하고 데이터에 포함할까요?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * `boolean` 타입인 경우, 발췌문을 파싱하고 포함할지 여부를 나타냅니다. (HTML로 렌더링됨)\n   *\n   * `function` 타입인 경우, 콘텐츠에서 발췌문을 추출하는 방법을 제어합니다.\n   *\n   * `string` 타입인 경우, 발췌문을 추출하는 데 사용할 커스텀 구분자를 정의합니다.\n   * `excerpt`가 `true`인 경우 기본 구분자는 `---`입니다.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * 데이터를 변환합니다. 데이터는 컴포넌트나 마크다운 파일에서 가져올 경우,\n   * 클라이언트 번들에 JSON으로 포함됩니다.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## 데이터 로더의 \"export\" 타입 {#typed-data-loaders}\n\nTypeScript를 사용할 때, 로더와 `data` \"export\"를 다음과 같이 타입 지정할 수 있습니다:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // 데이터 타입\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // type checked loader options\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## 구성 {#configuration}\n\n로더 내부에서 구성 정보를 가져오려면 다음과 같이 코드를 사용해야 합니다:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/ko/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# VitePress 사이트 배포하기 {#deploy-your-vitepress-site}\n\n다음 가이드는 몇 가지 공통된 가정을 기반으로 합니다:\n\n- VitePress 사이트는 프로젝트의 `docs` 디렉토리 안에 있다.\n- 기본 빌드 출력 디렉토리(`.vitepress/dist`)를 사용하고 있다.\n- VitePress는 프로젝트의 로컬 종속성으로 설치되어 있으며, `package.json`에 다음 스크립트가 설정되어 있다:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## 로컬에서 빌드하고 테스트하기 {#build-and-test-locally}\n\n1. 이 명령어를 실행하여 문서를 빌드합니다:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. 빌드가 완료되면, 다음 명령어를 실행하여 로컬에서 미리보기를 합니다:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   `preview` 명령은 출력 디렉토리 `.vitepress/dist`를 `http://localhost:4173`에서 제공할 것입니다. 이를 사용하여 프로덕션에 푸시하기 전에 모든 것이 잘 보이는지 확인할 수 있습니다.\n\n3. `--port` 인자를 전달하여 서버의 포트를 구성할 수 있습니다.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   이제 `docs:preview` 메서드가 `http://localhost:8080`에서 서버를 시작합니다.\n\n## public 기본 경로 설정하기 {#setting-a-public-base-path}\n\n기본적으로 사이트가 도메인의 루트 경로(`/`)에 배포된다고 가정합니다. 예를 들어 사이트가 `https://mywebsite.com/blog/` 와 같은 서브 경로에서 제공될 경우, VitePress 구성에서 [`base`](../reference/site-config#base) 옵션을 `'/blog/'`로 설정해야 합니다.\n\n**예**: Github(또는 GitLab) Pages를 사용하여 `user.github.io/repo/`에 배포하는 경우, `base`를 `/repo/`로 설정하세요.\n\n## HTTP 캐시 헤더 {#http-cache-headers}\n\n프로덕션 서버에서 HTTP 헤더를 제어할 수 있다면, 반복 방문 시 더 나은 성능을 위해 `cache-control` 헤더를 구성할 수 있습니다.\n\n프로덕션 빌드는 정적 자산(JavaScript, CSS, `public`가 아닌 곳에서 가져온 에셋)에 대해 해시된 파일 이름을 사용합니다. 브라우저 개발 도구의 네트워크 탭을 사용하여 프로덕션 미리보기를 검사하면 `app.4f283b18.js`와 같은 파일을 볼 수 있습니다.\n\n이 `4f283b18` 해시는 파일의 내용에서 생성됩니다. 동일한 해시된 URL은 동일한 파일 내용을 제공할 것이 보장되며, 내용이 변경되면 URL도 변경됩니다. 이는 이러한 파일에 대해 가장 강력한 캐시 헤더를 안전하게 사용할 수 있음을 의미합니다. 모든 이러한 파일은 출력 디렉토리의 `assets/` 아래에 배치되므로, 다음 헤더를 구성할 수 있습니다:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Netlify `_headers` 파일 예시\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\n참고: `_headers` 파일은 [public 디렉토리](./asset-handling#the-public-directory)에 배치해야 합니다. 이 경우 `docs/public/_headers`에 위치하여 출력 디렉토리에 그대로 복사됩니다.\n\n[Netlify 커스텀 헤더 문서](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details Vercel 내의 `vercel.json` 구성 예시\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n참고: `vercel.json` 파일은 **리포지토리**의 루트에 배치해야 합니다.\n\n[Vercel 헤더 구성에 대한 문서](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## 플랫폼 가이드 {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\n새 프로젝트를 설정하고 대시보드를 사용하여 다음 설정을 변경하세요:\n\n- **빌드 명령어:** `npm run docs:build`\n- **출력 디렉토리:** `docs/.vitepress/dist`\n- **노드 버전:** `20` (또는 그 이상)\n\n::: warning\nHTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 Vue에 의미가 있는 주석을 출력에서 제거할 것입니다. 제거되면 하이드레이션 불일치 오류가 발생할 수 있습니다.\n:::\n\n### GitHub Pages\n\n1. 프로젝트의 `.github/workflows` 디렉토리 안에 `deploy.yml`이라는 파일을 만들고 다음과 같은 내용을 추가하세요:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # VitePress 사이트를 GitHub Pages에 빌드하고 배포하는 샘플 워크플로우\n   #\n   name: VitePress 사이트를 Pages에 배포\n\n   on:\n     # `main` 브랜치를 대상으로 하는 푸시에서 실행됩니다. 기본 브랜치로 `master`를 사용하는 경우 여기를 `master`로 변경하세요.\n     push:\n       branches: [main]\n\n     # Actions 탭에서 이 워크플로우를 수동으로 실행할 수 있게 합니다.\n     workflow_dispatch:\n\n   # GitHub Pages에 배포할 수 있도록 GITHUB_TOKEN의 권한을 설정합니다.\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # 진행 중인 실행과 마지막으로 대기 중인 실행 사이에 대기 중인 실행을 건너뛰어 하나의 동시 배포만 허용합니다.\n   # 그러나 이러한 프로덕션 배포가 완료되도록 진행 중인 실행은 취소하지 않습니다.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # 빌드 작업\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # lastUpdated가 활성화되지 않은 경우 필요하지 않음\n         # - uses: pnpm/action-setup@v4 # pnpm을 사용하는 경우 주석 해제\n         #   with:\n         #     version: 9\n         # - uses: oven-sh/setup-bun@v1 # Bun을 사용하는 경우 주석 해제\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # 또는 pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # 또는 pnpm install / yarn install / bun install\n         - name: Build with VitePress\n           run: npm run docs:build # 또는 pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # 배포 작업\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   VitePress의 `base` 옵션이 제대로 구성되어 있는지 확인하세요. 자세한 내용은 [public 기본 경로 설정하기](#setting-a-public-base-path)를 참고하세요.\n   :::\n\n2. 리포지토리 설정의 \"Pages\" 메뉴 항목에서 \"Build and deployment > Source\"에서 \"GitHub Actions\"를 선택하세요.\n\n3. 변경 사항을 `main` 브랜치에 푸시하고 GitHub Actions 워크플로우가 완료될 때까지 기다립니다. 설정에 따라 사이트가 `https://<username>.github.io/[repository]/` 또는 `https://<custom-domain>/`에 배포된 것을 볼 수 있습니다. 사이트는 `main` 브랜치에 푸시할 때마다 자동으로 배포됩니다.\n\n### GitLab Pages\n\n1. VitePress 구성에서 `outDir`을 `../public`으로 설정하세요. `https://<username>.gitlab.io/<repository>/`에 배포하려면 `base` 옵션을 `'/<repository>/'`로 구성하세요. 커스텀 도메인, 유저 또는 그룹 페이지에 배포하거나 GitLab에서 \"Use unique domain\" 설정이 활성화된 경우에는 `base`가 필요하지 않습니다.\n\n2. 변경 사항을 적용할 때마다 사이트를 빌드하고 배포하도록 하기 위해 프로젝트의 루트에 다음 내용을 가진 `.gitlab-ci.yml` 파일을 생성하세요:\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # alpine 과 같은 작은 도커 이미지를 사용하고 있고 lastUpdated 가 활성화된 경우 주석 처리를 제거하세요.\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. [공식 문서](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration)를 따르세요.\n\n2. 구성 파일에 다음 값을 설정하세요(필요하지 않은 값들, 예를 들어 `api_location` 같은 것은 제거하세요):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\n[CloudRay](https://cloudray.io/)로 VitePress 프로젝트를 배포하려면 이 [지침](https://cloudray.io/articles/how-to-deploy-vitepress-site)을 따르세요.\n\n### Firebase\n\n1. 프로젝트 루트에 `firebase.json`과 `.firebaserc`를 생성하세요:\n\n   `firebase.json`:\n\n   ```json  [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. `npm run docs:build`를 실행한 후, 배포하려면 이 명령어를 실행하세요:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static)에 제공된 문서와 가이드를 따르세요.\n\n2. 프로젝트 루트에 아래 내용을 포함한 `static.json` 파일을 생성하세요:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\n[Hostinger](https://www.hostinger.com/web-apps-hosting)로 VitePress 프로젝트를 배포하려면 이 [지침](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/)을 따르세요. 빌드 설정을 구성할 때 프레임워크로 VitePress를 선택하고 루트 디렉터리를 `./docs`로 조정하세요.\n\n### Kinsta\n\n[VitePress](https://kinsta.com/static-site-hosting/) 웹사이트를 [Kinsta](https://kinsta.com/static-site-hosting/)에 배포하려면 이 [지침](https://kinsta.com/docs/vitepress-static-site-example/)을 따르세요.\n\n### Stormkit\n\n[VitePress](https://stormkit.io) 프로젝트를 [Stormkit](https://www.stormkit.io)에 배포하려면 이 [지침](https://stormkit.io/blog/how-to-deploy-vitepress)을 따르세요.\n\n### Surge\n\n1. `npm run docs:build`를 실행한 후, 배포하기 위해 이 명령어를 실행하세요:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\n다음은 Nginx 서버 블록 구성의 예입니다. 이 설정은 일반적인 텍스트 기반 에셋에 대한 gzip 압축, VitePress 사이트의 정적 파일을 적절한 캐싱 헤더와 함께 제공하는 규칙 및 `cleanUrls: true`를 처리하는 규칙을 포함합니다.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # 콘텐츠 위치\n        root /app;\n\n        # 정확히 일치하는 파일 -> 정제된 URL로 역방향 매핑 -> 폴더 -> 파일 없음\n        try_files $uri $uri.html $uri/ =404;\n\n        # 존재하지 않는 페이지\n        error_page 404 /404.html;\n\n        # index.html이 없는 폴더는 이 설정에서 403 오류를 발생시킴\n        error_page 403 /404.html;\n\n        # 캐싱 헤더 조정\n        # assets 폴더의 파일들은 해시된 파일명 사용\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\n이 구성은 빌드된 VitePress 사이트가 서버의 `/app` 디렉토리에 위치한다고 가정합니다. 사이트 파일이 다른 곳에 위치한 경우 `root` 지시문을 적절하게 조정하세요.\n\n::: warning index.html을 기본값으로 설정하지 마세요.\ntry_files는 다른 Vue 애플리케이션처럼 index.html을 기본값으로 할 수 없습니다. 이는 페이지 상태가 유효하지 않게 만듭니다.\n:::\n\n추가 정보는 [공식 nginx 문서](https://nginx.org/en/docs/), 이슈 [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235) 및 Mehdi Merah의 [블로그 포스트](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings)에서 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# 기본 테마 확장하기 {#extending-the-default-theme}\n\nVitePress의 기본 테마는 문서화에 최적화되어 있으며, 커스텀할 수 있습니다. 포괄적인 옵션 목록은 [기본 테마 구성](../reference/default-theme-config)을 참고하세요.\n\n그러나 구성만으로는 충분하지 않을 수 있습니다. 예를 들어:\n\n1. CSS 스타일링을 조정해야 하는 경우.\n2. 전역 컴포넌트를 등록하기 위해 Vue 애플리케이션 인스턴스를 수정해야 하는 경우.\n3. 레이아웃 슬롯을 통해 테마에 커스텀 컨텐츠를 삽입해야 하는 경우.\n\n이러한 고급 커스터마이징은 기본 테마를 \"확장\"하는 커스텀 테마 사용이 필요 합니다.\n\n::: tip\n진행하기 전에, 커스텀 테마가 어떻게 작동하는지 이해하려면 먼저 [커스텀 테마 사용하기](./custom-theme)를 읽어보세요.\n:::\n\n## CSS 커스터마이징하기 {#customizing-css}\n\n기본 테마의 CSS는 루트 레벨의 CSS 변수를 재정의하여 커스터마이징 할 수 있습니다:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\n재정의할 수 있는 기본 테마 CSS 변수는 [여기](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css)를 참고하세요.\n\n## 다른 폰트 사용하기 {#using-different-fonts}\n\nVitePress는 기본 폰트로 [Inter](https://rsms.me/inter/)를 사용하며, 빌드 결과물에 폰트를 포함시킵니다. 폰트는 프로덕션 환경에서 자동으로 미리 로드되지만, 다른 메인 폰트를 사용하고자 할 경우 이는 바람직하지 않을 수 있습니다.\n\n빌드 결과물에 Inter를 포함시키지 않으려면, `vitepress/theme-without-fonts`에서 테마를 \"import\" 합니다:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* 일반 텍스트 폰트 */\n  --vp-font-family-mono: /* 코드 폰트 */\n}\n```\n\n::: warning\n선택적 컴포넌트인 [팀 페이지](../reference/default-theme-team-page) 등을 사용하는 경우, 반드시 이들도 `vitepress/theme-without-fonts`에서 \"import\" 해야 합니다!\n:::\n\n폰트가 `@font-face`를 통해 참조된 로컬 파일인 경우, 에셋으로 처리되어 해시된 파일 이름으로 `.vitepress/dist/assets`에 포함됩니다. 이 파일을 미리 로드하려면 [transformHead](../reference/site-config#transformhead) 빌드 훅을 사용해야 합니다:\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // 폰트를 매칭하기 위해 정규식을 적절히 조정하세요\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## 전역 컴포넌트 등록하기 {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 커스텀 전역 컴포넌트 등록\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nTypeScript를 사용하는 경우:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 커스텀 전역 컴포넌트 등록\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nVite를 사용하므로, Vite의 [glob import 기능](https://vitejs.dev/guide/features.html#glob-import)을 활용하여 컴포넌트 디렉터리를 자동으로 등록할 수 있습니다.\n\n## 레이아웃 슬롯 {#layout-slots}\n\n기본 테마의 `<Layout/>` 컴포넌트는 페이지의 특정 위치에 컨텐츠를 삽입할 수 있는 몇 가지 슬롯을 가지고 있습니다. 다음은 아웃라인 앞에 컴포넌트를 삽입하는 예제입니다:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // 슬롯을 삽입하는 래퍼 컴포넌트로\n  // Layout을 재정의합니다\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      My custom sidebar top content\n    </template>\n  </Layout>\n</template>\n```\n\n또는 렌더 함수를 사용할 수도 있습니다.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\n기본 테마 레이아웃에서 사용할 수 있는 슬롯의 전체 목록:\n\n- 전문(front-matter)으로 `layout: 'doc'` (기본값)이 활성화된 경우:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- 전문으로 `layout: 'home'`이 활성화된 경우:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- 전문으로 `layout: 'page'`이 활성화된 경우:\n  - `page-top`\n  - `page-bottom`\n- 페이지를 찾을 수 없음(404)일 때:\n  - `not-found`\n- 항상:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## 뷰 트랜지션 API 사용하기 {#using-view-transitions-api}\n\n### 외형 토글 {#on-appearance-toggle}\n\n기본 테마를 확장하여 컬러 모드가 전환될 때 커스텀 트랜지션 효과를 제공할 수 있습니다. 예제:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\n결과 (**광과민성 주의!**: 색상 깜빡임, 갑작스러운 움직임, 밝은 빛):\n\n<details>\n<summary>데모</summary>\n\n![외형 토글 트랜지션 데모](/appearance-toggle-transition.webp)\n\n</details>\n\n뷰 트랜지션에 대한 자세한 정보는 [크롬 문서](https://developer.chrome.com/docs/web-platform/view-transitions/)를 참고하세요.\n\n### 라우트 변경 시 {#on-route-change}\n\n곧 제공될 예정입니다.\n\n## 내부 컴포넌트 재정의하기 {#overriding-internal-components}\n\nVite의 [별칭](https://vitejs.dev/config/shared-options.html#resolve-alias)을 사용하여 기본 테마 컴포넌트를 커스텀 컴포넌트로 대체할 수 있습니다:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\n컴포넌트의 정확한 이름을 알고 싶다면 [Vitepress 소스 코드](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components)를 참고하세요. 컴포넌트는 내부적으로 사용되기 때문에, 마이너 릴리즈 사이에 이름이 변경될 가능성이 있습니다.\n"
  },
  {
    "path": "docs/ko/guide/frontmatter.md",
    "content": "# 전문 {#frontmatter}\n\n## 사용법 {#usage}\n\nVitePress는 모든 마크다운 파일에서 YAML 전문(frontmatter)을 지원하며, [gray-matter](https://github.com/jonschlinkert/gray-matter)로 이를 파싱합니다. 전문은 마크다운 파일의 맨 위에 있어야 하며(모든 엘리먼트 포함 `<script>` 태그 이전), 세 개의 대시 라인 사이에 유효한 YAML 형태로 작성되어야 합니다. 예:\n\n```md\n---\ntitle: VitePress로 문서 작성하기\neditLink: true\n---\n```\n\n많은 사이트 또는 기본 테마 구성 옵션은 전문에 해당 옵션이 있습니다. 전문을 사용하여 현재 페이지에 대한 특정 동작을 재정의할 수 있습니다. 자세한 내용은 [전문 구성 레퍼런스](../reference/frontmatter-config)를 참고하세요.\n\n또한 페이지에서 동적 Vue 표현식에 사용할 커스텀 전문 데이터를 정의할 수도 있습니다.\n\n## 전문 데이터에 접근하기 {#accessing-frontmatter-data}\n\n전문 데이터는 특별한 `$frontmatter` 전역 변수를 통해 접근할 수 있습니다:\n\n다음은 마크다운 파일에서 이를 사용하는 예입니다:\n\n```md\n---\ntitle: VitePress로 문서 작성하기\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\n가이드 내용\n```\n\n현재 페이지의 전문 데이터는 [`useData()`](../reference/runtime-api#usedata) 헬퍼를 사용하여 `<script setup>`에서도 접근할 수 있습니다.\n\n## 기타 전문 형식 {#alternative-frontmatter-formats}\n\nVitePress는 중괄호로 시작하고 끝나는 JSON 전문 문법도 지원합니다:\n\n```json\n---\n{\n  \"title\": \"해커처럼 블로깅하기\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/ko/guide/getting-started.md",
    "content": "\n# 시작하기 {#getting-started}\n\n## 온라인에서 사용해보기 {#try-it-online}\n\n[StackBlitz](https://vitepress.new)에서 브라우저로 즉시 VitePress를 사용해 볼 수 있습니다.\n\n## 설치 {#installation}\n\n### 사전 준비 사항 {#prerequisites}\n\n- [Node.js](https://nodejs.org/) 버전 20 이상.\n- VitePress를 명령줄 인터페이스(CLI)를 통해 접근하기 위한 터미널.\n- [마크다운](https://en.wikipedia.org/wiki/Markdown) 문법 지원이 있는 텍스트 에디터.\n  - [VSCode](https://code.visualstudio.com/)와 [공식 Vue 확장 프로그램](https://marketplace.visualstudio.com/items?itemName=Vue.volar) 사용을 권장합니다.\n\nVitePress는 단독으로 사용하거나 기존 프로젝트에 설치할 수 있습니다. 두 경우 모두 다음과 같이 설치할 수 있습니다:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip 참고\n\nVitePress는 ESM 전용 패키지입니다. `require()`를 사용하여 가져오지 마시고, `package.json`에 `\"type\": \"module\"`이 포함되어 있는지 확인하거나, 관련 파일(예: `.vitepress/config.js`)의 확장자를 `.mjs`/`.mts`로 변경하세요. 자세한 내용은 [Vite 문제 해결 가이드](http://vitejs.dev/ko/guide/troubleshooting.html#this-package-is-esm-only)를 참고하세요. 또한, 비동기 CJS 컨텍스트에서는 `await import('vitepress')`를 사용할 수 있습니다.\n\n:::\n\n### 설정 마법사 {#setup-wizard}\n\nVitePress는 기본 프로젝트를 구축하는 데 도움이 되는 명령줄 설정 마법사를 제공합니다. 설치 후, 마법사를 시작하려면 다음을 실행하세요:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\n몇 가지 간단한 질문들이 나타날 것입니다:\n\n<<< @/snippets/init.ansi\n\n::: tip 피어 의존성으로서의 Vue\n커스텀을 위해 Vue 컴포넌트나 API를 사용하려는 경우, `vue`를 명시적으로 의존성으로 설치해야 합니다.\n:::\n\n## 파일 구조 {#file-structure}\n\n독립형 VitePress 사이트를 구축하려는 경우, 현재 디렉터리(`./`)에 사이트를 구축할 수 있습니다. 그러나 기존 프로젝트에서 다른 소스 코드와 함께 VitePress를 설치하는 경우, 프로젝트의 나머지 부분과 분리되도록 중첩된 디렉터리(e.g. `./docs`)에 사이트를 구축하는 것이 좋습니다.\n\nVitePress 프로젝트를 `./docs`에 구축하기로 한 경우, 생성된 파일 구조는 다음과 같아야 합니다:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\n`docs` 디렉터리는 VitePress 사이트의 **프로젝트 루트**로 간주됩니다. `.vitepress` 디렉터리는 VitePress의 구성 파일, 개발 서버 캐시, 빌드 출력, 선택적 커스텀 테마 코드가 있는 위치입니다.\n\n::: tip\n기본적으로 VitePress는 개발 서버 캐시를 `.vitepress/cache`에 저장하고, 프로덕션 빌드 출력을 `.vitepress/dist`에 저장합니다. Git을 사용하는 경우, 이러한 디렉토리를 `.gitignore` 파일에 추가해야 합니다. 또는 이러한 위치를 수동으로 [구성](../reference/site-config#outdir)할 수도 있습니다.\n:::\n\n### 구성 파일 {#the-config-file}\n\n구성 파일(`.vitepress/config.js`)을 사용하면 사이트의 제목과 설명과 같은 VitePress 사이트의 다양한 측면을 커스터마이즈할 수 있습니다:\n\n```js [.vitepress/config.js]\nexport default {\n  // 사이트 옵션\n  title: 'VitePress',\n  description: '그냥 해보는 중.',\n\n  themeConfig: {\n    // 테마 옵션\n  }\n}\n```\n\n테마의 동작은 `themeConfig` 옵션을 통해 구성할 수도 있습니다. 모든 구성 옵션에 대한 자세한 내용은 [구성 레퍼런스](../reference/site-config)를 참고하세요.\n\n### 소스 파일 {#source-files}\n\n`.vitepress` 디렉토리 외부의 마크다운 파일은 **소스 파일**로 간주됩니다.\n\nVitePress는 **파일 기반 라우팅**을 사용합니다: 각 `.md` 파일은 동일한 경로에 해당하는 `.html` 파일로 컴파일됩니다. 예를 들어, `index.md`는 `index.html`로 컴파일되며, 결과적으로 VitePress 사이트의 루트 경로 `/`에서 방문할 수 있습니다.\n\n또한 VitePress는 간결한 URL 생성, 경로 재작성, 동적 페이지 생성 기능을 제공합니다. 이러한 내용은 [라우팅 가이드](./routing)에서 다룹니다.\n\n## 실행 및 작동 {#up-and-running}\n\n설치 과정에서 허용한 경우, 도구는 다음 npm 스크립트를 `package.json`에 추가했을 것입니다:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\n`docs:dev` 스크립트는 즉각적인 핫 업데이트가 가능한 로컬 개발 서버를 시작합니다. 다음 명령어로 실행할 수 있습니다:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nnpm 스크립트 대신 VitePress를 직접 호출할 수도 있습니다:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\n더 많은 명령줄 사용법은 [CLI 레퍼런스](../reference/cli)에 문서화되어 있습니다.\n\n개발 서버는 `http://localhost:5173`에서 실행되어야 합니다. 브라우저에서 URL을 방문하여 새 사이트를 확인하세요!\n\n## 다음 단계는? {#what-s-next}\n\n- 마크다운과 이 파일로 생성된 HTML이 어떻게 매핑되는지 더 잘 이해하려면 [라우팅 가이드](./routing)를 참고하세요.\n\n- 페이지에서 할 수 있는 작업, 예를 들어 마크다운 콘텐츠 작성이나 Vue 컴포넌트 사용에 대해 더 알아보려면 가이드의 \"글쓰기\" 섹션을 참조하세요. 시작하기 좋은 곳은 [마크다운 확장](./markdown)에 대해 배우는 것입니다.\n\n- 기본 문서 테마에서 제공하는 기능을 탐색하려면 [기본 테마 구성 레퍼런스](../reference/default-theme-config)를 확인하세요.\n\n- 사이트의 외관을 더 맞춤화하려면 [기본 테마 확장](./extending-default-theme) 또는 [커스텀 테마 빌드](./custom-theme)를 탐색하세요.\n\n- 문서 사이트가 형태를 갖추면 [배포 가이드](./deploy)를 꼭 읽어보세요.\n"
  },
  {
    "path": "docs/ko/guide/i18n.md",
    "content": "# i18n {#internationalization}\n\n내장된 i18n 기능을 사용하려면 다음과 같은 디렉토리 구조를 만들어야 합니다:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\n그런 다음 `docs/.vitepress/config.ts`에서:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // 공통 프로퍼티 및 기타 최상위 항목...\n\n  locales: {\n    root: {\n      label: '영어',\n      lang: 'en'\n    },\n    fr: {\n      label: '프랑스어',\n      lang: 'fr', // 선택 사항, `html` 태그에 `lang` 어트리뷰트로 추가됩니다\n      link: '/fr/guide' // 기본적으로 /fr/ -- navbar 번역 메뉴에 표시됩니다 (외부 링크 가능)\n\n      // 다른 로케일 특유의 프로퍼티...\n    }\n  }\n})\n```\n\n각 로케일(루트 포함)에 대해 다음 프로퍼티를 재정의할 수 있습니다:\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // 기존 헤드 항목과 병합되며, 중복된 메타 태그는 자동으로 제거됩니다\n  themeConfig?: ThemeConfig // 얕게 병합됩니다, 공통 항목은 최상위 themeConfig 항목에 넣을 수 있습니다\n}\n```\n\n기본 테마의 플레이스홀더 텍스트를 커스텀하는 방법에 대한 자세한 내용은 [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) 인터페이스를 참고하십시오. 로케일 수준에서 `themeConfig.algolia` 또는 `themeConfig.carbonAds`를 재정의하지 마십시오. 다국어 검색을 사용하려면 [Algolia docs](../reference/default-theme-search#i18n)를 참조하십시오.\n\n**전문가 팁:** 구성 파일은 `docs/.vitepress/config/index.ts`로 저장할 수도 있습니다. 로케일마다 구성 파일을 생성한 후 `index.ts`에서 병합하고 내보내어 내용을 구성하는 데 도움이 될 수 있습니다.\n\n## 각 로케일별 디렉토리 {#separate-directory-for-each-locale}\n\n다음은 완벽한 구조입니다:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\n그러나 기본적으로 VitePress는 `/`를 `/en/`로 리다이렉션하지 않습니다. 이를 위해 서버를 구성해야 합니다. 예를 들어, Netlify에서는 다음과 같이 `docs/public/_redirects` 파일을 추가할 수 있습니다:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**전문가 팁:** 위의 접근 방식을 사용하는 경우 `nf_lang` 쿠키를 사용하여 유저의 언어 선택을 유지할 수 있습니다:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## RTL 지원 (실험적) {#rtl-support-experimental}\n\nRTL 지원을 위해, 구성 파일에 `dir: 'rtl'`을 지정하고 <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> 또는 <https://github.com/elchininet/postcss-rtlcss>와 같은 RTLCSS PostCSS 플러그인을 사용하세요. PostCSS 플러그인을 구성하여 CSS 명시성 문제를 방지하기 위해 `:where([dir=\"ltr\"])` 및 `:where([dir=\"rtl\"])`을 접두사로 사용해야 합니다.\n"
  },
  {
    "path": "docs/ko/guide/markdown.md",
    "content": "# 마크다운 확장 기능 {#markdown-extensions}\n\nVitePress는 내장된 마크다운 확장 기능을 제공합니다.\n\n## 헤더 앵커 {#header-anchors}\n\n헤더에는 자동으로 앵커 링크가 적용됩니다. 앵커 렌더링은 `markdown.anchor` 옵션을 사용하여 구성할 수 있습니다.\n\n### 커스텀 앵커 {#custom-anchors}\n\n자동 생성된 앵커 대신 커스텀 앵커 태그를 지정하려면 헤딩에 접미사를 추가하세요:\n\n```\n# Using custom anchors {#my-anchor}\n```\n\n이를 통해 기본값인 `#using-custom-anchors` 대신 `#my-anchor`로 헤딩에 링크할 수 있습니다.\n\n## 링크 {#links}\n\n내부 링크와 외부 링크 모두 특별하게 취급됩니다.\n\n### 내부 링크 {#internal-links}\n\n내부 링크는 SPA 탐색을 위한 라우터 링크로 변환됩니다. 또한 각 하위 디렉터리에 포함된 모든 `index.md`는 자동으로 `index.html`로 변환되며, 해당 URL은 `/`로 설정됩니다.\n\n예를 들어, 다음과 같은 디렉터리 구조가 주어진 경우:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\n그리고 현재 `foo/one.md`에 있다고 가정하면:\n\n```md\n[Home](/) <!-- 사용자를 루트 index.md로 보냅니다 -->\n[foo](/foo/) <!-- foo 디렉토리의 index.html로 보냅니다 -->\n[foo heading](./#heading) <!-- foo index 파일의 헤딩으로 앵커링합니다 -->\n[bar - three](../bar/three) <!-- 확장자를 생략할 수 있습니다 -->\n[bar - three](../bar/three.md) <!-- .md를 추가할 수 있습니다 -->\n[bar - four](../bar/four.html) <!-- 또는 .html을 추가할 수 있습니다 -->\n```\n\n### 페이지 접미사 {#page-suffix}\n\n페이지와 내부 링크는 기본적으로 `.html` 접미사와 함께 생성됩니다.\n\n### 외부 링크 {#external-links}\n\n외부 링크는 자동으로 `target=\"_blank\" rel=\"noreferrer\"`를 갖습니다.\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## 전문 {#frontmatter}\n\n[YAML 전문](https://jekyllrb.com/docs/front-matter/)이 기본적으로 지원됩니다:\n\n```yaml\n---\ntitle: Blogging Like a Hacker\nlang: en-US\n---\n```\n\n이 데이터는 페이지의 나머지 부분과 모든 커스텀 및 테마 컴포넌트에서 사용할 수 있습니다.\n\n자세한 내용은 [전문](../reference/frontmatter-config)을 참고하세요.\n\n## GitHub 스타일 테이블 {#github-style-tables}\n\n**입력**\n\n```md\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n```\n\n**출력**\n\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n\n## 이모지 :tada: {#emoji}\n\n**입력**\n\n```\n:tada: :100:\n```\n\n**출력**\n\n:tada: :100:\n\n[모든 이모지의 목록](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs)이 제공됩니다.\n\n## 목차 {#table-of-contents}\n\n**입력**\n\n```\n[[toc]]\n```\n\n**출력**\n\n[[toc]]\n\n목차의 렌더링은 `markdown.toc` 옵션을 사용하여 구성할 수 있습니다.\n\n## 커스텀 컨테이너 {#custom-containers}\n\n커스텀 컨테이너는 타입, 제목, 콘텐츠를 정의할 수 있습니다.\n\n### 기본 제목 {#default-title}\n\n**입력**\n\n```md\n::: info\n정보 상자입니다.\n:::\n\n::: tip\n팁입니다.\n:::\n\n::: warning\n경고입니다.\n:::\n\n::: danger\n위험한 경고입니다.\n:::\n\n::: details\n세부 정보 블록입니다.\n:::\n```\n\n**출력**\n\n::: info\n정보 상자입니다.\n:::\n\n::: tip\n팁입니다.\n:::\n\n::: warning\n경고입니다.\n:::\n\n::: danger\n위험한 경고입니다.\n:::\n\n::: details\n세부 정보 블록입니다.\n:::\n\n### 사용자 정의 제목 {#custom-title}\n\n컨테이너의 \"타입\" 바로 뒤에 텍스트를 추가하여 커스텀 제목을 설정할 수 있습니다.\n\n**입력**\n\n````md\n::: danger 정지\n위험 지대, 진행하지 마세요\n:::\n\n::: details 코드를 보려면 클릭하세요\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n````\n\n**출력**\n\n::: danger 정지\n위험 지대, 진행하지 마세요\n:::\n\n::: details 코드를 보려면 클릭하세요\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n\n또는 사이트 구성에 다음을 추가하여 커스텀 제목을 전역적으로 설정할 수 있습니다. 이는 제목을 영어로 작성하지 않을 경우 유용합니다:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: '팁',\n      warningLabel: '경고',\n      dangerLabel: '위험',\n      infoLabel: '정보',\n      detailsLabel: '세부 정보'\n    }\n  }\n  // ...\n})\n```\n\n### `raw`\n\n이것은 VitePress와 스타일 및 라우터 충돌을 방지하기 위해 사용할 수 있는 특별한 컨테이너입니다. 컴포넌트 라이브러리를 문서화할 때 특히 유용합니다. 더 나은 분리를 위해 [whyframe](https://whyframe.dev/docs/integrations/vitepress)을 참고해 볼 수 있습니다.\n\n**문법**\n\n```md\n::: raw\n`<div class=\"vp-raw\">`로 감쌉니다\n:::\n```\n\n`vp-raw` 클래스는 엘리먼트에 직접 사용할 수도 있습니다. 스타일 분리는 현재 선택 사항입니다:\n\n- 선호하는 패키지 매니저를 사용하여 `postcss`를 설치하세요:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- `docs/postcss.config.mjs`라는 파일을 만들고 다음 내용을 추가하세요:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  다음과 같이 옵션을 전달할 수 있습니다:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // 기본값은 [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## GitHub 스타일 알림 {#github-flavored-alerts}\n\nVitePress는 [GitHub 스타일 알림](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)을 콜아웃으로 렌더링하는 것을 지원합니다. 이것은 [커스텀 컨테이너](#custom-containers)와 같은 방식으로 렌더링됩니다.\n\n```md\n> [!NOTE]\n> 문서를 빠르게 탐색할 때에도 사용자가 놓치지 말아야 할 중요한 정보.\n\n> [!TIP]\n> 사용자가 보다 원활하게 목표를 달성하는 데 도움이 되는 정보\n\n> [!IMPORTANT]\n> 사용자가 목표를 달성하는 데 중요한 정보.\n\n> [!WARNING]\n> 위험 가능성 때문에 사용자의 즉각적인 주의가 필요한 중요한 정보.\n\n> [!CAUTION]\n> 실행할 경우 잠재적으로 부정적인 결과를 생성한다는 것을 알리는 정보.\n```\n\n> [!NOTE]\n> 문서를 빠르게 탐색할 때에도 사용자가 놓치지 말아야 할 중요한 정보.\n\n> [!TIP]\n> 사용자가 보다 원활하게 목표를 달성하는 데 도움이 되는 정보\n\n> [!IMPORTANT]\n> 사용자가 목표를 달성하는 데 중요한 정보.\n\n> [!WARNING]\n> 위험 가능성 때문에 사용자의 즉각적인 주의가 필요한 중요한 정보.\n\n> [!CAUTION]\n> 실행할 경우 잠재적으로 부정적인 결과를 생성한다는 것을 알리는 정보.\n\n## 코드 블록 내 구문 강조 {#syntax-highlighting-in-code-blocks}\n\nVitePress는 마크다운 코드 블록 내 언어 문법을 색상이 있는 텍스트로 강조하기 위해 [Shiki](https://github.com/shikijs/shiki)를 사용합니다. Shiki는 다양한 프로그래밍 언어를 지원합니다. 코드 블록의 시작 백틱에 유효한 언어 별칭을 추가하기만 하면 됩니다:\n\n**입력**\n\n````markdown\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````markdown\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**출력**\n\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\nShiki의 리포지터리에서 사용 가능한 [유효한 언어 목록](https://shiki.style/languages)이 제공됩니다.\n\n또한 애플리케이션 구성에서 구문 강조 테마를 커스텀 할 수 있습니다. 자세한 내용은 [`markdown` 옵션](../reference/site-config#markdown)을 참고하세요.\n\n## 코드 블록에서 라인 강조 {#line-highlighting-in-code-blocks}\n\n**입력**\n\n````markdown\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: '강조됨!'\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js{4}\nexport default {\n  data() {\n    return {\n      msg: '강조됨!'\n    }\n  }\n}\n```\n\n단일 라인 뿐만 아니라 여러 개의 단일 라인, 범위 또는 둘 다 지정할 수도 있습니다:\n\n- 라인 범위: `{5-8}`, `{3-10}`, `{10-17}`\n- 여러 단일 라인: `{4,7,9}`\n- 라인 범위와 단일 라인: `{4,7-13,16,23-27,40}`\n\n**입력**\n\n````markdown\n```js{1,4,6-8}\nexport default { // 강조됨\n  data () {\n    return {\n      msg: `강조됨!\n      이 줄은 강조되지 않습니다,\n      하지만 이 줄과 다음 2줄은 강조됩니다.`,\n      motd: 'VitePress는 멋져요',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js{1,4,6-8}\nexport default { // 강조됨\n  data () {\n    return {\n      msg: `강조됨!\n      이 줄은 강조되지 않습니다,\n      하지만 이 줄과 다음 2줄은 강조됩니다.`,\n      motd: 'VitePress는 멋져요',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\n또는 `// [!code highlight]` 주석을 사용하여 직접 라인에 강조를 추가할 수 있습니다.\n\n**입력**\n\n````markdown\n```js\nexport default {\n  data () {\n    return {\n      msg: '강조됨!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: '강조됨!' // [!code highlight]\n    }\n  }\n}\n```\n\n## 코드 블록에서 포커싱 {#focus-in-code-blocks}\n\n`// [!code focus]` 주석을 라인에 추가하면 해당 라인이 포커싱되고 코드의 다른 부분은 흐릿하게 처리됩니다.\n\n추가로 `// [!code focus:<lines>]`를 사용하여 포커싱할 라인 수를 정의할 수 있습니다.\n\n**입력**\n\n````markdown\n```js\nexport default {\n  data () {\n    return {\n      msg: '포커싱됨!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: '포커싱됨!' // [!code focus]\n    }\n  }\n}\n```\n\n## 코드 블록 내 차이점 색 강조 {#colored-diffs-in-code-blocks}\n\n`// [!code --]` 또는 `// [!code ++]` 주석을 라인에 추가하면 해당 라인의 차이점을 나타내며, 코드 블록의 색상을 유지합니다.\n\n**입력**\n\n````markdown\n```js\nexport default {\n  data () {\n    return {\n      msg: '삭제됨' // [!!code --]\n      msg: '추가됨' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: '삭제됨' // [!code --]\n      msg: '추가됨' // [!code ++]\n    }\n  }\n}\n```\n\n## 코드 블록 내 오류 및 경고 {#errors-and-warnings-in-code-blocks}\n\n`// [!code warning]` 또는 `// [!code error]` 주석을 라인에 추가하면 해당 라인이 색칠됩니다.\n\n**입력**\n\n````markdown\n```js\nexport default {\n  data () {\n    return {\n      msg: '오류', // [!!code error]\n      msg: '경고' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**출력**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: '오류', // [!code error]\n      msg: '경고' // [!code warning]\n    }\n  }\n}\n```\n\n## 라인 번호 {#line-numbers}\n\n구성을 통해 각 코드 블록에 라인 번호를 활성화할 수 있습니다:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\n자세한 내용은 [`markdown` 옵션](../reference/site-config#markdown)을 참고하세요.\n\n구성에서 지정한 값을 무시하려면 펜싱 코드 블록에 `:line-numbers` / `:no-line-numbers` 마크를 추가하면 됩니다.\n\n또한 `=`를 `:line-numbers` 뒤에 추가하여 시작 라인 번호를 커스텀 할 수도 있습니다. 예를 들어 `:line-numbers=2`는 코드 블록의 라인 번호가 `2`부터 시작함을 의미합니다.\n\n**입력**\n\n````md\n```ts {1}\n// 줄 번호는 기본적으로 비활성화되어 있음\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// 줄 번호가 활성화됨\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// 줄 번호가 활성화되고 2부터 시작함\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n````\n\n**출력**\n\n```ts {1}\n// 줄 번호는 기본적으로 비활성화되어 있음\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// 줄 번호가 활성화됨\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// 줄 번호가 활성화되고 2부터 시작함\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n\n## 코드 스니펫 가져오기 {#import-code-snippets}\n\n다음 문법을 통해 기존 파일에서 코드 스니펫을 가져올 수 있습니다:\n\n```md\n<<< @/파일경로\n```\n\n다음과 같이 [라인 강조](#line-highlighting-in-code-blocks)도 지원합니다:\n\n```md\n<<< @/파일경로{강조 할 라인}\n```\n\n**입력**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**코드 파일**\n\n<<< @/snippets/snippet.js\n\n**출력**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\n`@`의 값은 소스 루트에 해당합니다. 기본값은 VitePress 프로젝트 루트이지만, `srcDir`이 구성되어 있을 경우에는 다릅니다. 상대 경로에서도 가져올 수도 있습니다:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\n특정 부분의 코드 파일만 포함하려면 [VS Code 리전](https://code.visualstudio.com/docs/editor/codebasics#_folding)을 사용할 수 있습니다. 파일 경로 뒤에 `#`을 사용한 다음 커스텀 리전 이름을 제공할 수 있습니다:\n\n**입력**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**코드 파일**\n\n<<< @/snippets/snippet-with-region.js\n\n**출력**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\n괄호(`{}`) 안에 언어를 지정할 수도 있습니다:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- 라인 강조와 함께: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- 라인 번호와 함께: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\n이는 파일 확장명에서 소스 언어를 유추할 수 없을 때 유용합니다.\n\n## 코드 그룹 {#code-groups}\n\n다음과 같이 여러 코드 블록을 그룹화할 수 있습니다:\n\n**입력**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**출력**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\n코드 그룹에서 [스니펫 가져오기](#import-code-snippets)도 할 수 있습니다:\n\n**입력**\n\n```md\n::: code-group\n\n<!-- 기본적으로 파일 이름이 제목으로 사용됩니다 -->\n\n<<< @/snippets/snippet.js\n\n<!-- 커스텀 제목도 제공할 수 있습니다 -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [지역 스니펫]\n\n:::\n```\n\n**출력**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [지역 스니펫]\n\n:::\n\n## 마크다운 파일 포함 {#markdown-file-inclusion}\n\n마크다운 파일을 다른 마크다운 파일에 포함시킬 수 있으며, 중첩도 가능합니다.\n\n::: tip\n마크다운 경로 앞에 `@`를 붙일 수도 있으며, 이는 소스 루트로 작동합니다. 기본적으로 이는 VitePress 프로젝트 루트이며, `srcDir`이 구성되지 않은 경우입니다.\n:::\n\n다음과 같이 상대적인 마크다운 파일을 포함시킬 수 있습니다:\n\n**입력**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**해당 파일** (`parts/basics.md`)\n\n```md\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**동일한 코드**\n\n```md\n# Docs\n\n## Basics\n\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n라인 범위 선택도 지원합니다:\n\n**입력**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**해당 파일** (`parts/basics.md`)\n\n```md\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**동일한 코드**\n\n```md\n# Docs\n\n## Basics\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n선택된 라인 범위의 형식은 `{3,}`, `{,10}`, `{1,10}`이 될 수 있습니다.\n\n[VS Code 리전](https://code.visualstudio.com/docs/editor/codebasics#_folding)을 사용하여 코드 파일의 해당 부분만 포함할 수도 있습니다. 파일 경로 뒤에 `#`를 붙이고 커스텀 영역 이름을 제공할 수 있습니다:\n\n**입력**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md#basic-usage{,2}-->\n<!--@@include: ./parts/basics.md#basic-usage{5,}-->\n```\n\n**해당 파일** (`parts/basics.md`)\n\n```md\n<!-- #region basic-usage -->\n## Usage Line 1\n\n## Usage Line 2\n\n## Usage Line 3\n<!-- #endregion basic-usage -->\n```\n\n**동일한 코드**\n\n```md\n# Docs\n\n## Basics\n\n## Usage Line 1\n\n## Usage Line 3\n```\n\n::: warning\n파일이 존재하지 않더라도 오류가 발생하지 않는다는 점에 유의하십시오. 따라서 이 기능을 사용할 때 내용이 예상대로 렌더링되고 있는지 확인해야 합니다.\n:::\n\n## 수식 {#math-equations}\n\n선택 사항입니다. 활성화하려면 `markdown-it-mathjax3`를 설치하고 설정 파일에서 `markdown.math`를 `true`로 설정해야 합니다:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**입력**\n\n```md\n$a \\ne 0$ 일 때, $(ax^2 + bx + c = 0)$의 두 해는 다음과 같습니다:\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**맥스웰 방정식:**\n\n| 방정식                                                                                                                                                                  | 설명                                                                                |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                    | $\\vec{\\mathbf{B}}$의 발산은 0입니다                                                 |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                        | $\\vec{\\mathbf{E}}$의 회전은 $\\vec{\\mathbf{B}}$의 시간에 따른 변화율에 비례합니다     |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                               |\n```\n\n**출력**\n\n$a \\ne 0$ 일 때, $(ax^2 + bx + c = 0)$의 두 해는 다음과 같습니다:\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**맥스웰 방정식:**\n\n| 방정식                                                                                                                                                                  | 설명                                                                                |\n| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                    | $\\vec{\\mathbf{B}}$의 발산은 0입니다                                                 |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                        | $\\vec{\\mathbf{E}}$의 회전은 $\\vec{\\mathbf{B}}$의 시간에 따른 변화율에 비례합니다     |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                               |\n\n## 이미지 지연 로딩 {#image-lazy-loading}\n\n마크다운을 통해 추가된 각 이미지에 대해 지연 로딩을 활성화하려면 구성 파일에서 `lazyLoading`을 `true`로 설정하세요:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // 이미지 지연 로딩은 기본적으로 비활성화 되어 있습니다\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## 고급 설정 {#advanced-configuration}\n\nVitePress는 마크다운 렌더러로 [markdown-it](https://github.com/markdown-it/markdown-it)을 사용합니다. 위의 많은 확장 기능은 커스텀 플러그인을 통해 구현됩니다. `.vitepress/config.js`의 `markdown` 옵션을 사용하여 `markdown-it` 인스턴스를 추가로 커스터마이즈할 수 있습니다:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // markdown-it-anchor의 옵션\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // @mdit-vue/plugin-toc의 옵션\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // 더 많은 markdown-it 플러그인을 사용!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\n구성 가능한 프로퍼티의 전체 목록은 [레퍼런스: 앱 구성](../reference/site-config#markdown)에서 확인하세요.\n"
  },
  {
    "path": "docs/ko/guide/migration-from-vitepress-0.md",
    "content": "# Migration from VitePress 0.x {#migration-from-vitepress-0-x}\n\nIf you're coming from VitePress 0.x version, there're several breaking changes due to new features and enhancement. Please follow this guide to see how to migrate your app over to the latest VitePress.\n\n## App Config {#app-config}\n\n- The internationalization feature is not yet implemented.\n\n## Theme Config {#theme-config}\n\n- `sidebar` option has changed its structure.\n  - `children` key is now named `items`.\n  - Top level item may not contain `link` at the moment. We're planning to bring it back.\n- `repo`, `repoLabel`, `docsDir`, `docsBranch`, `editLinks`, `editLinkText` are removed in favor of more flexible api.\n  - For adding GitHub link with icon to the nav, use [Social Links](../reference/default-theme-nav#navigation-links) feature.\n  - For adding \"Edit this page\" feature, use [Edit Link](../reference/default-theme-edit-link) feature.\n- `lastUpdated` option is now split into `config.lastUpdated` and `themeConfig.lastUpdatedText`.\n- `carbonAds.carbon` is changed to `carbonAds.code`.\n\n## Frontmatter Config {#frontmatter-config}\n\n- `home: true` option has changed to `layout: home`. Also, many Homepage related settings have been modified to provide additional features. See [Home Page guide](../reference/default-theme-home-page) for details.\n- `footer` option is moved to [`themeConfig.footer`](../reference/default-theme-config#footer).\n"
  },
  {
    "path": "docs/ko/guide/migration-from-vuepress.md",
    "content": "# Migration from VuePress {#migration-from-vuepress}\n\n## Config {#config}\n\n### Sidebar {#sidebar}\n\nThe sidebar is no longer automatically populated from frontmatter. You can [read the frontmatter yourself](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) to dynamically populate the sidebar. [Additional utilities for this](https://github.com/vuejs/vitepress/issues/96) may be provided in the future.\n\n## Markdown {#markdown}\n\n### Images {#images}\n\nUnlike VuePress, VitePress handles [`base`](./asset-handling#base-url) of your config automatically when you use static image.\n\nHence, now you can render images without `img` tag.\n\n```diff\n- <img :src=\"$withBase('/foo.png')\" alt=\"foo\">\n+ ![foo](/foo.png)\n```\n\n::: warning\nFor dynamic images you still need `withBase` as shown in [Base URL guide](./asset-handling#base-url).\n:::\n\nUse `<img.*withBase\\('(.*)'\\).*alt=\"([^\"]*)\".*>` regex to find and replace it with `![$2]($1)` to replace all the images with `![](...)` syntax.\n\n---\n\nmore to follow...\n"
  },
  {
    "path": "docs/ko/guide/mpa-mode.md",
    "content": "# MPA 모드 <Badge type=\"warning\" text=\"실험적\" /> {#mpa-mode}\n\nMPA (다중 페이지 애플리케이션) 모드는 명령줄에서 `vitepress build --mpa`를 통해 활성화할 수 있으며, 구성 파일에서 `mpa: true` 옵션을 통해서도 활성화할 수 있습니다.\n\nMPA 모드에서는 모든 페이지가 기본적으로 JavaScript 없이 렌더링됩니다. 그 결과, 프로덕션 사이트는 감사 도구로부터 초기 방문 성능 점수가 더 좋을 가능성이 있습니다.\n\n그러나 SPA 탐색이 없기 때문에 페이지 간 링크는 전체 페이지를 새로 고침합니다. MPA 모드에서의 포스트-로드 탐색은 SPA 모드만큼 즉각적으로 느껴지지 않을 것입니다.\n\n또한 기본적으로 JS가 없다는 것은 Vue를 순전히 서버 사이드 템플릿 언어로 사용하고 있다는 것을 의미합니다. 브라우저에서는 이벤트 핸들러가 첨부되지 않으므로 상호작용이 없습니다. 클라이언트 사이드 JavaScript를 로드하려면 특별한 `<script client>` 태그를 사용해야 합니다:\n\n```html\n<script client>\n  document.querySelector('h1').addEventListener('click', () => {\n    console.log('client side JavaScript!')\n  })\n</script>\n\n# Hello\n```\n\n`<script client>`는 VitePress 전용 기능이며, Vue 기능이 아닙니다. 이 기능은 `.md` 파일과 `.vue` 파일에서 모두 작동하지만, MPA 모드에서만 사용됩니다. 모든 테마 컴포넌트의 클라이언트 스크립트는 함께 번들링되지만, 특정 페이지에 대한 클라이언트 스크립트는 개별적으로 처리됩니다.\n\n`<script client>`는 **Vue 컴포넌트 코드로 평가되지 않음**을 유의하십시오. 이는 단순한 JavaScript 모듈로 처리됩니다. 이러한 이유로, 사이트가 최소한의 클라이언트 사이드 상호작용을 요구하는 경우에만 MPA 모드를 사용하는 것이 좋습니다.\n"
  },
  {
    "path": "docs/ko/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# 라우팅 {#routing}\n\n## 파일 기반 라우팅 {#file-based-routing}\n\nVitePress는 파일 기반 라우팅을 사용하므로, 생성된 HTML 페이지는 소스 마크다운 파일의 디렉토리 구조에서 매핑됩니다. 예를 들어, 다음과 같은 디렉토리 구조가 있다고 가정하면:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\n생성된 HTML 페이지는 다음과 같습니다:\n\n```\nindex.md                  -->  /index.html (/ 로 접근 가능)\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html (/guide/ 로 접근 가능)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\n생성된 HTML은 정적 파일을 제공할 수 있는 모든 웹 서버에서 호스팅할 수 있습니다.\n\n## 루트와 소스 디렉토리 {#root-and-source-directory}\n\nVitePress 프로젝트의 파일 구조에는 두 가지 중요한 개념이 있습니다: **프로젝트 루트**와 **소스 디렉토리**입니다.\n\n### 프로젝트 루트 {#project-root}\n\n프로젝트 루트는 VitePress가 `.vitepress` 특수 디렉토리를 찾으려고 하는 위치입니다. `.vitepress` 디렉토리는 VitePress의 구성 파일, 개발 서버 캐시, 빌드 출력물, 그리고 선택적인 커스텀 테마 코드를 위한 예약된 위치입니다.\n\n명령줄에서 `vitepress dev`나 `vitepress build`를 실행하면 VitePress는 현재 작업 디렉토리를 프로젝트 루트로 사용합니다. 서브 디렉토리를 루트로 지정하려면 명령어에 상대 경로를 전달해야 합니다. 예를 들어, VitePress 프로젝트가 `./docs`에 위치한 경우, `vitepress dev docs`를 실행해야 합니다:\n\n```\n.\n├─ docs                    # 프로젝트 루트\n│  ├─ .vitepress           # 구성 폴더\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\n이렇게 하면 다음과 같은 소스에서 HTML로의 매핑이 이루어집니다:\n\n```\ndocs/index.md            -->  /index.html (/ 로 접근 가능)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### 소스 디렉토리 {#source-directory}\n\n소스 디렉터리는 마크다운 소스 파일이 저장되는 위치입니다. 기본적으로 프로젝트 루트와 동일합니다. 그러나 [`srcDir`](../reference/site-config#srcdir) 구성 옵션으로 설정할 수 있습니다.\n\n`srcDir` 옵션은 프로젝트 루트를 기준으로 해석됩니다. 예를 들어, `srcDir: 'src'`로 설정하면 파일 구조는 다음과 같이 됩니다:\n\n```\n.                          # 프로젝트 루트\n├─ .vitepress              # 구성 디렉터리\n└─ src                     # 소스 디렉터리\n   ├─ getting-started.md\n   └─ index.md\n```\n\n소스에서 HTML로 매핑된 결과:\n\n```\nsrc/index.md            -->  /index.html (/ 로 접근 가능)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## 페이지 간 연결 {#linking-between-pages}\n\n페이지 간 링크를 만들 때 절대 경로와 상대 경로 모두 사용할 수 있습니다. `.md`와 `.html` 확장자 모두 작동하지만, VitePress가 구성에 따라 최종 URL을 생성할 수 있도록 파일 확장자를 생략하는 것이 좋은 방법입니다.\n\n```md\n<!-- Do -->\n[시작하기](./getting-started)\n[시작하기](../guide/getting-started)\n\n<!-- Don't -->\n[시작하기](./getting-started.md)\n[시작하기](./getting-started.html)\n```\n\n이미지와 같은 에셋에 링크하는 방법에 대해 더 알아보려면 [에셋 처리](./asset-handling)를 참고하세요.\n\n### VitePress 페이지가 아닌 페이지로 연결 {#linking-to-non-vitepress-pages}\n\nVitePress로 생성되지 않은 페이지에 연결하려면 전체 URL(새 탭에서 열림)을 사용하거나 명시적으로 target을 지정해야 합니다:\n\n**입력**\n\n```md\n[Link to pure.html](/pure.html){target=\"_self\"}\n```\n\n**출력**\n\n[Link to pure.html](/pure.html){target=\"_self\"}\n\n::: tip 참고\n\n마크다운 링크에서 `base`는 URL 앞에 자동으로 추가됩니다. 이는 기본 경로 외부의 페이지에 링크하려면 링크에 `../../pure.html`과 같은 내용이 필요하다는 것을 의미합니다(브라우저에서 현재 페이지를 기준으로 해석됨).\n\n또는 앵커 태그 문법을 직접 사용할 수도 있습니다:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Link to pure.html</a>\n```\n\n:::\n\n## 간결한 URL 생성 {#generating-clean-urls}\n\n::: warning 서버 지원 필요\nVitePress가 간결한 URL을 제공하려면 서버 측 지원이 필요합니다.\n:::\n\n기본적으로 VitePress는 `.html`로 끝나는 URL로 들어오는 링크를 처리합니다. 하지만 일부 사용자는 `.html` 확장자가 없는 \"간결한 URL\"을 선호할 수 있습니다. 예를 들어, `example.com/path.html` 대신 `example.com/path`.\n\n일부 서버 또는 호스팅 플랫폼(예: Netlify, Vercel, GitHub Pages)은 리다이렉션 없이 `/foo`와 같은 URL을 `/foo.html`로 매핑할 수 있는 기능을 제공합니다:\n\n- Netlify와 GitHub Pages는 기본적으로 이 기능을 지원합니다.\n- Vercel은 [`vercel.json`에서 `cleanUrls` 옵션을 활성화](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls)해야 합니다.\n\n이 기능을 사용할 수 있는 경우, VitePress의 자체 [`cleanUrls`](../reference/site-config#cleanurls) 구성 옵션을 활성화해서:\n\n- 페이지 간의 들어오는 링크가 `.html` 확장자 없이 생성됩니다.\n- 현재 경로가 `.html`로 끝나는 경우, 라우터가 확장자 없는 경로로 클라이언트 리다이렉션을 수행합니다.\n\n하지만 서버가 이러한 구성을 지원하지 않는 경우, 다음과 같은 디렉토리 구조를 수동으로 사용해야 합니다:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## 라우트 재작성 {#route-rewrites}\n\n프로젝트의 소스 디렉토리 구조와 생성된 페이지 간의 매핑을 사용자 정의할 수 있습니다. 이는 복잡한 프로젝트 구조를 가질 때 유용합니다. 예를 들어, 여러 패키지가 있는 모노레포를 가지고 있고, 소스 파일과 함께 문서를 다음과 같이 배치하고 싶다고 가정해 봅시다:\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ pkg-a-code.ts\n│  │      └─ pkg-a-docs.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ pkg-b-code.ts\n│         └─ pkg-b-docs.md\n```\n\n그리고 VitePress 페이지를 다음과 같이 생성하고 싶다고 가정해 봅시다:\n\n```\npackages/pkg-a/src/pkg-a-docs.md  -->  /pkg-a/index.html\npackages/pkg-b/src/pkg-b-docs.md  -->  /pkg-b/index.html\n```\n\n이것은 [`rewrites`](../reference/site-config#rewrites) 옵션을 구성하여 구현할 수 있습니다:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',\n    'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'\n  }\n}\n```\n\n`rewrites` 옵션은 동적 라우트 파라미터도 지원합니다. 위 예에서 많은 패키지를 가지고 있다면 모든 경로를 나열하는 것이 번거로울 것입니다. 동일한 파일 구조를 가지고 있는 경우, 구성은 다음과 같이 간단하게 만들 수 있습니다:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/(.*)': ':pkg/index.md'\n  }\n}\n```\n\n라우트 재작성은 `path-to-regexp` 패키지를 사용하여 컴파일됩니다. 보다 고급 문법에 대해서는 [여기](https://github.com/pillarjs/path-to-regexp#parameters)를 참고하십시오.\n\n::: warning 재작성과 상대 링크\n\n재작성 기능이 활성화되면, **상대 링크는 재작성된 경로를 기준으로 해야 합니다**. 예를 들어, `packages/pkg-a/src/pkg-a-code.md`에서 `packages/pkg-b/src/pkg-b-code.md`로 상대 링크를 생성하려면, 다음과 같이 사용해야 합니다:\n\n```md\n[Link to PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## 동적 라우트 {#dynamic-routes}\n\n단일 마크다운 파일과 동적 데이터를 사용하여 여러 페이지를 생성할 수 있습니다. 예를 들어, 프로젝트의 모든 패키지에 해당하는 페이지를 생성하는 `packages/[pkg].md` 파일을 만들 수 있습니다. 여기서 `[pkg]` 세그먼트는 각 페이지를 구분하는 라우트 **파라미터**입니다.\n\n### 경로 로더 파일 {#paths-loader-file}\n\nVitePress는 정적 사이트 생성기이므로, 가능한 페이지 경로는 빌드 시에 결정되어야 합니다. 따라서 동적 라우트 페이지는 반드시 **경로 로더 파일**과 함께 제공되어야 합니다. `packages/[pkg].md`의 경우, `packages/[pkg].paths.js` (`.ts`도 지원됩니다) 파일이 필요합니다:\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # route template\n   └─ [pkg].paths.js   # route paths loader\n```\n\n경로 로더는 `paths` 메서드를 기본 내보내기로 제공하는 객체를 포함해야 합니다. `paths` 메서드는 `params` 객체 프로퍼티를 가진 배열을 반환해야 합니다. 이 객체들 각각이 해당하는 페이지를 생성하게 됩니다.\n\n다음과 같이 `paths` 배열이 주어진 경우:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\n생성된 HTML 페이지는 다음과 같습니다:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### 여러 파라미터 {#multiple-params}\n\n동적 라우트는 여러 파라미터를 포함할 수 있습니다:\n\n**파일 구조**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**경로 로더**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**결과물**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### 동적으로 경로 생성 {#dynamically-generating-paths}\n\n경로 로더 모듈은 Node.js에서 실행되며 빌드 시에만 실행됩니다. 로컬 또는 원격 데이터를 사용하여 동적으로 경로 배열을 생성할 수 있습니다.\n\n로컬 파일에서 경로 생성:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\n원격 데이터에서 경로 생성:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### 페이지에서 파라미터에 접근 {#accessing-params-in-page}\n\n파라미터를 사용하여 각 페이지에 추가 데이터를 전달할 수 있습니다. 마크다운 라우트 파일은 `$params` 전역 프로퍼티를 통해 Vue 표현식에서 현재 페이지 파라미터에 접근할 수 있습니다:\n\n```md\n- 패키지 이름: {{ $params.pkg }}\n- 버전: {{ $params.version }}\n```\n\n또는 [`useData`](../reference/runtime-api#usedata) 런타임 API를 통해 현재 페이지의 파라미터에 접근할 수 있습니다. 이는 마크다운 파일과 Vue 컴포넌트 모두에서 사용할 수 있습니다:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params는 Vue ref입니다\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### 원시 콘텐츠 렌더링 {#rendering-raw-content}\n\n페이지에 전달되는 파라미터는 클라이언트 JavaScript 페이로드에서 직렬화되므로, 원격 CMS에서 가져온 원시 Markdown이나 HTML 콘텐츠와 같은 무거운 데이터를 파라미터로 전달하지 마십시오.\n\n대신, 각 경로 객체의 `content` 프로퍼티를 사용하여 이러한 콘텐츠를 각 페이지에 전달할 수 있습니다:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // 원시 마크다운 또는 HTML\n      }\n    })\n  }\n}\n```\n\n그런 다음 특수 문법을 사용하여 마크다운 파일 자체의 일부로 콘텐츠를 렌더링할 수 있습니다:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/ko/guide/sitemap-generation.md",
    "content": "# 사이트맵 생성 {#sitemap-generation}\n\nVitePress는 사이트의 `sitemap.xml` 파일 생성을 지원합니다. 이를 활성화하려면 `.vitepress/config.js`에 다음을 추가하십시오:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\n`<lastmod>` 태그를 `sitemap.xml`에 포함하려면 [`lastUpdated`](../reference/default-theme-last-updated) 옵션을 활성화할 수 있습니다.\n\n## 옵션 {#options}\n\n사이트맵 지원은 [`sitemap`](https://www.npmjs.com/package/sitemap) 모듈에 의해 제공됩니다. 구성 파일의 `sitemap` 옵션에 지원되는 모든 옵션을 전달할 수 있습니다. 이러한 옵션은 `SitemapStream` 생성자에 직접 전달됩니다. 자세한 내용은 [`sitemap` 문서](https://www.npmjs.com/package/sitemap#options-you-can-pass)를 참고하세요. 예:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\n구성 파일에서 `base`를 사용하는 경우, `hostname` 옵션에 이것을 추가해야 합니다:\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## `transformItems` Hook {#transformitems-hook}\n\n`sitemap.transformItems` 훅을 사용하여 `sitemap.xml` 파일에 작성되기 전에 사이트맵 아이템을 수정할 수 있습니다. 이 훅은 사이트맵 아이템 배열을 인자로 받고 사이트맵 아이템 배열을 반환해야 합니다. 예제:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // 새로운 아이템 추가 또는 기존 아이템 수정/필터링\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ko/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# SSR 호환성 {#ssr-compatibility}\n\nVitePress는 Vue의 서버 사이드 렌더링(SSR) 기능을 사용하여 프로덕션 빌드 중에 Node.js에서 애플리케이션을 사전 렌더링합니다. 이는 테마 컴포넌트의 모든 커스텀 코드가 SSR 호환성을 준수해야 함을 의미합니다.\n\n공식 Vue 문서의 [SSR 섹션](https://vuejs.org/guide/scaling-up/ssr.html)은 SSR이 무엇인지, SSR / SSG 간의 관계, 그리고 SSR 친화적인 코드를 작성할 때의 일반적인 주의 사항에 대해 더 많은 정보를 제공합니다. 핵심 원칙은 Vue 컴포넌트의 `beforeMount` 또는 `mounted` 훅에서만 브라우저 / DOM API에 접근하는 것입니다.\n\n## `<ClientOnly>`\n\nSSR 친화적이지 않은 컴포넌트(예: 커스텀 디렉티브를 포함한 컴포넌트)를 사용하거나 시연하는 경우, 내장된 `<ClientOnly>` 컴포넌트로 해당 컴포넌트를 래핑할 수 있습니다:\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## \"import\" 시 브라우저 API에 접근하는 라이브러리 {#libraries-that-access-browser-api-on-import}\n\n일부 컴포넌트나 라이브러리는 **\"import\" 시** 브라우저 API에 접근합니다. \"import\" 시 브라우저 환경을 가정하는 코드를 사용하려면, 동적 \"import\"를 사용해야 합니다.\n\n### Mounted 훅에서 가져오기 {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // 코드 사용하기\n  })\n})\n</script>\n```\n\n### 조건부 가져오기 {#conditional-import}\n\n`import.meta.env.SSR` 플래그([Vite 환경 변수](https://vitejs.dev/guide/env-and-mode.html#env-variables)의 일부)를 사용하여 종속성을 조건부로 \"import\" 할 수도 있습니다:\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // 코드 사용하기\n  })\n}\n```\n\n[`Theme.enhanceApp`](./custom-theme#theme-interface)은 비동기로 사용할 수 있기 때문에, \"import\" 시 브라우저 API에 접근하는 Vue 플러그인을 조건부로 \"import\"하고 등록할 수 있습니다:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nTypeScript를 사용하는 경우:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress는 \"import\" 시 브라우저 API에 접근하는 Vue 컴포넌트를 \"import\" 할 수 있는 편리한 헬퍼를 제공합니다.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\n대상 컴포넌트에 props/children/slots를 전달할 수도 있습니다:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // h() 에 전달된 인자 - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => '기본 슬롯',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', '하나'), h('span', '둘')]\n    }\n  ],\n\n  // 컴포넌트가 로드된 후 콜백함수, 비동기일 수 있음\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\n대상 컴포넌트는 래퍼 컴포넌트의 mounted 훅에서만 \"import\" 됩니다.\n"
  },
  {
    "path": "docs/ko/guide/using-vue.md",
    "content": "# 마크다운에서 Vue 사용하기 {#using-vue-in-markdown}\n\nVitePress에서는 각 마크다운 파일이 HTML로 컴파일된 후 [Vue 단일 파일 컴포넌트](https://vuejs.org/guide/scaling-up/sfc.html)로 처리됩니다. 이는 마크다운 내에서 Vue 컴포넌트를 사용하거나 동적 템플릿을 사용하거나 `<script>` 태그를 추가하여 임의의 페이지 내 Vue 컴포넌트 로직을 사용할 수 있다는 것을 의미합니다.\n\nVitePress는 Vue의 컴파일러를 활용하여 마크다운 콘텐츠의 순수 정적 부분을 자동으로 감지하고 최적화합니다. 정적 콘텐츠는 단일 플레이스홀더 노드로 최적화되어 초기 방문 시 페이지의 JavaScript 페이로드에서 제거됩니다. 또한 클라이언트 측 하이드레이션 중에도 건너뜁니다. 요약하자면 특정 페이지에서는 동적 부분에 대해서만 비용을 지불하면 됩니다.\n\n::: tip SSR 호환성\n모든 Vue 사용은 SSR과 호환되어야 합니다. 자세한 내용 및 일반적인 해결 방법은 [SSR 호환성](./ssr-compat)을 참고하세요.\n:::\n\n## 템플릿 {#templating}\n\n### 보간 문법 {#interpolation}\n\n각 마크다운 파일은 먼저 HTML로 컴파일된 다음 Vue 컴포넌트로 Vite 프로세스 파이프라인에 전달됩니다. 이는 텍스트에서 Vue 스타일 보간 문법을 사용할 수 있음을 의미합니다:\n\n**입력**\n\n```md\n{{ 1 + 1 }}\n```\n\n**출력**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### 디렉티브 {#directives}\n\n디렉티브도 사용할 수 있습니다(원시 HTML도 마크다운에서 작동함):\n\n**입력**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**출력**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` & `<style>` {#script-and-style}\n\n루트 레벨의 `<script>` 및 `<style>` 태그는 마크다운 파일에서 Vue SFCs에서와 마찬가지로 작동하며, `<script setup>`, `<style module>` 등도 포함됩니다. 여기서 주요 차이점은 `<template>` 태그가 없다는 것입니다: 다른 모든 루트 레벨의 컨텐츠는 마크다운입니다. 또한 **모든 태그는 전문 이후에 배치**되어야 합니다:\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## 마크다운 컨텐츠\n\n현재 카운트: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">증가</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning 마크다운에서 `<style scoped>` 사용을 피하세요\n마크다운에서 `<style scoped>`를 사용할 때는 현재 페이지의 모든 엘리먼트에 특수한 어트리뷰트를 추가해야 하므로 페이지 크기를 크게 부풀릴 수 있습니다. 페이지에서 로컬 범위의 스타일링이 필요한 경우 `<style module>`을 사용하는 것이 좋습니다.\n:::\n\n또한 현재 페이지의 메타데이터에 접근할 수 있는 [`useData` 헬퍼](../reference/runtime-api#usedata)와 같은 VitePress의 런타임 API에도 접근할 수 있습니다:\n\n**입력**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**출력**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"마크다운에서 Vue 사용하기\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## 컴포넌트 사용하기 {#using-components}\n\n마크다운 파일 내에서 Vue 컴포넌트를 직접 가져와서 사용할 수 있습니다.\n\n### 마크다운에서 컴포넌트 가져오기 {#importing-in-markdown}\n\n컴포넌트가 몇 페이지에서만 사용되는 경우, 사용되는 곳에서 명시적으로 가져오는 것이 좋습니다. 이렇게 하면 적절하게 코드를 분할하고 관련 페이지가 표시될 때만 로드할 수 있습니다:\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# 문서\n\n이것은 커스텀 컴포넌트를 사용하는 .md입니다\n\n<CustomComponent />\n\n## 더 많은 문서\n\n...\n```\n\n### 전역적으로 컴포넌트 등록하기 {#registering-components-globally}\n\n컴포넌트가 대부분의 페이지에서 사용될 경우, Vue 앱 인스턴스를 커스텀하여 전역적으로 등록할 수 있습니다. [기본 테마 확장](./extending-default-theme#registering-global-components)의 관련 섹션을 예제를 참고하세요.\n\n::: warning 중요\n커스텀 컴포넌트의 이름에 하이픈이 포함되어 있거나 파스칼케이스(PascalCase)인지 확인하세요. 그렇지 않으면 인라인 요소로 처리되어 `<p>` 태그 안에 래핑됩니다. `<p>`는 블록 엘리먼트를 내부에 배치할 수 없기 때문에 하이드레이션 불일치가 발생합니다.\n:::\n\n### 헤더에 <ComponentInHeader /> 컴포넌트 사용하기  {#using-components-in-headers}\n\n헤더에서 Vue 컴포넌트를 사용할 수 있지만, 다음 문법간 차이점에 주의해야 합니다:\n\n| 마크다운                                                   | 출력 HTML                               | 파싱된 헤더 |\n|--------------------------------------------------------| ----------------------------------------- | ------------- |\n| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre>     | `<h1>text <Tag/></h1>`                    | `text`        |\n| <pre v-pre><code> # text \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>` |\n\n`<code>`로 감싼 HTML은 있는 그대로 표시되며, **감싸지 않은** HTML만 Vue에 의해 파싱됩니다.\n\n::: tip\n출력된 HTML은 [Markdown-it](https://github.com/Markdown-it/Markdown-it)에 의해 생성되며, 파싱된 헤더는 VitePress에 의해 처리됩니다(사이드바와 문서 제목 모두에 사용됩니다).\n:::\n\n\n## 이스케이프 {#escaping}\n\nVue 보간 문법을 회피하려면, `<span>` 또는 다른 엘리먼트에 `v-pre` 디렉티브를 사용하여 감쌀 수 있습니다:\n\n**입력**\n\n```md\n이것은 <span v-pre>{{ 그대로 표시됩니다 }}</span>\n```\n\n**출력**\n\n<div class=\"escape-demo\">\n  <p>이것은 <span v-pre>{{ 그대로 표시됩니다 }}</span></p>\n</div>\n\n또는 전체 문단을 `v-pre` 커스텀 컨테이너로 감쌀 수도 있습니다:\n\n```md\n::: v-pre\n{{ 이것은 그대로 표시됩니다 }}\n:::\n```\n\n**출력**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ 이것은 그대로 표시됩니다 }}\n:::\n\n</div>\n\n## 코드 블록에서 이스케이프 해제하기 {#unescape-in-code-blocks}\n\n기본적으로 모든 펜스 코드 블록은 자동으로 `v-pre`로 감싸져 있어, 내부에서는 Vue 문법이 처리되지 않습니다. 펜스 내부에서 Vue 스타일 보간 문법을 사용하려면, `js-vue`처럼 언어에 `-vue` 접미사를 추가할 수 있습니다:\n\n**입력**\n\n````md\n```js-vue\n안녕하세요 {{ 1 + 1 }}\n```\n````\n\n**출력**\n\n```js-vue\n안녕하세요 {{ 1 + 1 }}\n```\n\n이로 인해 특정 토큰이 올바르게 강조 표시되지 않을 수 있습니다.\n\n## CSS 전처리기 사용하기 {#using-css-pre-processors}\n\nVitePress는 CSS 전처리기인 `.scss`, `.sass`, `.less`, `.styl`, `.stylus` 파일에 대해 [기본 지원](https://vitejs.dev/guide/features.html#css-pre-processors)을 제공합니다. 이를 위해 Vite 전용 플러그인을 설치할 필요는 없지만, 해당 전처리기 자체는 설치해야 합니다:\n\n```\n# .scss 및 .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl 및 .stylus\nnpm install -D stylus\n```\n\n그런 다음 마크다운 및 테마 컴포넌트에서 다음과 같이 사용할 수 있습니다:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## 텔레포트 사용하기 {#using-teleports}\n\nVitePress는 현재 body로 텔레포트를 사용하는 SSG만 지원합니다. 다른 대상에 대해 텔레포트를 사용하려면 내장된 `<ClientOnly>` 컴포넌트로 감싸거나 [`postRender` 훅](../reference/site-config#postrender)을 통해 최종 페이지 HTML의 올바른 위치에 텔레포트 마크업을 삽입할 수 있습니다.\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n"
  },
  {
    "path": "docs/ko/guide/what-is-vitepress.md",
    "content": "# VitePress란 무엇인가? {#what-is-vitepress}\n\nVitePress는 빠르고 컨텐츠 중심의 웹사이트를 구축하기 위해 설계된 [정적 사이트 생성기](https://en.wikipedia.org/wiki/Static_site_generator) (SSG)입니다. 다시말해 VitePress는 [마크다운](https://en.wikipedia.org/wiki/Markdown)으로 작성된 소스 컨텐츠를 가져와서 테마를 적용하고, 어디에나 쉽게 배포할 수 있는 정적 HTML 페이지를 생성합니다.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\n그냥 한번 사용해보고 싶으신가요? [빠른 시작](./getting-started)으로 건너뛰세요.\n\n</div>\n\n## 사용 사례 {#use-cases}\n\n- **문서화**\n\n  VitePress는 기술 문서를 위해 설계된 기본 테마가 함께 제공됩니다. 지금 읽고 있는 이 페이지와 [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) 및 [다양한 프로젝트](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code) 문서는  모두 이 테마를 기반으로 합니다.\n\n  [Vue.js 공식 문서](https://vuejs.org/)도 VitePress 기반으로 되어 있으며, 여러 번역본에 걸쳐 공유되는 커스텀 테마를 사용합니다.\n\n- **블로그, 포트폴리오 및 마케팅 사이트**\n\n  VitePress는 표준 Vite + Vue 애플리케이션의 개발자 경험을 가진 [커스텀 테마](./custom-theme)를 지원합니다. Vite 기반이기 때문에 Vite 생태계의 풍부한 플러그인을 직접 활용할 수 있습니다. 또한, VitePress는 [데이터 로딩](./data-loading) (로컬 또는 원격) 및 [동적 라우트 생성](./routing#dynamic-routes)을 위한 유연한 API를 제공합니다. 빌드 시점에 데이터를 결정할 수 있다면 거의 모든 것을 구축할 수 있습니다.\n\n  공식 [Vue.js 블로그](https://blog.vuejs.org/)는 로컬 콘텐츠 기반의 인덱스 페이지를 생성하는 간단한 블로그입니다.\n\n## 개발자 경험 {#developer-experience}\n\nVitePress는 마크다운 컨텐츠를 다룰 때 훌륭한 개발자 경험(DX)을 제공하고자 합니다.\n\n- **[Vite로 작동](https://vitejs.dev/)**: 즉각적인 서버 시작 가능, 페이지 새로고침 없이 즉시(<100ms) 수정 사항 반영.\n\n- **[내장된 마크다운 확장 기능](./markdown)**: 서문, 표, 구문 강조 등 무엇이든 가능. 특히 VitePress는 코드 블록 작업을 위한 고급 기능을 많이 제공하여 기술적 문서에 이상적.\n\n- **[Vue로 향상된 마크다운](./using-vue)**: 각 마크다운 페이지는 HTML과 100% 문법 호환성을 가진 Vue [단일 파일 컴포넌트](https://vuejs.org/guide/scaling-up/sfc.html)입니다. Vue 템플릿 기능이나 컴포넌트를 사용하여 정적 콘텐츠에 상호작용 기능을 포함할 수 있습니다.\n\n## 성능 {#performance}\n\n전통적인 SSG들과 달리, VitePress로 생성된 웹사이트는 초기 방문 시 정적 HTML을 제공하지만, 이후 사이트 내 탐색에 대해서는 [단일 페이지 애플리케이션](https://en.wikipedia.org/wiki/Single-page_application) (SPA)이 됩니다. 이 모델은 성능에 대한 최적의 균형을 제공합니다:\n\n- **빠른 초기 로딩**\n\n  초기 페이지 방문은 사전 렌더링된 HTML을 제공하여 빠른 로딩 속도와 최적의 SEO를 제공합니다. 그 후 페이지를 Vue SPA로 전환하는 JavaScript 번들이 로드됩니다(이것을 \"하이드레이션\"이라고 함). 일반적으로 SPA 하이드레이션이 느리다고 생각할 수 있지만, Vue 3의 성능과 컴파일러 최적화 덕분에 이 과정은 매우 빠릅니다. [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F)에서 일반적인 VitePress 사이트는 네트워크 속도가 느린 저가형 모바일 기기에서도 거의 완벽한 성능 점수를 얻습니다.\n\n- **빠른 포스트 로드 탐색**\n\n  더 중요한 것은 SPA 모델이 처음 로드된 후 더 나은 UX를 제공한다는 것입니다. 이후 사이트 내에서 탐색을 해도 전체 페이지가 다시 로드되는 현상이 더 이상 발생하지 않습니다. 대신 페이지의 콘텐츠를 불러와 동적으로 업데이트 합니다. 또한 VitePress는 뷰포트 내에 있는 링크의 페이지 청크를 자동으로 미리 가져옵니다. 이렇게 하면 대부분의 경우 유저는 이미 로드된 페이지에서 탐색할 때 새 페이지가 즉시 로드됩니다.\n\n- **페널티 없는 상호작용**\n\n  정적 마크다운 내에 내장된 동적 Vue 부분을 하이드레이션 할 수 있도록 각 마크다운 페이지는 Vue 컴포넌트로 처리되고 JavaScript로 컴파일됩니다. 이는 비효율적으로 보일 수 있지만, Vue 컴파일러는 정적 부분과 동적 부분을 분리하여 하이드레이션 비용과 페이로드 크기를 최소화합니다. 초기 페이지 로드 시, 정적 부분은 자동으로 JavaScript 페이로드에서 제거되고 하이드레이션 중 건너뜁니다.\n\n## VuePress는 어떤가요? {#what-about-vuepress}\n\nVitePress는 VuePress의 후속 버전 입니다. 원래 VuePress는 Vue 2와 webpack을 기반으로 했습니다. Vue 3와 Vite를 기반으로 한 VitePress는 훨씬 더 나은 DX, 더 나은 프로덕션 성능, 더 다듬어진 기본 테마, 더 유연한 커스터마이징 API를 제공합니다.\n\nVitePress와 VuePress의 API 차이는 주로 테마와 커스터마이징에 있습니다. 기본 테마를 사용하는 VuePress 1을 사용 중이라면 VitePress로의 마이그레이션은 비교적 간단할 것입니다.\n\nVuePress 2도 Vue 3와 Vite를 지원하며 VuePress 1과의 호환성을 높이기 위해 많은 노력이 투자되었습니다. 그러나 두 SSG를 병렬로 유지하는 것은 지속 가능하지 않으므로 Vue 팀은 장기적인 관점에서 주요 권장 SSG인 VitePress에 집중하기로 결정했습니다.\n"
  },
  {
    "path": "docs/ko/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue 기반 정적 사이트 생성기\n  tagline: 단 몇 분 만에 마크다운을 우아한 문서로 변환\n  actions:\n    - theme: brand\n      text: VitePress란 무엇인가?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: 빠른 시작\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: 콘텐츠에 집중\n    details: 마크다운으로만 아름다운 문서 사이트를 쉽게 만들기.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Vite DX(개발자 경험) 즐겨보기\n    details: 즉각적인 서버 시작, 매우 빠른 업데이트, Vite 생태계 플러그인을 활용.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Vue로 커스터마이징\n    details: Vue 문법과 컴포넌트를 마크다운에서 직접 사용하거나 Vue로 커스텀 테마를 구축.\n  - icon: 🚀\n    title: 웹사이트를 빠르게 제공\n    details: 정적 HTML로 빠른 초기 로딩, 클라이언트 측 라우팅을 통한 빠른 탐색.\n---\n"
  },
  {
    "path": "docs/ko/reference/cli.md",
    "content": "# 명령 줄 인터페이스 {#command-line-interface}\n\n## `vitepress dev`\n\n지정된 디렉터리를 루트로 하여 VitePress 개발 서버를 시작합니다. 기본값은 현재 디렉터리입니다. 현재 디렉터리에서 실행할 때 `dev` 명령은 생략할 수 있습니다.\n\n### 사용법 {#usage}\n\n```sh\n# 현재 디렉토리에서 시작, `dev` 생략\nvitepress\n\n# 하위 디렉터리에서 시작\nvitepress dev [root]\n```\n\n### 옵션 {#options}\n\n| 옵션             | 설명                                                              |\n| ---------------- | ----------------------------------------------------------------- |\n| `--open [path]`  | 시작 시 브라우저 열기 (`boolean \\| string`)                      |\n| `--port <port>`  | 포트 지정 (`number`)                                             |\n| `--base <path>`  | Public 기본 경로 (기본값: `/`) (`string`)                          |\n| `--cors`         | CORS 활성화                                                      |\n| `--strictPort`   | 지정된 포트가 이미 사용 중인 경우 종료 (`boolean`)               |\n| `--force`        | 옵티마이저가 캐시를 무시하고 다시 번들링하도록 강제 (`boolean`)  |\n\n## `vitepress build`\n\nVitePress 사이트를 프로덕션 빌드합니다.\n\n### 사용법 {#usage-1}\n\n```sh\nvitepress build [root]\n```\n\n### 옵션 {#options-1}\n\n| 옵션                          | 설명                                                                                          |\n| ----------------------------- |---------------------------------------------------------------------------------------------|\n| `--mpa` (실험적)              | 클라이언트 측 하이드레이션 없이 [MPA 모드](../guide/mpa-mode)로 빌드 (`boolean`)                               |\n| `--base <path>`               | Public 기본 경로 (기본값: `/`) (`string`)                                                              |\n| `--target <target>`           | 트랜스파일 대상 (기본값: `\"modules\"`) (`string`)                                                      |\n| `--outDir <dir>`              | **cwd** 기준 출력 디렉터리 (기본값: `<root>/.vitepress/dist`) (`string`)                               |\n| `--assetsInlineLimit <number>`| 바이트 단위의 정적 에셋 base64 인라인 임계값 (기본값: `4096`) (`number`)                                       |\n\n## `vitepress preview`\n\n프로덕션 빌드를 로컬에서 미리 보기 합니다.\n\n### 사용법 {#usage-2}\n\n```sh\nvitepress preview [root]\n```\n\n### 옵션 {#options-2}\n\n| 옵션             | 설명                                      |\n| ---------------- | ----------------------------------------- |\n| `--base <path>`  | Public 기본 경로 (기본값: `/`) (`string`)   |\n| `--port <port>`  | 포트 지정 (`number`)                      |\n\n## `vitepress init`\n\n현재 디렉터리에서 [설정 마법사](../guide/getting-started#setup-wizard)를 시작합니다.\n\n### 사용법 {#usage-3}\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-badge.md",
    "content": "# 배지 {#badge}\n\n배지는 헤더에 상태를 추가할 수 있게 해줍니다. 예를 들어, 섹션의 타입을 지정하거나 지원되는 버전을 표시하는 데 유용할 수 있습니다.\n\n## 사용법 {#usage}\n\n`Badge` 컴포넌트는 전역으로 사용 가능합니다.\n\n```html\n### 제목 <Badge type=\"info\" text=\"default\" />\n### 제목 <Badge type=\"tip\" text=\"^1.9.0\" />\n### 제목 <Badge type=\"warning\" text=\"배타\" />\n### 제목 <Badge type=\"danger\" text=\"주의\" />\n```\n\n위 코드는 다음과 같이 렌더링됩니다:\n\n### 제목 <Badge type=\"info\" text=\"default\" />\n### 제목 <Badge type=\"tip\" text=\"^1.9.0\" />\n### 제목 <Badge type=\"warning\" text=\"배타\" />\n### 제목 <Badge type=\"danger\" text=\"주의\" />\n\n## 커스텀 하위 노드 {#custom-children}\n\n`<Badge>`는 `children`을 받아서 배지 내부에 표시합니다.\n\n```html\n### 제목 <Badge type=\"info\">커스텀 노드</Badge>\n```\n\n### 제목 <Badge type=\"info\">커스텀 노드</Badge>\n\n## 타입 색상 커스터마이징 {#customize-type-color}\n\n배지의 스타일은 CSS 변수를 재정의하여 커스터마이징 할 수 있습니다. 다음은 기본값입니다:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\n`<Badge>` 컴포넌트는 다음과 같은 프로퍼티를 사용합니다:\n\n```ts\ninterface Props {\n  // `<slot>`이 전달되면, 이 값은 무시됨.\n  text?: string\n\n  // 기본값: `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-carbon-ads.md",
    "content": "# 카본 광고 {#carbon-ads}\n\nVitePress는 [카본 광고](https://www.carbonads.net/)에 대한 기본적인 지원을 제공합니다. 구성에서 카본 광고 자격 증명을 정의하면 VitePress는 페이지에 광고를 표시합니다.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n이 값들은 아래와 같이 카본 CDN 스크립트를 호출하는 데 사용됩니다.\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\n카본 광고 구성에 대해 더 알고 싶다면 [카본 광고 웹사이트](https://www.carbonads.net/)를 방문하세요.\n"
  },
  {
    "path": "docs/ko/reference/default-theme-config.md",
    "content": "# 기본 테마 구성 {#default-theme-config}\n\n테마 구성은 테마를 커스텀 할 수 있게 해줍니다. 구성 파일에서 `themeConfig` 옵션을 통해 테마 구성을 정의할 수 있습니다:\n\n```ts\nexport default {\n  lang: 'ko-KR',\n  title: 'VitePress',\n  description: 'Vite 및 Vue로 기반 정적 사이트 생성기.',\n\n  // 테마 관련 구성.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**이 페이지에 문서화된 옵션은 기본 테마에만 적용됩니다.** 다른 테마는 다른 테마 구성이 필요합니다. 커스텀 테마를 사용하는 경우, 테마 구성 객체는 테마에 전달되어 테마가 이를 기반으로 다르게 동작할 수 있습니다.\n\n## i18nRouting\n\n- 타입: `boolean`\n\n로케일을 `ko`로 변경하면 URL이 `/foo` (또는 `/en/foo/`)에서 `/ko/foo`로 변경됩니다. 이 동작을 비활성화하려면 `themeConfig.i18nRouting`을 `false`로 설정하세요.\n\n## logo\n\n- 타입: `ThemeableImage`\n\n네비게이션 바에 사이트 제목 바로 앞에 표시할 로고 파일입니다. 경로 문자열 또는 라이트/다크 모드에 대해 다른 로고를 설정할 수 있는 객체를 사용합니다.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- 타입: `string | false`\n\n이 항목을 커스텀하여 네비게이션 바의 기본 사이트 제목(애플리케이션 구성의 `title`)을 대체할 수 있습니다. `false`로 설정하면 네비게이션 바에서 제목이 비활성화됩니다. 이미 사이트 제목 텍스트가 포함된 `logo`가 있을 때 유용합니다.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hello World'\n  }\n}\n```\n\n## nav\n\n- 타입: `NavItem`\n\n네비게이션 바 메뉴 아이템의 구성입니다. 자세한 내용은 [기본 테마: 네비게이션 바](./default-theme-nav#navigation-links)를 참고하세요.\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: '가이드', link: '/guide' },\n      {\n        text: '드롭다운 메뉴',\n        items: [\n          { text: '항목 A', link: '/item-1' },\n          { text: '항목 B', link: '/item-2' },\n          { text: '항목 C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- 타입: `Sidebar`\n\n사이드바 메뉴 항목에 대한 구성입니다. 자세한 내용은 [기본 테마: 사이드바](./default-theme-sidebar)에서 확인하세요.\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '가이드',\n        items: [\n          { text: '소개', link: '/introduction' },\n          { text: '시작하기', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n}\n\nexport type SidebarItem = {\n  /**\n   * 아이템의 텍스트 레이블\n   */\n  text?: string\n\n  /**\n   * 아이템의 링크\n   */\n  link?: string\n\n  /**\n   * 아이템의 하위 항목\n   */\n  items?: SidebarItem[]\n\n  /**\n   * 명시하지 않은 경우, 그룹을 접을 수 없습니다.\n   *\n   * `true`: 그룹은 접을 수 있고 기본적으로 접혀 있습니다.\n   *\n   * `false`: 그룹은 접을 수 있고 기본적으로 펼쳐져 있습니다.\n   */\n  collapsed?: boolean\n\n  /**\n   * 하위 아이템에 대한 기본 경로입니다.\n   */\n  base?: string\n\n  /**\n   * 이전/다음 페이지의 푸터에 나타나는 텍스트를 커스텀 합니다.\n   */\n  docFooterText?: string\n\n  rel?: string\n  target?: string\n}\n```\n\n## aside\n\n- 타입: `boolean | 'left'`\n- 기본값: `true`\n- [전문](./frontmatter-config#aside)을 통해 페이지별로 재정의할 수 있습니다.\n\n`false`: 어사이드 컨테이너가 렌더링되지 않습니다.\\\n`true`: 어사이드가 오른쪽에 렌더링됩니다.\\\n`left`: 어사이드가 왼쪽에 렌더링됩니다.\n\n모든 뷰포트에서 비활성화하려면 `outline: false`를 사용해야 합니다.\n\n## outline\n\n- 타입: `Outline | Outline['level'] | false`\n- [전문](./frontmatter-config#outline)을 사용해 각 페이지별로 계층 구조를 재정의할 수 있습니다.\n\n이 값을 `false`로 설정하면 아웃라인(개요) 컨테이너가 렌더링되지 않습니다. 자세한 내용은 아래 인터페이스를 참고하세요:\n\n```ts\ninterface Outline {\n  /**\n   * 아웃라인에 표시할 제목 레벨.\n   * 단일 숫자는 해당 레벨의 제목만 표시됨을 의미합니다.\n   * 튜플이 전달되면, 첫 번째 숫자는 최소 수준을, 두 번째 숫자는 최대 수준을 나타냅니다.\n   * `'deep'`은 `[2, 6]`과 동일하며, 이는 `<h2>`에서 `<h6>`까지의 모든 제목이 표시됨을 의미합니다.\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * 아웃라인에 표시될 제목.\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- 타입: `SocialLink[]`\n\n이 옵션을 정의하여 네비게이션 바에 소셜 링크를 아이콘과 함께 표시할 수 있습니다.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // SVG를 문자열로 전달하여 커스텀 아이콘을 추가할 수도 있습니다:\n      {\n        icon: {\n          svg: '<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\" width=\"24px\" fill=\"#e8eaed\"><path d=\"m354-287 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-120l65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Zm247-350Z\"/></svg>'\n        },\n        link: '...',\n        // 접근성을 위해 커스텀 레이블을 포함할 수도 있습니다 (선택 사항이지만 권장됨):\n        ariaLabel: '스타 링크'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- 타입: `Footer`\n- [전문](./frontmatter-config#footer)을 사용해 페이지별로 재정의할 수 있습니다.\n\n푸터 구성입니다. 메시지 또는 저작권 텍스트를 푸터에 추가할 수 있지만, 이는 페이지에 사이드바가 포함되지 않은 경우에만 표시됩니다. 이는 디자인상의 이유 때문입니다.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'MIT 라이선스에 따라 릴리즈되었습니다.',\n      copyright: '저작권 © 2019-현재 홍길동'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- 타입: `EditLink`\n- [전문](./frontmatter-config#footer)을 사용해 페이지별로 재정의할 수 있습니다.\n\n편집 링크 기능을 사용하면 GitHub 또는 GitLab과 같은 Git 관리 서비스에서 페이지를 편집할 수 있는 링크를 표시할 수 있습니다. 자세한 내용은 [기본 테마: 편집 링크](./default-theme-edit-link)를 참고하세요.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'GitHub에서 이 페이지 편집하기'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- 타입: `LastUpdatedOptions`\n\n마지막 업데이트된 날짜의 텍스트와 날짜 형식을 커스텀 할 수 있습니다.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: '마지막 업데이트 날짜',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * {dateStyle: 'short', timeStyle: 'short'}\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- 타입: `AlgoliaSearch`\n\n[Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch)를 사용하여 문서 사이트를 검색할 수 있는 옵션입니다. 자세한 내용은 [기본 테마: 검색](./default-theme-search)을 참고하세요.\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\n전체 옵션은 [여기](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)에서 확인하세요.\n\n## carbonAds {#carbon-ads}\n\n- 타입: `CarbonAdsOptions`\n\n[Carbon Ads](https://www.carbonads.net/)를 표시할 수 있는 옵션입니다.\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\n자세한 내용은 [기본 테마: 카본 광고](./default-theme-carbon-ads)를 참고하세요.\n\n## docFooter\n\n- 타입: `DocFooter`\n\n이 옵션은 이전 및 다음 링크에 표시되는 텍스트를 커스텀하는 데 사용합니다. 영어로 문서를 작성하지 않는 경우 유용합니다. 또한 이전/다음 링크를 전역적으로 비활성화할 수도 있습니다. 선택적으로 이전/다음 링크를 활성화/비활성화하려면 [전문](./default-theme-prev-next-links)을 사용합니다.\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: '이전 페이지',\n      next: '다음 페이지'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- 타입: `string`\n- 기본값: `Appearance`\n\n이 옵션은 다크 모드 스위치 레이블을 커스텀할 때 사용합니다. 이 레이블은 모바일 뷰에서만 표시됩니다.\n\n## lightModeSwitchTitle\n\n- 타입: `string`\n- 기본값: `Switch to light theme`\n\n이 옵션은 라이트 모드 스위치 타이틀을 커스텀할 때 사용합니다. 이것은 호버(hover)할 때 나타납니다.\n\n## darkModeSwitchTitle\n\n- 타입: `string`\n- 기본값: `Switch to dark theme`\n\n호버 시 나타나는 다크 모드 스위치 타이틀을 커스텀할 때 사용합니다.\n\n## sidebarMenuLabel\n\n- 타입: `string`\n- 기본값: `Menu`\n\n사이드바 메뉴 레이블을 커스텀 할 때 사용합니다. 이 레이블은 모바일 뷰에서만 표시됩니다.\n\n## returnToTopLabel\n\n- 타입: `string`\n- 기본값: `Return to top`\n\n맨 위로 이동 버튼의 레이블을 커스텀 할 때 사용합니다. 이 레이블은 모바일 뷰에서만 표시됩니다.\n\n## langMenuLabel\n\n- 타입: `string`\n- 기본값: `Change language`\n\n네비게이션 바에서 언어 토글 버튼의 aria-label을 커스텀 할 때 사용합니다. 이는 [i18n](../guide/i18n)을 사용하는 경우에만 사용됩니다.\n\n## externalLinkIcon\n\n- 타입: `boolean`\n- 기본값: `false`\n\n마크다운의 외부 링크 옆에 외부 링크 아이콘을 표시할지 여부를 설정합니다.\n"
  },
  {
    "path": "docs/ko/reference/default-theme-edit-link.md",
    "content": "# 편집 링크 {#edit-link}\n\n## 사이트 단계에서 설정하기 {#site-level-config}\n\n편집 링크는 GitHub, GitLab과 같은 Git 관리 서비스에서 페이지를 편집할 수 있는 링크를 표시할 수 있게 해줍니다. 이를 활성화하려면 `themeConfig.editLink` 옵션을 구성에 추가하세요.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\n`pattern` 옵션은 링크의 URL 구조를 정의하며, `:path`는 페이지 경로로 대체됩니다.\n\n또한, [`PageData`](./runtime-api#usedata)를 인자로 받아 URL 문자열을 반환하는 순수 함수를 사용할 수도 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\n이 함수는 브라우저에서 직렬화되어 실행되므로, 부작용을 가지지 않고 해당 스코프 외부의 어떤 것도 참조하지 않도록 해야 합니다.\n\n기본적으로 이 설정은 문서 페이지 하단에 \"Edit this page\"이라는 텍스트 링크를 추가합니다. 이 텍스트는 `text` 옵션을 정의하여 커스터마이징 할 수 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: '이 페이지 편집 제안하기'\n    }\n  }\n}\n```\n\n## 전문에서 설정하기 {#frontmatter-config}\n\n페이지별로 이 기능을 비활성화하려면, 전문에서 `editLink` 옵션을 사용하세요:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-footer.md",
    "content": "# 푸터 {#footer}\n\n`themeConfig.footer`가 존재하면 VitePress는 페이지 하단에 전역 푸터를 표시합니다.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'MIT 라이선스에 따라 릴리즈되었습니다.',\n      copyright: '저작권 © 2019-현재 홍길동'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // 저작권 전에 표시되는 메시지.\n  message?: string\n\n  // 실제 저작권 텍스트.\n  copyright?: string\n}\n```\n\n위의 구성은 HTML 문자열도 지원합니다. 예를 들어, 푸터 텍스트에 링크를 포함하고 싶다면, 다음과 같이 구성을 수정하면 됩니다:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: '<a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">MIT 라이선스</a>에 따라 릴리즈되었습니다.',\n      copyright: '저작권 © 2019-현재 <a href=\"https://github.com/niceplugin\">홍길동</a>'\n    }\n  }\n}\n```\n\n::: warning\n`message`와 `copyright`는 `<p>` 엘리먼트 내부에 렌더링되므로 인라인 엘리먼트만 사용할 수 있습니다. 블록 엘리먼트를 추가하려면 [`layout-bottom`](../guide/extending-default-theme#layout-slots) 슬롯을 사용하는 것이 좋습니다.\n:::\n\n[사이드바](./default-theme-sidebar)가 표시되는 경우 푸터는 표시되지 않습니다.\n\n## 전문에서 설정하기 {#frontmatter-config}\n\n이 기능은 전문의 `footer` 옵션을 사용하여 페이지별로 비활성화 할 수 있습니다.\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-home-page.md",
    "content": "# 홈 페이지 {#home-page}\n\nVitePress 기본 테마는 홈 페이지 레이아웃을 제공합니다. 이것은 이 사이트의 [홈 페이지](../)에도 사용되었습니다. `layout: home`을 [전문](./frontmatter-config)에 지정하여 어느 페이지에서도 이를 사용할 수 있습니다.\n\n```yaml\n---\nlayout: home\n---\n```\n\n하지만 이 옵션만으로는 많은 것을 할 수 없습니다. 다행히도 `hero` 및 `features`와 같은 추가 옵션을 설정하여 홈 페이지에 다양한 사전 템플릿 \"섹션\"들을 추가할 수 있습니다.\n\n## Hero 섹션 {#hero-section}\n\nHero 섹션은 홈 페이지의 상단에 위치합니다. Hero 섹션을 구성하는 방법은 다음과 같습니다.\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue 기반 정적 사이트 생성기\n  tagline: 단 몇 분 만에 마크다운을 우아한 문서로 변환\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: VitePress란 무엇인가?\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // `text` 위에 브랜드 색상으로 표시되는 문자열.\n  // 제품명 등 간략한 내용을 추천.\n  name?: string\n\n  // hero 섹션의 본문.\n  // `h1` 태그로 정의됨.\n  text: string\n\n  // `text` 아래에 표시되는 슬로건 문자열.\n  tagline?: string\n\n  // `text` 및 `tagline` 옆에 표시되는 이미지.\n  image?: ThemeableImage\n\n  // hero 섹션에 표시할 버튼 리스트.\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // 버튼의 색상 테마. 기본값: `brand`\n  theme?: 'brand' | 'alt'\n\n  // 버튼의 레이블.\n  text: string\n\n  // 버튼의 목적지 링크.\n  link: string\n\n  // 링크의 target 어트리뷰트.\n  target?: string\n\n  // 링크의 rel 어트리뷰트.\n  rel?: string\n}\n```\n\n### `name` 색상 커스터마이징 {#customizing-the-name-color}\n\nVitePress는 `name`에 브랜드 색상(`--vp-c-brand-1`)을 사용합니다. 하지만 `--vp-home-hero-name-color` 변수를 재정의하여 이 색상을 커스텀 할 수 있습니다.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\n또한 `--vp-home-hero-name-background` 변수를 정의해 추가적으로 `name`을 그라데이션 색상으로 커스터마이징도 가능합니다.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## Features 섹션 {#features-section}\n\nFeatures 섹션에서는 Hero 섹션 바로 아래에 표시할 각 feature를 원하는 만큼 나열할 수 있습니다. 이를 구성하려면 `features` 옵션을 전문에 전달하면 됩니다.\n\n각 feature에 아이콘을 제공할 수 있으며, 이는 이모지 또는 이미지의 형태일 수 있습니다. 아이콘으로 이미지(svg, png, jpeg 등)를 사용하려면 적절한 너비와 높이를 제공해야 하며, 필요에 따라 설명, 이미지의 고유 크기, 다크 테마와 라이트 테마에 대한 변형 아이콘도 제공할 수 있습니다.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Simple and minimal, always\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // 각 feature 박스에 표시할 아이콘.\n  icon?: FeatureIcon\n\n  // feature의 제목.\n  title: string\n\n  // feature의 세부 정보.\n  details: string\n\n  // feature 컴포넌트 클릭 시 링크.\n  // 링크는 내부 또는 외부 모두 가능.\n  //\n  // 예: `guide/reference/default-theme-home-page` 또는 `https://example.com`\n  link?: string\n\n  // feature 컴포넌트 내 표시될 링크 텍스트.\n  // `link` 옵션과 함께 사용하는 것을 추천.\n  //\n  // 예: `더 알아보기`, `페이지 방문` 등\n  linkText?: string\n\n  // `link` 옵션을 위한 링크 rel 어트리뷰트.\n  //\n  // 예: `external`\n  rel?: string\n\n  // `link` 옵션을 위한 링크 target 어트리뷰트.\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## 마크다운 컨텐츠 {#markdown-content}\n\n홈 페이지 레이아웃에 추가 컨텐츠를 작성하려면 전문 구분선 `---` 아래에 마크다운을 추가하면 됩니다.\n\n````md\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue 기반 정적 사이트 생성기\n---\n\n## 시작하기\n\n`npx`를 사용하여 VitePress를 바로 시작할 수 있습니다!\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n\n::: info\n`layout: home` 페이지의 추가 컨텐츠에 자동으로 기본 마크다운 스타일이 적용됩니다(영문 원서에서는 반대로 설명함). 스타일을 적용하지 않으려면 전문에 `markdownStyles: false`를 추가하면 됩니다.\n:::\n"
  },
  {
    "path": "docs/ko/reference/default-theme-last-updated.md",
    "content": "# 마지막 업데이트 날짜 {#last-updated}\n\n마지막 업데이트 날짜는 페이지 오른쪽 하단에 표시됩니다. 이를 활성화하려면 구성 파일에 `lastUpdated` 옵션을 추가하세요.\n\n::: tip\n마크다운 파일을 커밋해야 업데이트된 시간을 확인할 수 있습니다.\n:::\n\n## 사이트 단계에서 설정하기 {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## 전문에서 설정하기 {#frontmatter-config}\n\n페이지별로 이 기능을 비활성화하려면, 전문에서 `lastUpdated` 옵션을 사용하세요:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n자세한 내용은 [기본 테마: lastUpdated](./default-theme-config#lastupdated)를 참고하세요. 테마 레벨에서 참(truthy) 값을 설정하면, 사이트나 페이지 레벨에서 명시적으로 비활성화하지 않는 한 이 기능이 활성화됩니다.\n"
  },
  {
    "path": "docs/ko/reference/default-theme-layout.md",
    "content": "# 레이아웃 {#layout}\n\n페이지의 [전문](./frontmatter-config)에 `layout` 옵션을 설정하여 페이지 레이아웃을 선택할 수 있습니다. `doc`, `page`, `home` 세 가지 레이아웃 옵션이 있습니다. 아무것도 지정하지 않으면 `doc` 페이지로 처리됩니다.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## `doc` 레이아웃 {#doc-layout}\n\n`doc` 옵션은 기본 레이아웃으로, 전체 마크다운 콘텐츠를 \"문서\" 스타일로 변환합니다. 이 레이아웃은 전체 콘텐츠를 `vp-doc` CSS 클래스로 감싸고, 하위 엘리먼트에 스타일을 적용하는 방식으로 작동합니다.\n\n`p`나 `h2` 같은 거의 모든 일반적인 엘리먼트들이 특별한 스타일을 갖게 됩니다. 따라서 마크다운 콘텐츠에 커스텀 HTML을 추가할 경우, 해당 HTML도 이러한 스타일의 영향을 받게 된다는 점을 유념해야 합니다.\n\n이 레이아웃에서는 아래에 나열된 문서 전용 기능들도 제공됩니다. 이 기능들은 오직 이 레이아웃에서만 활성화됩니다.\n\n- 편집 링크\n- 이전/다음 링크\n- 개요(outline)\n- [카본 광고](./default-theme-carbon-ads)\n\n## `page` 레이아웃 {#page-layout}\n\n`page` 옵션은 \"빈 페이지\"로 처리됩니다. 마크다운은 여전히 파싱되며, 모든 [마크다운 확장 기능](../guide/markdown)이 `doc` 레이아웃과 동일하게 작동하지만, 기본 스타일링은 적용되지 않습니다.\n\n이 페이지 레이아웃은 VitePress 테마가 마크업에 영향을 미치지 않도록 하여, 모든 스타일을 직접 지정할 수 있게 해줍니다. 이는 커스텀 페이지를 만들고자 할 때 유용합니다.\n\n이 레이아웃에서도 페이지에 매칭되는 사이드바 구성이 있는 경우 사이드바는 여전히 표시됩니다.\n\n## `home` 레이아웃 {#home-layout}\n\n`home` 옵션은 템플릿화된 \"홈 페이지\"를 생성합니다. 이 레이아웃에서는 `hero`와 `features` 같은 추가 옵션을 설정하여 콘텐츠를 더 커스터마이징 할 수 있습니다. 자세한 내용은 [기본 테마: 홈 페이지](./default-theme-home-page)를 참고하세요.\n\n## 레이아웃 없음 {#no-layout}\n\n어떤 레이아웃도 원하지 않는 경우, 전문에 `layout: false`를 전달할 수 있습니다. 이 옵션은 (기본적으로 사이드바, 네비게이션 바, 또는 푸터가 없는) 완전히 커스터마이징 가능한 랜딩 페이지를 만들고자 할 때 유용합니다.\n\n## 커스텀 레이아웃 {#custom-layout}\n\n커스텀 레이아웃을 사용할 수도 있습니다:\n\n```md\n---\nlayout: foo\n---\n```\n\n이것은 컨텍스트에 등록된 `foo`라는 이름의 컴포넌트를 찾습니다. 예를 들어 `.vitepress/theme/index.ts`에서 컴포넌트를 전역으로 등록할 수 있습니다:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-nav.md",
    "content": "# 네비게이션 바 {#nav}\n\n네비게이션 바는 페이지 상단에 표시되며, 사이트 제목, 전역 메뉴 링크 등이 포함됩니다.\n\n## 사이트 제목 및 로고 {#site-title-and-logo}\n\n기본적으로 네비게이션 바는 [`config.title`](./site-config#title) 값을 참조하여 사이트 제목을 표시합니다. 여기에 표시되는 내용을 변경하려면 `themeConfig.siteTitle` 옵션에 커스텀 텍스트를 정의합니다.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'My Custom Title'\n  }\n}\n```\n\n사이트에 로고가 있는 경우, 이미지의 경로를 전달하여 로고를 표시할 수 있습니다. 로고는 `public` 폴더에 배치하고, 이것의 절대 경로를 정의해야 합니다.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\n로고를 추가하면 사이트 제목과 함께 표시됩니다. 로고만 필요하고 사이트 제목 텍스트를 숨기고 싶다면, `siteTitle` 옵션을 `false`로 설정하면 됩니다.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\n로고에 `alt` 어트리뷰트를 추가하거나 다크/라이트 모드에 따라 커스터마이징 하려면, 로고를 객체 형태로 전달해야 합니다. 자세한 내용은 [`themeConfig.logo`](./default-theme-config#logo)를 참고하세요.\n\n## 네비게이션 바 링크 {#navigation-links}\n\n`themeConfig.nav` 옵션을 정의하여 네비게이션 바에 링크를 추가할 수 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: '가이드', link: '/guide' },\n      { text: '구성', link: '/config' },\n      { text: '변경사항', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text`는 네비게이션 바에 표시되는 실제 텍스트이며, `link`는 텍스트를 클릭했을 때 이동할 링크입니다. 링크의 경로는 `.md` 접미사 없이 실제 파일 경로로 설정하며, 항상 `/`로 시작해야 합니다.\n\n`link`는 또한 [`PageData`](./runtime-api#usedata)를 인자로 받아 경로를 반환하는 함수가 될 수도 있습니다.\n\n네비게이션 바 링크는 드롭다운 메뉴가 될 수 있습니다. 이를 위해 `link` 옵션에 `items` 키를 설정합니다.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: '가이드', link: '/guide' },\n      {\n        text: '드롭다운 메뉴',\n        items: [\n          { text: '항목 A', link: '/item-1' },\n          { text: '항목 B', link: '/item-2' },\n          { text: '항목 C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n드롭다운 메뉴의 제목(위 예제에서 `드롭다운 메뉴`)은 드롭다운 대화 상자를 여는 버튼이 되므로 `link` 프로퍼티를 가질 수 없습니다.\n\n드롭다운 메뉴 아이템에 더 많은 중첩된 아이템을 전달하여 \"섹션\"을 추가할 수도 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: '가이드', link: '/guide' },\n      {\n        text: '드롭다운 메뉴',\n        items: [\n          {\n            // 섹션의 제목.\n            text: '섹션 A 제목',\n            items: [\n              { text: '섹션 A 항목 A', link: '...' },\n              { text: '섹션 B 항목 B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: '드롭다운 메뉴',\n        items: [\n          {\n            // 제목을 생략할 수도 있습니다.\n            items: [\n              { text: '섹션 A 항목 A', link: '...' },\n              { text: '섹션 B 항목 B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### 링크의 \"active\" 상태 커스터마이징 {#customize-link-s-active-state}\n\n네비게이션 바 메뉴 아이템은 현재 페이지가 매칭되는 경로에 있을 때 강조 표시됩니다. 매칭할 경로를 커스터마이징 하려면 `activeMatch` 프로퍼티에 정규식을 문자열 값으로 정의합니다.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // `/config/` 경로에 있을 때\n      // 이 링크는 활성화된 상태가 됩니다.\n      {\n        text: '가이드',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch`는 정규식이어야 하지만, 문자열로 정의해야 합니다. 실제 RegExp 객체를 사용할 수 없는 이유는 빌드하는 동안 직렬화할 수 없기 때문입니다.\n:::\n\n### 링크의 \"target\" 및 \"rel\" 어트리뷰트 커스터마이징 {#customize-link-s-target-and-rel-attributes}\n\n기본적으로 VitePress는 링크가 외부 링크인지 여부에 따라 `target`과 `rel` 어트리뷰트를 자동으로 결정합니다. 하지만 원한다면 이를 커스터마이징 할 수도 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'GitHub 쇼핑몰',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored' // https://developers.google.com/search/docs/crawling-indexing/qualify-outbound-links\n      }\n    ]\n  }\n}\n```\n\n## 소셜 링크 {#social-links}\n\n[`socialLinks`](./default-theme-config#sociallinks)를 참고하세요.\n\n## 커스텀 컴포넌트 {#custom-components}\n\n네비게이션 바에 커스텀 컴포넌트를 포함하려면 `component` 옵션을 사용하세요. `component` 키는 Vue 컴포넌트 이름이어야 하며, [Theme.enhanceApp](../guide/custom-theme#theme-interface)을 사용하여 전역적으로 등록해야 합니다.\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'My Menu',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // 컴포넌트에 전달할 선택적 프로퍼티\n            props: {\n              title: 'My Custom Component'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\n그런 다음, 컴포넌트를 전역적으로 등록해야 합니다:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\n컴포넌트는 네비게이션 바에 렌더링될 것입니다. VitePress는 컴포넌트에 다음과 같은 추가 프로퍼티를 제공합니다:\n\n- `screenMenu`: 컴포넌트가 모바일 네비게이션 바 메뉴 내부에 있는지를 나타내는 선택적 boolean 값\n\ne2e 테스트 예제를 [여기](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress)에서 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/reference/default-theme-prev-next-links.md",
    "content": "# 이전/다음 링크 {#prev-next-links}\n\n문서 하단에 표시되는 이전 페이지와 다음 페이지의 텍스트와 링크를 커스터마이징 할 수 있습니다. 사이드바에 있는 텍스트와 다른 텍스트를 원할 경우 유용합니다. 또한 푸터를 비활성화하거나 사이드바에 포함되지 않은 페이지로 링크할 때도 유용할 수 있습니다.\n\n## prev\n\n- 타입: `string | false | { text?: string; link?: string }`\n\n- 세부 사항:\n\n  이전 페이지로 가는 링크에 표시할 텍스트/링크를 지정합니다. 전문에서 이 항목을 설정하지 않으면, 사이드바 구성에서 텍스트/링크가 유추됩니다.\n\n- 예제:\n\n  - 텍스트만 커스터마이징하려면:\n\n    ```yaml\n    ---\n    prev: '시작하기 | 마크다운'\n    ---\n    ```\n\n  - 텍스트와 링크를 모두 커스터마이즈하려면:\n\n    ```yaml\n    ---\n    prev:\n      text: '마크다운 확장 기능'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - 이전 페이지를 숨기려면:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\n`prev`와 동일하지만, 다음 페이지에 대한 설정입니다.\n"
  },
  {
    "path": "docs/ko/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# 검색 {#search}\n\n## 로컬 검색 {#local-search}\n\nVitePress는 [minisearch](https://github.com/lucaong/minisearch/)로 브라우저 내 인덱스를 사용하는 퍼지(full-text) 검색을 지원합니다. 이 기능을 활성화하려면 `.vitepress/config.ts` 파일에서 `themeConfig.search.provider` 옵션을 `'local'`로 설정하면 됩니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\n예제 결과:\n\n![검색 모달의 스크린샷](/search.png)\n\n대안으로 [Algolia DocSearch](#algolia-search), <https://www.npmjs.com/package/vitepress-plugin-search>, <https://www.npmjs.com/package/vitepress-plugin-pagefind>와 같은 커뮤니티 플러그인을 사용할 수도 있습니다.\n\n### i18n {#local-search-i18n}\n\n다국어 검색을 사용하려면 다음과 같은 구성을 사용해야 합니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          ko: { // 기본 로케일을 번역하려면 `root`로 설정하세요\n            translations: {\n              button: {\n                buttonText: '검색',\n                buttonAriaLabel: '검색'\n              },\n              modal: {\n                displayDetails: '상세 목록 표시',\n                resetButtonTitle: '검색 재설정',\n                backButtonTitle: '검색 닫기',\n                noResultsText: '결과가 없습니다',\n                footer: {\n                  selectText: '선택',\n                  selectKeyAriaLabel: 'Enter',\n                  navigateText: '이동',\n                  navigateUpKeyAriaLabel: '위쪽 화살표',\n                  navigateDownKeyAriaLabel: '아래쪽 화살표',\n                  closeText: '닫기',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### MiniSearch 옵션 {#minisearch-options}\n\nMiniSearch를 다음과 같이 구성할 수 있습니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n더 자세한 내용은 [MiniSearch 문서](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html)를 참고하세요.\n\n### 커스텀 컨텐츠 렌더러 {#custom-content-renderer}\n\n마크다운 컨텐츠를 인덱싱하기 전에 렌더링하는 데 사용되는 함수를 커스터마이징할 수 있습니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // HTML 문자열을 반환\n        }\n      }\n    }\n  }\n})\n```\n\n이 함수는 클라이언트 사이드 사이트 데이터에서 제거되므로, Node.js API를 사용할 수 있습니다.\n\n#### 예제: 검색에서 페이지 제외 {#example-excluding-pages-from-search}\n\n페이지의 전문에 `search: false`를 추가하여 검색에서 해당 페이지를 제외할 수 있습니다. 또는:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 참고\n커스텀 `_render` 함수가 제공된 경우, `search: false` 전문을 직접 처리해야 합니다. 또한, `md.renderAsync`가 호출되기 전에 `env` 객체가 완전히 채워지지 않으므로, `frontmatter`와 같은 선택적 `env` 프로퍼티에 대한 검사는 그 이후에 수행해야 합니다.\n:::\n\n#### 예제: 콘텐츠 변환 - 앵커 추가 {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Algolia 검색 {#algolia-search}\n\nVitePress는 [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch)를 사용한 문서 사이트 검색 기능을 지원합니다. 시작 가이드를 참고하세요. `.vitepress/config.ts`에서 이 기능을 사용하려면 최소한 다음 구성을 제공해야 합니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\n다국어 검색을 사용하려면 다음과 같이 구성해야 합니다:\n\n<details>\n<summary>클릭하여 펼치기</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\n자세한 내용은 [공식 Algolia 문서](https://docsearch.algolia.com/docs/api#translations)를 참고하세요. 빠르게 시작하려면 이 사이트에서 사용하는 번역을 [GitHub 저장소](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code)에서 복사할 수도 있습니다.\n\n### Algolia Ask AI 지원 {#ask-ai}\n\n**Ask AI** 기능을 사용하려면 `askAi` 옵션을 추가하세요:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"내-어시스턴트-ID\"\n        // 또는\n        askAi: {\n          // 최소한 Algolia에서 받은 assistantId를 제공해야 합니다\n          assistantId: 'XXXYYY',\n          // 선택적 재정의 — 생략하면 상위 appId/apiKey/indexName 값이 재사용됩니다\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 참고\nAsk AI를 사용하지 않으려면 `askAi` 옵션을 생략하면 됩니다.\n:::\n\n### Ask AI 사이드 패널 {#ask-ai-side-panel}\n\nDocSearch v4.5+는 선택적 **Ask AI 사이드 패널**을 지원합니다. 활성화되면 기본적으로 **Ctrl/Cmd+I**로 열 수 있습니다. [사이드 패널 API 참조](https://docsearch.algolia.com/docs/sidepanel/api-reference)에 전체 옵션 목록이 있습니다.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // @docsearch/sidepanel-js SidepanelProps API 반영\n            panel: {\n              variant: 'floating', // 또는 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n키보드 단축키를 비활성화해야 하는 경우 사이드 패널의 `keyboardShortcuts` 옵션을 사용하세요:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### 모드 (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nVitePress가 키워드 검색과 Ask AI를 통합하는 방식을 선택적으로 제어할 수 있습니다:\n\n- `mode: 'auto'` (기본값): 키워드 검색이 구성된 경우 `hybrid`를 추론하고, 그렇지 않으면 Ask AI 사이드 패널이 구성된 경우 `sidePanel`을 추론합니다.\n- `mode: 'sidePanel'`: 사이드 패널만 강제 (키워드 검색 버튼 숨김).\n- `mode: 'hybrid'`: 키워드 검색 모달 + Ask AI 사이드 패널 활성화 (키워드 검색 구성 필요).\n- `mode: 'modal'`: Ask AI를 DocSearch 모달 내부에 유지 (사이드 패널을 구성한 경우에도).\n\n#### Ask AI만 (키워드 검색 없음) {#ask-ai-only}\n\n**Ask AI 사이드 패널만** 사용하려면 최상위 키워드 검색 구성을 생략하고 `askAi` 아래에 자격 증명을 제공할 수 있습니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### 크롤러 구성 {#crawler-config}\n\n이 사이트에서 사용하는 예제 구성을 소개합니다:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/ko/reference/default-theme-sidebar.md",
    "content": "# 사이드바 {#sidebar}\n\n사이드바는 문서의 기본 탐색 블록입니다. [`themeConfig.sidebar`](./default-theme-config#sidebar)에서 사이드바 메뉴를 구성할 수 있습니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '가이드',\n        items: [\n          { text: '소개', link: '/introduction' },\n          { text: '시작하기', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 기본 사용법 {#the-basics}\n\n사이드바 메뉴의 가장 간단한 형태는 링크 배열을 전달하는 것입니다. 첫 번째 계층 아이템은 사이드바의 \"섹션\"을 정의합니다. 이 섹션에는 제목인 `text`와 실제 탐색 링크인 `items`가 포함되어야 합니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '섹션 제목 A',\n        items: [\n          { text: '아이템 A', link: '/item-a' },\n          { text: '아이템 B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: '섹션 제목 B',\n        items: [\n          { text: '아이템 C', link: '/item-c' },\n          { text: '아이템 D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n각 `link`는 `/`로 시작하는 실제 파일 경로를 지정해야 합니다. 링크 끝에 슬래시를 추가하면 해당 디렉터리의 `index.md`를 보여줍니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '가이드',\n        items: [\n          // 이것은 `/guide/index.md` 페이지를 보여줍니다.\n          { text: '소개', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n사이드바 아이템을 루트 단계에서 최대 6단계까지 중첩할 수 있습니다. 6단계를 초과하는 중첩 아이템은 무시되며 사이드바에 표시되지 않습니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '1단계',\n        items: [\n          {\n            text: '2단계',\n            items: [\n              {\n                text: '3단계',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 여러 사이드바 {#multiple-sidebars}\n\n페이지 경로에 따라 다른 사이드바를 표시할 수 있습니다. 예를 들어 이 사이트처럼 문서의 각 섹션을 \"가이드\"와 \"레퍼런스\" 페이지에 따라 별도로 만들고 싶을 수 있습니다.\n\n이를 위해 먼저 각 섹션 디렉터리로 페이지를 구성합니다:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\n그런 다음 각 섹션에 대한 사이드바를 정의하도록 구성 파일을 업데이트합니다. 이런 경우에는 배열 대신 객체를 전달해야 합니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // 이 사이드바는 유저가\n      // `guide` 디렉토리에 있을 때 표시됩니다.\n      '/guide/': [\n        {\n          text: '가이드',\n          items: [\n            { text: '개요', link: '/guide/' },\n            { text: '하나', link: '/guide/one' },\n            { text: '둘', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // 이 사이드바는 유저가\n      // `config` 디렉토리에 있을 때 표시됩니다.\n      '/config/': [\n        {\n          text: '설정',\n          items: [\n            { text: '개요', link: '/config/' },\n            { text: '셋', link: '/config/three' },\n            { text: '넷', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## 접을 수 있는 사이드바 그룹 {#collapsible-sidebar-groups}\n\n사이드바 그룹에 `collapsed` 옵션을 추가하면 각 섹션을 접거나 펼칠 수 있는 토글 버튼이 표시됩니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '섹션 제목 A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\n모든 섹션은 기본적으로 \"열림\" 상태입니다. 초기 페이지 로드 시 \"닫힘\" 상태로 두려면 `collapsed` 옵션을 `true`로 설정합니다.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: '섹션 제목 A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/ko/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Developer',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# 팀 페이지 {#team-page}\n\n팀을 소개하고자 할 때, 팀 컴포넌트를 사용하여 팀 페이지를 구성할 수 있습니다. 이 컴포넌트를 사용하는 방법은 두 가지가 있습니다. 하나는 문서 페이지에 포함시키는 방법이고, 다른 하나는 전체 팀 페이지를 만드는 방법입니다.\n\n## 페이지에서 팀 구성원 보여주기 {#show-team-members-in-a-page}\n\n`vitepress/theme`에서 제공되는 `<VPTeamMembers>` 컴포넌트를 사용하여, 어떤 페이지에서도 팀 구성원 목록을 표시할 수 있습니다.\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# Our Team\n\nSay hello to our awesome team.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\n위 코드는 카드 형태의 엘리먼트로 팀 구성원을 표시합니다. 아래와 비슷한 형태로 표시됩니다.\n\n<VPTeamMembers size=\"small\" :members />\n\n`<VPTeamMembers>` 컴포넌트는 `small`과 `medium` 두 가지 크기로 제공됩니다. 개인의 선호도에 따라 선택할 수 있지만, 일반적으로 `small` 사이즈가 문서 페이지에 더 적합합니다. 또한, 각 구성원에 \"설명\"이나 \"후원\" 버튼과 같은 프로퍼티를 추가할 수도 있습니다. 자세한 내용은 [`<VPTeamMembers>`](#vpteammembers)에서 확인할 수 있습니다.\n\n문서 페이지에 팀 구성원을 포함시키는 것은 전용 팀 페이지를 만드는 것이 과할 수 있는 소규모 팀이나, 문서의 맥락에 따라 일부 구성원을 소개할 때 좋습니다.\n\n만약 많은 수의 구성원이 있거나, 팀 구성원을 보여줄 더 많은 공간이 필요하다면, [전체 팀 페이지 만들기](#create-a-full-team-page)를 고려해 보세요.\n\n## 전체 팀 페이지 만들기 {#create-a-full-team-page}\n\n팀 구성원을 문서 페이지에 추가하는 대신, 전체 팀 페이지를 만들어 [홈 페이지](./default-theme-home-page)를 커스텀하는 것처럼 팀 페이지를 만들 수도 있습니다.\n\n팀 페이지를 만들려면, 먼저 새로운 마크다운 파일을 생성하세요. 파일 이름은 중요하지 않지만, 여기서는 `team.md`라고 부르겠습니다. 이 파일에서 전문 옵션에 `layout: page`를 설정한 후, `TeamPage` 컴포넌트를 사용하여 페이지 구조를 구성합니다.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\n전체 팀 페이지를 만들 때는 모든 컴포넌트를 `<VPTeamPage>` 컴포넌트로 감싸야 합니다. 이 컴포넌트는 중첩된 팀 관련 컴포넌트들이 적절한 레이아웃 구조와 간격을 갖도록 합니다.\n\n`<VPPageTitle>` 컴포넌트는 페이지 제목 섹션을 추가합니다. 제목은 `<h1>` 헤딩으로 표시됩니다. `#title`과 `#lead` 슬롯을 사용하여 팀에 대한 설명을 작성할 수 있습니다.\n\n`<VPMembers>` 컴포넌트는 문서 페이지에서 사용할 때와 동일하게 작동하며, 팀 구성원 목록을 표시합니다.\n\n### 팀 구성원을 구분하기 위한 섹션 추가 {#add-sections-to-divide-team-members}\n\n팀 페이지에 \"섹션\"을 추가할 수도 있습니다. 예를 들어, 핵심 팀 구성원과 커뮤니티 파트너와 같은 다양한 유형의 팀 구성원이 있을 수 있습니다. 이 구성원들을 섹션으로 나누어 각 그룹의 역할을 더 잘 설명할 수 있습니다.\n\n이를 위해 이전에 만든 `team.md` 파일에 `<VPTeamPageSection>` 컴포넌트를 추가하세요.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Our Team</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\n`<VPTeamPageSection>` 컴포넌트는 `VPTeamPageTitle` 컴포넌트처럼 `#title`과 `#lead` 슬롯을 가질 수 있으며, 팀 구성원을 표시하기 위한 `#members` 슬롯도 있습니다.\n\n`#members` 슬롯 내부에는 `<VPTeamMembers>` 컴포넌트를 추가해야 합니다.\n\n## `<VPTeamMembers>`\n\n`<VPTeamMembers>` 컴포넌트는 주어진 팀 구성원 목록을 표시합니다.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // 각 구성원 사이즈. 기본값: `medium`\n  size?: 'small' | 'medium'\n\n  // 표시할 구성원 목록.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // 구성원 아바타 이미지.\n  avatar: string\n\n  // 구성원 이름.\n  name: string\n\n  // 구성원 이름 아래에 표시될 직함.\n  // 예: 개발자, 소프트웨어 엔지니어 등\n  title?: string\n\n  // 구성원이 속한 조직.\n  org?: string\n\n  // 조직의 URL.\n  orgLink?: string\n\n  // 구성원에 대한 설명.\n  desc?: string\n\n  // 소셜 링크. 예: GitHub, Twitter 등.\n  // 소셜 링크 객체를 전달해야 함.\n  // 참고: https://vitepress.dev/ko/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // 구성원의 후원 페이지 URL.\n  sponsor?: string\n\n  // 후원 링크 텍스트. 기본값: 'Sponsor'\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\n전체 팀 페이지를 만들 때 사용하는 루트 컴포넌트입니다. 단일 슬롯만 허용하며, 전달된 모든 팀 관련 컴포넌트에 스타일을 적용합니다.\n\n## `<VPTeamPageTitle>`\n\n페이지의 \"제목\" 섹션을 추가합니다. `<VPTeamPage>` 아래 맨 처음에 사용하는 것이 가장 좋습니다. `#title`과 `#lead` 슬롯이 있습니다.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\n팀 페이지 내에서 \"섹션\"을 생성합니다. `#title`, `#lead`, `#members` 슬롯이 있습니다. `<VPTeamPage>` 안에 원하는 만큼 섹션을 추가할 수 있습니다.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/ko/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# 전문 구성 {#frontmatter-config}\n\n전문은 페이지 기반 구성을 가능하게 합니다. 각 마크다운 파일에서 전문 구성을 사용하여 사이트 수준 또는 테마 수준의 구성 옵션을 재정의할 수 있습니다. 또한, 전문에서만 정의할 수 있는 구성 옵션도 있습니다.\n\n사용 예:\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\nVue 표현식에서 `$frontmatter` 전역 변수를 통해 전문 데이터에 접근할 수 있습니다:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- 타입: `string`\n\n페이지의 제목입니다. [config.title](./site-config#title)과 동일하며, 사이트 레벨의 구성을 재정의합니다.\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- 타입: `string | boolean`\n\n제목의 접미사입니다. [config.titleTemplate](./site-config#titletemplate)와 동일하며, 사이트 레벨의 구성을 재정의합니다.\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Vite & Vue powered static site generator\n---\n```\n\n## description\n\n- 타입: `string`\n\n페이지의 설명입니다. [config.description](./site-config#description)과 동일하며, 사이트 레벨의 구성을 재정의합니다.\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- 타입: `HeadConfig[]`\n\n현재 페이지에 삽입할 추가 head 태그를 지정합니다. 사이트 수준 구성에 의해 삽입된 head 태그 뒤에 추가됩니다.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## 기본 테마 전용 {#default-theme-only}\n\n다음 전문 옵션은 기본 테마를 사용할 때만 적용됩니다.\n\n### layout\n\n- 타입: `doc | home | page`\n- 기본값: `doc`\n\n페이지의 레이아웃을 결정합니다.\n\n- `doc` - 마크다운 컨텐츠에 기본 문서 스타일을 적용합니다.\n- `home` - \"홈 페이지\"를 위한 특별 레이아웃입니다. 아름다운 랜딩 페이지를 빠르게 만들기 위해 `hero` 및 `features`와 같은 옵션을 추가할 수 있습니다.\n- `page` - `doc`과 유사하게 작동하지만 콘텐츠에 스타일을 적용하지 않습니다. 완전히 커스텀 페이지를 만들 때 유용합니다.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"홈 페이지 전용\" />\n\n`layout`이 `home`으로 설정된 경우, 홈 히어로 섹션의 내용을 정의합니다. 자세한 내용은 [기본 테마: 홈 페이지](./default-theme-home-page)에서 확인할 수 있습니다.\n\n### features <Badge type=\"info\" text=\"홈 페이지 전용\" />\n\n`layout`이 `home`으로 설정된 경우, 기능 섹션에 표시할 항목을 정의합니다. 자세한 내용은 [기본 테마: 홈 페이지](./default-theme-home-page)에서 확인할 수 있습니다.\n\n### navbar\n\n- 타입: `boolean`\n- 기본값: `true`\n\n[네비게이션 바](./default-theme-nav)를 표시할지 여부를 설정합니다.\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- 타입: `boolean`\n- 기본값: `true`\n\n[사이드바](./default-theme-sidebar)를 표시할지 여부를 설정합니다.\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- 타입: `boolean | 'left'`\n- 기본값: `true`\n\n`doc` 레이아웃에서 어사이드(aside) 컴포넌트의 위치를 정의합니다.\n\n이 값을 `false`로 설정하면 어사이드 컨테이너가 렌더링되지 않습니다.\\\n이 값을 `true`로 설정하면 어사이드를 오른쪽에 렌더링합니다.\\\n이 값을 `'left'`로 설정하면 어사이드를 왼쪽에 렌더링합니다.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- 타입: `number | [number, number] | 'deep' | false`\n- 기본값: `2`\n\n페이지에 표시할 아웃라인(개요) 헤더의 레벨을 설정합니다. [config.themeConfig.outline.level](./default-theme-config#outline)과 동일하며, 사이트 수준 구성에서 설정된 값을 재정의합니다.\n\n### lastUpdated\n\n- 타입: `boolean | Date`\n- 기본값: `true`\n\n현재 페이지의 푸터에 [마지막 업데이트 날짜](./default-theme-last-updated) 텍스트를 표시할지 여부를 설정합니다. 날짜/시간이 지정되면 마지막 git 수정 타임스탬프 대신 해당 날짜/시간이 표시됩니다.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- 타입: `boolean`\n- 기본값: `true`\n\n현재 페이지의 푸터에 [편집 링크](./default-theme-edit-link)를 표시할지 여부를 설정합니다.\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- 타입: `boolean`\n- 기본값: `true`\n\n[푸터](./default-theme-footer)를 표시할지 여부를 설정합니다.\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- 타입: `string`\n\n페이지에 추가할 클래스 입니다.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\n그런 다음 `.vitepress/theme/custom.css` 파일에서 이 페이지의 스타일을 커스텀 할 수 있습니다:\n\n```css\n.custom-page-class {\n  /* 페이지별 스타일 */\n}\n```\n"
  },
  {
    "path": "docs/ko/reference/runtime-api.md",
    "content": "# 런타임 API {#runtime-api}\n\nVitePress는 애플리케이션 데이터를 액세스할 수 있는 여러 내장 API를 제공합니다. 그리고 전역적으로 사용할 수 있는 몇 가지 내장 컴포넌트도 제공합니다.\n\n헬퍼 메서드는 `vitepress`에서 전역적으로 사용할 수 있으며, 주로 커스텀 테마의 Vue 컴포넌트에서 사용됩니다. 또한 마크다운 파일이 Vue [단일 파일 컴포넌트](https://vuejs.org/guide/scaling-up/sfc.html)로 컴파일되기 때문에 `.md` 페이지 내에서도 사용할 수 있습니다.\n\n`use*`로 시작하는 메서드는 [Vue 3 Composition API](https://vuejs.org/guide/introduction.html#composition-api) 함수(\"컴포저블\")를 나타내며, 이는 `setup()` 또는 `<script setup>` 내부에서만 사용할 수 있습니다.\n\n## `useData` <Badge type=\"info\" text=\"컴포저블\" />\n\n페이지별 데이터를 반환합니다. 반환된 객체는 다음과 같은 타입을 가집니다:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * 사이트 레벨 메타데이터\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * .vitepress/config.js 의 themeConfig\n   */\n  theme: Ref<T>\n  /**\n   * 페이지 레벨 메타데이터\n   */\n  page: Ref<PageData>\n  /**\n   * 페이지 전문 메타데이터\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * 동적 라우트 파라미터\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  /**\n   * 현재 위치 해시\n   */\n  hash: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**예제:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"컴포저블\" />\n\n다음과 같은 타입으로 현재 라우트 객체를 반환합니다:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"컴포저블\" />\n\n프로그래밍 방식으로 다른 페이지로 이동할 수 있도록 VitePress 라우터 인스턴스를 반환합니다.\n\n```ts\ninterface Router {\n  /**\n   * 현재 route.\n   */\n  route: Route\n  /**\n   * 새 URL로 이동.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * 라우트가 변경되기 전에 호출. 탐색을 취소하려면 `false`를 반환.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * 페이지 컴포넌트가 로드되기 전(히스토리 상태가 업데이트된 후)에 호출.\n   * 탐색을 취소하려면 `false`를 반환.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * 라우트가 변경된 후 호출.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"헬퍼\" />\n\n- **타입**: `(path: string) => string`\n\n구성된 [`base`](./site-config#base)를 지정된 URL 경로에 추가합니다. [Base URL](../guide/asset-handling#base-url)을 참고하세요.\n\n## `<Content />` <Badge type=\"info\" text=\"컴포넌트\" />\n\n`<Content />` 컴포넌트는 렌더링된 마크다운 내용을 표시합니다. [커스텀 테마를 만들 때](../guide/custom-theme) 유용합니다.\n\n```vue\n<template>\n  <h1>Custom Layout!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"컴포넌트\" />\n\n`<ClientOnly />` 컴포넌트는 클라이언트 측에서만 슬롯을 렌더링합니다.\n\nVitePress 애플리케이션은 정적 빌드를 생성할 때 Node.js에서 서버 렌더링되므로 모든 Vue 사용은 범용 코드 요구 사항을 준수해야 합니다. 간단히 말해서, 브라우저 / DOM API는 반드시 beforeMount 또는 mounted 훅에서만 접근해야 합니다.\n\nSSR 친화적이지 않은(예: 커스텀 디렉티브를 포함하는) 컴포넌트를 사용하는 경우, 이를 `ClientOnly` 컴포넌트 내부에 래핑할 수 있습니다.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- 참고: [SSR 호환성](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"템플릿 전역\" />\n\nVue 표현식에서 현재 페이지의 [전문](../guide/frontmatter) 데이터에 직접 접근합니다.\n\n```md\n---\ntitle: Hello\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"템플릿 전역\" />\n\nVue 표현식에서 현재 페이지의 [동적 라우트 파라미터](../guide/routing#dynamic-routes)에 직접 접근합니다.\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/ko/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# 사이트 구성 {#site-config}\n\n사이트 구성(config)은 사이트의 전역 설정을 정의할 수 있는 곳입니다. 애플리케이션 구성 옵션은 사용 중인 테마와 상관없이 모든 VitePress 사이트에 적용되는 설정을 정의합니다. 예를 들어 기본 디렉터리나 사이트의 제목 등이 있습니다.\n\n## 개요 {#overview}\n\n### 구성 분석 {#config-resolution}\n\n구성 파일은 항상 `<root>/.vitepress/config.[ext]`에서 처리됩니다. 여기서 `<root>`는 VitePress [프로젝트 루트](../guide/routing#root-and-source-directory)를 의미하며, `[ext]`는 지원되는 파일 확장자 중 하나입니다. TypeScript는 기본적으로 지원됩니다. 지원되는 확장자에는 `.js`, `.ts`, `.mjs`, `.mts`가 포함됩니다.\n\n구성 파일에서는 ES 모듈 구문을 사용하는 것이 권장됩니다. 구성 파일은 객체를 \"default export\"해야 합니다:\n\n```ts\nexport default {\n  // 애플리케이션 레벨의 구성 옵션\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n  ...\n}\n```\n\n::: details 동적(비동기) 구성\n\n구성을 동적으로 생성해야 하는 경우, 함수를 \"default export\" 할 수 있습니다. 예:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // 애플리케이션 레벨의 구성 옵션\n    lang: 'en-US',\n    title: 'VitePress',\n    description: 'Vite & Vue powered static site generator.',\n\n    // 테마 레벨의 구성 옵션\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\n최상위 수준의 `await`도 사용할 수 있습니다. 예:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // 앱 레벨 설정 옵션\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue를 활용한 정적 사이트 생성기.',\n\n  // 테마 레벨 설정 옵션\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### 구성 인텔리센스 {#config-intellisense}\n\n`defineConfig` 헬퍼를 사용하면 구성 옵션에 대해 TypeScript 기반의 인텔리센스(자동완성)를 제공받을 수 있습니다. IDE가 이를 지원하는 경우, JavaScript와 TypeScript 모두에서 작동합니다.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### 타입이 지정된 테마 구성 {#typed-theme-config}\n\n기본적으로 `defineConfig` 헬퍼는 기본 테마에서 테마 구성 타입을 예측합니다:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // 타입은 `DefaultTheme.Config`\n  }\n})\n```\n\n커스텀 테마를 사용하고 테마 구성에 대한 타입 검사를 원한다면, `defineConfigWithTheme`를 사용하고 제네릭 인수를 통해 커스텀 테마의 구성 타입을 전달해야 합니다:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // 타입은 `ThemeConfig`\n  }\n})\n```\n\n### Vite, Vue, Markdown 설정 {#vite-vue-markdown-config}\n\n- **Vite**\n\n  VitePress 구성에서 [vite](#vite) 옵션을 사용하여 기본 Vite 인스턴스를 구성할 수 있습니다. 별도의 Vite 구성 파일을 만들 필요는 없습니다.\n\n- **Vue**\n\n  VitePress는 이미 Vite의 공식 Vue 플러그인([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue))을 포함하고 있습니다. VitePress 구성에서 [vue](#vue) 옵션을 사용하여 해당 옵션을 구성할 수 있습니다.\n\n- **Markdown**\n\n  [Markdown-It](https://github.com/markdown-it/markdown-it) 인스턴스를 VitePress 구성에서 [markdown](#markdown) 옵션을 사용하여 구성할 수 있습니다.\n\n## 사이트 메타데이터 {#site-metadata}\n\n### title\n\n- 타입: `string`\n- 기본값: `VitePress`\n- [전문](./frontmatter-config#title)을 통해 페이지별로 재정의 가능\n\n사이트의 제목입니다. 기본 테마를 사용할 경우, 이는 내비게이션 바에 표시됩니다.\n\n[`titleTemplate`](#titletemplate)이 정의되지 않은 경우, 모든 개별 페이지 제목의 기본 접미사로 사용됩니다. 개별 페이지의 최종 제목은 첫 번째 `<h1>` 헤더의 텍스트 콘텐츠와 전역 `title`을 접미사로 결합한 것입니다. 예를 들어 다음 구성과 페이지 콘텐츠가 있을 경우:\n\n```ts\nexport default {\n  title: 'My Awesome Site'\n}\n```\n\n```md\n# Hello\n```\n\n페이지의 제목은 `Hello | My Awesome Site`가 됩니다.\n\n### titleTemplate\n\n- 타입: `string | boolean`\n- [전문](./frontmatter-config#titletemplate)을 통해 페이지별로 재정의 가능\n\n각 페이지의 제목 접미사 또는 전체 제목을 커스터마이징할 수 있습니다. 예를 들어:\n\n```ts\nexport default {\n  title: 'My Awesome Site',\n  titleTemplate: 'Custom Suffix'\n}\n```\n\n```md\n# Hello\n```\n\n페이지의 제목은 `Hello | Custom Suffix`가 됩니다.\n\n제목이 렌더링되는 방식을 완전히 커스터마이징하려면 `titleTemplate`에서 `:title` 심볼을 사용할 수 있습니다:\n\n```ts\nexport default {\n  titleTemplate: ':title - Custom Suffix'\n}\n```\n\n여기서 `:title`은 페이지의 첫 번째 `<h1>` 헤더에서 추론된 텍스트로 대체됩니다. 이전 예제 페이지의 제목은 `Hello - Custom Suffix`가 됩니다.\n\n이 옵션을 `false`로 설정하여 제목 접미사를 비활성화할 수 있습니다.\n\n### description\n\n- 타입: `string`\n- 기본값: `A VitePress site`\n- [전문](./frontmatter-config#description)을 통해 페이지별로 재정의 가능\n\n사이트의 설명입니다. 이는 페이지 HTML의 `<meta>` 태그로 렌더링됩니다.\n\n```ts\nexport default {\n  description: 'A VitePress site'\n}\n```\n\n### head\n\n- 타입: `HeadConfig[]`\n- 기본값: `[]`\n- [전문](./frontmatter-config#head)을 통해 페이지별로 추가 가능\n\n페이지 HTML의 `<head>` 태그에 렌더링할 추가 엘리먼트입니다. 추가한 태그는 VitePress 태그 뒤 ~ 닫는 `head` 태그 앞에 렌더링됩니다.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### 예제: 파비콘 추가 {#example-adding-a-favicon}\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // favicon.ico를 public 디렉토리에 배치하거나 base가 설정된 경우,\n  // /base/favicon.ico를 사용하세요.\n/* 다음과 같이 랜더링:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### 예제: Google 폰트 추가 {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* 다음과 같이 랜더링:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### 예제: 서비스 워커 등록 {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* 다음과 같이 랜더링:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### 예제: Google Analytics 사용 {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* 다음과 같이 랜더링:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- 타입: `string`\n- 기본값: `en-US`\n\n사이트의 언어 어트리뷰트입니다. 이는 페이지 HTML의 `<html lang=\"en-US\">` 태그로 렌더링됩니다.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- 타입: `string`\n- 기본값: `/`\n\n사이트가 배포될 기본 URL입니다. 예를 들어 GitHub Pages와 같이 서브 경로에 사이트를 배포하려는 경우 이것을 설정해야 합니다. `https://foo.github.io/bar/` 에 사이트를 배포하려면 `'/bar/'`로 설정해야 합니다. 항상 슬래시로 시작하고 끝나야 합니다.\n\n이것은 다른 옵션에서 `/`로 시작하는 모든 URL에 자동으로 추가되므로, 한 번만 지정하면 됩니다.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## 라우팅 {#routing}\n\n### cleanUrls\n\n- 타입: `boolean`\n- 기본값: `false`\n\n`true`로 설정하면 VitePress는 URL에서 `.html`을 제거합니다. [간결한 URL 생성](../guide/routing#generating-clean-urls)을 참고하세요.\n\n::: warning 서버 지원 필요\n이를 활성화하려면 호스팅 플랫폼에서 추가 구성이 필요할 수 있습니다. 서버가 `/foo`를 방문할 때 **리디렉션 없이** `/foo.html`을 제공할 수 있어야 합니다.\n:::\n\n### rewrites\n\n- 타입: `Record<string, string>`\n\n커스텀 디렉터리와 URL 매핑을 정의합니다. 자세한 내용은 [라우팅: 라우트 재작성](../guide/routing#route-rewrites)을 참고하세요.\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## 빌드 {#build}\n\n### srcDir\n\n- 타입: `string`\n- 기본값: `.`\n\n마크다운 페이지가 저장되는 디렉터리입니다. 프로젝트 루트에 상대적입니다. 또한 [루트와 소스 디렉터리](../guide/routing#root-and-source-directory)를 참고하세요.\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- 타입: `string`\n- 기본값: `undefined`\n\n소스 컨텐츠에서 제외해야 하는 마크다운 파일을 매칭하기 위한 [glob 패턴](https://github.com/mrmlnc/fast-glob#pattern-syntax)입니다.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- 타입: `string`\n- 기본값: `./.vitepress/dist`\n\n사이트의 빌드 결과물 위치입니다. [프로젝트 루트](../guide/routing#root-and-source-directory)에 상대적입니다.\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- 타입: `string`\n- 기본값: `assets`\n\n생성된 에셋을 포함할 디렉터리를 지정합니다. 경로는 [`outDir`](#outdir) 내에 있어야 하며, 그것을 기준으로 처리됩니다.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- 타입: `string`\n- 기본값: `./.vitepress/cache`\n\n캐시 파일을 위한 디렉터리입니다. [프로젝트 루트](../guide/routing#root-and-source-directory)에 상대적입니다. [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir)을 참고하세요.\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- 타입: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- 기본값: `false`\n\n`true`로 설정하면, 빌드 시 죽은 링크로 인해 실패하지 않습니다.\n\n`'localhostLinks'`로 설정하면, 죽은 링크가 있으면 빌드에 실패하지만 `localhost` 링크는 확인하지 않습니다.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\n정확히 일치하는 URL 문자열, 정규 표현식 패턴, 커스텀 필터 함수로 구성된 배열도 가능합니다.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // \"/playground\"과 정확히 일치하는 url 무시\n    '/playground',\n    // 모든 localhost 링크 무시\n    /^https?:\\/\\/localhost/,\n    // 모든 \"/repl/\" 포함 링크 무시\n    /\\/repl\\//,\n    // 커스텀 함수, \"ignore\"를 포함한 모든 링크 무시\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"실험적\" />\n\n- 타입: `boolean`\n- 기본값: `false`\n\n`true`로 설정하면 페이지 메타데이터를 초기 HTML에 인라인으로 삽입하는 대신 별도의 JavaScript 청크로 추출합니다. 이렇게 하면 각 페이지의 HTML 페이로드가 작아지고 페이지 메타데이터를 캐시할 수 있어, 사이트에 많은 페이지가 있을 때 서버 대역폭을 줄일 수 있습니다.\n\n### mpa <Badge type=\"warning\" text=\"실험적\" />\n\n- 타입: `boolean`\n- 기본값: `false`\n\n`true`로 설정하면 프로덕션 애플리케이션이 [MPA 모드](../guide/mpa-mode)로 빌드됩니다. MPA 모드는 기본적으로 0kb JavaScript를 제공하지만, 클라이언트 사이드 탐색을 비활성화하고 상호작용을 위한 명시적인 옵트인을 필요로 합니다.\n\n## 테마 {#theming}\n\n### appearance\n\n- 타입: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`\n- 기본값: `true`\n\n다크 모드를 활성화 여부를 설정합니다 (`.dark` 클래스를 `<html>` 엘리먼트에 추가).\n\n- `true`: 기본 테마는 유저의 선호 색상 설정에 따라 결정됩니다.\n- `dark`: 유저가 수동으로 변경하지 않는 한 기본 테마는 다크 모드가 됩니다.\n- `false`: 유저는 테마를 전환할 수 없습니다.\n- `'force-dark'`: 테마는 항상 다크 모드가 되며 유저는 이를 전환할 수 없습니다.\n- `'force-auto'`: 테마는 항상 유저의 선호 색상 설정에 따라 결정되며 유저는 이를 전환할 수 없습니다.\n\n이 옵션은 `vitepress-theme-appearance` 키를 사용하여 로컬 스토리지에서 유저 설정을 복원하는 인라인 스크립트를 삽입합니다. 이는 페이지가 렌더링되기 전에 `.dark` 클래스가 적용되어 깜박임을 방지합니다.\n\n`appearance.initialValue`는 `'dark'` 또는 `undefined`만 가능합니다. Refs 또는 getter는 지원되지 않습니다.\n\n### lastUpdated\n\n- 타입: `boolean`\n- 기본값: `false`\n\n각 페이지의 마지막 업데이트 타임스탬프를 Git을 사용하여 가져올지 여부를 설정합니다. 타임스탬프는 각 페이지의 페이지 데이터에 포함되며, [`useData`](./runtime-api#usedata)를 통해 접근할 수 있습니다.\n\n기본 테마를 사용할 때, 이 옵션을 활성화하면 각 페이지의 마지막 업데이트 시간이 표시됩니다. [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) 옵션을 통해 텍스트를 커스터마이징할 수 있습니다.\n\n## 커스터마이징 {#customization}\n\n### markdown\n\n- 타입: `MarkdownOption`\n\n마크다운 파서 옵션을 구성합니다. VitePress는 파서로 [Markdown-it](https://github.com/markdown-it/markdown-it)을 사용하고, 언어 구문 강조를 위해 [Shiki](https://github.com/shikijs/shiki)를 사용합니다. 이 옵션 내에서 다양한 마크다운 관련 옵션을 전달하여 필요에 맞게 조정할 수 있습니다.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\n사용 가능한 모든 옵션에 대해서는 [타입 선언 및 jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts)를 참고하세요.\n\n### vite\n\n- 타입: `import('vite').UserConfig`\n\n내부 Vite 개발 서버/번들러에 직접 [Vite 구성](https://vitejs.dev/config/)을 전달합니다.\n\n```js\nexport default {\n  vite: {\n    // Vite 구성 옵션\n  }\n}\n```\n\n### vue\n\n- 타입: `import('@vitejs/plugin-vue').Options`\n\n내부 플러그인 인스턴스에 직접 [`@vitejs/plugin-vue` 옵션](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options)을 전달합니다.\n\n```js\nexport default {\n  vue: {\n    // @vitejs/plugin-vue 옵션\n  }\n}\n```\n\n## 빌드 훅 {#build-hooks}\n\nVitePress 빌드 훅은 웹사이트에 새로운 기능과 동작을 추가할 수 있게 합니다:\n\n- 사이트맵\n- 검색 인덱싱\n- PWA\n- 텔레포트\n\n### buildEnd\n\n- 타입: `(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd`는 빌드 CLI 훅으로, 빌드(SSG)가 완료된 후 VitePress CLI 프로세스가 종료되기 전에 실행됩니다.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender\n\n- 타입: `(context: SSGContext) => Awaitable<SSGContext | void>`\n\n`postRender`는 빌드 훅으로, SSG 렌더링이 완료되었을 때 호출됩니다. 이를 통해 SSG 동안 텔레포트 콘텐츠를 핸들링 할 수 있습니다.\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead\n\n- 타입: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead`는 각 페이지를 생성하기 전에 헤드를 변환하는 빌드 훅입니다. VitePress 구성에 정적으로 추가할 수 없는 헤드 항목을 추가할 수 있습니다. 기존 항목과 자동으로 병합되므로 추가 항목만 반환하면 됩니다.\n\n::: warning\n`context` 내부의 어떤 것도 변경하지 마세요.\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // 예: index.md (srcDir에 상대적)\n  assets: string[] // js/css가 아닌 모든 에셋을 완전히 처리된 public URL로 표시.\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\n이 훅은 사이트를 정적으로 생성할 때만 호출됩니다. 개발 중에는 호출되지 않습니다. 개발 중에 동적 헤드 항목을 추가해야 하는 경우, [`transformPageData`](#transformpagedata) 훅을 대신 사용할 수 있습니다:\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `VitePress`\n            : `${pageData.title} | VitePress`\n      }\n    ])\n  }\n}\n```\n\n#### 예제: 표준 URL `<link>` 추가 {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n\n- 타입: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml`은 각 페이지의 내용을 디스크에 저장하기 전에 변환하는 빌드 훅입니다.\n\n::: warning\n`context` 내부의 어떤 것도 변경하지 마세요. HTML 내용을 수정하면 런타임에 하이드레이션 문제가 발생할 수 있습니다.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n\n- 타입: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData`는 각 페이지의 `pageData`를 변환하는 훅입니다. `pageData`를 직접 변경하거나, 변경된 값을 반환하여 페이지 데이터에 병합할 수 있습니다.\n\n::: warning\n`context` 내부의 어떤 것도 변경하지 마세요. 이 훅에서 네트워크 요청이나 이미지 생성과 같은 무거운 연산이 있을 경우 개발 서버의 성능에 영향을 줄 수 있으니 주의하세요. 조건부 로직을 위해 `process.env.NODE_ENV === 'production'`을 확인할 수 있습니다.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // 또는 병합할 데이터 반환\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/lunaria.config.json",
    "content": "{\n  \"$schema\": \"./node_modules/@lunariajs/core/config.schema.json\",\n  \"repository\": {\n    \"name\": \"vuejs/vitepress\",\n    \"rootDir\": \"docs\"\n  },\n  \"files\": [\n    {\n      \"location\": \"**/config.ts\",\n      \"pattern\": \"@lang/@path\",\n      \"type\": \"universal\"\n    },\n    {\n      \"location\": \"**/*.md\",\n      \"pattern\": \"@lang/@path\",\n      \"type\": \"universal\"\n    }\n  ],\n  \"defaultLocale\": {\n    \"label\": \"English\",\n    \"lang\": \"en\"\n  },\n  \"locales\": [\n    {\n      \"label\": \"简体中文\",\n      \"lang\": \"zh\"\n    },\n    {\n      \"label\": \"Português\",\n      \"lang\": \"pt\"\n    },\n    {\n      \"label\": \"Русский\",\n      \"lang\": \"ru\"\n    },\n    {\n      \"label\": \"Español\",\n      \"lang\": \"es\"\n    },\n    {\n      \"label\": \"한국어\",\n      \"lang\": \"ko\"\n    },\n    {\n      \"label\": \"فارسی\",\n      \"lang\": \"fa\"\n    },\n    {\n      \"label\": \"日本語\",\n      \"lang\": \"ja\"\n    }\n  ],\n  \"outDir\": \".vitepress/dist/_translations\",\n  \"ignoreKeywords\": [\"lunaria-ignore\"]\n}\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vitepress dev\",\n    \"build\": \"vitepress build\",\n    \"preview\": \"vitepress preview\",\n    \"lunaria:build\": \"lunaria build\",\n    \"lunaria:open\": \"open-cli .vitepress/dist/_translations/index.html\"\n  },\n  \"devDependencies\": {\n    \"@lunariajs/core\": \"^0.1.1\",\n    \"markdown-it-mathjax3\": \"^4.3.2\",\n    \"open-cli\": \"^8.0.0\",\n    \"postcss-rtlcss\": \"^5.7.1\",\n    \"vitepress\": \"workspace:*\",\n    \"vitepress-plugin-group-icons\": \"^1.7.1\",\n    \"vitepress-plugin-llms\": \"^1.11.1\"\n  }\n}\n"
  },
  {
    "path": "docs/pt/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Gerador de Site Estático desenvolvido com Vite e Vue.',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/pt/guide/': { base: '/pt/guide/', items: sidebarGuide() },\n      '/pt/reference/': { base: '/pt/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edite esta página no GitHub'\n    },\n\n    footer: {\n      message: 'Lançado sob licença MIT',\n      copyright: `Direitos reservados © 2019-${new Date().getFullYear()} Evan You`\n    },\n\n    docFooter: {\n      prev: 'Anterior',\n      next: 'Próximo'\n    },\n\n    outline: {\n      label: 'Nesta página'\n    },\n\n    lastUpdated: {\n      text: 'Atualizado em'\n    },\n\n    notFound: {\n      title: 'PÁGINA NÃO ENCONTRADA',\n      quote:\n        'Mas se você não mudar de direção e continuar procurando, pode acabar onde está indo.',\n      linkLabel: 'ir para a página inicial',\n      linkText: 'Me leve para casa'\n    },\n\n    langMenuLabel: 'Alterar Idioma',\n    returnToTopLabel: 'Voltar ao Topo',\n    sidebarMenuLabel: 'Menu Lateral',\n    darkModeSwitchLabel: 'Tema Escuro',\n    lightModeSwitchTitle: 'Mudar para Modo Claro',\n    darkModeSwitchTitle: 'Mudar para Modo Escuro',\n    skipToContentLabel: 'Pular para o Conteúdo'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'Guia',\n      link: '/pt/guide/what-is-vitepress',\n      activeMatch: '/pt/guide/'\n    },\n    {\n      text: 'Referência',\n      link: '/pt/reference/site-config',\n      activeMatch: '/pt/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/pt/'\n        },\n        {\n          text: 'Registro de Mudanças',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'Contribuindo',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Introdução',\n      collapsed: false,\n      items: [\n        { text: 'O que é VitePress？', link: 'what-is-vitepress' },\n        { text: 'Iniciando', link: 'getting-started' },\n        { text: 'Roteamento', link: 'routing' },\n        { text: 'Implantação', link: 'deploy' }\n      ]\n    },\n    {\n      text: 'Escrevendo',\n      collapsed: false,\n      items: [\n        { text: 'Extensões Markdown', link: 'markdown' },\n        { text: 'Manipulando Ativos', link: 'asset-handling' },\n        { text: 'Frontmatter', link: 'frontmatter' },\n        { text: 'Usando Vue em Markdown', link: 'using-vue' },\n        { text: 'Internacionalização', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'Personalização',\n      collapsed: false,\n      items: [\n        { text: 'Usando um tema personalizado', link: 'custom-theme' },\n        { text: 'Estendendo o tema padrão', link: 'extending-default-theme' },\n        {\n          text: 'Carregamento de dados no momento da compilação',\n          link: 'data-loading'\n        },\n        { text: 'Compatibilidade SSR', link: 'ssr-compat' },\n        { text: 'Conectando a um CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: 'Experimental',\n      collapsed: false,\n      items: [\n        { text: 'Modo MPA', link: 'mpa-mode' },\n        { text: 'Geração de Sitemap', link: 'sitemap-generation' }\n      ]\n    },\n    {\n      text: 'Configuração e Referência da API',\n      base: '/pt/reference/',\n      link: 'site-config'\n    }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Referência',\n      items: [\n        { text: 'Configuração do Site', link: 'site-config' },\n        { text: 'Configuração Frontmatter', link: 'frontmatter-config' },\n        { text: 'API do tempo de execução', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: 'Tema padrão',\n          base: '/pt/reference/default-theme-',\n          items: [\n            { text: 'Visão Geral', link: 'config' },\n            { text: 'Navegação', link: 'nav' },\n            { text: 'Barra Lateral', link: 'sidebar' },\n            { text: 'Página Inicial', link: 'home-page' },\n            { text: 'Rodapé', link: 'footer' },\n            { text: 'Layout', link: 'layout' },\n            { text: 'Distintivo', link: 'badge' },\n            { text: 'Página da Equipe', link: 'team-page' },\n            { text: 'Links Anterior / Próximo', link: 'prev-next-links' },\n            { text: 'Editar Link', link: 'edit-link' },\n            { text: 'Selo Temporal de Atualização', link: 'last-updated' },\n            { text: 'Busca', link: 'search' },\n            { text: 'Carbon Ads', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: 'Buscar',\n        buttonAriaLabel: 'Buscar'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: 'Limpar',\n          clearButtonAriaLabel: 'Limpar a consulta',\n          closeButtonText: 'Fechar',\n          closeButtonAriaLabel: 'Fechar',\n          placeholderText: 'Buscar na documentação ou perguntar ao Ask AI',\n          placeholderTextAskAi: 'Faça outra pergunta...',\n          placeholderTextAskAiStreaming: 'Respondendo...',\n          searchInputLabel: 'Buscar',\n          backToKeywordSearchButtonText:\n            'Voltar para a busca por palavra-chave',\n          backToKeywordSearchButtonAriaLabel:\n            'Voltar para a busca por palavra-chave',\n          newConversationPlaceholder: 'Faça uma pergunta',\n          conversationHistoryTitle: 'Meu histórico de conversas',\n          startNewConversationText: 'Iniciar uma nova conversa',\n          viewConversationHistoryText: 'Histórico de conversas',\n          threadDepthErrorPlaceholder: 'Limite de conversa atingido'\n        },\n        newConversation: {\n          newConversationTitle: 'Como posso ajudar hoje?',\n          newConversationDescription:\n            'Eu busco na sua documentação para ajudar a encontrar guias de configuração, detalhes de funcionalidades e dicas de solução de problemas rapidamente.'\n        },\n        footer: {\n          selectText: 'Selecionar',\n          submitQuestionText: 'Enviar pergunta',\n          selectKeyAriaLabel: 'Tecla Enter',\n          navigateText: 'Navegar',\n          navigateUpKeyAriaLabel: 'Seta para cima',\n          navigateDownKeyAriaLabel: 'Seta para baixo',\n          closeText: 'Fechar',\n          backToSearchText: 'Voltar à busca',\n          closeKeyAriaLabel: 'Tecla Escape',\n          poweredByText: 'Com tecnologia de'\n        },\n        errorScreen: {\n          titleText: 'Não foi possível obter resultados',\n          helpText: 'Talvez você queira verificar sua conexão de rede.'\n        },\n        startScreen: {\n          recentSearchesTitle: 'Recentes',\n          noRecentSearchesText: 'Nenhuma pesquisa recente',\n          saveRecentSearchButtonTitle: 'Salvar esta pesquisa',\n          removeRecentSearchButtonTitle: 'Remover esta pesquisa do histórico',\n          favoriteSearchesTitle: 'Favoritos',\n          removeFavoriteSearchButtonTitle:\n            'Remover esta pesquisa dos favoritos',\n          recentConversationsTitle: 'Conversas recentes',\n          removeRecentConversationButtonTitle:\n            'Remover esta conversa do histórico'\n        },\n        noResultsScreen: {\n          noResultsText: 'Nenhum resultado encontrado para',\n          suggestedQueryText: 'Tente pesquisar por',\n          reportMissingResultsText:\n            'Acha que esta consulta deveria retornar resultados?',\n          reportMissingResultsLinkText: 'Avise-nos.'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'Perguntar à IA: ',\n          noResultsAskAiPlaceholder:\n            'Não encontrou nos documentos? Peça ajuda ao Ask AI: '\n        },\n        askAiScreen: {\n          disclaimerText:\n            'As respostas são geradas por IA e podem conter erros. Verifique.',\n          relatedSourcesText: 'Fontes relacionadas',\n          thinkingText: 'Pensando...',\n          copyButtonText: 'Copiar',\n          copyButtonCopiedText: 'Copiado!',\n          copyButtonTitle: 'Copiar',\n          likeButtonTitle: 'Curtir',\n          dislikeButtonTitle: 'Não curtir',\n          thanksForFeedbackText: 'Obrigado pelo seu feedback!',\n          preToolCallText: 'Buscando...',\n          duringToolCallText: 'Buscando...',\n          afterToolCallText: 'Pesquisado',\n          stoppedStreamingText: 'Você interrompeu esta resposta',\n          errorTitleText: 'Erro no chat',\n          threadDepthExceededMessage:\n            'Esta conversa foi encerrada para manter respostas precisas.',\n          startNewConversationButtonText: 'Iniciar uma nova conversa'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'Perguntar à IA',\n            buttonAriaLabel: 'Perguntar à IA'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'Perguntar à IA',\n              conversationHistoryTitle: 'Meu histórico de conversas',\n              newConversationText: 'Iniciar uma nova conversa',\n              viewConversationHistoryText: 'Histórico de conversas'\n            },\n            promptForm: {\n              promptPlaceholderText: 'Faça uma pergunta',\n              promptAnsweringText: 'Respondendo...',\n              promptAskAnotherQuestionText: 'Faça outra pergunta',\n              promptDisclaimerText:\n                'As respostas são geradas por IA e podem conter erros.',\n              promptLabelText:\n                'Pressione Enter para enviar ou Shift+Enter para nova linha.',\n              promptAriaLabelText: 'Entrada do prompt'\n            },\n            conversationScreen: {\n              preToolCallText: 'Buscando...',\n              searchingText: 'Buscando...',\n              toolCallResultText: 'Pesquisado',\n              conversationDisclaimer:\n                'As respostas são geradas por IA e podem conter erros. Verifique.',\n              reasoningText: 'Raciocinando...',\n              thinkingText: 'Pensando...',\n              relatedSourcesText: 'Fontes relacionadas',\n              stoppedStreamingText: 'Você interrompeu esta resposta',\n              copyButtonText: 'Copiar',\n              copyButtonCopiedText: 'Copiado!',\n              likeButtonTitle: 'Curtir',\n              dislikeButtonTitle: 'Não curtir',\n              thanksForFeedbackText: 'Obrigado pelo seu feedback!',\n              errorTitleText: 'Erro no chat'\n            },\n            newConversationScreen: {\n              titleText: 'Como posso ajudar hoje?',\n              introductionText:\n                'Eu busco na sua documentação para ajudar a encontrar guias de configuração, detalhes de funcionalidades e dicas de solução de problemas rapidamente.'\n            },\n            logo: {\n              poweredByText: 'Com tecnologia de'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/pt/guide/asset-handling.md",
    "content": "# Manipulação de Ativos {#asset-handling}\n\n## Referenciando Ativos Estáticos {#referencing-static-assets}\n\nTodos os arquivos Markdown são compilados em componentes Vue e processados por [Vite](https://vitejs.dev/guide/assets.html). Você pode **e deve** referenciar quaisquer ativos usando URLs relativas:\n\n```md\n![Uma imagem](./imagem.png)\n```\n\nVocê pode referenciar ativos estáticos em seus arquivos markdown, seus componentes `*.vue` no tema, estilos e simples arquivos `.css`, usando caminhos públicos absolutos (com base na raiz do projeto) ou caminhos relativos (com base em seu sistema de arquivos). Este último é semelhante ao comportamento que você está acostumado se já usou Vite, Vue CLI ou o `file-loader` do webpack.\n\nTipos comuns de arquivos de imagem, mídia e fonte são detectados e incluídos automaticamente como ativos.\n\nTodos os ativos referenciados, incluindo aqueles usando caminhos absolutos, serão copiados para o diretório de saída com um nome de arquivo hash na compilação de produção. Ativos nunca referenciados não serão copiados. Ativos de imagem menores que 4KB serão incorporados em base64 - isso pode ser configurado pela opção [`vite`](../reference/site-config#vite) da configuração.\n\nTodas as referências de caminho **estáticas**, incluindo caminhos absolutos, devem ser baseadas na estrutura do seu diretório de trabalho.\n\n## O Diretório Público {#the-public-directory}\n\nÀs vezes, pode ser necessário fornecer ativos estáticos que não são referenciados diretamente em nenhum de seus componentes do tema ou Markdown, ou você pode querer servir certos arquivos com o nome de arquivo original. Exemplos de tais arquivos incluem `robots.txt`, favicons e ícones PWA.\n\nVocê pode colocar esses arquivos no diretório `public` sob o [diretório fonte](./routing#source-directory). Por exemplo, se a raiz do seu projeto for `./docs` e estiver usando a localização padrão do diretório fonte, então o diretório público será `./docs/public`.\n\nOs ativos colocados em `public` serão copiados para a raiz do diretório de saída como são.\n\nObserve que você deve referenciar arquivos colocados em `public` usando o caminho absoluto da raiz - por exemplo, `public/icon.png` deve sempre ser referenciado no código fonte como `/icon.png`.\n\n## URL Base {#base-url}\n\nSe seu site for implantado em uma URL que não seja a raiz, será necessário definir a opção `base` em `.vitepress/config.js`. Por exemplo, se você planeja implantar seu site em `https://foo.github.io/bar/`, então `base` deve ser definido como `'/bar/'` (sempre deve começar e terminar com uma barra).\n\nTodos os caminhos dos seus ativos estáticos são processados automaticamente para se ajustar aos diferentes valores de configuração `base`. Por exemplo, se você tiver uma referência absoluta a um ativo sob `public` no seu markdown:\n\n```md\n![Uma imagem](/imagem-dentro-de-public.png)\n```\n\nVocê **não** precisa atualizá-lo quando alterar o valor de configuração `base` nesse caso.\n\nNo entanto, se você estiver criando um componente de tema que vincula ativos dinamicamente, por exemplo, uma imagem cujo `src` é baseado em um valor de configuração do tema:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nNesse caso, é recomendável envolver o caminho com o [`auxiliar withBase`](../reference/runtime-api#withbase) fornecido por VitePress:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/pt/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# Conectando a um CMS {#connecting-to-a-cms}\n\n## Fluxo de Trabalho Geral {#general-workflow}\n\nConectar VitePress a um CMS orbitará majoritariamente sobre [Rotas Dinâmicas](./routing#dynamic-routes). Certifique-se de entender como funcionam antes de proceder.\n\nComo cada CMS funcionará de forma diferente, aqui podemos fornecer apenas um fluxo de trabalho genérico que precisará ser adaptado para cada cenário específico.\n\n1. Se seu CMS exige autenticação, crie um arquivo `.env` para armazenar os tokens da API e carregá-los como:\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. Obtenha os dados necessários do CMS e formate-os em caminhos de dados apropriados:\n\n    ```js\n    export default {\n      async paths() {\n        // use a biblitoca do cliente CMS respectiva se preciso\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // token se necessário\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* título, autores, data, etc. */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. Apresente o conteúdo na página:\n\n    ```md\n    # {{ $params.title }}\n\n    - por {{ $params.author }} em {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## Guias de Integração {#integration-guides}\n\nSe você tiver escrito um guia sobre como integrar VitePress com um CMS específico, por favor use o link \"Edite esta página\" abaixo para enviá-lo para cá!\n"
  },
  {
    "path": "docs/pt/guide/custom-theme.md",
    "content": "# Usando um Tema Personalizado {#using-a-custom-theme}\n\n## Resolução de Tema {#theme-resolving}\n\nVocê pode habilitar um tema personalizado criando um arquivo `.vitepress/theme/index.js` ou `.vitepress/theme/index.ts` (o \"arquivo de entrada do tema\"):\n\n```\n.\n├─ docs                # raiz do projeto\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # entrada do tema\n│  │  └─ config.js     # arquivo de configuração\n│  └─ index.md\n└─ package.json\n```\n\nVitePress sempre usará o tema personalizado em vez do tema padrão quando detectar a presença de um arquivo de entrada do tema. No entanto, você pode [estender o tema padrão](./extending-default-theme) para realizar personalizações avançadas sobre ele.\n\n## Interface do Tema {#theme-interface}\n\nUm tema personalizado do VitePress é definido como um objeto com a seguinte interface:\n\n```ts\ninterface Theme {\n  /**\n   * Componente raiz de layout para toda página\n   * @required\n   */\n  Layout: Component\n  /**\n   * Aprimora a instância da aplicação Vue\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * Estende outro tema, chamando seu `enhanceApp` antes do nosso\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // instância da aplicação Vue\n  router: Router // instância do roteador VitePress\n  siteData: Ref<SiteData> // Metadados do nível do site\n}\n```\n\nO arquivo de entrada do tema deve exportar o tema como sua exportação padrão:\n\n```js [.vitepress/theme/index.js]\n\n// Você pode importar arquivos Vue diretamente no arquivo de entrada do tema\n// VitePress já está pré-configurado com @vitejs/plugin-vue.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nA exportação padrão é o único contrato para um tema personalizado, e apenas a propriedade `Layout` é exigida. Tecnicamente, um tema do VitePress pode ser tão simples quanto um único componente Vue.\n\nDentro do seu componente de layout, ele funciona como uma aplicação Vite + Vue 3 normal. Note que o tema também precisa ser [compatível com SSR](./ssr-compat).\n\n## Construindo um Layout {#building-a-layout}\n\nO componente de layout mais básico precisa conter um componente [`<Content />`](../reference/runtime-api#content):\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <!-- aqui é onde o conteúdo markdown será apresentado -->\n  <Content />\n</template>\n```\n\nO layout acima simplesmente renderiza o markdown de toda página como HTML. A primeira melhoria que podemos adicionar é lidar com erros 404:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Página 404 personalizada!\n  </div>\n  <Content v-else />\n</template>\n```\n\nO auxiliar [`useData()`](../reference/runtime-api#usedata) fornece todos os dados em tempo de execução que precisamos para mostrar layouts diferentes. Um dos outros dados que podemos acessar é o frontmatter da página atual. Podemos aproveitar isso para permitir que o usuário final controle o layout em cada página. Por exemplo, o usuário pode indicar que a página deve usar um layout especial de página inicial com:\n\n```md\n---\nlayout: home\n---\n```\n\nE podemos ajustar nosso tema para lidar com isso:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Página 404 personalizada!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Página inicial personalizada!\n  </div>\n  <Content v-else />\n</template>\n```\n\nVocê pode, é claro, dividir o layout em mais componentes:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Layout Personalizado!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> renders <Content /> -->\n</template>\n```\n\nConsulte a [Referência da API em Tempo de Execução](../reference/runtime-api) para tudo que está disponível em componentes de tema. Além disso, você pode aproveitar [Carregamento de Dados em Tempo de Compilação](./data-loading) para gerar layouts orientados por dados - por exemplo, uma página que lista todas as postagens do blog no projeto atual.\n\n## Distribuindo um Tema Personalizado {#distributing-a-custom-theme}\n\nA maneira mais fácil de distribuir um tema personalizado é fornecê-lo como um [repositório de modelo no GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).\n\nSe você deseja distribuir seu tema como um pacote npm, siga estas etapas:\n\n1. Exporte o objeto do tema como a exportação padrão no seu arquivo de pacote.\n\n2. Se aplicável, exporte a definição de configuração de tipo do tema como `ThemeConfig`.\n\n3. Se seu tema exigir ajustes na configuração VitePress, exporte essa configuração em um subdiretório do pacote (por exemplo, `meu-tema/config`) para que o usuário possa estendê-la.\n\n4. Documente as opções de configuração do tema (tanto via arquivo de configuração quanto em frontmatter).\n\n5. Forneça instruções claras sobre como consumir seu tema (veja abaixo).\n\n## Consumindo um Tema Personalizado {#consuming-a-custom-theme}\n\nPara consumir um tema externo, importe-o e reexporte-o a partir do arquivo de entrada do tema personalizado:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nSe o tema precisar ser estendido:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nSe o tema exigir uma configuração especial do VitePress, você também precisará estendê-lo em sua própria configuração:\n\n```ts\n// .vitepress/theme/config.ts\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // estenda a configuração base do tema (se preciso)\n  extends: baseConfig\n}\n```\n\nFinalmente, se o tema fornecer tipos para a configuração do tema:\n\n```ts\n// .vitepress/theme/config.ts\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // O tipo é `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/pt/guide/data-loading.md",
    "content": "# Carregamento de Dados em Tempo de Compilação {#build-time-data-loading}\n\nVitePress fornece um recurso chamado **carregadores de dado** que permite carregar dados arbitrários e importá-los de páginas ou de componentes. O carregamento de dados é executado **apenas no tempo da construção**: os dados resultantes serão serializados como JSON no pacote JavaScript final.\n\nOs carregadores de dados podem ser usados para buscar dados remotos ou gerar metadados com base em arquivos locais. Por exemplo, você pode usar carregadores de dados para processar todas as suas páginas API locais e gerar automaticamente um índice de todas as entradas da API.\n\n## Uso Básico {#basic-usage}\n\nUm arquivo de carregador de dados deve terminar com `.data.js` ou `.data.ts`. O arquivo deve fornecer uma exportação padrão de um objeto com o método `load()`:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\nO módulo do carregador é avaliado apenas no Node.js, então você pode importar APIs Node e dependências npm conforme necessário.\n\nVocê pode então importar dados deste arquivo em páginas `.md` e componentes `.vue` usando a exportação nomeada `data`:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\nSaída:\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\nVocê notará que o próprio carregador de dados não exporta o `data`. É o VitePress chamando o método `load()` nos bastidores e expondo implicitamente o resultado por meio da exportação nomeada `data`.\n\nIsso funciona mesmo se o carregador for assíncrono:\n\n```js\nexport default {\n  async load() {\n    // buscar dados remotos\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## Dados de Arquivos Locais {#data-from-local-files}\n\nQuando você precisa gerar dados com base em arquivos locais, você deve usar a opção `watch` no carregador de dados para que as alterações feitas nesses arquivos possam acionar atualizações rápidas.\n\nA opção `watch` também é conveniente porque você pode usar [padrões glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para corresponder a vários arquivos. Os padrões podem ser relativos ao próprio arquivo do carregador, e a função `load()` receberá os arquivos correspondentes como caminhos absolutos.\n\nO exemplo a seguir mostra o carregamento de arquivos CSV e a transformação deles em JSON usando [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Como este arquivo só é executado no tempo da construção, você não enviará o procesador CSV para o cliente!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles será um array de caminhos absolutos dos arquivos correspondidos.\n    // gerar um array de metadados de post que pode ser usada para mostrar\n    // uma lista no layout do tema\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\nAo construir um site focado em conteúdo, frequentemente precisamos criar uma página de \"arquivo\" ou \"índice\": uma página onde listamos todas as entradas disponíveis em nossa coleção de conteúdo, por exemplo, artigos de blog ou páginas de API. Nós **podemos** implementar isso diretamente com a API de carregador de dados, mas como este é um caso de uso tão comum, VitePress também fornece um auxiliar `createContentLoader` para simplificar isso:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* opções */)\n```\n\nO auxiliar aceita um padrão glob relativo ao [diretório fonte](./routing#source-directory) e retorna um objeto de carregador de dados `{ watch, load }` que pode ser usado como exportação padrão em um arquivo de carregador de dados. Ele também implementa cache com base nos selos de data do arquivo para melhorar o desempenho no desenvolvimento.\n\nNote que o carregador só funciona com arquivos Markdown - arquivos não-Markdown correspondidos serão ignorados.\n\nOs dados carregados serão um _array_ com o tipo `ContentData[]`:\n\n```ts\ninterface ContentData {\n  // URL mapeada para a página. Ex: /posts/hello.html (não inclui a base)\n  // itere manualmente ou use `transform` personalizado para normalizar os caminhos\n  url: string\n  // dados frontmatter da página\n  frontmatter: Record<string, any>\n\n  // os seguintes estão presentes apenas se as opções relevantes estiverem habilitadas\n  // discutiremos sobre eles abaixo\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nPor padrão, apenas `url` e `frontmatter` são fornecidos. Isso ocorre porque os dados carregados serão incorporados como JSON no pacote do cliente, então precisamos ser cautelosos com seu tamanho. Aqui está um exemplo de como usar os dados para construir uma página de índice de blog mínima:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>Todos os posts do blog</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>por {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### Opções {#options}\n\nOs dados padrão podem não atender a todas as necessidades - você pode optar por transformar os dados usando opções:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // incluir fonte markdown crua?\n  render: true,     // incluir HTML completo da página apresentada?\n  excerpt: true,    // incluir excerto?\n  transform(rawData) {\n    // mapeie, ordene ou filtre os dados crus conforme quiser.\n    // o resultado final é o que será enviado ao cliente.\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // fonte markdown crua\n      page.html    // HTML completo da página apresentada\n      page.excerpt // HTML do excerto apresentado (conteúdo acima do primeiro `---`)\n      return {/* ... */}\n    })\n  }\n})\n```\n\nVeja como é usado no [blog Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).\n\nA API `createContentLoader` também pode ser usada dentro dos [ganchos de construção](../reference/site-config#build-hooks):\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // gerar arquivos com base nos metadados dos posts, por exemplo, feed RSS\n  }\n}\n```\n\n**Tipos**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * Incluir src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * Renderizar src para HTML e incluir nos dados?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * Se `boolean`, deve-se processar e incluir o resumo? (apresentado como HTML)\n   *\n   * Se `function`, controla como o excerto é extraído do conteúdo.\n   *\n   * Se `string`, define um separador personalizado a ser usado para extrair o\n   * excerto. O separador padrão é `---` se `excerpt` for `true`.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * Transforma os dados. Observe que os dados serão incorporados como JSON no pacote do cliente\n   * se importados de componentes ou arquivos markdown.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## Carregadores de Dados com Tipos {#typed-data-loaders}\n\nAo usar TypeScript, você pode tipar seu carregador e exportar `data` da seguinte forma:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // tipo de dado\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // opções do carregador verificadas pelo tipo\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## Configuração {#configuration}\n\nPara obter as informações de configuração dentro de um carregador, você pode usar um código como este:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/pt/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# Implante seu Site VitePress {#deploy-your-vitepress-site}\n\nOs guias a seguir são baseados em alguns pressupostos:\n\n- O site VitePress está dentro do diretório `docs` do seu projeto.\n- Você está usando o diretório de saída de compilação padrão (`.vitepress/dist`).\n- VitePress está instalado como uma dependência local em seu projeto, e você configurou os seguintes scripts em seu `package.json`:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## Compilar e Testar Localmente {#build-and-test-locally}\n\n1. Execute este comando para compilar a documentação:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. Após a compilação, veja a prévia local executando:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   O comando `preview` inicializará um servidor web estático local que servirá o diretório de saída `.vitepress/dist` em `http://localhost:4173`. Você pode usar isso para garantir que tudo esteja correto antes de enviar para produção.\n\n3. Você pode configurar a porta do servidor passando `--port` como argumento.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   Agora o método `docs:preview` implantará o servidor em `http://localhost:8080`.\n\n## Configurando um Caminho Base Público {#setting-a-public-base-path}\n\nPor padrão, assumimos que o site será implantado no caminho raiz de um domínio (`/`). Se seu site for servido em um subcaminho, por exemplo, `https://meusite.com/blog/`, você precisa então configurar a opção [`base`](../reference/site-config#base) para `'/blog/'` na configuração VitePress.\n\n**Exemplo:** Ao usar GitHub Pages (ou GitLab Pages) e implantar em `user.github.io/repo/`, defina seu `base` como `/repo/`.\n\n## Cabeçalhos de Cache HTTP {#http-cache-headers}\n\nSe você tiver controle sobre os cabeçalhos HTTP de seu servidor em produção, pode-se configurar cabeçalhos `cache-control` para obter melhor desempenho em visitas repetidas.\n\nA compilação de produção usa nomes de arquivos com hash para ativos estáticos (JavaScript, CSS e outros ativos importados que não estão em `public`). Se você inspecionar a prévia de produção usando as ferramentas de desenvolvedor do seu nevegador na aba rede, verá arquivos como `app.4f283b18.js`.\n\nEste hash `4f283b18` é gerado a partir do conteúdo deste arquivo. A mesma URL com hash é garantida para servir o mesmo conteúdo do arquivo - se o conteúdo mudar, as URLs também mudam. Isso significa que você pode usar com segurança os cabeçalhos de cache mais fortes para esses arquivos. Todos esses arquivos serão colocados em `assets/` no diretório de saída, então você pode configurar o seguinte cabeçalho para eles:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Exemplo de arquivo `_headers` do Netlify\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\nNota: o arquivo `_headers` deve ser colocado no [diretório public](./asset-handling#the-public-directory) - em nosso caso, `docs/public/_headers` - para que ele seja copiado exatamente para o diretório de saída.\n\n[Documentação de cabeçalhos personalizados do Netlify](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details Exemplo de configuração Vercel em `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nNota: o arquivo `vercel.json` deve ser colocado na raiz do seu **repositório**.\n\n[Documentação Vercel sobre configuração de cabeçalhos](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## Guias de Plataforma {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\nConfigure um novo projeto e altere estas configurações usando seu painel:\n\n- **Comando de Compilação:** `npm run docs:build`\n- **Diretório de Saída:** `docs/.vitepress/dist`\n- **Versão do Node:** `20` (ou superior)\n\n::: warning\nNão ative opções como _Auto Minify_ para código HTML. Isso removerá comentários da saída que têm significado para Vue. Haverão erros de incompatibilidade de hidratação se forem removidos.\n:::\n\n### GitHub Pages\n\n1. Crie um arquivo chamado `deploy.yml` dentro do diretório `.github/workflows` do seu projeto com algum conteúdo como este:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Exemplo de fluxo de trabalho para compilar e implantar um site VitePress no GitHub Pages\n   #\n   name: Implante o site VitePress no Pages\n\n   on:\n     # Executa em pushes direcionados à branch `main`.\n     # Altere para `master` se estiver usando a branch `master` como padrão.\n     push:\n       branches: [main]\n\n     # Permite executar manualmente este fluxo de trabalho na guia Actions\n     workflow_dispatch:\n\n   # Define permissões GITHUB_TOKEN para a implantação no GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Permite apenas uma implantação simultânea, pulando execuções em fila entre a execução em andamento e a última da fila.\n   # No entanto, NÃO cancela execuções em andamento, pois queremos permitir que essas implantações de produção sejam concluídas.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Trabalho de compilação\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # Não necessário se lastUpdated não estiver habilitado\n         # - uses: pnpm/action-setup@v4 # Descomente isso se estiver usando pnpm\n         #   with:\n         #     version: 9\n         # - uses: oven-sh/setup-bun@v1 # Descomente isso se estiver usando Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # ou pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # ou pnpm install / yarn install / bun install\n        - name: Build with VitePress\n          run: npm run docs:build # ou pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Trabalho de implantação\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   Certifique-se de que a opção `base` em seu VitePress esteja configurada corretamente. Veja [Configurando um Caminho Base Público](#setting-a-public-base-path) para mais detalhes.\n   :::\n\n2. Nas configurações do seu repositório sob o item do menu \"Pages\", selecione \"GitHub Actions\" em \"Build and deployment > Source\".\n\n3. Envie suas alterações para a branch `main` e aguarde a conclusão do fluxo de trabalho do GitHub Actions. Você verá seu site implantado em `https://<username>.github.io/[repository]/` ou `https://<custom-domain>/` dependendo das suas configurações. Seu site será implantado automaticamente em cada push para a branch `main`.\n\n### GitLab Pages\n\n1. Defina `outDir` na configuração VitePress como `../public`. Configure a opção `base` para `'/<repository>/'` se você deseja implantar em `https://<username>.gitlab.io/<repository>/`. Você não precisa de `base` se estiver implantando em um domínio personalizado, páginas de usuário ou grupo, ou se a configuração \"Use unique domain\" estiver habilitada no GitLab.\n\n2. Crie um arquivo chamado `.gitlab-ci.yml` na raiz do seu projeto com o conteúdo abaixo. Isso construirá e implantará seu site sempre que você fizer alterações no conteúdo:\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Descomente isso se estiver usando imagens pequenas do Docker como o Alpine e tiver lastUpdated habilitado\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. Siga a [documentação oficial](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration).\n\n2. Configure esses valores em seu arquivo de configuração (e remova aqueles que você não precisa, como `api_location`):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\nVocê pode implantar seu projeto VitePress com a [CloudRay](https://cloudray.io/) seguindo estas [instruções](https://cloudray.io/articles/how-to-deploy-vitepress-site).\n\n### Firebase\n\n1. Crie `firebase.json` e `.firebaserc` na raiz do seu projeto:\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<SEU_ID_FIREBASE>\"\n     }\n   }\n   ```\n\n2. Após executar `npm run docs:build`, execute este comando para implantar:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. Siga a documentação e o guia fornecidos em [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static).\n\n2. Crie um arquivo chamado `static.json` na raiz do seu projeto com o conteúdo abaixo:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\nVocê pode implantar seu projeto VitePress com a [Hostinger](https://www.hostinger.com/web-apps-hosting) seguindo estas [instruções](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/). Ao configurar as opções de build, escolha VitePress como framework e ajuste o diretório raiz para `./docs`.\n\n### Kinsta\n\nVocê pode implantar seu site VitePress em [Kinsta](https://kinsta.com/static-site-hosting/) seguindo estas [instruções](https://kinsta.com/docs/vitepress-static-site-example/).\n\n### Stormkit\n\nVocê pode implantar seu projeto VitePress na [Stormkit](https://www.stormkit.io) seguindo estas [instruções](https://stormkit.io/blog/how-to-deploy-vitepress).\n\n### Surge\n\n1. Após executar `npm run docs:build`, execute este comando para implantar:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\nAqui está um exemplo de configuração de bloco de servidor Nginx. Essa configuração inclui compressão gzip para ativos comuns baseados em texto, regras para servir os arquivos estáticos do seu site VitePress com cabeçalhos de cache apropriados, assim como lidar com `cleanUrls: true`.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # content location\n        root /app;\n\n        # exact matches -> reverse clean urls -> folders -> not found\n        try_files $uri $uri.html $uri/ =404;\n\n        # non existent pages\n        error_page 404 /404.html;\n\n        # a folder without index.html raises 403 in this setup\n        error_page 403 /404.html;\n\n        # adjust caching headers\n        # files in the assets folder have hashes filenames\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nEssa configuração presume que o site VitePress compilado está localizado no diretório `/app` no seu servidor. Ajuste a diretiva `root` de acordo caso os arquivos do site estejam em outro lugar.\n\n::: warning Não use index.html por padrão\nA resolução de try_files não deve padronizar para index.html como em outras aplicações Vue. Isso resultará em um estado de página inválido.\n:::\n\nMais informações podem ser encontradas na [documentação oficial do nginx](https://nginx.org/en/docs/), nestas issues [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235) assim como neste [post do blog](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings) de Mehdi Merah.\n"
  },
  {
    "path": "docs/pt/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# Estendendo o Tema Padrão {#extending-the-default-theme}\n\nO tema padrão do VitePress é otimizado para documentação e pode ser personalizado. Consulte a [Visão Geral de Configuração do Tema Padrão](../reference/default-theme-config) para uma lista abrangente de opções.\n\nNo entanto, há casos em que apenas a configuração não será suficiente. Por exemplo:\n\n1. É necessário ajustar a estilização CSS;\n2. É necessário modificar a instância da aplicação Vue, por exemplo para registrar componentes globais;\n3. É necessário injetar conteúdo personalizado no tema por meio de _slots_ no layout.\n\nEssas personalizações avançadas exigirão o uso de um tema personalizado que \"estende\" o tema padrão.\n\n::: tip\nAntes de prosseguir, certifique-se de ler primeiro [Usando um Tema Personalizado](./custom-theme) para entender como temas personalizados funcionam.\n:::\n\n## Personalizando o CSS {#customizing-css}\n\nO CSS do tema padrão pode ser personalizado substituindo as variáveis CSS no nível raiz:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\nVeja as [variáveis CSS do tema padrão](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) que podem ser substituídas.\n\n## Usando Fontes Diferentes {#using-different-fonts}\n\nVitePress usa [Inter](https://rsms.me/inter/) como fonte padrão e incluirá as fontes na saída de compilação. A fonte também é pré-carregada automaticamente em produção. No entanto, isso pode não ser desejável se você quiser usar uma fonte principal diferente.\n\nPara evitar a inclusão de Inter na saída de compilação, importe o tema de `vitepress/theme-without-fonts`:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* fonte de texto normal */\n  --vp-font-family-mono: /* fonte de código */\n}\n```\n\n::: warning\nSe estiver usando componentes opcionais como os componentes da [Página da Equipe](../reference/default-theme-team-page), certifique-se de também importá-los de `vitepress/theme-without-fonts`!\n:::\n\nSe a sua fonte é um arquivo local referenciado via `@font-face`, ela será processada como um ativo e incluída em `.vitepress/dist/assets` com um nome de arquivo hash. Para pré-carregar esse arquivo, use o gancho de construção [transformHead](../reference/site-config#transformhead):\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // ajuste o regex para corresponder à sua fonte\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## Registrando Componentes Globais {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // registre seus componentes globais personalizados\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nSe estiver usando TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // registre seus componentes globais personalizados\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nComo estamos usando Vite, você também pode aproveitar a [funcionalidade de importação glob](https://vitejs.dev/guide/features.html#glob-import) do Vite para registrar automaticamente um diretório de componentes.\n\n## _Slots_ no Layout {#layout-slots}\n\nO componente `<Layout/>` do tema padrão possui alguns _slots_ que podem ser usados para injetar conteúdo em locais específicos da página. Aqui está um exemplo de como injetar um componente antes do esquema :\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // substitua o Layout por um componente envolvente que\n  // injeta os slots\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      Meu conteúdo personalizado superior da barra lateral\n    </template>\n  </Layout>\n</template>\n```\n\nOu você também pode usar a função _render_.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nLista completa de _slots_ disponíveis no layout do tema padrão:\n\n- Quando `layout: 'doc'` (padrão) está habilitado via frontmatter:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- Quando `layout: 'home'` está habilitado via frontmatter:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- Quando `layout: 'page'` está habilitado via frontmatter:\n  - `page-top`\n  - `page-bottom`\n- Na página não encontrada (404):\n  - `not-found`\n- Sempre:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## Usando a API View Transitions\n\n### Na Alternância de Aparência {#on-appearance-toggle}\n\nVocê pode estender o tema padrão para fornecer uma transição personalizada quando o modo de cor é alternado. Um exemplo:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\nResultado (**atenção!**: cores piscantes, movimentos súbitos, luzes brilhantes):\n\n<details>\n<summary>Demo</summary>\n\n![Demo de Transição de Alternância de Aparência](/appearance-toggle-transition.webp)\n\n</details>\n\nConsulte [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) para mais detalhes sobre _view transitions_.\n\n### Na Mudança de Rota {#on-route-change}\n\nEm breve.\n\n## Substituindo Componentes Internos {#overriding-internal-components}\n\nVocê pode usar os [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) Vite para substituir os componentes do tema padrão pelos seus personalizados:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\nPara saber o nome exato do componente consulte [nosso código fonte](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Como os componentes são internos, há uma pequena chance de que o nome deles seja atualizado entre lançamentos secundários.\n"
  },
  {
    "path": "docs/pt/guide/frontmatter.md",
    "content": "# Frontmatter\n\n## Utilização {#usage}\n\nVitePress suporta frontmatter YAML em todos os arquivos Markdown, processando-os com [gray-matter](https://github.com/jonschlinkert/gray-matter). O frontmatter deve estar no topo do arquivo Markdown (antes de qualquer elemento, incluindo tags `<script>`), e deve ter a forma de um YAML válido entre linhas com traços triplos. Exemplo:\n\n```md\n---\ntitle: Documentação com VitePress\neditLink: true\n---\n```\n\nMuitas opções de configuração do site ou do tema padrão têm opções correspondentes no frontmatter. Você pode usar o frontmatter para sobrepor um comportamento específico apenas para a página atual. Para mais detalhes, veja [Referência de Configuração do Frontmatter](../reference/frontmatter-config).\n\nVocê também pode definir dados próprios frontmatter personalizados, para serem usados em expressões Vue dinâmicas na página.\n\n## Acesso aos Dados do Frontmatter {#accessing-frontmatter-data}\n\nOs dados do frontmatter podem ser acessados por meio da variável global especial `$frontmatter`:\n\nAqui está um exemplo de como você poderia usá-lo em seu arquivo Markdown:\n\n```md\n---\ntitle: Documentação com VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nConteúdo do guia\n```\n\nVocê também pode acessar os dados do frontmatter da página atual em `<script setup>` com o auxiliar [`useData()`](../reference/runtime-api#usedata).\n\n## Formatos Alternativos do Frontmatter {#alternative-frontmatter-formats}\n\nVitePress também suporta a sintaxe frontmatter JSON, começando e terminando com chaves:\n\n```json\n---\n{\n  \"title\": \"Criando blog como um hacker\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/pt/guide/getting-started.md",
    "content": "# Iniciando {#getting-started}\n\n## Experimente Online {#try-it-online}\n\nVocê pode experimentar VitePress diretamente no seu navegador em [StackBlitz](https://vitepress.new).\n\n## Instalação {#installation}\n\n### Pré-requisitos {#prerequisites}\n\n- [Node.js](https://nodejs.org/) na versão 20 ou superior.\n- Terminal para acessar VitePress através da sua interface de linha de comando (CLI).\n- Editor de texto com suporte a sintaxe [Markdown](https://en.wikipedia.org/wiki/Markdown).\n  - [VSCode](https://code.visualstudio.com/) é recomendado, junto com a [extensão oficial Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nVitePress pode ser usado sozinho, ou ser instalado em um projeto já existente. Em ambos os casos, você pode instalá-lo com:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip NOTA\n\nVitePress é um pacote apenas para ESM. Não use `require()` para importá-lo, e certifique de que o `package.json` mais próximo contém `\"type\": \"module\"`, ou mude a extensão do arquivo de seus arquivos releavantes como `.vitepress/config.js` para `.mjs`/`.mts`. Refira-se ao [Guia de resolução de problemas Vite](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only) para mais detalhes. Além disso, dentro de contextos de JavaScript comum assíncronos, você pode usar `await import('vitepress')`.\n\n:::\n\n### Assistente de Instalação {#setup-wizard}\n\nVitePress tem embutido um assistente de instalação pela linha de comando que irá ajudar a construir um projeto básico. Depois da instalação, inicie o assistente rodando:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nVocê será cumprimentado com algumas perguntas simples:\n\n<<< @/snippets/init.ansi\n\n::: tip Vue como Dependência Correspondente\nSe você tem a intenção de realizar personalização que usa componentes Vue ou APIs, você deve instalar explicitamente `vue` como uma dependência correspondente.\n:::\n\n## Estrutura de Arquivos {#file-structure}\n\nSe você estiver construindo um site VitePress individual, você pode desenvolver seu site no diretório atual (`./`). Entretanto, se você está instalando VitePress em um projeto existente juntamente com outro código fonte, é recomendado construir o site em um diretório aninhado (e.g. `./docs`) para que esteja separado do resto do seu projeto.\n\nAssumindo qa escolha de desenvolver o projeto VitePress em `./docs`, a estrutura de arquivos gerada deve parecer com a seguinte:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\nO diretório `docs` é considerado a **raiz do projeto** do seu site VitePress. O diretório `.vitepress` é um local reservado para arquivos de configuração VitePress, cache do servidor de desenvolvimento, resultados da build, e código de personalização de tema opcional.\n\n::: tip\nPor padrão, VitePress armazena o cache do servidor de desenvolvimento em `.vitepress/cache`, e o resultado da build de produção em `.vitepress/dist`. Se usar Git, você deve adicioná-los ao seu arquivo `.gitignore`. Estes locais também podem ser [configurados](../reference/site-config#outdir).\n:::\n\n### O arquivo de configuração {#the-config-file}\n\nO arquivo de configuração (`.vitepress/config.js`) permite que você personalize vários aspectos do seu site VitePress, com as opções mais básicas sendo o título e a descrição do site:\n\n```js [.vitepress/config.js]\nexport default {\n  // opções a nível do site\n  title: 'VitePress',\n  description: 'Só uma brincadeira.',\n\n  themeConfig: {\n    // opções a nível do tema\n  }\n}\n```\n\nVocê também pode configurar o comportamento do tema através da opção `themeConfig`. Consulte a [Referência de Configuração](../reference/site-config) para detalhes completos sobre todas as opções de configuração.\n\n### Arquivos Fonte {#source-files}\n\nArquivos Markdown fora do diretório `.vitepress` são considerados **arquivos fonte**.\n\nVitePress usa **roteamento baseado em arquivos**: cada arquivo `.md` é compilado em um arquivo correspondente `.html` com o mesmo caminho. Por exemplo, `index.md` será compilado em `index.html`, e pode ser visitado no caminho raiz `/` do site VitePress resultante.\n\nVitePress também fornece a habilidade de gerar URLs limpas, reescrever caminhos, e gerar páginas dinamicamente. Estes serão tratados no [Guia de Roteamento](./routing).\n\n## Instalado e Funcionando {#up-and-running}\n\nA ferramenta deve ter também injetado os seguintes scripts npm no seu `package.json` se você permitiu isso durante o processo de instalação:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\nO script `docs:dev` iniciará um servidor de desenvolvimento local com atualizações instantâneas. Rode-o com o seguinte comando:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nEm vez de scripts npm, você também pode invocar VitePress diretamente com:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nMais usos da linha de comando estão documentados na [Referência CLI](../reference/cli).\n\nO servidor de desenvolvimento deve estar rodando em `http://localhost:5173`. Visite a URL no seu navegador para ver o seu novo site em ação!\n\n## O que vem depois? {#what-s-next}\n\n- Para melhor entender como arquivos markdown são mapeados no HTML gerado, prossiga para o [Guia de Roteamento](./routing).\n\n- Para descobrir mais sobre o que você pode fazer em uma página, como escrever conteúdo markdown ou usar um componente Vue, refira-se a seção \"Escrevendo\" do guia. Um ótimo lugar para começar seria aprendendo mais sobre [Extensões Markdown](./markdown).\n\n- Para explorar as funcionalidades fornecidas pelo tema padrão da documentação, confira a [Referência de Configuração do Tema Padrão](../reference/default-theme-config).\n\n- Se você quer aprofundar a personalização da aparência do seu site, explore tanto em [Estenda o Tema Padrão](./extending-default-theme) como [Construa um Tema Personalizado](./custom-theme).\n\n- Uma vez que sua documentação tomar forma, certifique-se de ler o [Guia de Lançamento](./deploy).\n"
  },
  {
    "path": "docs/pt/guide/i18n.md",
    "content": "# Internacionalização {#internationalization}\n\nPara usar recursos de i18n integrados, é necessário criar uma estrutura de diretórios da seguinte forma:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\nEm seguida, no arquivo `docs/.vitepress/config.ts`:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // propriedades compartilhadas e outras coisas de nível superior...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    fr: {\n      label: 'French',\n      lang: 'fr', // opcional, será adicionado como atributo `lang` na tag `html`\n      link: '/fr/guide' // padrão /fr/ -- aparece no menu de traduções da barra de navegação, pode ser externo\n\n      // outras propriedades específicas de cada idioma...\n    }\n  }\n})\n```\n\nAs seguintes propriedades podem ser substituídas para cada idioma (incluindo a raiz):\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // será mesclado com as entradas head existentes, as metatags duplicadas são removidas automaticamente\n  themeConfig?: ThemeConfig // será mesclado superficialmente, coisas comuns podem ser colocadas na entrada de n[ivel superior de themeConfig\n}\n```\n\nConsulte a interface [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) para obter detalhes sobre a personalização dos textos marcadores do tema padrão. Não substitua `themeConfig.algolia` ou `themeConfig.carbonAds` no nível do idioma. Consulte a [documentação Algolia](../reference/default-theme-search#i18n) para usar a pesquisa multilínguas.\n\n**Dica profissional:** O arquivo de configuração pode ser armazenado em `docs/.vitepress/config/index.ts` também. Isso pode ajudar a organizar as coisas criando um arquivo de configuração por idioma e então mesclá-los e exportá-los a partir de `index.ts`.\n\n## Diretório separado para cada localização {#separate-directory-for-each-locale}\n\nA seguinte estrutura é totalmente válida:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\nNo entanto, VitePress não redirecionará `/` para `/en/` por padrão. Você precisará configurar seu servidor para isso. Por exemplo, no Netlify, você pode adicionar um arquivo `docs/public/_redirects` assim:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**Dica profissional:** Se estiver usando a abordagem acima, você pode usar o cookie `nf_lang` para persistir a escolha de idioma do usuário:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## Suporte a RTL (Experimental) {#rtl-support-experimental}\n\nPara suporte a RTL (Right to Left), especifique `dir: 'rtl'` na configuração e use algum plugin RTLCSS PostCSS como <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> ou <https://github.com/elchininet/postcss-rtlcss>. Você precisará configurar seu plugin PostCSS para usar `:where([dir=\"ltr\"])` e `:where([dir=\"rtl\"])` como prefixos para evitar problemas de especificidade CSS.\n"
  },
  {
    "path": "docs/pt/guide/markdown.md",
    "content": "# Extensões Markdown {#markdown-extensions}\n\nVitePress vem com Extensões Markdown embutidas.\n\n## Âncoras de Cabeçalho {#header-anchors}\n\nCabeçalhos recebem a aplicação automaticamente de links âncora. A apresentação das âncoras pode ser configurada usando a opção `markdown.anchor`.\n\n### Âncoras personalizadas {#custom-anchors}\n\nPara especificar uma _tag_ âncora personalizada para um cabeçalho em vez de usar aquela gerada automaticamente, adicione um sufixo ao cabeçalho:\n\n```\n# Usando âncoras personalizadas {#minha-ancora}\n```\n\nIsso permite que você tenha um link do cabeçalho como `#minha-ancora` em vez do padrão `#usando-ancoras-personalizadas`.\n\n## Links {#links}\n\nAmbos os links internos e externos recebem tratamento especial.\n\n### Links Internos {#internal-links}\n\nOs links internos são convertidos em links de roteador para navegação SPA. Além disso, todo arquivo `index.md` contido em cada subdiretório será automaticamente convertido para `index.html`, com a URL correspondente `/`.\n\nPor exemplo, dada a seguinte estrutura de diretórios:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nE supondo que você esteja em `foo/one.md`:\n\n```md\n[Página Inicial](/) <!-- leva o usuário ao index.md raiz -->\n[foo](/foo/) <!-- leva o usuário ao index.html do diretório foo -->\n[foo heading](./#heading) <!-- ancora o usuário a um cabeçalho do arquivo índice foo -->\n[bar - three](../bar/three) <!-- você pode omitir a extensão -->\n[bar - three](../bar/three.md) <!-- você pode adicionar .md -->\n[bar - four](../bar/four.html) <!-- ou você pode adicionar .html -->\n```\n\n### Sufixo de Página {#page-suffix}\n\nPáginas e links internos são gerados com o sufixo `.html` por padrão.\n\n### Links Externos {#external-links}\n\nLinks externos recebem automaticamente `target=\"_blank\" rel=\"noreferrer\"`:\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress no GitHub](https://github.com/vuejs/vitepress)\n\n## Frontmatter {#frontmatter}\n\n[YAML frontmatter](https://jekyllrb.com/docs/front-matter/) é suportado por padrão:\n\n```yaml\n---\ntítulo: Escrevendo como um Hacker\nidioma: pt-BR\n---\n```\n\nEsses dados estarão disponíveis para o restante da página, junto com todos os componentes personalizados e de temas.\n\nPara mais detalhes, veja [Frontmatter](../reference/frontmatter-config).\n\n## Tabelas ao Estilo GitHub {#github-style-tables}\n\n**Entrada**\n\n```md\n| Tabelas       |    São        |  Legais |\n| ------------- | :-----------: |   ----: |\n| col 3 está    | à direita     |   $1600 |\n| col 2 está    | centralizada  |     $12 |\n| listras       |   são legais  |      $1 |\n```\n\n**Saída**\n\n| Tabelas       |    São        |   Legais |\n| ------------- | :-----------: |   -----: |\n| col 3 está    | à direita     |   \\$1600 |\n| col 2 está    | centralizada  |     \\$12 |\n| listras       |   são legais  |      \\$1 |\n\n## Emoji :tada:\n\n**Entrada**\n\n```\n:tada: :100:\n```\n\n**Saída**\n\n:tada: :100:\n\nUma [lista de todos os emojis](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs) está disponível.\n\n## Tabela de Conteúdo (TOC)\n\n**Entrada**\n\n```\n[[toc]]\n```\n\n**Saída**\n\n[[toc]]\n\nA apresentação de TOC (Table of Contents) pode ser configurada usando a opção `markdown.toc`.\n\n## Recipientes Personalizados {#custom-containers}\n\nRecipientes personalizados podem ser definidos por seus tipos, títulos e conteúdos.\n\n### Título Padrão {#default-title}\n\n**Entrada**\n\n```md\n::: info\nEste é um bloco de informações.\n:::\n\n::: tip\nEste é um aviso.\n:::\n\n::: warning\nEste é um aviso.\n:::\n\n::: danger\nEste é um aviso de perigo.\n:::\n\n::: details\nEste é um bloco de detalhes.\n:::\n```\n\n**Saída**\n\n::: info\nEste é um bloco de informações.\n:::\n\n::: tip\nEste é um aviso.\n:::\n\n::: warning\nEste é um aviso.\n:::\n\n::: danger\nEste é um aviso de perigo.\n:::\n\n::: details\nEste é um bloco de detalhes.\n:::\n\n### Título Personalizado {#custom-title}\n\nVocê pode definir um título personalizado adicionando o texto imediatamente após o \"tipo\" do recipiente.\n\n**Entrada**\n\n````md\n::: danger STOP\nZona de perigo, não prossiga\n:::\n\n::: details Clique para ver o código\n```js\nconsole.log('Olá, VitePress!')\n```\n:::\n````\n\n**Saída**\n\n::: danger STOP\nZona de perigo, não prossiga\n:::\n\n::: details Clique para ver o código\n```js\nconsole.log('Olá, VitePress!')\n```\n:::\n\nAlém disso, você pode definir títulos personalizados globalmente adicionando o seguinte conteúdo no arquivo de configuração do site, útil se não estiver escrevendo em inglês:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: '提示',\n      warningLabel: '警告',\n      dangerLabel: '危险',\n      infoLabel: '信息',\n      detailsLabel: '详细信息'\n    }\n  }\n  // ...\n})\n```\n\n### `raw`\n\nEste é um recipiente especial que pode ser usado para evitar conflitos de estilo e roteador com VitePress. Isso é especialmente útil ao documentar bibliotecas de componentes. Você também pode verificar [whyframe](https://whyframe.dev/docs/integrations/vitepress) para melhor isolamento.\n\n**Sintaxe**\n\n```md\n::: raw\nEnvolve em um `<div class=\"vp-raw\">`\n:::\n```\n\nA classe `vp-raw` também pode ser usada diretamente em elementos. O isolamento de estilo é atualmente opcional:\n\n- Instale o `postcss` com seu gerenciador de pacotes preferido:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- Crie um arquivo chamado `docs/postcss.config.mjs` e adicione o seguinte:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  Você pode passar opções assim:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // o padrão é [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## Alertas no estilo GitHub {#github-flavored-alerts}\n\nVitePress também suporta [alertas no estilo GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) para apresentar como um bloco de chamada. Eles serão apresentados da mesma forma que [elementos personalizados](#custom-containers).\n\n```md\n> [!NOTE]\n> Destaca informações que os usuários devem levar em consideração, mesmo ao ler rapidamente.\n\n> [!TIP]\n> Informações opcionais para ajudar o usuário a ter mais sucesso.\n\n> [!IMPORTANT]\n> Informações cruciais necessárias para que os usuários tenham sucesso.\n\n> [!WARNING]\n> Conteúdo crítico exigindo atenção imediata do usuário devido a riscos potenciais.\n\n> [!CAUTION]\n> Potenciais consequências negativas de uma ação.\n```\n\n> [!NOTE]\n> Destaca informações que os usuários devem levar em consideração, mesmo ao ler rapidamente.\n\n> [!TIP]\n> Informações opcionais para ajudar o usuário a ter mais sucesso.\n\n> [!IMPORTANT]\n> Informações cruciais necessárias para que os usuários tenham sucesso.\n\n> [!WARNING]\n> Conteúdo crítico exigindo atenção imediata do usuário devido a riscos potenciais.\n\n> [!CAUTION]\n> Potenciais consequências negativas de uma ação.\n\n## Destaque de Sintaxe em Blocos de Código {#syntax-highlighting-in-code-blocks}\n\nVitePress utiliza [Shiki](https://github.com/shikijs/shiki) para destacar a sintaxe da linguagem em blocos de código Markdown, usando texto colorido. Shiki suporta uma ampla variedade de linguagens de programação. Tudo o que você precisa fazer é adicionar um _alias_ de linguagem válido após os crases iniciais do bloco de código:\n\n**Entrada**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\nUma [lista de linguagens válidas](https://shiki.style/languages) está disponível no repositório Shiki.\n\nVocê também pode personalizar o tema de destaque de sintaxe na configuração do aplicativo. Consulte as [opções `markdown`](../reference/site-config#markdown) para mais detalhes.\n\n## Destaque de Linha em Blocos de Código {#line-highlighting-in-code-blocks}\n\n**Entrada**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!'\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!'\n    }\n  }\n}\n```\n\nAlém de uma única linha, você também pode especificar múltiplas linhas únicas, intervalos, ou ambos:\n\n- Intervalos de linha: por exemplo, `{5-8}`, `{3-10}`, `{10-17}`\n- Múltiplas linhas únicas: por exemplo, `{4,7,9}`\n- Intervalos de linha e linhas únicas: por exemplo, `{4,7-13,16,23-27,40}`\n\n**Entrada**\n\n````\n```js{1,4,6-8}\nexport default { // Destacado\n  data () {\n    return {\n      msg: `Destacado!\n      Esta linha não está destacada,\n      mas esta e as próximas 2 estão.`,\n      motd: 'VitePress é incrível',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js{1,4,6-8}\nexport default { // Destacado\n  data () {\n    return {\n      msg: `Destacado!\n      Esta linha não está destacada,\n      mas esta e as próximas 2 estão.`,\n      motd: 'VitePress é incrível',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\nAlternativamente, é possível destacar diretamente na linha usando o comentário `// [!code highlight]`.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Destacado!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Destacado!' // [!code destaque]\n    }\n  }\n}\n```\n\n## Foco em Blocos de Código {#focus-in-code-blocks}\n\nAdicionando o comentário `// [!code focus]` em uma linha irá destacá-la e desfocar as outras partes do código.\n\nAlém disso, você pode definir o número de linhas para focar usando `// [!code focus:<linhas>]`.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Focado!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Focado!' // [!code focus]\n    }\n  }\n}\n```\n\n## Diferenças Coloridas em Blocos de Código {#colored-diffs-in-code-blocks}\n\nAdicionar os comentários `// [!code --]` ou `// [!code ++]` em uma linha criará uma diferença nessa linha, mantendo as cores do bloco de código.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removido' // [!!code --]\n      msg: 'Adicionado' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removido' // [!code --]\n      msg: 'Adicionado' // [!code ++]\n    }\n  }\n}\n```\n\n## Erros e Avisos em Blocos de Código {#errors-and-warnings-in-code-blocks}\n\nAdicionar os comentários `// [!code warning]` ou `// [!code error]` em uma linha colorirá os blocos conforme apropriado.\n\n**Entrada**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Erro', // [!!code error]\n      msg: 'Aviso' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**Saída**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Erro', // [!code error]\n      msg: 'Aviso' // [!code warning]\n    }\n  }\n}\n```\n\n## Números de Linha {#line-numbers}\n\nVocê pode habilitar números de linha para cada bloco de código através do arquivo de configuração:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\nConsulte as [opções markdown](../reference/site-config#markdown) para mais detalhes.\n\nVocê pode adicionar a marca `:line-numbers` / `:no-line-numbers` em seus blocos de código para substituir o valor definido na configuração.\n\nVocê também pode personalizar o número inicial da linha adicionando `=` após `:line-numbers`. Por exemplo, `:line-numbers=2` significa que os números das linhas nos blocos de código começarão a partir de `2`.\n\n**Entrada**\n\n````md\n```ts {1}\n// números de linha desativados por padrão\nconst line2 = 'Esta é a linha 2'\nconst line3 = 'Esta é a linha 3'\n```\n\n```ts:line-numbers {1}\n// números de linha ativados\nconst line2 = 'Esta é a linha 2'\nconst line3 = 'Esta é a linha 3'\n```\n\n```ts:line-numbers=2 {1}\n// números de linha ativados e começam do 2\nconst line3 = 'Esta é a linha 3'\nconst line4 = 'Esta é a linha 4'\n```\n````\n\n**Saída**\n\n```ts {1}\n// números de linha desativados por padrão\nconst line2 = 'Esta é a linha 2'\nconst line3 = 'Esta é a linha 3'\n```\n\n```ts:line-numbers {1}\n// números de linha ativados\nconst line2 = 'Esta é a linha 2'\nconst line3 = 'Esta é a linha 3'\n```\n\n```ts:line-numbers=2 {1}\n// números de linha ativados e começam do 2\nconst line3 = 'Esta é a linha 3'\nconst line4 = 'Esta é a linha 4'\n```\n\n## Importar _Snippets_ de Código {#import-code-snippets}\n\nVocê pode importar trechos de código de arquivos existentes usando a seguinte sintaxe:\n\n```md\n<<< @/filepath\n```\n\nTambém suporta [destaque de linha](#line-highlighting-in-code-blocks):\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**Entrada**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**Arquivo de Código**\n\n<<< @/snippets/snippet.js\n\n**Saída**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\nO valor de `@` corresponde à raiz do código fonte. Por padrão, é a raiz do projeto VitePress, a menos que `srcDir` seja configurado. Alternativamente, você também pode importar de caminhos relativos:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\nVocê também pode usar uma [região VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding) para incluir apenas a parte correspondente do arquivo de código. Você pode fornecer um nome de região personalizado após um `#` seguindo o caminho do arquivo:\n\n**Entrada**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**Arquivo de Código**\n\n<<< @/snippets/snippet-with-region.js\n\n**Saída**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\nVocê também pode especificar o idioma dentro das chaves (`{}`), assim:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- com destaque de linha: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- com números de linha: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nIsso é útil se a linguagem original não puder ser inferida pela extensão do arquivo.\n\n## Grupos de Código {#code-groups}\n\nVocê pode agrupar vários blocos de código assim:\n\n**Entrada**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**Saída**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nVocê também pode [importar _snippets_ de código](#import-code-snippets) em grupos de código:\n\n**Entrada**\n\n```md\n::: code-group\n\n<!-- nome de arquivo usado como título por padrão -->\n\n<<< @/snippets/snippet.js\n\n<!-- você pode fornecer um personalizado também -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n```\n\n**Output**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n\n## Inclusão de Arquivo Markdown {#markdown-file-inclusion}\n\nVocê pode incluir um arquivo markdown em outro arquivo markdown, mesmo aninhado.\n\n::: tip\nVocê também pode prefixar o caminho do markdown com `@`, ele atuará como a raiz de origem. Por padrão, é a raiz do projeto VitePress, a menos que `srcDir` seja configurado.\n:::\n\nPor exemplo, você pode incluir um arquivo markdown relativo usando isto:\n\n**Entrada**\n\n```md\n# Documentação\n\n## Conceitos Básicos\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**Arquivo da Parte** (`parts/basics.md`)\n\n```md\nAlgumas coisas básicas.\n\n### Configuração\n\nPode ser criada usando `.foorc.json`.\n```\n\n**Código Equivalente**\n\n```md\n# Documentação\n\n## Conceitos Básicos\n\nAlgumas coisas básicas.\n\n### Configuração\n\nPode ser criada usando `.foorc.json`.\n```\n\nTambém suporta a seleção de um intervalo de linhas:\n\n**Entrada**\n\n```md\n# Documentação\n\n## Conceitos Básicos\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**Arquivo da Parte** (`parts/basics.md`)\n\n```md\nAlgumas coisas básicas.\n\n### Configuração\n\nPode ser criada usando `.foorc.json`.\n```\n\n**Código Equivalente**\n\n```md\n# Documentação\n\n## Conceitos Básicos\n\n### Configuração\n\nPode ser criada usando `.foorc.json`.\n```\n\nO formato do intervalo de linhas selecionado pode ser: `{3,}`, `{,10}`, `{1,10}`\n\n::: warning\nObserve que isso não gera erros se o arquivo não estiver presente. Portanto, ao usar esse recurso, certifique-se de que o conteúdo está sendo mostrado como esperado.\n:::\n\n## Equações Matemáticas {#math-equations}\n\nIsso é atualmente opcional. Para ativá-lo, você precisa instalar `markdown-it-mathjax3` e definir `markdown.math` como `true` no seu arquivo de configuração:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**Entrada**\n\n```md\nQuando $a \\ne 0$, existem duas soluções para $(ax^2 + bx + c = 0)$ e elas são\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Equações de Maxwell:**\n\n| equação                                                                                                                                                                  | descrição                                                                                |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | a divergência de $\\vec{\\mathbf{B}}$ é zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | a rotacional de $\\vec{\\mathbf{E}}$ é proporcional à taxa de variação de $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _hã?_                                                                                     |\n\n**Saída**\n\nQuando $a \\ne 0$, existem duas soluções para $(ax^2 + bx + c = 0)$ e são\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Equações de Maxwell:**\n\n| equação                                                                                                                                                                  | descrição                                                                                |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | a divergência de $\\vec{\\mathbf{B}}$ é zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | a rotacional de $\\vec{\\mathbf{E}}$ é proporcional à taxa de variação de $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _hã?_                                                                                     |\n\n## _Lazy Loading_ de Imagens {#image-lazy-loading}\n\nVocê pode ativar o \"carregamento folgado\" para cada imagem adicionada via markdown definindo `lazyLoading` como `true` no seu arquivo de configuração:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // o carregamento folgado de imagens está desativado por padrão\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## Configuração Avançada {#advanced-configuration}\n\nVitePress usa [markdown-it](https://github.com/markdown-it/markdown-it) como interpretador Markdown. Muitas das extensões acima são implementadas por meio de _plugins_ personalizados. Você pode personalizar ainda mais a instância `markdown-it` usando a opção `markdown` em `.vitepress/config.js`:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // opções para markdown-it-anchor\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // opções para @mdit-vue/plugin-toc\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // use mais plugins markdown-it!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\nConsulte a lista completa de propriedades configuráveis em [Referência de Configuração: Configuração da Aplicação](../reference/site-config#markdown).\n"
  },
  {
    "path": "docs/pt/guide/mpa-mode.md",
    "content": "# Modo MPA <Badge type=\"warning\" text=\"experimental\" /> {#mpa-mode}\n\nO modo MPA (Aplicação Multipáginas) pode ser habilitado pela linha de comando com `vitepress build --mpa`, ou através da configuração pela opção `mpa: true`.\n\nNo modo MPA, todas as páginas são apresentadas por padrão sem qualquer JavaScript incluído. Como resultado, o site em produção provavelmente terá uma nota de desempenho de visita inicial superior com ferramentas de auditoria.\n\nEntretanto, devido a ausência de navegação SPA, links entre páginas acarretarão em recarregamentos de página completos. Navegações pós-carregamento no modo MPA não parecerão tão instantâneas quanto no modo SPA.\n\nTambém note que não ter JavaScript por padrão significa que você está essencialmente utilizando Vue como modelo de linguagem no lado do servidor. Nenhum manipulador de evento será embutido no navegador, então não haverá interatividade. Para carregar JavaScript no lado do cliente, você precisará usar a tag especial `<script client>`:\n\n```html\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('JavaScript no lado do cliente!')\n})\n</script>\n\n# Olá\n```\n\n`<script client>` é uma funcionalidade exclusiva VitePress, não uma funcionalidade Vue. Funciona tanto em arquivos `.md` quanto em arquivos `.vue`, mas apenas no modo MPA. Scripts de cliente em todos os componentes do tema serão empacotados juntos, enquanto o script do cliente para uma página específica será dividido apenas para aquela página.\n\nNote que `<script client>` **não é avaliado como código de componente Vue**: é processado como um simples módulo JavaScript. Por esta razão, o modo MPA deve ser usado apenas se seu site exige o mínimo absoluto de interatividade no lado do cliente.\n"
  },
  {
    "path": "docs/pt/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# Roteamento {#routing}\n\n## Roteamento baseado em Arquivos {#file-based-routing}\n\nVitePress utiliza roteamento baseado em arquivos, isso significa que as páginas HTML geradas são mapeadas da estrutura de diretórios dos arquivos fonte Markdown. Por exemplo, dada a seguinte estrutura de diretório:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\nAs páginas HTML geradas serão:\n\n```\nindex.md                  -->  /index.html (acessível por /)\nprologue.md                -->  /prologue.html\nguide/index.md             -->  /guide/index.html (acessível por /guide/)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\nO HTML resultante pode ser hospedado em qualquer servidor web que possa servir arquivos estáticos.\n\n## Diretório Raiz e Fonte {#root-and-source-directory}\n\nExistem dois conceitos importantes na estrutura de arquivos de um projeto VitePress: o **diretório raiz** e o **diretório fonte**.\n\n### Diretório Raiz {#project-root}\n\nO diretório raiz é onde o VitePress procura pelo diretório especial `.vitepress`. O diretório `.vitepress` é um local reservado para o arquivo de configuração do VitePress, o cache do servidor de desenvolvimento, o resultado da compilação e o código de personalização de tema opcional.\n\nAo executar `vitepress dev` ou `vitepress build` no terminal, VitePress usará o diretório atual como diretório raiz do projeto. Para especificar um subdiretório como raiz, é necessário passar o caminho relativo para o comando. Por exemplo, se o projeto VitePress estiver localizado em `./docs`, deve-se executar `vitepress dev docs`:\n\n```\n.\n├─ docs                    # diretório raiz\n│  ├─ .vitepress           # diretório de configuração\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nIsso resultará no seguinte mapeamento da fonte para HTML:\n\n```\ndocs/index.md            -->  /index.html (acessível como /)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### Diretório Fonte {#source-directory}\n\nO diretório fonte é onde seus arquivos fonte em Markdown estão. Por padrão, é o mesmo que o diretório raiz. No entanto, você pode configurá-lo por meio da opção de configuração [`srcDir`](../reference/site-config#srcdir).\n\nA opção `srcDir` é resolvida em relação ao diretório raiz do projeto. Por exemplo, com `srcDir: 'src'`, sua estrutura de arquivos ficará assim:\n\n```\n.                          # diretório raiz\n├─ .vitepress              # diretório de configuração\n└─ src                     # diretório fonte\n   ├─ getting-started.md\n   └─ index.md\n```\n\nO mapeamento resultante da fonte para HTML:\n\n```\nsrc/index.md            -->  /index.html (acessível como /)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## Links Entre Páginas {#linking-between-pages}\n\nVocê pode usar tanto caminhos absolutos quanto relativos ao vincular páginas. Note que, embora ambas as extensões `.md` e `.html` funcionem, a prática recomendada é omitir as extensões de arquivo para que o VitePress possa gerar as URLs finais com base na sua configuração.\n\n```md\n<!-- Fazer -->\n[Getting Started](./getting-started)\n[Getting Started](../guide/getting-started)\n\n<!-- Não Fazer -->\n[Getting Started](./getting-started.md)\n[Getting Started](./getting-started.html)\n```\n\nSaiba mais sobre a vinculação de ativos, como imagens, em [Manipulação de Ativos](./asset-handling).\n\n### Vinculação a Páginas Não VitePress {#linking-to-non-vitepress-pages}\n\nSe você deseja vincular a uma página em seu site que não é gerada pelo VitePress, será necessário usar a URL completa (abre em uma nova guia) ou especificar explicitamente o destino:\n\n**Entrada**\n\n```md\n[Link para pure.html](/pure.html){target=\"_self\"}\n```\n\n**Saída**\n\n[Link para pure.html](/pure.html){target=\"_self\"}\n\n::: tip Nota\n\nNos links Markdown, a `base` é automaticamente adicionada à URL. Isso significa que, se você deseja vincular a uma página fora da sua base, será necessário algo como `../../pure.html` no link (resolvido em relação à página atual pelo navegador).\n\nAlternativamente, pode-se usar diretamente a sintaxe da tag âncora:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Link para pure.html</a>\n```\n\n:::\n\n## Geração de URLs Limpas {#generating-clean-urls}\n\n::: warning Suporte do Servidor Necessário\nPara servir URLs limpas com VitePress, é necessário suporte no lado do servidor.\n:::\n\nPor padrão, VitePress resolve links de entrada para URLs que terminam com `.html`. No entanto, alguns usuários podem preferir \"URLs limpas\" sem a extensão `.html`, por exemplo, `example.com/caminho` em vez de `example.com/caminho.html`.\n\nAlguns servidores ou plataformas de hospedagem (por exemplo, Netlify, Vercel, GitHub Pages) fornecem a habilidade de mapear uma URL como `/foo` para `/foo.html` se ela existir, sem redirecionamento:\n\n- Netlify e GitHub Pages suportam isso por padrão.\n- Vercel requer a ativação da opção [`cleanUrls` no `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).\n\nSe essa funcionalidade estiver disponível para você, também se pode ativar a própria opção de configuração [`cleanUrls`](../reference/site-config#cleanurls) de VitePress para que:\n\n- Links de entrada entre páginas sejam gerados sem a extensão `.html`.\n- Se o caminho atual terminar com `.html`, o roteador realizará um redirecionamento no lado do cliente para o caminho sem extensão.\n\nNo entanto, se você não puder configurar o servidor com esse suporte, será necessário recorrer manualmente à seguinte estrutura de diretório:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n# Reescrita de Rota {#route-rewrites}\n\nVocê pode personalizar o mapeamento entre a estrutura de diretórios fonte e as páginas geradas. Isso é útil quando você tem uma estrutura de projeto complexa. Por exemplo, digamos que você tenha um monorepo com vários pacotes e gostaria de colocar as documentações junto com os arquivos fonte desta forma:\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ pkg-a-code.ts\n│  │      └─ pkg-a-docs.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ pkg-b-code.ts\n│         └─ pkg-b-docs.md\n```\n\nE você deseja que as páginas VitePress sejam geradas assim:\n\n```\npackages/pkg-a/src/pkg-a-docs.md  -->  /pkg-a/index.html\npackages/pkg-b/src/pkg-b-docs.md  -->  /pkg-b/index.html\n```\n\nVocê pode realizar isso configurando a opção [`rewrites`](../reference/site-config#rewrites) assim:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',\n    'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'\n  }\n}\n```\n\nA opção `rewrites` também suporta parâmetros de rota dinâmicos. No exemplo acima, seria verboso listar todos os caminhos se você tiver muitos pacotes. Dado que todos eles têm a mesma estrutura de arquivo, você pode simplificar a configuração assim:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/(.*)': ':pkg/index.md'\n  }\n}\n```\n\nOs caminhos de reescrita são compilados usando o pacote `path-to-regexp` - consulte [sua documentação](https://github.com/pillarjs/path-to-regexp#parameters) para uma sintaxe mais avançada.\n\n::: warning Links Relativos com Reescritas\n\nQuando as reescritas estão habilitadas, **links relativos devem ser baseados nos caminhos reescritos**. Por exemplo, para criar um link relativo de `packages/pkg-a/src/pkg-a-code.md` para `packages/pkg-b/src/pkg-b-code.md`, deve-se usar:\n\n```md\n[Link para PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## Rotas Dinâmicas {#dynamic-routes}\n\nVocê pode gerar muitas páginas usando um único arquivo Markdown e dados dinâmicos. Por exemplo, você pode criar um arquivo `packages/[pkg].md` que gera uma página correspondente para cada pacote em um projeto. Aqui, o segmento `[pkg]` é um **parâmetro** de rota que diferencia cada página das outras.\n\n### Arquivo de Carregamento de Caminhos {#paths-loader-file}\n\nComo VitePress é um gerador de site estático, os caminhos possíveis das páginas devem ser determinados no momento da compilação. Portanto, uma página de rota dinâmica **deve** ser acompanhada por um **arquivo de carregamento de caminhos**. Para `packages/[pkg].md`, precisaremos de `packages/[pkg].paths.js` (`.ts` também é suportado):\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # modelo de rota\n   └─ [pkg].paths.js   # carregador de caminhos da rota\n```\n\nO carregador de caminhos deve fornecer um objeto com um método `paths` como sua exportação padrão. O método `paths` deve retornar um _array_ de objetos com uma propriedade `params`. Cada um desses objetos gerará uma página correspondente.\n\nDado o seguinte _array_ `paths`:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\nAs páginas HTML geradas serão:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### Múltiplos Parâmetros {#multiple-params}\n\nUma rota dinâmica pode conter múltiplos parâmetros:\n\n**Estrutura de Arquivo**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**Carregador de Caminhos**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**Saída**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### Gerando Caminhos Dinamicamente {#dynamically-generating-paths}\n\nO módulo de carregamento de caminhos é executado no Node.js e apenas durante o momento de compilação. Você pode gerar dinamicamente o _array_ de caminhos usando qualquer dado, seja local ou remoto.\n\nGerando caminhos a partir de arquivos locais:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\nGerando caminhos a partir de dados remotos:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### Acessando Parâmetros na Página {#accessing-params-in-page}\n\nVocê pode usar os parâmetros para passar dados adicionais para cada página. O arquivo de rota Markdown pode acessar os parâmetros da página atual em expressões Vue através da propriedade global `$params`:\n\n```md\n- nome do pacote: {{ $params.pkg }}\n- versão: {{ $params.version }}\n```\n\nVocê também pode acessar os parâmetros da página atual através da API de tempo de execução [`useData`](../reference/runtime-api#usedata). Isso está disponível tanto em arquivos Markdown quanto em componentes Vue:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params é uma ref Vue\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### Apresentando Conteúdo Cru {#rendering-raw-content}\n\nParâmetros passados para a página serão serializados na carga JavaScript do cliente, portanto, evite passar dados pesados nos parâmetros, como Markdown cru ou conteúdo HTML obtido de um CMS remoto.\n\nEm vez disso, você pode passar tal conteúdo para cada página usando a propriedade `content` em cada objeto de caminho:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // Markdown ou HTML cru\n      }\n    })\n  }\n}\n```\n\nEm seguida, use a seguinte sintaxe especial para apresentar o conteúdo como parte do próprio arquivo Markdown:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/pt/guide/sitemap-generation.md",
    "content": "# Geração de Sitemap {#sitemap-generation}\n\nVitePress vem com suporte embutido para gerar um arquivo `sitemap.xml` para seu site. Para habilitar, adicione o seguinte ao seu `.vitepress/config.js`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n})\n```\n\nPara ter tags `<lastmod>` em seu `sitemap.xml`, você pode habilitar a opção [`lastUpdated`](../reference/default-theme-last-updated).\n\n## Opções {#options}\n\nO suporte de Sietmap é alimentado pelo módulo [`sitemap`](https://www.npmjs.com/package/sitemap). Você pode passar qualquer uma das opções suportadas por ele na opção `sitemap` do seu arquivo de configuração. Esses serão passados diretamente ao construtor `SitemapStream`. Refira-se a [documentação `sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass) para mais detalhes. Exemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n})\n```\n\n## Gancho `transformItems`\n\nVocê pode usar o gancho `sitemap.transformItems` para modificar os itens do sitemap antes de eles serem escritos no arquivo `sitemap.xml`. Este gancho é chamado com um _array_ de itens sitemap e espera um _array_ de itens sitemap como retorno. Exemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // adiciona novos itens ou modifica/filtra itens existentes\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n})\n```\n"
  },
  {
    "path": "docs/pt/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# Compatibilidade SSR {#ssr-compatibility}\n\nVitePress pré-interpreta a aplicação no Node.js durante a compilação de produção, utilizando as capacidades de Interpretação do Lado do Servidor (SSR) do Vue. Isso significa que todo o código personalizado nos componentes do tema está sujeito à Compatibilidade SSR.\n\nA [seção SSR na documentação Vue oficial](https://vuejs.org/guide/scaling-up/ssr.html) fornece mais contexto sobre o que é SSR, a relação entre SSR / SSG e notas comuns sobre escrever código amigável a SSR. A regra geral é acessar apenas APIs do navegador / DOM nos gatilhos `beforeMount` ou `mounted` dos componentes Vue.\n\n## `<ClientOnly>`\n\nSe você estiver usando ou demonstrando componentes que não são compatíveis com SSR (por exemplo, contêm diretivas personalizadas), você pode envolvê-los no componente embutido `<ClientOnly>`:\n\n```md\n<ClientOnly>\n  <ComponenteNaoCompativelComSSR />\n</ClientOnly>\n```\n\n## Bibliotecas que Acessam a API do Navegador na Importação {#libraries-that-access-browser-api-on-import}\n\nAlguns componentes ou bibliotecas acessam APIs do navegador **na importação**. Para usar código que assume um ambiente de navegador na importação, você precisa importá-los dinamicamente.\n\n### Importando no Gatilho `mounted` {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-que-acessa-window-na-importacao').then((module) => {\n    // usar código\n  })\n})\n</script>\n```\n\n### Importação Condicional {#conditional-import}\n\nVocê também pode importar condicionalmente uma dependência usando o sinalizador `import.meta.env.SSR` (parte das [variáveis de ambiente Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-que-acessa-window-na-importacao').then((module) => {\n    // usar código\n  })\n}\n```\n\nComo [`Theme.enhanceApp`](./custom-theme#theme-interface) pode ser assíncrono, você pode importar condicionalmente e registrar plugins Vue que acessam APIs do navegador na importação:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-que-acessa-window-na-importacao')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nSe estiver usando TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-que-acessa-window-na-importacao')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress fornece um auxiliar de conveniência para importar componentes Vue que acessam APIs do navegador na importação.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('componente-que-acessa-window-na-importacao')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nVocê também pode passar propriedades/filhos/_slots_ para o componente alvo:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('componente-que-acessa-window-na-importacao'),\n\n  // os argumentos são passados para h() - https://vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'slot padrão',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'um'), h('span', 'dois')]\n    }\n  ],\n\n  // retorno de chamada depois que o componente é carregado, pode ser assíncrono\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nO componente alvo só será importado no gatilho `mounted` do componente que o envolve.\n"
  },
  {
    "path": "docs/pt/guide/using-vue.md",
    "content": "# Usando Vue em Markdown {#using-vue-in-markdown}\n\nEm VitePress, cada arquivo Markdown é compilado para HTML e então processado como um [Componente de Arquivo Único Vue](https://vuejs.org/guide/scaling-up/sfc.html). Isso significa que você pode usar qualquer funcionalidade Vue dentro do Markdown, incluindo a interpolação dinâmica, usar componentes Vue ou lógica arbitrária de componentes Vue dentro da página adicionando uma tag `<script>`.\n\nVale ressaltar que VitePress aproveita o compilador Vue para detectar e otimizar automaticamente as partes puramente estáticas do conteúdo Markdown. Os conteúdos estáticos são otimizados em nós de espaço reservado únicos e eliminados da carga JavaScript da página para visitas iniciais. Eles também são ignorados durante a hidratação no lado do cliente. Em resumo, você só paga pelas partes dinâmicas em qualquer página específica.\n\n::: tip Compatibilidade SSR\nTodo uso do Vue precisa ser compatível com SSR. Consulte [Compatibilidade SSR](./ssr-compat) para detalhes e soluções comuns.\n:::\n\n## Criação de _Templates_ {#templating}\n\n### Interpolação {#interpolation}\n\nCada arquivo Markdown é primeiro compilado para HTML e depois passado como um componente Vue para a canalização de processos Vite. Isso significa que você pode usar interpolação no estilo Vue no texto:\n\n**Entrada**\n\n```md\n{{ 1 + 1 }}\n```\n\n**Saída**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### Diretivas {#directives}\n\nDiretivas também funcionam (observe que, por definiçào, HTML cru também é válido em Markdown):\n\n**Entrada**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**Saída**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` e `<style>`\n\nAs tags `<script>` e `<style>` em nível raiz nos arquivos Markdown funcionam igualmente como nos Componentes de Arquivo Único Vue, incluindo `<script setup>`, `<style module>`, e etc. A principal diferença aqui é que não há uma tag `<template>`: todo outro conteúdo em nível raiz é Markdown. Além disso, observe que todas as tags devem ser colocadas **após** o frontmatter:\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## Conteúdo Markdown\n\nA contagem é: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Incrementar</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning Evite `<style scoped>` no Markdown\nQuando usado no Markdown, `<style scoped>` exige a adição de atributos especiais a cada elemento na página atual, o que aumentará significativamente o tamanho da página. `<style module>` é preferido quando é necessária uma estilização localizada em uma página.\n:::\n\nVocê também tem acesso às APIs de tempo de execução VitePress, como o [auxiliar `useData`](../reference/runtime-api#usedata), que fornece acesso aos metadados da página atual:\n\n**Entrada**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**Saída**\n\n```json\n{\n  \"path\": \"/usando-vue.html\",\n  \"title\": \"Usando Vue em Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## Usando Componentes {#using-components}\n\nVocê pode importar e usar componentes Vue diretamente nos arquivos Markdown.\n\n### Importando no Markdown {#importing-in-markdown}\n\nSe um componente é usado apenas por algumas páginas, é recomendável importá-los explicitamente onde são usados. Isso permite que eles sejam divididos adequadamente e carregados apenas quando as páginas relevantes são mostradas:\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# Documentação\n\nEste é um arquivo .md usando um componente personalizado\n\n<CustomComponent />\n\n## Mais documentação\n\n...\n```\n\n### Registrando Componentes Globalmente {#registering-components-globally}\n\nSe um componente for usado na maioria das páginas, eles podem ser registrados globalmente personalizando a instância do aplicativo Vue. Consulte a seção relevante em [Estendendo o Tema Padrão](./extending-default-theme#registering-global-components) para um exemplo.\n\n::: warning IMPORTANT\nCertifique-se de que o nome de um componente personalizado contenha um hífen ou esteja em PascalCase. Caso contrário, ele será tratado como um elemento alinhado e envolvido dentro de uma tag `<p>`, o que levará a uma incompatibilidade de hidratação pois `<p>` não permite que elementos de bloco sejam colocados dentro dele.\n:::\n\n### Usando Componentes Em Cabeçalhos <ComponentInHeader /> {#using-components-in-headers}\n\nVocê pode usar componentes Vue nos cabeçalhos, mas observe a diferença entre as seguintes sintaxes:\n\n| Markdown                                                | HTML de Saída                               | Cabeçalho Processado |\n| ------------------------------------------------------- | ----------------------------------------- | ------------- |\n| <pre v-pre><code> # texto &lt;Tag/&gt; </code></pre>     | `<h1>texto <Tag/></h1>`                    | `texto`        |\n| <pre v-pre><code> # texto \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>texto <code>&lt;Tag/&gt;</code></h1>` | `texto <Tag/>` |\n\nO HTML envolvido por `<code>` será exibido como é; somente o HTML que **não** estiver envolvido será analisado pelo Vue.\n\n::: tip\nO HTML de saída é realizado por [Markdown-it](https://github.com/Markdown-it/Markdown-it), enquanto os cabeçalhos processados são manipulados pelo VitePress (e usados tanto na barra lateral quanto no título do documento).\n:::\n\n## Escapes {#escaping}\n\nVocê pode escapar de interpolações Vue envolvendo-as em um `<span>` ou outros elementos com a diretiva `v-pre`:\n\n**Entrada**\n\n```md\nIsto <span v-pre>{{ será exibido como é }}</span>\n```\n\n**Saída**\n\n<div class=\"escape-demo\">\n  <p>Isto <span v-pre>{{ será exibido como é }}</span></p>\n</div>\n\nAlternativamente, você pode envolver todo o parágrafo em um container personalizado `v-pre`:\n\n```md\n::: v-pre\n{{ Isto será exibido como é }}\n:::\n```\n\n**Output**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ Isto será exibido como é }}\n:::\n\n</div>\n\n## \"Des-escape\" em Blocos de Código {#unescape-in-code-blocks}\n\nPor padrão, todos os blocos de código cercados são automaticamente envolvidos com `v-pre`, então nenhuma sintaxe Vue será processada dentro deles. Para permitir a interpolação no estilo Vue dentro do cercado, você pode adicionar a linguagem com o sufixo `-vue` , por exemplo, `js-vue`:\n\n**Entrada**\n\n````md\n```js-vue\nOlá {{ 1 + 1 }}\n```\n````\n\n**Saída**\n\n```js-vue\nOlá {{ 1 + 1 }}\n```\n\nObserve que isso pode impedir que certos tokens sejam realçados corretamente.\n\n## Usando Pré-processadores CSS {#using-css-pre-processors}\n\nO VitePress possui [suporte embutido](https://vitejs.dev/guide/features.html#css-pre-processors) para pré-processadores CSS: arquivos `.scss`, `.sass`, `.less`, `.styl` e `.stylus`. Não é necessário instalar plugins específicos do Vite para eles, mas o próprio pré-processador correspondente deve ser instalado:\n\n```\n# .scss e .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl e .stylus\nnpm install -D stylus\n```\n\nEntão você pode usar o seguinte em Markdown e nos componentes do tema:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## Usando _Teleports_ {#using-teleports}\n\nVitePress atualmente oferece suporte a SSG para _teleports_ apenas para o corpo. Para outros alvos, você pode envolvê-los dentro do componente embutido `<ClientOnly>` ou injetar a marcação de _teleport_ na localização correta em sua página final HTML por meio do [gancho `postRender`](../reference/site-config#postrender).\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n"
  },
  {
    "path": "docs/pt/guide/what-is-vitepress.md",
    "content": "# O que é VitePress? {#what-is-vitepress}\n\nO VitePress é um [Gerador de Site Estático](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) projetado para criar sites rápidos e centrados em conteúdo. Em suma, VitePress utiliza seu conteúdo-fonte escrito em [Markdown](https://en.wikipedia.org/wiki/Markdown), aplica um tema a ele e gera páginas HTML estáticas que podem ser facilmente implantadas em qualquer lugar.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nQuer apenas experimentar? Pule para o [Início Rápido](./getting-started).\n\n</div>\n\n## Casos de Uso {#use-cases}\n\n- **Documentação**\n\n  VitePress vem com um tema padrão projetado para documentação técnica. Ele alimenta esta página que você está lendo agora, juntamente com a documentação [Vite](https://vitejs.dev/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia.vuejs.org/), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) e [muitos outros](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code).\n\n  A [documentação oficial Vue.js](https://vuejs.org/) também é baseada em VitePress, mas usa um tema personalizado compartilhado entre várias traduções.\n\n- **Blogs, Portfólios e Sites de Marketing**\n\n  VitePress suporta [temas totalmente personalizáveis](./custom-theme), com a experiência de desenvolvedor padrão de uma aplicação Vite + Vue. A construção com Vite significa que você pode aproveitar diretamente plugins Vite de seu rico ecossistema. Adicionalmente, VitePress fornece APIs flexíveis para [carregar dados](./data-loading) (locais ou remotos) e [gerar rotas dinamicamente](./routing#dynamic-routes). Você pode usá-lo para construir praticamente qualquer coisa desde que os dados possam ser determinados no momento da construção.\n\n  O [blog oficial Vue.js](https://blog.vuejs.org/) é um blog simples que gera sua página inicial baseada em conteúdo local.\n\n## Experiência de Desenvolvedor {#developer-experience}\n\nVitePress visa proporcionar excelente Experiência de Desenvolvedor (DX) ao trabalhar com conteúdo em Markdown.\n\n- **[Alimentado por Vite:](https://vitejs.dev/)** inicialização instantânea do servidor, com edições sempre refletidas instantaneamente (<100ms) sem recarregamento de página.\n\n- **[Extensões Markdown Integradas:](./markdown)** Frontmatter, tabelas, destaque de sintaxe... você escolhe. Especificamente, VitePress fornece muitos recursos avançados para trabalhar com blocos de código, tornando-o ideal para documentação altamente técnica.\n\n- **[Markdown Aprimorado por Vue:](./using-vue)** cada página Markdown é também um [Componente de Arquivo Único Vue](https://pt.vuejs.org/guide/scaling-up/sfc.html), graças à compatibilidade de sintaxe de 100% do template Vue com HTML. Você pode incorporar interatividade em seu conteúdo estático usando recursos de template Vue ou componentes Vue importados.\n\n## Desempenho {#performance}\n\nAo contrário de muitos SSGs tradicionais, um site gerado pelo VitePress é na verdade uma [Aplicação de Página Única](https://en.wikipedia.org/wiki/Single-page_application) (SPA).\n\n- **Carregamento Inicial Rápido**\n\n  A visita inicial a qualquer página será servida com o HTML estático pré-renderizado para velocidade de carregamento rápida e SEO otimizado. A página então carrega um pacote JavaScript que transforma a página em uma SPA Vue (\"hidratação\"). O processo de hidratação é extremamente rápido: no [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), sites típicos VitePress alcançam pontuações de desempenho quase perfeitas, mesmo em dispositivos móveis de baixo desempenho com uma rede lenta.\n\n- **Navegação Rápida pós-carregamento**\n\n  Mais importante ainda, o modelo SPA leva a uma melhor experiência do usuário **após** o carregamento inicial. A navegação subsequente dentro do site não causará mais uma recarga completa da página. Em vez disso, o conteúdo da página de entrada será buscado e atualizado dinamicamente. VitePress também pré-carrega automaticamente pedaços de página para links que estão dentro do viewport. Na maioria dos casos, a navegação pós-carregamento parecerá instantânea.\n\n- **Interatividade Sem Penalidades**\n\n  Para ser capaz de hidratar as partes dinâmicas Vue incorporadas dentro do Markdown estático, cada página Markdown é processada como um componente Vue e compilada em JavaScript. Isso pode parecer ineficiente, mas o compilador Vue é inteligente o suficiente para separar as partes estáticas e dinâmicas, minimizando tanto o custo de hidratação quanto o tamanho da carga. Para o carregamento inicial da página, as partes estáticas são automaticamente eliminadas da carga JavaScript e puladas durante a hidratação.\n\n## E o VuePress? {#what-about-vuepress}\n\nVitePress é o sucessor espiritual de VuePress. VuePress era orginalmente baseado em Vue 2 e webpack. Com Vue 3 e Vite, VitePress oferece uma experiência de desenvolvedor significativamente melhor, melhor desempenho em produção, um tema padrão mais polido e uma API de personalização mais flexível.\n\nA diferença da API entre VitePress e VuePress reside principalmente em temas e personalização. Se você estiver usando VuePress 1 com o tema padrão, a migração para VitePress deve ser relativamente simples.\n\nTambém houve esforço investido em VuePress 2, que também suporta Vue 3 e Vite com melhor compatibilidade do que VuePress 1. No entanto, manter dois SSGs em paralelo não é sustentável, então a equipe Vue decidiu focar em VitePress como o principal SSG recomendado a longo prazo.\n"
  },
  {
    "path": "docs/pt/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Gerador de Site Estático Vite & Vue\n  tagline: Markdown para Lindos Documentos em Minutos\n  actions:\n    - theme: brand\n      text: O que é VitePress?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: Iniciar\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: Foco no seu conteúdo\n    details: Cria sites de documentação belos e sem esforço apenas com markdown.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Aproveite a experiência Vite\n    details: Início de servidor instantâneo, atualizações ultrarrápidas, e plugins do ecossistema Vite.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Personalize com Vue\n    details: Use sintaxe e componentes Vue diretamente em markdown, ou construa temas personalizados com Vue.\n  - icon: 🚀\n    title: Entregue Sites Rápidos\n    details: Carregamento inicial rápido com HTML estático, navegação rápida com roteamento no lado do cliente.\n---\n"
  },
  {
    "path": "docs/pt/reference/cli.md",
    "content": "# Interface de Linha de Comando {#command-line-interface}\n\n## `vitepress dev`\n\nInicia o servidor de desenvolvimento VitePress com o diretório designado como raiz. Por padrão usa o diretório atual. O comando `dev` pode também ser omitido ao rodar no diretório atual.\n\n### Uso\n\n```sh\n# inicia no diretório atual, omitindo `dev`\nvitepress\n\n# inicia em um subdiretório\nvitepress dev [root]\n```\n\n### Opções {#options}\n\n| Opção          | Descrição                                                       |\n| --------------- | ----------------------------------------------------------------- |\n| `--open [path]` | Abre o navegador na inicialização (`boolean \\| string`)                     |\n| `--port <port>` | Especifica porta (`number`)                                           |\n| `--base <path>` | Caminho base público (padrão: `/`) (`string`)                        |\n| `--cors`        | Habilita CORS                                                       |\n| `--strictPort`  | Interrompe se a porta especificada já está em uso (`boolean`)              |\n| `--force`       | Força o otimizador a ignorar o cache e reempacotar (`boolean`) |\n\n## `vitepress build`\n\nCompila o site VitePress para produção.\n\n### Uso\n\n```sh\nvitepress build [root]\n```\n\n### Opções\n\n| Opção                         | Descrição                                                                                                         |\n| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |\n| `--mpa` (experimental)         | Compila no [Modo MPA](../guide/mpa-mode) sem hidratação no lado do cliente  (`boolean`)                                    |\n| `--base <path>`                | Caminho base público (padrão: `/`) (`string`)                                                                          |\n| `--target <target>`            | Transpila o alvo (padrão: `\"modules\"`) (`string`)                                                                  |\n| `--outDir <dir>`               | Diretório de saída relativo ao **cwd** (padrão: `<root>/.vitepress/dist`) (`string`)                                 |\n| `--assetsInlineLimit <number>` | Limite em bytes para alinhar ativos em  base64 (padrão: `4096`) (`number`)                                          |\n\n## `vitepress preview`\n\nPrevê localmente a compilação de produção.\n\n### Uso\n\n```sh\nvitepress preview [root]\n```\n\n### Opções\n\n| Opção          | Descrição                                |\n| --------------- | ------------------------------------------ |\n| `--base <path>` | Caminho base público (padrão: `/`) (`string`) |\n| `--port <port>` | Especifica porta (`number`)                    |\n\n## `vitepress init`\n\nInicia o [Assistente de Instalação](../guide/getting-started#setup-wizard) no diretório atual.\n\n### Uso\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-badge.md",
    "content": "# Emblema {#badge}\n\nO emblema permite adicionar status aos seus cabeçalhos. Por exemplo, pode ser útil especificar o tipo da seção ou a versão suportada.\n\n## Uso {#usage}\n\nVocê pode usar o componente `Badge` que está disponível globalmente.\n\n```html\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n```\n\nO código acima é apresentado como:\n\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n\n## Filiação Personalizada {#custom-children}\n\n`<Badge>` aceita `children` (filhos), que serão exibidos no emblema.\n\n```html\n### Title <Badge type=\"info\">custom element</Badge>\n```\n\n### Title <Badge type=\"info\">custom element</Badge>\n\n## Personalize o Tipo de Cor {#customize-type-color}\n\nVocê pode personalizar o estilo dos emblemas sobrepondo variáveis CSS. Os seguintes são os valores padrão:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\nO componente `<Badge>` aceita as seguintes propriedades:\n\n```ts\ninterface Props {\n  // Quando `<slot>` é passado, esse valor é ignorado.\n  text?: string\n\n  // O padrão é `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-carbon-ads.md",
    "content": "# Carbon Ads {#carbon-ads}\n\nVitePress tem suporte embutido para [Carbon Ads](https://www.carbonads.net/). Ao definir as credenciais Carbon Ads na configuração, VitePress mostrará anúncios na página.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'seu-código-carbon',\n      placement: 'sua-veiculação-carbon'\n    }\n  }\n}\n```\n\nEsses valores são usados para chamar o sript em CDN do carbon como mostrado abaixo.\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nPara aprender mais sobre a configuração Carbon Ads, por favor visite [Site Carbon Ads](https://www.carbonads.net/).\n"
  },
  {
    "path": "docs/pt/reference/default-theme-config.md",
    "content": "# Configuração do Tema Padrão {#default-theme-config}\n\nA configuração do tema permite que você personalize seu tema. Você pode definir a configuração do tema através da opção `themeConfig` no arquivo de configuração:\n\n```ts\nexport default {\n  lang: 'pt-BR',\n  title: 'VitePress',\n  description: 'Gerador de site estático Vite & Vue.',\n\n  // Configurações relacionadas ao tema.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**As opções documentadas nesta página se aplicam apenas ao tema padrão.** Temas diferentes esperam configurações de tema diferentes. Ao usar um tema personalizado, o objeto de configuração do tema será passado para o tema para que se possam definir comportamentos condicionais.\n\n## i18nRouting\n\n- Tipo: `boolean`\n\nAlterar o local para, por exemplo, `zh` alterará a URL de `/foo` (ou `/en/foo/`) para `/zh/foo`. Você pode desativar esse comportamento definindo `themeConfig.i18nRouting` como `false`.\n\n## logo\n\n- Tipo: `ThemeableImage`\n\nArquivo de logo a ser exibido na barra de navegação, logo antes do título do site. Aceita um caminho em string, ou um objeto para definir um logo diferente para os modos claro/escuro.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- Tipo: `string | false`\n\nVocê pode personalizar este item para substituir o título padrão do site (`title` na configuração da aplicação) na navegação. Quando definido como `false`, o título na navegação será desativado. Útil quando você tem um `logo` que já contém o título do site.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Olá Mundo'\n  }\n}\n```\n\n## nav\n\n- Tipo: `NavItem`\n\nA configuração para o item do menu de navegação. Mais detalhes em [Tema Padrão: Navegação](./default-theme-nav#navigation-links).\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      {\n        text: 'Menu Dropdown',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- Tipo: `Sidebar`\n\nA configuração para o item do menu da barra lateral. Mais detalhes em [Tema Padrão: Barra Lateral](./default-theme-sidebar).\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          { text: 'Introdução', link: '/introduction' },\n          { text: 'Começando', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[]\n}\n\nexport type SidebarItem = {\n  /**\n   * O rótulo de texto do item.\n   */\n  text?: string\n\n  /**\n   * O link do item.\n   */\n  link?: string\n\n  /**\n   * Os filhos do item.\n   */\n  items?: SidebarItem[]\n\n  /**\n   * Se não especificado, o grupo não é retrátil.\n   *\n   * Se `true`, o grupo é retrátil e é colapsado por padrão.\n   *\n   * Se `false`, o grupo é retrátil, mas expandido por padrão.\n   */\n  collapsed?: boolean\n}\n```\n\n## aside\n\n- Tipo: `boolean | 'left'`\n- Padrão: `true`\n- Pode ser anulado por página via [frontmatter](./frontmatter-config#aside)\n\nDefinir este valor como `false` impede a apresentação do elemento aside.\\\nDefinir este valor como `true` apresenta o aside à direita.\\\nDefinir este valor como `left` apresenta o aside à esquerda.\n\nSe você quiser desativá-lo para todas as visualizações, você deve usar `outline: false` em vez disso.\n\n## outline\n\n- Tipo: `Outline | Outline['level'] | false`\n- O nível pode ser sobreposto por página via [frontmatter](./frontmatter-config#outline)\n\nDefinir este valor como `false` impede a apresentação do elemento _outline_. Consulte a interface para obter mais detalhes:\n\n```ts\ninterface Outline {\n  /**\n   * Os níveis de títulos a serem exibidos na outline.\n   * Um único número significa que apenas os títulos desse nível serão exibidos.\n   * Se uma tupla for passada, o primeiro número é o nível mínimo e o segundo número é o nível máximo.\n   * `'deep'` é o mesmo que `[2, 6]`, o que significa que todos os títulos de `<h2>` a `<h6>` serão exibidos.\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * O título a ser exibido na outline.\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- Tipo: `SocialLink[]`\n\nVocê pode definir esta opção para mostrar os links de redes sociais com ícones na navegação.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // Você também pode adicionar ícones personalizados passando SVG como string:\n       {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // Você também pode incluir um rótulo personalizado para acessibilidade (opcional mas recomendado):\n        ariaLabel: 'cool link'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- Tipo: `Footer`\n- Pode ser sobreposto por página via [frontmatter](./frontmatter-config#footer)\n\nConfiguração do rodapé. Você pode adicionar uma mensagem ou texto de direitos autorais no rodapé, no entanto, ela só será exibida quando a página não contiver uma barra lateral. Isso se deve a preocupações de design.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Lançado sob a Licença MIT.',\n      copyright: 'Direitos autorais © 2019-presente Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- Tipo: `EditLink`\n- Pode ser sobreposto por página via [frontmatter](./frontmatter-config#editlink)\n\nO _EditLink_ permite exibir um link para editar a página em serviços de gerenciamento Git, como GitHub ou GitLab. Consulte [Tema Padrão: Editar Link](./default-theme-edit-link) para mais detalhes.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Editar esta página no GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- Tipo: `LastUpdatedOptions`\n\nPermite personalização para o texto de última atualização e o formato de data.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Atualizado em',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- Tipo: `AlgoliaSearch`\n\nUma opção para dar suporte à pesquisa em seu site de documentação usando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Saiba mais em [Tema Padrão: Pesquisa](./default-theme-search).\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\nVeja todas as opções [aqui](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts).\n\n## carbonAds {#carbon-ads}\n\n- Tipo: `CarbonAdsOptions`\n\nUma opção para mostrar [Carbon Ads](https://www.carbonads.net/).\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'seu-código-carbon',\n      placement: 'sua-veiculação-carbon'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\nSaiba mais em [Tema Padrão: Carbon Ads](./default-theme-carbon-ads).\n\n## docFooter\n\n- Tipo: `DocFooter`\n\nPode ser usado para personalizar o texto que aparece acima dos links anterior e próximo. Útil se não estiver escrevendo documentação em inglês. Também pode ser usado para desabilitar globalmente os links anterior/próximo. Se você quiser ativar/desativar seletivamente os links anterior/próximo, pode usar [frontmatter](./default-theme-prev-next-links).\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Página anterior',\n      next: 'Próxima página'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- Tipo: `string`\n- Padrão: `Appearance`\n\nPode ser usado para personalizar o rótulo do botão de modo escuro. Esse rótulo é exibido apenas na visualização móvel.\n\n## lightModeSwitchTitle\n\n- Tipo: `string`\n- Padrão: `Switch to light theme`\n\nPode ser usado para personalizar o título do botão de modo claro que aparece ao passar o mouse.\n\n## darkModeSwitchTitle\n\n- Tipo: `string`\n- Padrão: `Switch to dark theme`\n\nPode ser usado para personalizar o título do botão de modo escuro que aparece ao passar o mouse.\n\n## sidebarMenuLabel\n\n- Tipo: `string`\n- Padrão: `Menu`\n\nPode ser usado para personalizar o rótulo do menu da barra lateral. Esse rótulo é exibido apenas na visualização móvel.\n\n## returnToTopLabel\n\n- Tipo: `string`\n- Padrão: `Return to top`\n\nPode ser usado para personalizar o rótulo do botão de retorno ao topo. Esse rótulo é exibido apenas na visualização móvel.\n\n## langMenuLabel\n\n- Tipo: `string`\n- Padrão: `Change language`\n\nPode ser usado para personalizar o aria-label do botão de idioma na barra de navegação. Isso é usado apenas se você estiver usando [i18n](../guide/i18n).\n\n## externalLinkIcon\n\n- Tipo: `boolean`\n- Padrão: `false`\n\nSe deve mostrar um ícone de link externo ao lado de links externos no markdown.\n"
  },
  {
    "path": "docs/pt/reference/default-theme-edit-link.md",
    "content": "# Editar Link {#edit-link}\n\n## Configuração a nível de Site {#site-level-config}\n\nEditar Link permite que você mostre um link para editar a página com serviços de gerenciamento Git, como GitHub ou GitLab. Para habilitar, adicione a opção `themeConfig.editLink` na sua configuração.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\nA opção `pattern` define a estrutura da URL para o link, e `:path` será substituído com o mesmo caminho de página.\n\nVocê também pode colocar uma função pura que aceita [`PageData`](./runtime-api#usedata) como argumento e retorna uma URL em string.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nIsso não deve gerar efeitos colaterais ou acessar qualquer coisa fora do seu escopo, uma vez que será serializado e executado no navegador.\n\nPor padrão, isso irá adicionar o link com texto \"Edite essa página\" no final da página de documentação. Você pode personalizar esse texto ao definir a opção `text`.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edite essa página no GitHub'\n    }\n  }\n}\n```\n\n## Configuração Frontmatter {#frontmatter-config}\n\nA funcionalidade pode ser desabilitada por página usando a opção `editLink` no frontmatter:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-footer.md",
    "content": "# Rodapé {#footer}\n\nVitePress irá mostrar o rodapé global na parte inferior da página quando `themeConfig.footer` está presente.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Lançado sob Licença MIT.',\n      copyright: 'Direitos Reservados © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // A mensagem mostrada logo antes do copyright.\n  message?: string\n\n  // O próprio texto de copyright.\n  copyright?: string\n}\n```\n\nA configuração acima também suporta strings HTML. Então, por exemplo, se você quiser configurar o texto de rodapé para ter alguns links, você pode ajustar a configuração como o seguinte:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Lançado sob <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">Licença MIT</a>.',\n      copyright: 'Direitos Reservados © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning\nApenas elementos _inline_ serão usados em `message` e `copyright` conforme eles são apresentados dentro do elemento  `<p>`. Se você quiser adicionar elementos de tipo _block_, considere usar o _slot_ [`layout-bottom`](../guide/extending-default-theme#layout-slots).\n:::\n\nNote que o rodapé não será mostrado quando a [Barra Lateral](./default-theme-sidebar) estiver visível.\n\n## Configuração Frontmatter {#frontmatter-config}\n\nIsso pode ser desabilitado por página usando a opção `footer` em frontmatter:\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-home-page.md",
    "content": "# Página Inicial {#home-page}\n\nO tema padrão VitePress fornece um layout de página inicial, que você também pode ver em uso [na página inicial deste site](../). Você pode usá-lo em qualquer uma de suas páginas especificando `layout: home` em [frontmatter](./frontmatter-config).\n\n```yaml\n---\nlayout: home\n---\n```\n\nNo entanto, essa opção sozinha não faz muito. Você pode adicionar várias \"seções\" diferentes pré-modeladas à página inicial definindo opções adicionais como `hero` e `features`.\n\n## Seção Hero {#hero-section}\n\nA seção _Hero_ fica no topo da página inicial. Aqui segue como você pode configurar a seção _Hero_.\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Gerador de site estático com Vite & Vue.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: Iniciar\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: Ver no GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // A string mostrada acima de `text`. Vem com a cor da marca\n  // e espera-se que seja curta, como o nome do produto.\n  name?: string\n\n  // O texto principal para a seção hero.\n  // Isso será definido como uma tag `h1`.\n  text: string\n\n  // Slogan exibido abaixo de `text`.\n  tagline?: string\n\n  // A imagem é exibida ao lado da área de texto e slogan.\n  image?: ThemeableImage\n\n  // Botões acionáveis para exibir na seção hero da página inicial.\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // Tema de cor do botão. Padrão: `brand`.\n  theme?: 'brand' | 'alt'\n\n  // Rótulo do botão.\n  text: string\n\n  // Destino do link do botão.\n  link: string\n\n  // Atributo target do link.\n  target?: string\n\n  // Atributo rel do link.\n  rel?: string\n}\n```\n\n### Personalizando a cor do nome {#customizing-the-name-color}\n\nVitePress usa a cor da marca (`--vp-c-brand-1`) para `name`. No entanto, você pode personalizar essa cor sobrescrevendo a variável `--vp-home-hero-name-color`.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nVocê também pode personalizá-la ainda mais combinando `--vp-home-hero-name-background` para dar ao `name` uma cor degradê.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## Seção de Funcionalidades {#features-section}\n\nNa seção de funcionalidades, você pode listar qualquer número de funcionalidades que deseja mostrar imediatamente após a seção _Hero_. Para configurá-la, passe a opção `features` para o frontmatter.\n\nVocê pode fornecer um ícone para cada funcionalidade, que pode ser um emoji ou qualquer tipo de imagem. Quando o ícone configurado é uma imagem (svg, png, jpeg...), você deve fornecer o ícone com a largura e altura apropriadas; você também pode fornecer a descrição, seu tamanho intrínseco, bem como suas variantes para temas escuros e claros quando necessário.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Simples e minimalista, sempre\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Outro recurso legal\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Outro recurso legal\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // Mostra ícone em cada bloco de funcionalide.\n  icon?: FeatureIcon\n\n  // Título da funcionalidade.\n  title: string\n\n  // Detalhes da funcionalidade.\n  details: string\n\n  // Link quando clicado no componente de funcionalidade.\n  // O link pode ser interno ou externo.\n  //\n  // ex. `guide/reference/default-theme-home-page` ou `https://example.com`\n  link?: string\n\n  // Texto do link a ser exibido dentro do componente de funcionalidade.\n  //  Melhor usado com a opção `link`.\n  //\n  // ex. `Saiba mais`, `Visitar página`, etc.\n  linkText?: string\n\n  // Atributo rel do link para a opção `link`.\n  //\n  // ex. `external`\n  rel?: string\n\n  // Atributo target do link para a opção `link`.\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-last-updated.md",
    "content": "# Última Atualização {#last-updated}\n\nO tempo em que o conteúdo foi atualizado pela última vez será mostrado no canto inferior direito da página. Para habilitar, adicione a opção `lastUpdated` na sua configuração.\n\n::: tip\nVocê precisa fazer _commit_ no arquivo markdown para ver o tempo atualizado.\n:::\n\n## Configuração a nível de Site {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## Configuração Frontmatter {#frontmatter-config}\n\nIsso pode ser desabilitado por página usando a opção `lastUpdated` no frontmatter:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nRefira-se ao [Tema Padrão: Última Atualização](./default-theme-config#lastupdated) para mais detalhes. Qualquer valor positivo a nível de tema também habilitará a funcionalidade a não ser que esteja explicitamente desabilitada a nível de página ou de site.\n"
  },
  {
    "path": "docs/pt/reference/default-theme-layout.md",
    "content": "# Layout {#layout}\n\nVocê pode escolher o layout da página definindo a opção de `layout` para o [frontmatter](./frontmatter-config) da página. Há três opções de layout: `doc`, `page` e `home`. Se nada for especificado, a página será tratada como página `doc`.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## Layout do documento {#doc-layout}\n\nA opção `doc` é o layout padrão e estiliza todo o conteúdo Markdown com o visual de \"documentação\". Ela funciona agrupando todo o conteúdo na classe CSS `vp-doc`, e aplicando os estilos aos elementos abaixo dela.\n\nQuase todos os elementos genéricos, como `p` ou `h2`, recebem um estilo especial. Portanto, lembre-se de que se você adicionar qualquer HTML personalizado dentro de um conteúdo Markdown, ele também será afetado por esses estilos.\n\nEle também fornece recursos específicos de documentação listados abaixo. Esses recursos estão habilitados apenas neste layout.\n\n- Editar link\n- Links Anterior e Próximo\n- _Outline_\n- [Carbon Ads](./default-theme-carbon-ads)\n\n## Layout da Página {#page-layout}\n\nA opção `page` é tratada como \"página em branco\". O Markdown ainda será processado e todas as [Extensões Markdown](../guide/markdown) funcionarão da mesma forma que o layout `doc`, mas este não receberá nenhum estilo padrão.\n\nO layout da página permitirá que você estilize tudo sem que o tema VitePress afete a marcação. Isso é útil quando você deseja criar sua própria página personalizada.\n\nObserve que mesmo neste layout, a barra lateral ainda aparecerá se a página tiver uma configuração de barra lateral correspondente.\n\n## Layout da Home {#home-layout}\n\nA opção `home` gerará um modelo de _\"Homepage\"_. Nesse layout você pode definir opções extras, como `hero` e `features`, para personalizar ainda mais o conteúdo. Visite [Tema padrão: Página Inicial](./default-theme-home-page)  para obter mais detalhes.\n\n## Sem Layout {#no-layout}\n\nSe você não quiser nenhum layout, pode passar `layout: false` pelo frontmatter. Esta opção é útil se você deseja uma página de destino totalmente personalizável (sem barra lateral, barra de navegação ou rodapé por padrão).\n\n## Layout Personalizado {#custom-layout}\n\nVocê também pode usar um layout personalizado:\n\n```md\n---\nlayout: foo\n---\n```\n\nIsto irá procurar um componente chamado `foo` registrado no contexto. Por exemplo, você pode registrar seu componente globalmente em `.vitepress/theme/index.ts`:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-nav.md",
    "content": "# Navegação {#nav}\n\nReferente a barra de navegação exibida no topo da página. Ela contém o título do site, links do menu global, e etc.\n\n## Título do Site e Logo {#site-title-and-logo}\n\nPor padrão, a navegação mostra o título do site referenciando o valor de [`config.title`](./site-config#title). Se desejar alterar o que é exibido na navegação, você pode definir um texto personalizado na opção `themeConfig.siteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'Meu Título Personalizado'\n  }\n}\n```\n\nSe você tiver um logo para seu site, pode mostrá-lo passando o caminho para a imagem. Você deve colocar o logo diretamente dentro da pasta `public`, e definir o caminho absoluto para ele.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nAo adicionar um logo, ele é mostrado juntamente com o título do site. Se seu logo tem tudo o que você precisa e se você desejar ocultar o texto do título, defina `false` na opção `siteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nVocê também pode passar um objeto como logo se quiser adicionar um atributo `alt` ou personalizá-lo com base no modo claro/escuro. Consulte [`themeConfig.logo`](./default-theme-config#logo) para obter detalhes.\n\n## Links de Navegação {#navigation-links}\n\nVocê pode definir a opção `themeConfig.nav` para adicionar links à sua navegação.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      { text: 'Configuração', link: '/config' },\n      { text: 'Registro de Alterações', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` é o próprio texto mostrado na navegação, e o `link` é o link para o qual será navegado quando o texto for clicado. Para o link, defina o caminho para o próprio arquivo sem o prefixo `.md` e sempre comece com `/`.\n\nO `link` também pode ser uma função que aceita [`PageData`](./runtime-api#usedata) como argumento e retorna o caminho.\n\nLinks de navegação também podem ser menus _dropdown_. Para fazer isso, defina a chave `items` na opção do link.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guide' },\n      {\n        text: 'Menu Dropdown',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nNote que o título do menu _dropdown_ (`Menu Dropdown` no exemplo acima) não pode ter a propriedade `link`, pois ele se torna um botão para abrir o diálogo dropdown.\n\nVocê também pode adicionar \"seções\" aos itens do menu _dropdown_ passando mais itens aninhados.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guia', link: '/guia' },\n      {\n        text: 'Menu Dropdown',\n        items: [\n          {\n            // Título da seção.\n            text: 'Título da Seção A',\n            items: [\n              { text: 'Item A da Seção A', link: '...' },\n              { text: 'Item B da Seção B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Menu Dropdown',\n        items: [\n          {\n            // Você também pode omitir o título.\n            items: [\n              { text: 'Item A da Seção A', link: '...' },\n              { text: 'Item B da Seção B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Personalizar o estado \"ativo\" do link {#customize-link-s-active-state}\n\nOs itens do menu de navegação serão destacados quando a página atual estiver no caminho correspondente. Se desejar personalizar o caminho a ser correspondido, defina a propriedade `activeMatch` e regex como um valor em string.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // Este link fica no estado ativo quando\n      // o usuário está no caminho `/config/`.\n      {\n        text: 'Guia',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch` deve ser uma string regex, mas você deve defini-la como uma string. Não podemos usar um objeto RegExp real aqui porque ele não é serializável durante o momento de construção.\n:::\n\n### Personalizar os atributos \"target\" e \"rel\" de links {#customize-link-s-target-and-rel-attributes}\n\nPor padrão, VitePress determina automaticamente os atributos `target` e `rel` baseado em um link externo ou não. Mas se você quiser, também pode personalizá-los.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Merchandise',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## Links Sociais {#social-links}\n\nConsulte [`socialLinks`](./default-theme-config#sociallinks).\n"
  },
  {
    "path": "docs/pt/reference/default-theme-prev-next-links.md",
    "content": "# Links Anterior e Próximo {#prev-next-links}\n\nVocê pode personalizar o texto e o link para os botões de Anterior e Próximo mostrados ao fim da página. Isso é útil quando você quer mostrar um texto diferente daquele que você tem na barra lateral. Além disso, você pode achar útil desabilitar o rodapé ou link para a página para ela não ser incluída na sua barra lateral.\n\n## prev\n\n- Tipo: `string | false | { text?: string; link?: string }`\n\n- Detalhes:\n\n  Especifica o texto/link para mostrar no link para a página anterior. Se você não ver isso no frontmatter, o texto/link será inferido da configuração da barra lateral.\n\n- Exemplos:\n\n  - Para personalizar apenas o texto:\n\n    ```yaml\n    ---\n    prev: 'Iniciar | Markdown'\n    ---\n    ```\n\n  - Para personalizar ambos texto e link:\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - Para esconder a página anterior:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\nO mesmo que `prev` mas para a próxima página.\n"
  },
  {
    "path": "docs/pt/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# Pesquisa {#search}\n\n## Pesquisa Local {#local-search}\n\nVitePress oferece suporte à pesquisa de texto completa usando um índice no navegador graças ao [minisearch](https://github.com/lucaong/minisearch/). Para habilitar esse recurso, basta definir a opção `themeConfig.search.provider` como `'local'` no arquivo `.vitepress/config.ts`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\nExemplo de resultado:\n\n![captura de tela do modal de pesquisa](/search.png)\n\nAlternativamente, você pode usar [Algolia DocSearch](#algolia-search) ou alguns plugins da comunidade como <https://www.npmjs.com/package/vitepress-plugin-search> ou <https://www.npmjs.com/package/vitepress-plugin-pagefind>.\n\n### i18n {#local-search-i18n}\n\nVocê pode usar uma configuração como esta para usar a pesquisa multilínguas:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          pt: { // torne isto `root` se quiser traduzir a localidade padrão\n            translations: {\n              button: {\n                buttonText: 'Pesquisar',\n                buttonAriaLabel: 'Pesquisar'\n              },\n              modal: {\n                displayDetails: 'Mostrar lista detalhada',\n                resetButtonTitle: 'Redefinir pesquisa',\n                backButtonTitle: 'Fechar pesquisa',\n                noResultsText: 'Nenhum resultado',\n                footer: {\n                  selectText: 'Selecionar',\n                  selectKeyAriaLabel: 'Enter',\n                  navigateText: 'Navegar',\n                  navigateUpKeyAriaLabel: 'Seta para cima',\n                  navigateDownKeyAriaLabel: 'Seta para baixo',\n                  closeText: 'Fechar',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### Opções MiniSearch {#minisearch-options}\n\nVocê pode configurar o MiniSearch assim:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nSaiba mais na [documentação do MiniSearch](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).\n\n### Apresentador de Conteúdo Personalizado {#custom-content-renderer}\n\nVocê pode personalizar a função usada para apresentar o conteúdo markdown antes de indexá-lo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // retorna uma string HTML\n        }\n      }\n    }\n  }\n})\n```\n\nEssa função será removida dos dados do site no lado do cliente, então você pode usar APIs do Node.js nela.\n\n#### Exemplo: Excluindo páginas da pesquisa {#example-excluding-pages-from-search}\n\nVocê pode excluir páginas da pesquisa adicionando `search: false` ao frontmatter da página. Alternativamente:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Nota\nNo caso uma função `_render` personalizada ser fornecida, você precisa manipular o `search: false` do frontmatter por conta própria. Além disso, o objeto `env` não estará completamente populado antes que `md.renderAsync` seja chamado, então verificações em propriedades opcionais `env`, como `frontmatter`, devem ser feitas após isso.\n:::\n\n#### Exemplo: Transformando conteúdo - adicionando âncoras {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Pesquisa Algolia {#algolia-search}\n\nVitePress oferece suporte à pesquisa em seu site de documentação usando [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Consulte o guia de início deles. Em seu arquivo `.vitepress/config.ts`, você precisará fornecer pelo menos o seguinte para que funcione:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\nVocê pode usar uma configuração como esta para usar a pesquisa multilínguas:\n\n<details>\n<summary>Clique para expandir</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\nConsulte a [documentação oficial da Algolia](https://docsearch.algolia.com/docs/api#translations) para saber mais. Para começar rapidamente, você também pode copiar as traduções usadas por este site do [nosso repositório no GitHub](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code).\n\n### Suporte ao Algolia Ask AI {#ask-ai}\n\nSe quiser incluir o **Ask AI**, adicione `askAi` em `options`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"SEU-ID-DO-ASSISTENTE\"\n        // OU\n        askAi: {\n          // no mínimo, você deve fornecer o assistantId recebido da Algolia\n          assistantId: 'XXXYYY',\n          // substituições opcionais — se omitidas, os valores appId/apiKey/indexName de nível superior são reutilizados\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Nota\nCaso queira apenas a pesquisa por palavra-chave, omita `askAi`.\n:::\n\n### Painel Lateral do Ask AI {#ask-ai-side-panel}\n\nO DocSearch v4.5+ suporta um **painel lateral do Ask AI** opcional. Quando habilitado, pode ser aberto com **Ctrl/Cmd+I** por padrão. A [Referência da API do Painel Lateral](https://docsearch.algolia.com/docs/sidepanel/api-reference) contém a lista completa de opções.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // Espelha a API do @docsearch/sidepanel-js SidepanelProps\n            panel: {\n              variant: 'floating', // ou 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nSe precisar desabilitar o atalho de teclado, use a opção `keyboardShortcuts` do painel lateral:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### Modo (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nVocê pode controlar opcionalmente como o VitePress integra a pesquisa por palavra-chave e o Ask AI:\n\n- `mode: 'auto'` (padrão): infere `hybrid` quando a pesquisa por palavra-chave está configurada, caso contrário `sidePanel` quando o painel lateral do Ask AI está configurado.\n- `mode: 'sidePanel'`: força apenas o painel lateral (oculta o botão de pesquisa por palavra-chave).\n- `mode: 'hybrid'`: habilita o modal de pesquisa por palavra-chave + painel lateral do Ask AI (requer configuração de pesquisa por palavra-chave).\n- `mode: 'modal'`: mantém o Ask AI dentro do modal do DocSearch (mesmo se você configurou o painel lateral).\n\n#### Apenas Ask AI (sem pesquisa por palavra-chave) {#ask-ai-only}\n\nSe quiser usar **apenas o painel lateral do Ask AI**, você pode omitir a configuração de pesquisa por palavra-chave de nível superior e fornecer as credenciais em `askAi`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### Configuração _Crawler_ {#crawler-config}\n\nAqui está um exemplo de configuração baseado na qual este site usa:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/pt/reference/default-theme-sidebar.md",
    "content": "# Barra Lateral {#sidebar}\n\nA barra lateral é o bloco principal de navegação da sua documentação. Você pode configurar o menu da barra lateral em [`themeConfig.sidebar`](./default-theme-config#sidebar).\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          { text: 'Introdução', link: '/introduction' },\n          { text: 'Iniciando', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## O Básico {#the-basics}\n\nA forma mais simples do menu da barra lateral é passar um único _array_ de links. O item do primeiro nível define a \"seção\" da barra lateral. Ele deve conter `text`, que é o título da seção, e `items` que são os próprios links de navegação.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título da Seção A',\n        items: [\n          { text: 'Item A', link: '/item-a' },\n          { text: 'Item B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Título da Seção B',\n        items: [\n          { text: 'Item C', link: '/item-c' },\n          { text: 'Item D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\nCada `link` deve especificar o caminho para o próprio arquivo começando com `/`. Se você adicionar uma barra no final do link, será mostrado o `index.md` do diretório correspondente.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guia',\n        items: [\n          // Isso mostra a página `/guide/index.md`.\n          { text: 'Introdução', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nVocê pode aninhar ainda mais os itens da barra lateral até 6 níveis de profundidade contando a partir do nível raiz. Note que níveis mais profundos que 6 serão ignorados e não serão exibidos na barra lateral.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Nível 1',\n        items: [\n          {\n            text: 'Nível 2',\n            items: [\n              {\n                text: 'Nível 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Múltiplas Barras Laterais {#multiple-sidebars}\n\nVocê pode mostrar uma barra lateral diferente dependendo do caminho da página. Por exemplo, como mostrado neste site, você pode querer criar seções separadas de conteúdo em sua documentação, como a página \"Guia\" e a página \"Configuração\".\n\nPara fazer isso, primeiro organize suas páginas em diretórios para cada seção desejada:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nEm seguida, atualize sua configuração para definir sua barra lateral para cada seção. Desta vez, você deve passar um objeto em vez de um array.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // Esta barra lateral é exibida quando um usuário\n      // está no diretório `guide`.\n      '/guide/': [\n        {\n          text: 'Guia',\n          items: [\n            { text: 'Índice', link: '/guide/' },\n            { text: 'Um', link: '/guide/one' },\n            { text: 'Dois', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // Esta barra lateral é exibida quando um usuário\n      // está no diretório `config`.\n      '/config/': [\n        {\n          text: 'Configuração',\n          items: [\n            { text: 'Índice', link: '/config/' },\n            { text: 'Três', link: '/config/three' },\n            { text: 'Quatro', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## Grupos Retráteis na Barra Lateral {#collapsible-sidebar-groups}\n\nAdicionando a opção `collapsed` ao grupo da barra lateral, ela mostra um botão para ocultar/mostrar cada seção.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título da Seção A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\nTodas as seções são \"abertas\" por padrão. Se você deseja que elas estejam \"fechadas\" na carga inicial da página, defina a opção `collapsed` como `true`.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Título da Seção A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/pt/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Criador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Desenvolvedor',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# Página da Equipe {#team-page}\n\nSe você quiser apresentar sua equipe, você pode usar componentes de equipe para construir a Página da Equipe. Existem duas maneiras de usar esses componentes. Uma é incorporá-lo na página de documento, e outra é criar uma Página de Equipe completa.\n\n## Mostrar membros da equipe em uma página {#show-team-members-in-a-page}\n\nVocê pode usar o componente `<VPTeamMembers>` exposto em `vitepress/theme` para exibir uma lista de membros da equipe em qualquer página.\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Criador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# Nosso time\n\nDiga olá à nossa equipe incrível.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\nO código acima exibirá um membro da equipe em um elemento tipo cartão. Ele deve exibir algo semelhante ao abaixo.\n\n<VPTeamMembers size=\"small\" :members />\n\nO componente `<VPTeamMembers>` vem em 2 tamanhos diferentes, pequeno `small` e médio `medium`. Enquanto é uma questão de preferência, geralmente o tamanho `small` deve encaixar melhor quando usado na página de documento. Além disso, você pode adicionar mais propriedades a cada membro, como adicionar o botão \"descrição\" ou \"patrocinador\". Saiba mais sobre em [`<VPTeamMembers>`](#vpteammembers).\n\nIncorporar membros da equipe na página de documento é bom para equipes de pequeno porte, onde ter uma página de equipe inteira dedicada pode ser demais, ou introduzir membros parciais como uma referência ao contexto da documentação.\n\nSe você tiver um grande número de membros, ou simplesmente quiser ter mais espaço para mostrar os membros da equipe, considere [criar uma página de equipe completa.](#create-a-full-team-page)\n\n## Criando uma página de equipe completa {#create-a-full-team-page}\n\nEm vez de adicionar membros da equipe à página de documento, você também pode criar uma Página de Equipe completa, da mesma forma que pode criar uma [Página Inicial](./default-theme-home-page) personalizada.\n\nPara criar uma página de equipe, primeiro crie um novo arquivo md. O nome do arquivo não importa, mas aqui vamos chamá-lo de `team.md`. Neste arquivo, defina a opção `layout: page` do frontmatter,  e então você poderá compor a estrutura da sua página usando componentes `TeamPage`.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Criador',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Nosso time\n    </template>\n    <template #lead>\n     O desenvolvimento do VitePress é orientado por uma equipe internacional,\n     alguns dos membros escolheram ser apresentados abaixo.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\nAo criar uma página de equipe completa, lembre-se de agrupar todos os componentes com o componente `<VPTeamPage>`. Este componente garantirá que todos os componentes aninhados relacionados à equipe obtenham a estrutura de layout adequada, como espaçamentos.\n\nO componente `<VPPageTitle>` adiciona a seção de título da página. O título é `<h1>`. Use os _slots_ `#title` e `#lead`para documentar sobre sua equipe.\n\n`<VPMembers>` funciona da mesma forma que quando usado em uma página de documento. Ele exibirá a lista de membros.\n\n### Adicione seções para dividir os membros da equipe {#add-sections-to-divide-team-members}\n\nVocê pode adicionar \"seções\" à página da equipe. Por exemplo, você pode ter diferentes tipos de membros da equipe, como membros da Equipe Principal e Parceiros da Comunidade. Você pode dividir esses membros em seções para explicar melhor os papéis de cada grupo.\n\nPara fazer isso, adicione o componente `<VPTeamPageSection>` ao arquivo `team.md` que criamos anteriormente.\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Nosso time</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Parceiros</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\nO componente `<VPTeamPageSection>` pode ter os _slots_ `#title` e `#lead` similar ao componente `VPTeamPageTitle`, e também o _slot_ `#members` para exibir os membros da equipe.\n\nLembre-se de colocar o componente `<VPTeamMembers>` dentro do _slot_ `#members`.\n\n## `<VPTeamMembers>`\n\nO componente `<VPTeamMembers>` exibe uma determinada lista de membros.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // Tamanho de cada membro. O padrão é `medium`.\n  size?: 'small' | 'medium'\n\n  // Lista de membros a serem exibidos.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // Imagem avatar do membro\n  avatar: string\n\n  // Nome do membro.\n  name: string\n\n  // Título a ser mostrado abaixo do nome do membro.\n  // Ex.: Desenvolvedor, Engenheiro de Software, etc.\n  title?: string\n\n  // Organização a qual o membro pertence.\n  org?: string\n\n  // URL da organização.\n  orgLink?: string\n\n  // Descrição do membro.\n  desc?: string\n\n  // Links sociais, por exemplo, GitHub, Twitter, etc.\n  // Você pode passar o objeto de Links Sociais aqui.\n  // Veja: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // URL da página de patrocinador do membro.\n  sponsor?: string\n\n  // Texto para o link do patrocinador. O padrão é 'Sponsor'.\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\nO componente raiz ao criar uma página de equipe completa. Ele aceita apenas um único _slot_. Ele estilizará todos os componentes relacionados à equipe passados.\n\n## `<VPTeamPageTitle>`\n\nAdiciona a seção \"título\" da página. Melhor usar logo no início sob `<VPTeamPage>`. Aceita os _slots_ `#title` e `#lead`.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Nosso time\n    </template>\n    <template #lead>\n      O desenvolvimento do VitePress é orientado por uma equipe internacional,\n      alguns dos membros escolheram ser apresentados abaixo.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\nCria uma \"seção\" na página da equipe. Aceita os _slots_ `#title`, `#lead` e `#members`. Você pode adicionar quantas seções quiser dentro de `<VPTeamPage>`.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Parceiros</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/pt/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# Configuração Frontmatter {#frontmatter-config}\n\nFrontmatter permite a configuração baseada em páginas. Em cada arquivo markdown, você pode usar a configuração frontmatter para sobrepor opções de configuração a nível de site ou de tema. Além disso, existem opções de configuração que só podem ser definidas em frontmatter.\n\nExemplo de uso:\n\n```md\n---\ntitle: Documentação com VitePress\neditLink: true\n---\n```\n\nVocê pode acessar os dados do frontmatter através da variável global `$frontmatter` em expressões Vue:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- Tipo: `string`\n\nTítulo para a página. É o mesmo que [config.title](./site-config#title), e sobrepõe a configuração a nível de site.\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- Tipo: `string | boolean`\n\nO sufixo para o título. É o mesmo que [config.titleTemplate](./site-config#titletemplate), e sobrepõe a configuração a nível de site.\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Gerador de site estático com Vite & Vue\n---\n```\n\n## description\n\n- Tipo: `string`\n\nDescrição para a página. É o mesmo que [config.description](./site-config#description), e sobrepõe a configuração a nível de site.\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- Tipo: `HeadConfig[]`\n\nEspecifica tags head adicionais a serem injetadas na página atual. Elas serão acrescentadas após as tags head injetadas pela configuração a nível de site.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## Somente no Tema Padrão {#default-theme-only}\n\nAs seguintes opções frontmatter são aplicáveis apenas ao usar o tema padrão.\n\n### layout\n\n- Tipo: `doc | home | page`\n- Padrão: `doc`\n\nDetermina o layout da página.\n\n- `doc` - Aplica estilos de documentação padrão ao conteúdo markdown.\n- `home` - Layout especial para a \"Página Inicial\". Você pode adicionar opções extras como `hero` e `features` para criar rapidamente uma bela página inicial.\n- `page` - Comporta-se de maneira semelhante a `doc`, mas não aplica estilos ao conteúdo. Útil quando você deseja criar uma página totalmente personalizada.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"apenas para página inicial\" />\n\nDefine o conteúdo da seção _hero_ na página inicial quando `layout` está definido como `home`. Mais detalhes em [Tema Padrão: Página Inicial](./default-theme-home-page).\n\n### features <Badge type=\"info\" text=\"apenas para página inicial\" />\n\nDefine os itens a serem exibidos na seção de funcionalidades quando `layout` está definido como `home`. Mais detalhes em [Tema Padrão: Página Inicial](./default-theme-home-page).\n\n### navbar\n\n- Tipo: `boolean`\n- Padrão: `true`\n\nSe deve exibir a [barra de navegação](./default-theme-nav).\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- Tipo: `boolean`\n- Padrão: `true`\n\nSe deve exibir a [barra lateral](./default-theme-sidebar).\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- Tipo: `boolean | 'left'`\n- Padrão: `true`\n\nDefine a localização do componente aside no layout `doc`.\n\nConfigurar este valor como `false` impede a apresentação do elemento aside.\\\nConfigurar este valor como `true` apresenta o aside à direita.\\\nConfigurar este valor como `'left'` apresenta o aside à esquerda.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- Tipo: `number | [number, number] | 'deep' | false`\n- Padrão: `2`\n\nOs níveis do cabeçalho no _outline_ a serem exibidos para a página. É o mesmo que [config.themeConfig.outline.level](./default-theme-config#outline), e sobrepõe o valor definido na configuração no nível do site.\n\n### lastUpdated\n\n- Tipo: `boolean | Date`\n- Padrão: `true`\n\nSe deve mostrar o texto de [última atualização](./default-theme-last-updated) no rodapé da página atual. Se uma data e hora específica forem especificadas, ela será exibida em vez do último horário de modificação do git.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- Tipo: `boolean`\n- Padrão: `true`\n\nSe deve exibir o [link de edição](./default-theme-edit-link) no rodapé da página atual.\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- Tipo: `boolean`\n- Padrão: `true`\n\nSe deve exibir o [rodapé](./default-theme-footer).\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- Tipo: `string`\n\nAdiciona um nome de classe extra a uma página específica.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nEm seguida, você pode personalizar os estilos desta página específica no arquivo `.vitepress/theme/custom.css`:\n\n```css\n.custom-page-class {\n  /* estilos específicos da página */\n}\n```\n"
  },
  {
    "path": "docs/pt/reference/runtime-api.md",
    "content": "# API em Tempo de Execução {#runtime-api}\n\nVitePress oferece várias APIs embutidas para permitir o acesso aos dados da aplicação. VitePress vem também com alguns componentes embutidos que podem ser usados globalmente.\n\nOs métodos auxiliares são importáveis globais de `vitepress` e geralmente são usados em componentes Vue de temas personalizados. No entanto, eles também podem ser usados dentro de páginas `.md` porque os arquivos markdown são compilados em [Componentes de Arquivo Único Vue (SFC)](https://vuejs.org/guide/scaling-up/sfc.html).\n\nMétodos que começam com `use*` indicam que é uma função da [API de Composição Vue 3](https://vuejs.org/guide/introduction.html#composition-api) (\"Composable\") que só pode ser usada dentro de `setup()` ou `<script setup>`.\n\n## `useData` <Badge type=\"info\" text=\"composable\" />\n\nRetorna dados específicos da página. O objeto retornado possui o seguinte tipo:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * Metadados do nível do site\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig de .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Metadados do nível da página\n   */\n  page: Ref<PageData>\n  /**\n   * Frontmatter da página\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * Parâmetros dinâmicos da rota\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**Exemplo:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" />\n\nRetorna o objeto de rota atual com o seguinte tipo:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" />\n\nRetorna a instância do roteador VitePress para que você possa navegar programaticamente para outra página.\n\n```ts\ninterface Router {\n  /**\n   * Rota atual.\n   */\n  route: Route\n  /**\n   * Navegar para uma nova URL.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * Chamado antes da mudança de rota. Retorne `false` para cancelar a navegação.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Chamado antes do carregamento do componente da página (depois que o estado do histórico é\n   * atualizado). Retorne `false` para cancelar a navegação.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Chamado após a mudança de rota.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" />\n\n- **Tipo**: `(path: string) => string`\n\nAnexa o [`base`](./site-config#base) configurado a um caminho de URL fornecido. Veja também [Base URL](../guide/asset-handling#base-url).\n\n## `<Content />` <Badge type=\"info\" text=\"component\" />\n\nO componente `<Content />` exibe o conteúdo markdown renderizado. Útil [ao criar seu próprio tema](../guide/custom-theme).\n\n```vue\n<template>\n  <h1>Layout Personalizado!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" />\n\nO componente `<ClientOnly />` revela seu _slot_ apenas no lado do cliente.\n\nComo as aplicações VitePress são interpretadas no lado do servidor em Node.js ao gerar builds estáticos, qualquer uso do Vue deve seguir os requisitos de código universal. Em resumo, certifique-se de acessar apenas APIs do Navegador / DOM em ganchos `beforeMount` ou `mounted`.\n\nSe você estiver usando ou demonstrando componentes que não são compatíveis com SSR (por exemplo, contêm diretivas personalizadas), você pode envolvê-los dentro do componente `ClientOnly`.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- Relacionado: [Compatibilidade SSR](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" />\n\nAcesse diretamente os dados [frontmatter](../guide/frontmatter) da página atual em expressões Vue.\n\n```md\n---\ntitle: Olá\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" />\n\nAcesse diretamente os [parâmetros de rota dinâmica](../guide/routing#dynamic-routes) da página atual em expressões Vue.\n\n```md\n- nome do pacote: {{ $params.pkg }}\n- versão: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/pt/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# Configuração do Site {#site-config}\n\nA configuração do site é onde você pode definir as configurações globais do site. As opções de configuração do aplicativo definem configurações que se aplicam a todos os sites VitePress, independentemente do tema que estão usando. Por exemplo, o diretório base ou o título do site.\n\n## Visão geral {#overview}\n\n### Resolução de Configuração {#config-resolution}\n\nO arquivo de configuração é sempre resolvido a partir de `<root>/.vitepress/config.[ext]`, onde `<root>` é a [raiz do projeto](../guide/routing#root-and-source-directory) VitePress e `[ext]` é uma das extensões de arquivo suportadas. O TypeScript é suportado de fábrica. As extensões suportadas incluem `.js`, `.ts`, `.mjs` e `.mts`.\n\nRecomenda-se usar a sintaxe de módulos ES nos arquivos de configuração. O arquivo de configuração deve exportar por padrão um objeto:\n\n```ts\nexport default {\n  // opções de configuração de nível da aplicação\n  lang: 'pt-BR',\n  title: 'VitePress',\n  description: 'Gerador de site estático Vite & Vue.',\n  ...\n}\n```\n\n::: details Configuração Dinâmica (Assíncrona)\n\nSe você precisar gerar dinamicamente a configuração, também pode exportar por padrão uma função. Por exemplo:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n  // opções de configuração de nível da aplicação\n    lang: 'pt-BR',\n    title: 'VitePress',\n    description: 'Gerador de site estático Vite & Vue.',\n\n    // opções de configuração de nível do tema\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nVocê também pode usar o `await` no nível superior. Como:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // opções de configuração de nível da aplicação\n    lang: 'pt-BR',\n    title: 'VitePress',\n    description: 'Gerador de site estático Vite & Vue.',\n\n  // opções de configuração de nível do tema\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### Configuração Intellisense {#config-intellisense}\n\nUsar o auxiliar `defineConfig` fornecerá Intellisense alimentado por TypeScript para as opções de configuração. Supondo que seu IDE o suporte, isso deve funcionar tanto em JavaScript quanto em TypeScript.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### Configuração de Tema Tipada {#typed-theme-config}\n\nPor padrão, o auxiliar `defineConfig` espera o tipo de configuração de tema do tema padrão:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // O tipo é `DefaultTheme.Config`\n  }\n})\n```\n\nSe você estiver usando um tema personalizado e desejar verificações de tipo para a configuração do tema, será necessário usar `defineConfigWithTheme` em vez disso, e passar o tipo de configuração para o seu tema personalizado por meio de um argumento genérico:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // O tipo é `ThemeConfig`\n  }\n})\n```\n\n### Configuração Vite, Vue & Markdown\n\n- **Vite**\n\n  Você pode configurar a instância subjacente do Vite usando a opção [vite](#vite) em sua configuração VitePress. Não é necessário criar um arquivo de configuração Vite separado.\n\n- **Vue**\n\n  VitePress já inclui o plugin Vue oficial para Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)). Você pode configurar suas opções usando a opção [vue](#vue) em sua configuração VitePress.\n\n- **Markdown**\n\n  Você pode configurar a instância subjacente de [Markdown-It](https://github.com/markdown-it/markdown-it) usando a opção [markdown](#markdown) em sua configuração VitePress.\n\n## Metadados do Site {#site-metadata}\n\n### title\n\n- Tipo: `string`\n- Padrão: `VitePress`\n- Pode ser substituído por página via [frontmatter](./frontmatter-config#title)\n\nTítulo do site. Ao usar o tema padrão, isso será exibido na barra de navegação.\n\nEle também será usado como o sufixo padrão para todos os títulos individuais das páginas, a menos que [`titleTemplate`](#titletemplate) seja definido. O título final de uma página individual será o conteúdo textual do seu primeiro cabeçalho `<h1>`, combinado com o título global como sufixo. Por exemplo, com a seguinte configuração e conteúdo da página:\n\n```ts\nexport default {\n  title: 'Meu Site Incrível'\n}\n```\n\n```md\n# Olá\n```\n\nO título da página será `Olá | Meu Site Incrível`.\n\n### titleTemplate\n\n- Tipo: `string | boolean`\n- Pode ser substituído por página via [frontmatter](./frontmatter-config#titletemplate)\n\nPermite personalizar o sufixo do título de cada página ou o título inteiro. Por exemplo:\n\n```ts\nexport default {\n  title: 'Meu Site Incrível',\n  titleTemplate: 'Sufixo Personalizado'\n}\n```\n\n```md\n# Olá\n```\n\nO título da página será `Olá | Sufixo Personalizado`.\n\nPara personalizar completamente como o título deve ser renderizado, você pode usar o símbolo `:title` em `titleTemplate`:\n\n```ts\nexport default {\n  titleTemplate: ':title - Sufixo Personalizado'\n}\n```\n\nAqui, `:title` será substituído pelo texto inferido do primeiro cabeçalho `<h1>` da página. O título do exemplo anterior da página será `Olá - Sufixo Personalizado`.\n\nA opção pode ser definida como `false` para desativar sufixos de título.\n\n### description\n\n- Tipo: `string`\n- Padrão: `Um site VitePress`\n- Pode ser substituído por página via [frontmatter](./frontmatter-config#descrição)\n\nDescrição para o site. Isso será apresentado como uma tag `<meta>` na página HTML.\n\n```ts\nexport default {\n  descrição: 'Um site VitePress'\n}\n```\n\n### head\n\n- Tipo: `HeadConfig[]`\n- Padrão: `[]`\n- Pode ser acrescentado por página via [frontmatter](./frontmatter-config#head)\n\nElementos adicionais para adicionar na tag `<head>` da página HTML. As tags adicionadas pelo usuário são mostradas antes da tag `head` de fechamento, após as tags VitePress.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### Exemplo: Adicionando um favicon {#example-adding-a-favicon}\n\n```ts\nexport default {\n  cabeça: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // coloque o favicon.ico no diretório public, se a base estiver definida, use /base/favicon.ico\n\n/* Mostraria:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### Exemplo: Adicionando Fontes do Google {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* Mostraria:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### Exemplo: Registrando um _service worker_ {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* Mostraria:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### Exemplo: Usando o Google Analytics {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* Mostraria:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- Tipo: `string`\n- Padrão: `en-US`\n\nO atributo de idioma para o site. Isso será mostrado como uma tag `<html lang=\"en-US\">` na página HTML.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- Tipo: `string`\n- Padrão: `/`\n\nA URL base em que o site será implantado. Você precisará definir isso se planeja implantar seu site em um subdiretório, por exemplo, no GitHub pages. Se você planeja implantar seu site em `https://foo.github.io/bar/` então você deve definir a base como `'/bar/'`. Deve sempre começar e terminar com uma barra.\n\nA base é automaticamente adicionada a todos as URLs que começam com / em outras opções, então você só precisa especificá-la uma vez.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## Roteamento {#routing}\n\n### cleanUrls\n\n- Tipo: `boolean`\n- Padrão: `false`\n\nQuando definido como `true`, VitePress removerá o `.html` no final dos URLs. Veja também [Geração de URLs Limpas](../guide/routing#generating-clean-urls).\n\n::: warning Suporte do Servidor Necessário\nAtivar isso pode exigir configurações adicionais em sua plataforma de hospedagem. Para funcionar, seu servidor deve ser capaz de servir `/foo.html` ao visitar `/foo` **sem redirecionamento**.\n:::\n\n### rewrites\n\n- Tipo: `Record<string, string>`\n\nDefine mapeamentos personalizados de diretório &lt;-&gt; URL. Veja [Roteamento: Reescrever Rotas](../guide/routing#route-rewrites) para mais detalhes.\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## Construção {#build}\n\n### srcDir\n\n- Tipo: `string`\n- Padrão: `.`\n\nO diretório onde suas páginas de markdown são armazenadas, relativo à raiz do projeto. Veja também [Diretório Raiz e Fonte](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- Tipo: `string`\n- Padrão: `undefined`\n\nUm [padrão glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) para corresponder a arquivos markdown que devem ser excluídos como conteúdo fonte.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- Tipo: `string`\n- Padrão: `./.vitepress/dist`\n\nA localização da saída da compilação para o site, relativa à [raiz do projeto](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- Tipo: `string`\n- Padrão: `assets`\n\nEspecifica o diretório para aninhar ativos gerados. O caminho deve estar dentro de [`outDir`](#outdir) e é resolvido em relação a ele.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- Tipo: `string`\n- Padrão: `./.vitepress/cache`\n\nO diretório para arquivos de cache, relativo à [raiz do projeto](../guide/routing#root-and-source-directory). Veja também: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- Tipo: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- Padrão: `false`\n\nQuando definido como `true`, VitePress não falhará na compilação devido a links quebrados.\n\nQuando definido como `'localhostLinks'`, a compilação falhará em links quebrados, mas não verificará links `localhost`.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\nTambém pode ser um _array_ de uma exata URL em string, padrões regex, ou funções de filtro personalizadas.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // ignora URL exata \"/playground\"\n    '/playground',\n    // ignora todos os links localhost\n    /^https?:\\/\\/localhost/,\n    // ignora todos os links incluindo \"/repl/\"\"\n    /\\/repl\\//,\n    // função personalizada, ignora todos os links incluindo \"ignore\"\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### mpa <Badge type=\"warning\" text=\"experimental\" />\n\n- Tipo: `boolean`\n- Padrão: `false`\n\nQuando definido como `true`, a aplicação em produção será compilada no [Modo MPA](../guide/mpa-mode). O modo MPA envia 0kb de JavaScript por padrão, às custas de desabilitar a navegação no lado do cliente e exigir permissão explícita para interatividade.\n\n## Tematização {#theming}\n\n### appearance\n\n- Tipo: `boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`\n- Padrão: `true`\n\nSe habilitar o modo escuro (adicionando a classe `.dark` ao elemento `<html>`).\n\n- Se a opção estiver definida como `true` o tema padrão é determinado pelo esquema de cores preferido do usuário.\n- Se a opção estiver definida como `dark` o tema é escuro por padrão, a menos que o usuário mude manualmente.\n- Se a opção estiver definida como `false` os usuários não poderão mudar o tema.\n\nEsta opção injeta um script em linha que restaura as configurações dos usuários do armazenamento local (_local storage_) usando a chave `vitepress-theme-appearance`. Isso garante que a classe `.dark` seja aplicada antes de a página ser mostrada para evitar oscilações.\n\n`appearance.initialValue` só pode ser `'dark' | undefined`. Refs ou getters não são suportados.\n\n### lastUpdated\n\n- Tipo: `boolean`\n- Padrão: `false`\n\nPara obter o selo de tempo da última atualização para cada página usando o Git. O selo de data será incluído nos dados de cada página, acessíveis via [`useData`](./runtime-api#usedata).\n\nAo usar o tema padrão, habilitar esta opção exibirá o horário da última atualização de cada página. Você pode personalizar o texto via opção [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext).\n\n## Personalização {#customization}\n\n### markdown\n\n- Tipo: `MarkdownOption`\n\nConfigure as opções do processador Markdown. VitePress usa [Markdown-it](https://github.com/markdown-it/markdown-it) como processador e [Shiki](https://github.com/shikijs/shiki) para destacar sintaxe de linguagem. Dentro desta opção, você pode passar várias opções Markdown relacionadas para atender às suas necessidades.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\nVerifique a [declaração de tipo e jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) para todas as opções disponíveis.\n\n### vite\n\n- Tipo: `import('vite').UserConfig`\n\nPasse a [Configuração Vite](https://vitejs.dev/config/) crua para o servidor interno / empacotador Vite.\n\n```js\nexport default {\n  vite: {\n    // Opções de configuração Vite\n  }\n}\n```\n\n### vue\n\n- Tipo: `import('@vitejs/plugin-vue').Options`\n\nPasse as opções [`@vitejs/plugin-vue`](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) cruas para a instância interna do plugin.\n\n```js\nexport default {\n  vue: {\n    // Opções @vitejs/plugin-vue\n  }\n}\n```\n\n## Ganchos de Compilação {#build-hooks}\n\nOs ganchos de compilação VitePress permitem adicionar novas funcionalidades ao seu site:\n\n- Sitemap\n- Indexação de Pesquisa\n- PWA\n- _Teleports_\n\n## buildEnd\n- Tipo: `(siteConfig: SiteConfig) => Awaitable<void>`\n`buildEnd` é um gancho de compilação CLI (Interface de Linha de Comando), ele será executado após a conclusão da compilação (SSG), mas antes que o processo VitePress CLI termine.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n## postRender\n- Tipo: `(context: SSGContext) => Awaitable<SSGContext | void>`\n- `postRender` é um gancho de compilação, chamado quando a interpretação SSG é concluída. Ele permitirá que você manipule o conteúdo de _teleports_ durante a geração de site estático.\n\n  ```ts\n  export default {\n    async postRender(context) {\n      // ...\n    }\n  }\n  ```\n\n  ```ts\n  interface SSGContext {\n    content: string\n    teleports?: Record<string, string>\n    [key: string]: any\n  }\n  ```\n\n## transformHead\n- Tipo: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` é um gancho de compilação para transformar o cabeçalho antes de gerar cada página. Isso permite adicionar entradas no cabeçalho que não podem ser adicionadas estaticamente à configuração VitePress. Você só precisa retornar entradas extras, que serão mescladas automaticamente com as existentes.\n\n::: warning\nNão faça mutações em qualquer item dentro de `context`.\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // e.g. index.md (relativo a srcDir)\n  assets: string[] // todos os ativos não-js/css com URL pública completamente resolvida\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nNote que este gancho só é chamado ao gerar o site estaticamente. Não é chamado durante o desenvolvimento. Se você precisar adicionar entradas de cabeçalho dinâmicas durante o desenvolvimento, pode usar o gancho [`transformPageData`](#transformpagedata) em seu lugar.\n\n  ```ts\n  export default {\n    transformPageData(pageData) {\n      pageData.frontmatter.head ??= []\n      pageData.frontmatter.head.push([\n        'meta',\n        {\n          name: 'og:title',\n          content:\n            pageData.frontmatter.layout === 'home'\n              ? `VitePress`\n              : `${pageData.title} | VitePress`\n        }\n      ])\n    }\n  }\n  ```\n\n#### Exemplo: Adicionar URL canônica `<link>` {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n- Tipo: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n`transformHtml` é um gancho de compilação para transformar o conteúdo de cada página antes de salvá-lo no disco.\n\n::: warning\nNão faça mutações em qualquer item dentro de `context`. Além disso, modificar o conteúdo HTML pode causar problemas de hidratação em tempo de execução.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n- Tipo: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` é um gancho para transformar os dados de cada página. Você pode fazer mutações diretamente em `pageData` ou retornar valores alterados que serão mesclados nos dados da página.\n\n::: warning\nNão faça mutações em qualquer item dentro de `context` e tenha cuidado pois isso pode impactar no desempenho do servidor de desenvolvimento, especialmente se você tiver algumas solicitações de rede ou computações pesadas (como gerar imagens) no gancho. Você pode verificar `process.env.NODE_ENV === 'production'` para lógica condicional.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // ou retorne dados a serem mesclados\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/public/pure.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>Plain HTML page | VitePress</title>\n    <meta charset=\"utf-8\" />\n    <meta name=\"robots\" content=\"noindex, nofollow\" />\n  </head>\n  <body>\n    <h1>Not part of the main VitePress docs site</h1>\n    <div>This page is plain HTML in the <code>public</code> directory.</div>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/ru/components/ModalDemo.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nconst showModal = ref(false)\n</script>\n\n<template>\n  <button class=\"modal-button\" @click=\"showModal = true\">\n    Показать модальное окно\n  </button>\n\n  <Teleport to=\"body\">\n    <Transition name=\"modal\">\n      <div v-show=\"showModal\" class=\"modal-mask\">\n        <div class=\"modal-container\">\n          <p>Привет из модального окна!</p>\n          <div class=\"model-footer\">\n            <button class=\"modal-button\" @click=\"showModal = false\">\n              Закрыть\n            </button>\n          </div>\n        </div>\n      </div>\n    </Transition>\n  </Teleport>\n</template>\n\n<style scoped>\n.modal-mask {\n  position: fixed;\n  z-index: 200;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  transition: opacity 0.3s ease;\n}\n\n.modal-container {\n  width: 300px;\n  margin: auto;\n  padding: 20px 30px;\n  background-color: var(--vp-c-bg);\n  border-radius: 2px;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);\n  transition: all 0.3s ease;\n}\n\n.model-footer {\n  margin-top: 8px;\n  text-align: right;\n}\n\n.modal-button {\n  padding: 4px 8px;\n  border-radius: 4px;\n  border-color: var(--vp-button-alt-border);\n  color: var(--vp-button-alt-text);\n  background-color: var(--vp-button-alt-bg);\n}\n\n.modal-button:hover {\n  border-color: var(--vp-button-alt-hover-border);\n  color: var(--vp-button-alt-hover-text);\n  background-color: var(--vp-button-alt-hover-bg);\n}\n\n.modal-enter-from,\n.modal-leave-to {\n  opacity: 0;\n}\n\n.modal-enter-from .modal-container,\n.modal-leave-to .modal-container {\n  transform: scale(1.1);\n}\n</style>\n"
  },
  {
    "path": "docs/ru/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: 'Генератор статических сайтов на основе Vite и Vue.',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/ru/guide/': { base: '/ru/guide/', items: sidebarGuide() },\n      '/ru/reference/': { base: '/ru/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Редактировать страницу'\n    },\n\n    footer: {\n      message: 'Опубликовано под лицензией MIT.',\n      copyright: '© 2019 – настоящее время, Эван Ю'\n    },\n\n    outline: { label: 'Содержание страницы' },\n\n    docFooter: {\n      prev: 'Предыдущая страница',\n      next: 'Следующая страница'\n    },\n\n    lastUpdated: {\n      text: 'Обновлено'\n    },\n\n    notFound: {\n      title: 'СТРАНИЦА НЕ НАЙДЕНА',\n      quote:\n        'Но если ты не изменишь направление и продолжишь искать, ты можешь оказаться там, куда направляешься.',\n      linkLabel: 'перейти на главную',\n      linkText: 'Отведи меня домой'\n    },\n\n    darkModeSwitchLabel: 'Оформление',\n    lightModeSwitchTitle: 'Переключить на светлую тему',\n    darkModeSwitchTitle: 'Переключить на тёмную тему',\n    sidebarMenuLabel: 'Меню',\n    returnToTopLabel: 'Вернуться к началу',\n    langMenuLabel: 'Изменить язык',\n    skipToContentLabel: 'Перейти к содержимому'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: 'Руководство',\n      link: '/ru/guide/what-is-vitepress',\n      activeMatch: '/ru/guide/'\n    },\n    {\n      text: 'Справочник',\n      link: '/ru/reference/site-config',\n      activeMatch: '/ru/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/ru/'\n        },\n        {\n          text: 'Изменения',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: 'Вклад',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Введение',\n      collapsed: false,\n      items: [\n        { text: 'Что такое VitePress?', link: 'what-is-vitepress' },\n        { text: 'Первые шаги', link: 'getting-started' },\n        { text: 'Маршрутизация', link: 'routing' },\n        { text: 'Развёртывание', link: 'deploy' }\n      ]\n    },\n    {\n      text: 'Написание',\n      collapsed: false,\n      items: [\n        { text: 'Расширения Markdown', link: 'markdown' },\n        { text: 'Обработка ресурсов', link: 'asset-handling' },\n        { text: 'Метаданные', link: 'frontmatter' },\n        { text: 'Использование Vue в Markdown', link: 'using-vue' },\n        { text: 'Интернационализация', link: 'i18n' }\n      ]\n    },\n    {\n      text: 'Настройка',\n      collapsed: false,\n      items: [\n        { text: 'Пользовательская тема', link: 'custom-theme' },\n        {\n          text: 'Расширение темы по умолчанию',\n          link: 'extending-default-theme'\n        },\n        {\n          text: 'Загрузка данных в режиме реального времени',\n          link: 'data-loading'\n        },\n        { text: 'Совместимость с SSR', link: 'ssr-compat' },\n        { text: 'Подключение к CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: 'Экспериментально',\n      collapsed: false,\n      items: [\n        { text: 'Режим MPA', link: 'mpa-mode' },\n        { text: 'Генерация карты сайта', link: 'sitemap-generation' }\n      ]\n    },\n    { text: 'Конфигурация и API', base: '/ru/reference/', link: 'site-config' }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: 'Справочник',\n      items: [\n        { text: 'Конфигурация сайта', link: 'site-config' },\n        { text: 'Конфигурация метаданных', link: 'frontmatter-config' },\n        { text: 'Runtime API', link: 'runtime-api' },\n        { text: 'Командная строка', link: 'cli' },\n        {\n          text: 'Тема по умолчанию',\n          base: '/ru/reference/default-theme-',\n          items: [\n            { text: 'Обзор', link: 'config' },\n            { text: 'Навигация', link: 'nav' },\n            { text: 'Сайдбар', link: 'sidebar' },\n            { text: 'Главная страница', link: 'home-page' },\n            { text: 'Футер', link: 'footer' },\n            { text: 'Макет', link: 'layout' },\n            { text: 'Значки', link: 'badge' },\n            { text: 'Страница команды', link: 'team-page' },\n            {\n              text: 'Предыдущая и следующая страницы',\n              link: 'prev-next-links'\n            },\n            { text: 'Ссылка для редактирования', link: 'edit-link' },\n            { text: 'Последнее обновление', link: 'last-updated' },\n            { text: 'Поиск', link: 'search' },\n            { text: 'Carbon Ads (реклама)', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: 'Поиск',\n        buttonAriaLabel: 'Поиск'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: 'Очистить',\n          clearButtonAriaLabel: 'Очистить запрос',\n          closeButtonText: 'Закрыть',\n          closeButtonAriaLabel: 'Закрыть',\n          placeholderText: 'Поиск по документации или задайте вопрос Ask AI',\n          placeholderTextAskAi: 'Задайте другой вопрос...',\n          placeholderTextAskAiStreaming: 'Отвечаю...',\n          searchInputLabel: 'Поиск',\n          backToKeywordSearchButtonText: 'Назад к поиску по ключевым словам',\n          backToKeywordSearchButtonAriaLabel:\n            'Назад к поиску по ключевым словам',\n          newConversationPlaceholder: 'Задайте вопрос',\n          conversationHistoryTitle: 'Моя история разговоров',\n          startNewConversationText: 'Начать новый разговор',\n          viewConversationHistoryText: 'История разговоров',\n          threadDepthErrorPlaceholder: 'Достигнут лимит разговора'\n        },\n        newConversation: {\n          newConversationTitle: 'Чем могу помочь сегодня?',\n          newConversationDescription:\n            'Я ищу по вашей документации, чтобы быстро помочь найти руководства по настройке, детали функций и советы по устранению неполадок.'\n        },\n        footer: {\n          selectText: 'Выбрать',\n          submitQuestionText: 'Отправить вопрос',\n          selectKeyAriaLabel: 'Клавиша Enter',\n          navigateText: 'Навигация',\n          navigateUpKeyAriaLabel: 'Стрелка вверх',\n          navigateDownKeyAriaLabel: 'Стрелка вниз',\n          closeText: 'Закрыть',\n          backToSearchText: 'Назад к поиску',\n          closeKeyAriaLabel: 'Клавиша Escape',\n          poweredByText: 'При поддержке'\n        },\n        errorScreen: {\n          titleText: 'Не удалось получить результаты',\n          helpText: 'Возможно, стоит проверить подключение к сети.'\n        },\n        startScreen: {\n          recentSearchesTitle: 'Недавние',\n          noRecentSearchesText: 'Нет недавних поисков',\n          saveRecentSearchButtonTitle: 'Сохранить этот поиск',\n          removeRecentSearchButtonTitle: 'Удалить этот поиск из истории',\n          favoriteSearchesTitle: 'Избранное',\n          removeFavoriteSearchButtonTitle: 'Удалить этот поиск из избранного',\n          recentConversationsTitle: 'Недавние разговоры',\n          removeRecentConversationButtonTitle:\n            'Удалить этот разговор из истории'\n        },\n        noResultsScreen: {\n          noResultsText: 'Не найдено результатов для',\n          suggestedQueryText: 'Попробуйте поискать',\n          reportMissingResultsText:\n            'Считаете, что по этому запросу должны быть результаты?',\n          reportMissingResultsLinkText: 'Сообщите нам.'\n        },\n        resultsScreen: {\n          askAiPlaceholder: 'Спросить ИИ: ',\n          noResultsAskAiPlaceholder:\n            'Не нашли в документации? Попросите Ask AI помочь: '\n        },\n        askAiScreen: {\n          disclaimerText:\n            'Ответы генерируются ИИ и могут содержать ошибки. Проверьте их.',\n          relatedSourcesText: 'Связанные источники',\n          thinkingText: 'Думаю...',\n          copyButtonText: 'Копировать',\n          copyButtonCopiedText: 'Скопировано!',\n          copyButtonTitle: 'Копировать',\n          likeButtonTitle: 'Нравится',\n          dislikeButtonTitle: 'Не нравится',\n          thanksForFeedbackText: 'Спасибо за отзыв!',\n          preToolCallText: 'Ищу...',\n          duringToolCallText: 'Ищу...',\n          afterToolCallText: 'Искал',\n          stoppedStreamingText: 'Вы остановили этот ответ',\n          errorTitleText: 'Ошибка чата',\n          threadDepthExceededMessage:\n            'Этот разговор закрыт, чтобы сохранить точность ответов.',\n          startNewConversationButtonText: 'Начать новый разговор'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: 'Спросить ИИ',\n            buttonAriaLabel: 'Спросить ИИ'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: 'Спросить ИИ',\n              conversationHistoryTitle: 'Моя история разговоров',\n              newConversationText: 'Начать новый разговор',\n              viewConversationHistoryText: 'История разговоров'\n            },\n            promptForm: {\n              promptPlaceholderText: 'Задайте вопрос',\n              promptAnsweringText: 'Отвечаю...',\n              promptAskAnotherQuestionText: 'Задайте другой вопрос',\n              promptDisclaimerText:\n                'Ответы генерируются ИИ и могут содержать ошибки.',\n              promptLabelText:\n                'Нажмите Enter, чтобы отправить, или Shift+Enter для новой строки.',\n              promptAriaLabelText: 'Ввод запроса'\n            },\n            conversationScreen: {\n              preToolCallText: 'Ищу...',\n              searchingText: 'Ищу...',\n              toolCallResultText: 'Искал',\n              conversationDisclaimer:\n                'Ответы генерируются ИИ и могут содержать ошибки. Проверьте их.',\n              reasoningText: 'Рассуждаю...',\n              thinkingText: 'Думаю...',\n              relatedSourcesText: 'Связанные источники',\n              stoppedStreamingText: 'Вы остановили этот ответ',\n              copyButtonText: 'Копировать',\n              copyButtonCopiedText: 'Скопировано!',\n              likeButtonTitle: 'Нравится',\n              dislikeButtonTitle: 'Не нравится',\n              thanksForFeedbackText: 'Спасибо за отзыв!',\n              errorTitleText: 'Ошибка чата'\n            },\n            newConversationScreen: {\n              titleText: 'Чем могу помочь сегодня?',\n              introductionText:\n                'Я ищу по вашей документации, чтобы быстро помочь найти руководства по настройке, детали функций и советы по устранению неполадок.'\n            },\n            logo: {\n              poweredByText: 'При поддержке'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/ru/guide/asset-handling.md",
    "content": "# Обработка ресурсов {#asset-handling}\n\n## Ссылки на статические ресурсы {#referencing-static-assets}\n\nВсе файлы Markdown компилируются в компоненты Vue и обрабатываются [Vite](https://vitejs.dev/guide/assets.html). Вы можете, **и должны**, ссылаться на любые ресурсы, используя относительные URL:\n\n```md\n![Изображение](./image.png)\n```\n\nВы можете ссылаться на статические ресурсы в ваших файлах разметки, ваших компонентах `*.vue` в теме, стилях и обычных файлах `.css`, используя абсолютные пути (основанные на корне проекта) или относительные пути (основанные на вашей файловой системе). Последнее похоже на поведение, к которому вы привыкли, если использовали Vite, Vue CLI или `file-loader` в webpack.\n\nРаспространённые типы файлов изображений, мультимедиа и шрифтов определяются и включаются в качестве ресурсов автоматически.\n\n::: tip Связанные файлы не рассматриваются как ресурсы\nPDF-файлы или другие документы, на которые есть ссылки в файлах с разметкой, не рассматриваются автоматически как ресурсы. Чтобы сделать связанные файлы доступными, вы должны вручную поместить их в каталог [`public`](#the-public-directory) вашего проекта.\n:::\n\nВсе ссылающиеся ресурсы, включая те, которые используют абсолютные пути, будут скопированы в выходной каталог с хэшированным именем файла в производственной сборке. Ресурсы, на которые никогда не ссылались, не будут скопированы. Изображения размером менее 4 КБ будут вставляться в формате base64 — это можно настроить с помощью опции конфигурации [`vite`](../reference/site-config#vite).\n\nВсе **статические** ссылки на пути, включая абсолютные пути, должны быть основаны на структуре ваших рабочих каталогов.\n\n## Директория `public` {#the-public-directory}\n\nИногда вам может понадобиться предоставить статические ресурсы, на которые нет прямых ссылок ни в одном из компонентов Markdown или темы, или вы можете захотеть предоставить определённые файлы с оригинальным именем. Примерами таких файлов являются `robots.txt`, `favicon.ico` и иконки PWA.\n\nВы можете поместить эти файлы в директорию `public` в [директории с исходными файлами](./routing#source-directory). Например, если корень вашего проекта — `./docs`, и вы используете стандартное расположение исходного каталога, то ваш публичный каталог будет `./docs/public`.\n\nРесурсы, размещённые в `public`, будут скопированы в корень выходного каталога как есть.\n\nОбратите внимание, что вы должны ссылаться на файлы, размещённые в `public`, используя корневой абсолютный путь — например, `public/icon.png` всегда должен упоминаться в исходном коде как `/icon.png`.\n\n## Базовый URL {#base-url}\n\nЕсли ваш сайт развёрнут на URL-адресе, не являющемся корневым, вам нужно установить параметр `base` в файле `.vitepress/config.js`. Например, если вы планируете развернуть свой сайт на `https://foo.github.io/bar/`, то параметр `base` следует установить на `'/bar/'` (он всегда должен начинаться и заканчиваться слэшем).\n\nВсе пути к статическим ресурсам автоматически обрабатываются с учётом различных значений конфигурации `base`. Например, если в вашей разметке есть абсолютная ссылка на ресурс в директории `public`:\n\n```md\n![Изображение](/image-inside-public.png)\n```\n\nВ этом случае вам **не** нужно обновлять его при изменении значения конфигурации `base`.\n\nОднако если вы создаете компонент темы, который динамически ссылается на активы, например, изображение, атрибут `src` которого основан на значении конфигурации темы:\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\nВ этом случае рекомендуется обернуть путь с помощью [хелпера `withBase`](../reference/runtime-api#withbase), предоставляемого VitePress:\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/ru/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# Подключение к CMS {#connecting-to-a-cms}\n\n## Общий рабочий процесс {#general-workflow}\n\nПодключение VitePress к CMS в значительной степени зависит от [динамических маршрутов](./routing#dynamic-routes). Прежде чем приступить к работе, убедитесь, что вы понимаете, как это работает.\n\nПоскольку каждая CMS работает по-своему, здесь мы можем предоставить лишь общую схему работы, которую вам нужно будет адаптировать под свой конкретный сценарий.\n\n1. Если ваша CMS требует аутентификации, создайте файл `.env` для хранения токенов API и загрузите его таким образом:\n\n   ```js\n   // posts/[id].paths.js\n   import { loadEnv } from 'vitepress'\n\n   const env = loadEnv('', process.cwd())\n   ```\n\n2. Получите необходимые данные из CMS и преобразуйте их в соответствующие пути:\n\n   ```js\n   export default {\n     async paths() {\n       // при необходимости используйте соответствующую клиентскую библиотеку CMS\n       const data = await (\n         await fetch('https://my-cms-api', {\n           headers: {\n             // токен, если необходимо\n           }\n         })\n       ).json()\n\n       return data.map((entry) => {\n         return {\n           params: { id: entry.id /* заголовок, автор, дата и т. д. */ },\n           content: entry.content\n         }\n       })\n     }\n   }\n   ```\n\n3. Отрисуйте содержимое страницы:\n\n   ```md\n   # {{ $params.title }}\n\n   - Автор: {{ $params.author }}, {{ $params.date }}\n\n   <!-- @content -->\n   ```\n\n## Руководства по интеграции {#integration-guides}\n\nЕсли вы написали руководство по интеграции VitePress с конкретной CMS, воспользуйтесь ссылкой «Редактировать эту страницу», чтобы добавить его сюда!\n"
  },
  {
    "path": "docs/ru/guide/custom-theme.md",
    "content": "# Пользовательская тема {#using-a-custom-theme}\n\n## Разрешение темы {#theme-resolving}\n\nВы можете включить пользовательскую тему, создав файл `.vitepress/theme/index.js` или `.vitepress/theme/index.ts` («файл входа темы»):\n\n```\n.\n├─ docs                # корень проекта\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # файл входа темы\n│  │  └─ config.js     # файл конфигурации\n│  └─ index.md\n└─ package.json\n```\n\nVitePress всегда будет использовать пользовательскую тему вместо темы по умолчанию, если обнаружит наличие входного файла темы. Однако вы можете [расширить тему по умолчанию](./extending-default-theme), чтобы выполнить расширенные настройки поверх нее.\n\n## Интерфейс темы {#theme-interface}\n\nПользовательская тема VitePress определяется как объект со следующим интерфейсом:\n\n```ts\ninterface Theme {\n  /**\n   * Корневой компонент макета для каждой страницы\n   * @required\n   */\n  Layout: Component\n  /**\n   * Улучшение экземпляра приложения Vue\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * Расширяем другую тему, вызывая её `enhanceApp` перед нашей\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // Экземпляр приложения Vue\n  router: Router // Экземпляр маршрутизатора VitePress\n  siteData: Ref<SiteData> // Метаданные на уровне сайта\n}\n```\n\nФайл входа темы должен экспортировать тему по умолчанию:\n\n```js [.vitepress/theme/index.js]\n\n// Вы можете напрямую импортировать файлы Vue в файле входа темы.\n// VitePress предварительно настроен с помощью @vitejs/plugin-vue.\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\nЭкспорт по умолчанию является единственным контрактом для пользовательской темы, и только свойство `Layout` является обязательным. Таким образом, технически тема VitePress может быть простой, как один компонент Vue.\n\nВнутри компонент макета работает так же, как и обычное приложение Vite + Vue 3. Обратите внимание, что тема также должна быть [SSR-совместимой](./ssr-compat).\n\n## Создание макета {#building-a-layout}\n\nСамый базовый компонент макета должен содержать компонент [`<Content />`](../reference/runtime-api#content):\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Пользовательский макет!</h1>\n\n  <!-- здесь будет отображаться содержимое в формате Markdown -->\n  <Content />\n</template>\n```\n\nПриведённая выше схема просто отображает разметку каждой страницы в виде HTML. Добавим обработку 404 ошибки в качестве первого улучшения:\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Пользовательский макет!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Пользовательская страница 404!\n  </div>\n  <Content v-else />\n</template>\n```\n\nХелпер [`useData()`](../reference/runtime-api#usedata) предоставляет нам все данные во время выполнения, необходимые для условной отрисовки различных макетов. Среди различных данных, к которым мы можем получить доступ, являются метаданные текущей страницы. Мы можем использовать это, чтобы позволить конечному пользователю управлять макетом на каждой странице. Например, пользователь может указать, что страница должна использовать специальный макет главной страницы:\n\n```md\n---\nlayout: home\n---\n```\n\nИ мы можем настроить нашу тему, чтобы справиться с этим:\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Пользовательский макет!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Пользовательская страница 404!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Пользовательская домашняя страница!\n  </div>\n  <Content v-else />\n</template>\n```\n\nКонечно, вы можете разделить макет на большее количество компонентов:\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Пользовательский макет!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> рендерит <Content /> -->\n</template>\n```\n\nОбратитесь к [Справочнику Runtime API](../reference/runtime-api), чтобы узнать обо всём, что доступно в компонентах темы. Кроме того, вы можете использовать [загрузку данных в режиме реального времени](./data-loading) для создания макета, управляемого данными — например, страницы со списком всех записей в блоге текущего проекта.\n\n## Распространение пользовательской темы {#distributing-a-custom-theme}\n\nСамый простой способ распространить пользовательскую тему — предоставить её в виде [репозитория шаблонов на GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository).\n\nЕсли вы хотите распространить тему в виде пакета npm, выполните следующие действия:\n\n1. Экспортируйте объект темы в качестве экспорта по умолчанию в записи пакета.\n\n2. Если есть возможность, экспортируйте определение типа конфигурации темы как `ThemeConfig`.\n\n3. Если ваша тема требует настройки конфигурации VitePress, экспортируйте эту конфигурацию в подпапку пакета (например. `my-theme/config`), чтобы пользователь мог расширить её.\n\n4. Документируйте параметры конфигурации темы (как через файл конфигурации, так и через метаданные).\n\n5. Предоставьте чёткие инструкции по использованию вашей темы (см. ниже).\n\n## Использование пользовательской темы {#consuming-a-custom-theme}\n\nЧтобы использовать внешнюю тему, импортируйте и реэкспортируйте её из элемента пользовательской темы:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\nЕсли тема требует расширения:\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\nЕсли тема требует специальных настроек VitePress, вам нужно будет также расширить их в своем собственном конфиге:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // расширить базовый конфиг темы (если необходимо)\n  extends: baseConfig\n}\n```\n\nНаконец, если тема предоставляет типы для своего конфига темы:\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // Тип `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/ru/guide/data-loading.md",
    "content": "# Загрузка данных в режиме реального времени {#build-time-data-loading}\n\nVitePress предоставляет функцию **загрузчиков данных**, которая позволяет загружать произвольные данные и импортировать их со страниц или компонентов. Загрузка данных выполняется **только во время сборки**: Полученные данные будут сериализованы в виде JSON в финальной сборке JavaScript.\n\nЗагрузчики данных могут использоваться для получения удалённых данных или генерирования метаданных на основе локальных файлов. Например, вы можете использовать загрузчики данных для анализа всех локальных страниц API и автоматического создания индекса всех записей API.\n\n## Пример использования {#basic-usage}\n\nФайл загрузчика данных должен заканчиваться либо `.data.js`, либо `.data.ts`. Файл должен предоставлять экспорт объекта по умолчанию с помощью метода `load()`:\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'мир'\n    }\n  }\n}\n```\n\nМодуль загрузчика выполняется только в Node.js, поэтому вы можете импортировать любые API Node и зависимости npm по мере необходимости.\n\nЗатем вы можете импортировать данные из этого файла в страницы `.md` и компоненты `.vue` с помощью экспорта с именем `data`:\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\nРезультат:\n\n```json\n{\n  \"hello\": \"мир\"\n}\n```\n\nВы заметите, что сам загрузчик данных не экспортирует `data`. Это VitePress вызывает метод `load()` за кулисами и неявно раскрывает результат через именованный экспорт `data`.\n\nЭто работает, даже если загрузчик асинхронный:\n\n```js\nexport default {\n  async load() {\n    // получение удалённых данных\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## Данные из локальных файлов {#data-from-local-files}\n\nЕсли вам нужно генерировать данные на основе локальных файлов, используйте опцию `watch` в загрузчике данных, чтобы изменения, внесённые в эти файлы, вызывали горячие обновления.\n\nОпция `watch` удобна ещё и тем, что вы можете использовать [шаблоны glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) для соответствия нескольким файлам. Шаблоны могут быть относительными к самому файлу загрузчика, а функция `load()` будет получать совпадающие файлы в виде абсолютных путей.\n\nВ следующем примере показана загрузка CSV-файлов и их преобразование в JSON с помощью [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/). Поскольку этот файл выполняется только во время сборки, вы не будете передавать CSV-парсер клиенту!\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchedFiles будет представлять собой массив абсолютных путей к найденным файлам.\n    // Формируем массив метаданных записи блога, которые можно использовать для визуализации списка в макете темы\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader` {#createcontentloader}\n\nПри создании сайта, ориентированного на контент, нам часто приходится создавать страницы типа «архив», или «индекс», на которых мы перечисляем все доступные записи в нашей коллекции контента. Например, записи в блоге или страницы API. Мы **можем** реализовать это напрямую с помощью API загрузчика данных, но поскольку это очень распространённый случай использования, VitePress также предоставляет функцию `createContentLoader`, чтобы упростить эту задачу:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md' /* параметры */)\n```\n\nЭта функция принимает шаблон glob относительно [исходного каталога](./routing#source-directory) и возвращает объект `{ watch, load }` загрузчика данных, который может быть использован в качестве экспорта по умолчанию в файле загрузчика данных. В нем также реализовано кэширование на основе временных меток изменения файлов для повышения производительности dev.\n\nОбратите внимание, что загрузчик работает только с файлами Markdown — совпадающие файлы, не относящиеся к Markdown, будут пропущены.\n\nЗагруженные данные будут представлять собой массив с типом `ContentData[]`:\n\n```ts\ninterface ContentData {\n  // отображаемый URL-адрес страницы, например: /posts/hello.html (не включает `base`)\n  // выполните итерацию вручную или используйте пользовательскую `трансформацию` для нормализации путей\n  url: string\n  // метаданные страницы\n  frontmatter: Record<string, any>\n\n  // следующие параметры присутствуют только в том случае, если соответствующие опции включены\n  // мы рассмотрим их ниже\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\nПо умолчанию указываются только `url` и `frontmatter`. Это связано с тем, что загруженные данные будут вложены в клиентский пакет в виде JSON, поэтому нам нужно быть осторожными с их размером. Вот пример использования этих данных для создания минимальной индексной страницы блога:\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>Все записи блога</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>by {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### Параметры {#options}\n\nДанные по умолчанию могут не соответствовать всем требованиям — вы можете изменить данные с помощью параметров:\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // включить исходный текст в формате Markdown?\n  render: true, // включать в себя полный HTML страницы?\n  excerpt: true, // включить отрывок?\n  transform(rawData) {\n    // составляйте карты, сортируйте или фильтруйте исходные данные по своему усмотрению.\n    // конечный результат — это то, что будет отправлено клиенту.\n    return rawData\n      .sort((a, b) => {\n        return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n      })\n      .map((page) => {\n        page.src // исходный текст в формате Markdown\n        page.html // отображение полной страницы HTML\n        page.excerpt // отображаемый отрывок HTML (содержимое выше первого `---`)\n        return {\n          /* ... */\n        }\n      })\n  }\n})\n```\n\nПосмотрите, как он используется в [блоге Vue.js](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts).\n\nAPI `createContentLoader` также можно использовать внутри [хуков сборки](../reference/site-config#build-hooks):\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // генерируем файлы на основе метаданных сообщений, например, RSS-канал\n  }\n}\n```\n\n**Типы**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * Включаем src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * Преобразовываем src в HTML и включаем в данные?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * Если `boolean`, то следует ли разбирать и включать отрывок? (отображается как HTML)\n   *\n   * Если `function`, то управляйте тем, как отрывок извлекается из содержимого.\n   *\n   * Если `string`, определите пользовательский разделитель, который будет использоваться для извлечения\n   * отрывка. Разделителем по умолчанию является `---`, если `excerpt` имеет значение `true`.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((\n        file: {\n          data: { [key: string]: any }\n          content: string\n          excerpt?: string\n        },\n        options?: any\n      ) => void)\n    | string\n\n  /**\n   * Преобразуйте данные. Обратите внимание, что при импорте из компонентов или файлов\n   * с разметкой данные будут вложены в клиентский пакет в виде JSON.\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## Загрузчики типизированных данных {#typed-data-loaders}\n\nПри использовании TypeScript можно ввести свой загрузчик и экспортировать `data` следующим образом:\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // тип данных\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // тип проверенных опций загрузчика\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## Конфигурация {#configuration}\n\nЧтобы получить информацию о конфигурации внутри загрузчика, вы можете использовать код, подобный этому:\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/ru/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# Развёртывание вашего сайта VitePress {#deploy-your-vitepress-site}\n\nСледующие инструкции основаны на некоторых общих предположениях:\n\n- Сайт VitePress находится в директории `docs` вашего проекта.\n- Вы используете выходной каталог сборки по умолчанию (`.vitepress/dist`).\n- VitePress установлен как локальная зависимость в вашем проекте, и вы установили следующие скрипты в вашем `package.json`:\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## Сборка и локальное тестирование {#build-and-test-locally}\n\n1. Выполните эту команду, чтобы собрать документацию:\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. После сборки просмотрите её локально, запустив команду:\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   Команда `preview` загрузит локальный статический веб-сервер, который будет обслуживать выходной каталог `.vitepress/dist` по адресу `http://localhost:4173`. Вы можете использовать его для теста, чтобы убедиться, что всё выглядит хорошо, прежде чем отправлять в производство.\n\n3. Можно указать порт сервера, передав `--port` в качестве аргумента.\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   Теперь метод `docs:preview` запустит сервер по адресу `http://localhost:8080`.\n\n## Установка публичного базового пути {#setting-a-public-base-path}\n\nПо умолчанию предполагается, что сайт будет развёрнут по корневому пути домена (`/`). Если ваш сайт будет обслуживаться по подпути, например, `https://mywebsite.com/blog/`, то в конфигурации VitePress необходимо установить для опции [`base`](../reference/site-config#base) значение `'/blog/'`.\n\n**Пример:** Если вы используете Github (или GitLab) Pages и развёртываете на `user.github.io/repo/`, то установите `base` на `/repo/`.\n\n## Заголовки кэша HTTP {#http-cache-headers}\n\nЕсли вы контролируете HTTP-заголовки на своем рабочем сервере, можно настроить заголовки `cache-control` для достижения лучшей производительности при повторных посещениях.\n\nВ производственной сборке используются хэшированные имена файлов для статических ресурсов (JavaScript, CSS и другие импортированные ресурсы, не находящиеся в `public`). Если вы просмотрите предварительную версию с помощью вкладки «Network» («Сеть») инструментов разработчика вашего браузера, вы увидите файлы типа `app.4f283b18.js`.\n\nЭтот хэш `4f283b18` генерируется из содержимого этого файла. Один и тот же хэшированный URL гарантированно обслуживает одно и то же содержимое файла — если содержимое меняется, то и URL тоже. Это означает, что можно смело использовать самые сильные настройки кэширования для этих файлов. Все такие файлы будут помещены в каталог `assets/` в выходном каталоге, поэтому вы можете настроить для них следующий заголовок:\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Пример файла Netlify `_headers`\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\nПримечание: файл `_headers` должен быть помещён в [директорию `public`](./asset-handling#the-public-directory) — в нашем случае `docs/public/_headers` — так, чтобы он был скопирован в выходной каталог.\n\n[Netlify custom headers documentation](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details Пример конфигурации Vercel в файле `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nПримечание: Файл `vercel.json` должен быть помещен в корень вашего **репозитория**.\n\n[Документация Vercel по конфигурации заголовков](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## Руководства по платформам {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\nСоздайте новый проект и измените эти настройки с помощью панели управления:\n\n- **Build Command:** `npm run docs:build`\n- **Output Directory:** `docs/.vitepress/dist`\n- **Node Version:** `20` (или выше)\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nНе включайте такие опции, как _Auto Minify_ для HTML-кода. Он удалит из вывода комментарии, которые имеют значение для Vue. При их удалении могут возникать ошибки несоответствия гидратации.\n:::\n\n### GitHub Pages\n\n1. Создайте файл с именем `deploy.yml` в директории `.github/workflows` вашего проекта с примерно таким содержанием:\n\n   ```yaml [.github/workflows/deploy.yml]\n   # Пример рабочего процесса для создания и развёртывания сайта VitePress на GitHub Pages\n   #\n   name: Deploy VitePress site to Pages\n\n   on:\n     # Выполняется при пушах, направленных в ветку `main`. Измените это значение на `master`, если вы\n     # используете ветку `master` в качестве ветки по умолчанию.\n     push:\n       branches: [main]\n\n     # Позволяет запустить этот рабочий процесс вручную на вкладке «Actions».\n     workflow_dispatch:\n\n   # Устанавливает разрешения GITHUB_TOKEN, чтобы разрешить развёртывание на страницах GitHub.\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # Разрешите только одно одновременное развёртывание, пропуская запуски, стоящие в очереди.\n   # Однако НЕ отменяйте текущие запуски, поскольку мы хотим дать возможность завершить производственные развёртывания.\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # Сборка\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # Не требуется, если функция lastUpdated не включена\n         # - uses: pnpm/action-setup@v4 # Раскомментируйте, если вы используете pnpm\n         #   with:\n         #     version: 9\n         # - uses: oven-sh/setup-bun@v1 # Раскомментируйте, если вы используете Bun\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # или pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # или pnpm install / yarn install / bun install\n         - name: Build with VitePress\n           run: npm run docs:build # или pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # Развёртывание\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning ПРЕДУПРЕЖДЕНИЕ\n   Убедитесь, что опция `base` в вашем VitePress настроена правильно. Дополнительные сведения см. в секции [Установка публичного базового пути](#setting-a-public-base-path).\n   :::\n\n2. В настройках вашего репозитория в разделе «Pages» выберите пункт меню «GitHub Actions» в секции «Build and deployment > Source».\n\n3. Внесите свои изменения в ветку `main` и дождитесь завершения процесса GitHub Actions. Вы должны увидеть, что ваш сайт развёрнут по адресу `https://<username>.github.io/[repository]/` или `https://<custom-domain>/` в зависимости от ваших настроек. Ваш сайт будет автоматически разворачиваться при каждом внесении изменений в ветке `main`.\n\n### GitLab Pages\n\n1. Установите значение `../public` для параметра `outDir` в конфигурации VitePress. Настройте опцию `base` на `'/<репозиторий>/'`, если вы хотите развернуть ваш проект по адресу `https://<имя пользователя>.gitlab.io/<репозиторий>/`. Вам не нужна опция `base`, если вы выполняете развёртывание на личном домене, страницах пользователя или группы, или если в GitLab включен параметр «Использовать уникальный домен».\n\n2. Создайте файл с именем `.gitlab-ci.yml` в корне вашего проекта с приведённым ниже содержимым. Это позволит создавать и развёртывать ваш сайт каждый раз, когда вы вносите изменения в его содержимое:\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # Отметьте это, если вы используете небольшие докер-образы, такие как alpine, и у вас включен lastUpdated\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. Следуйте [официальной документации](https://docs.microsoft.com/ru-ru/azure/static-web-apps/build-configuration).\n\n2. Установите эти значения в вашем конфигурационном файле (и удалите те, которые вам не нужны, например, `api_location`):\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\nВы можете развернуть свой проект VitePress с [CloudRay](https://cloudray.io/), следуя этим [инструкциям](https://cloudray.io/articles/how-to-deploy-vitepress-site).\n\n### Firebase\n\n1. Создайте `firebase.json` и `.firebaserc` в корне вашего проекта:\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. После запуска `npm run docs:build` выполните эту команду для развёртывания:\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. Следуйте документации и руководству, приведённому в [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static).\n\n2. Создайте файл `static.json` в корне вашего проекта со следующим содержимым:\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\nВы можете развернуть свой проект VitePress на [Hostinger](https://www.hostinger.com/web-apps-hosting), следуя этим [инструкциям](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/). При настройке параметров сборки выберите VitePress в качестве фреймворка и укажите корневой каталог `./docs`.\n\n### Kinsta\n\nВы можете развернуть свой сайт VitePress на [Kinsta](https://kinsta.com/static-site-hosting/), следуя этим [инструкциям](https://kinsta.com/docs/vitepress-static-site-example/).\n\n### Stormkit\n\nВы можете развернуть свой проект VitePress на [Stormkit](https://www.stormkit.io), следуя следующим [инструкциям](https://stormkit.io/blog/how-to-deploy-vitepress).\n\n### Surge\n\n1. После запуска `npm run docs:build` выполните эту команду для развёртывания:\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\nВот пример конфигурации блока сервера Nginx. Эта настройка включает сжатие gzip для общих текстовых ресурсов, правила обслуживания статических файлов вашего сайта VitePress с правильными заголовками кэширования и обработку параметра `cleanUrls: true`.\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # расположение контента\n        root /app;\n\n        # точные совпадения -> обратные чистые URL-адреса -> папки -> не найдены\n        try_files $uri $uri.html $uri/ =404;\n\n        # несуществующие страницы\n        error_page 404 /404.html;\n\n        # папка без index.html вызывает ошибку 403 в этой настройке\n        error_page 403 /404.html;\n\n        # настройка заголовков кэширования\n        # файлы в папке с ресурсами имеют хэши имён файлов\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\nЭта конфигурация предполагает, что ваш собранный сайт VitePress находится в директории `/app`. При необходимости измените директиву `root`, если файлы вашего сайта расположены в другом месте.\n\n::: warning Не используйте index.html по умолчанию\nРазрешение try_files не должно использовать index.html, как это делается в других приложениях Vue. Это может привести к недопустимому состоянию страницы.\n:::\n\nДополнительную информацию можно найти в официальной документации [Nginx](https://nginx.org/ru/docs/), а также в следующих обсуждениях: [#2837](https://github.com/vuejs/vitepress/discussions/2837), [#3235](https://github.com/vuejs/vitepress/issues/3235), а также в [блоге Mehdi Merah](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings).\n"
  },
  {
    "path": "docs/ru/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# Расширение темы по умолчанию {#extending-the-default-theme}\n\nТема VitePress по умолчанию оптимизирована для документации и может быть настроена по вашему усмотрению. Полный список опций можно найти в главе [Настройки темы по умолчанию](../reference/default-theme-config).\n\nОднако есть ряд случаев, когда одной лишь конфигурации будет недостаточно. Например:\n\n1. Вам нужно изменить стили CSS;\n2. Вам нужно изменить экземпляр приложения Vue, например, чтобы зарегистрировать глобальные компоненты;\n3. Вам нужно внедрить пользовательский контент в тему через слоты макета.\n\nЭти расширенные настройки потребуют использования пользовательской темы, которая «расширяет» тему по умолчанию.\n\n::: tip СОВЕТ\nПрежде чем приступить к работе, обязательно прочитайте главу [Пользовательская тема](./custom-theme), чтобы понять, как работают пользовательские темы.\n:::\n\n## Настройка CSS {#customizing-css}\n\nCSS темы по умолчанию можно настроить, переопределив переменные CSS корневого уровня:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\nСм. [переменные CSS темы по умолчанию](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css), которые можно переопределить.\n\n## Использование различных шрифтов {#using-different-fonts}\n\nVitePress использует [Inter](https://rsms.me/inter/) в качестве шрифта по умолчанию, и будет включать шрифты в вывод сборки. Шрифт также автоматически загружается в производство. Однако это может быть нежелательно, если вы хотите использовать другой основной шрифт.\n\nЧтобы не включать Inter в вывод сборки, импортируйте тему из `vitepress/theme-without-fonts`:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* normal text font */ --vp-font-family-mono:\n    /* code font */;\n}\n```\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nЕсли вы используете дополнительные компоненты, такие как [Страница команды](../reference/default-theme-team-page), убедитесь, что они также импортированы из `vitepress/theme-without-fonts`!\n:::\n\nЕсли ваш шрифт — это локальный файл, на который ссылаются через `@font-face`, он будет обработан как ресурс и включён в каталог `.vitepress/dist/assets` с хэшированным именем файла. Чтобы предварительно загрузить этот файл, используйте хук сборки [transformHead](../reference/site-config#transformhead):\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // настраиваем regex соответствующим образом, чтобы он соответствовал вашему шрифту\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## Регистрация глобальных компонентов {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // регистрируем пользовательские глобальные компоненты\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\nЕсли вы используете TypeScript:\n\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // регистрируем пользовательские глобальные компоненты\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\nПоскольку мы используем Vite, можно применять [глобальную функцию импорта](https://vitejs.dev/guide/features.html#glob-import) Vite для автоматической регистрации каталога компонентов.\n\n## Слоты макета {#layout-slots}\n\nКомпонент `<Layout/>` темы по умолчанию имеет несколько слотов, которые можно использовать для вставки содержимого в определённые места страницы. Вот пример внедрения компонента перед оглавлением:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // переопределяем макет с помощью компонента-обёртки,\n  // который внедряет слоты\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      Мой пользовательский контент в верхней части боковой панели\n    </template>\n  </Layout>\n</template>\n```\n\nТакже можно использовать функцию рендеринга.\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\nПолный список слотов, доступных в макете темы по умолчанию:\n\n- Когда `layout: 'doc'` (по умолчанию) включен через метаданные:\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- Когда `layout: 'home'` включен через метаданные:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- Когда `layout: 'page'` включен через метаданные:\n  - `page-top`\n  - `page-bottom`\n- На странице «Не найдено (404)»:\n  - `not-found`\n- Всегда:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## Использование View Transitions API {#using-view-transitions-api}\n\n### Переключение внешнего вида {#on-appearance-toggle}\n\nВы можете расширить стандартную тему, чтобы обеспечить пользовательский переход при переключении цветового режима. Пример:\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\nРезультат (**предупреждение!**: мигающие цвета, резкие движения, яркий свет):\n\n<details>\n<summary>Демонстрация</summary>\n\n![Демонстрация переходов](/appearance-toggle-transition.webp)\n\n</details>\n\nБолее подробно о переходах между представлениями читайте в [документации Chrome](https://developer.chrome.com/docs/web-platform/view-transitions/).\n\n### Изменение маршрута {#on-route-change}\n\nСкоро будет.\n\n## Переопределение внутренних компонентов {#overriding-internal-components}\n\nВы можете использовать [псевдонимы](https://vitejs.dev/config/shared-options.html#resolve-alias) Vite, чтобы заменить стандартные компоненты темы на свои собственные:\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\nЧтобы узнать точное название компонента, обратитесь к [нашему исходному коду](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components). Поскольку компоненты являются внутренними, есть небольшая вероятность того, что их название будет обновлено между минорными выпусками.\n"
  },
  {
    "path": "docs/ru/guide/frontmatter.md",
    "content": "# Метаданные {#frontmatter}\n\n## Использование {#usage}\n\nVitePress поддерживает метаданные YAML во всех Markdown-файлах, разбирая их с помощью [gray-matter](https://github.com/jonschlinkert/gray-matter). Метаданные должны находиться в верхней части Markdown-файла (перед любыми элементами, включая теги `<script>`) и иметь вид корректного YAML, заданного между тройными пунктирными линиями. Пример:\n\n```md\n---\ntitle: Документация с VitePress\neditLink: true\n---\n```\n\nМногие параметры конфигурации сайта или темы по умолчанию имеют соответствующие опции в блоке метаданных. Вы можете использовать метаданные, чтобы переопределить заданное поведение только для текущей страницы. Подробности см. в [Справочнике по настройке метаданных](../reference/frontmatter-config).\n\nВы также можете определить собственные метаданные, которые будут использоваться в динамических выражениях Vue на странице.\n\n## Доступ к метаданным {#accessing-frontmatter-data}\n\nДоступ к метаданным можно получить через специальную глобальную переменную `$frontmatter`:\n\nВот пример того, как можно использовать его в файле Markdown:\n\n```md\n---\ntitle: Документация с VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nСодержание руководства\n```\n\nВы также можете получить доступ к метаданным текущей страницы в `<script setup>` с помощью [хелпера `useData()`](../reference/runtime-api#usedata).\n\n## Альтернативные форматы метаданных {#alternative-frontmatter-formats}\n\nVitePress также поддерживает синтаксис метаданных JSON, начинающийся и заканчивающийся фигурными скобками:\n\n```json\n---\n{\n  \"title\": \"Веду блог как хакер\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/ru/guide/getting-started.md",
    "content": "# Первые шаги {#getting-started}\n\n## Попробуйте онлайн {#try-it-online}\n\nВы можете попробовать VitePress прямо в браузере на [StackBlitz](https://vitepress.new).\n\n## Установка {#installation}\n\n### Требования {#prerequisites}\n\n- [Node.js](https://nodejs.org/) версии 20 или выше.\n- Терминал для доступа к VitePress через интерфейс командной строки (CLI).\n- Текстовый редактор с поддержкой синтаксиса [Markdown](https://ru.wikipedia.org/wiki/Markdown).\n  - Рекомендуется использовать [VSCode](https://code.visualstudio.com/), а также [официальное расширение Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nVitePress можно использовать самостоятельно или установить в существующий проект. В обоих случаях вы можете установить его с помощью:\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip ПРИМЕЧАНИЕ\n\nVitePress — это пакет, предназначенный только для ESM. Не используйте `require()` для импорта, и убедитесь, что ближайший `package.json` содержит `\"type\": \"module\"`, или измените расширение соответствующих файлов, например, `.vitepress/config.js` на `.mjs`/`.mts`. Более подробную информацию см. в [Руководстве по устранению неполадок Vite](https://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only). Кроме того, внутри асинхронных контекстов CJS можно использовать `await import('vitepress')` вместо этого.\n\n:::\n\n### Мастер настройки {#setup-wizard}\n\nVitePress поставляется с мастером настройки командной строки, который поможет вам создать базовый проект. После установки запустите мастер, выполнив команду:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\nВас встретят несколькими простыми вопросами:\n\n<<< @/snippets/init.ansi\n\n::: tip Vue как зависимость\nЕсли вы собираетесь выполнять кастомизацию с использованием компонентов или API Vue, вам также следует явно установить `vue` в качестве зависимости.\n:::\n\n## Структура файлов {#file-structure}\n\nЕсли вы создаете отдельный сайт VitePress, вы можете разместить его в текущей директории (`./`). Однако если вы устанавливаете VitePress в существующий проект вместе с другим исходным кодом, рекомендуется поместить сайт во вложенную директорию (например, `./docs`), чтобы он был отделён от остальной части проекта.\n\nЕсли предположить, что вы решили разместить проект VitePress в `./docs`, то сгенерированная структура файлов должна выглядеть следующим образом:\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\nДиректория `docs` считается **корнем проекта** сайта VitePress. Директория `.vitepress` — это зарезервированное место для конфигурационного файла VitePress, кэша dev-сервера, результатов сборки и дополнительного кода настройки темы.\n\n::: tip СОВЕТ\nПо умолчанию VitePress хранит кэш своего dev-сервера в файле `.vitepress/cache`, а выходные данные сборки — в файле `.vitepress/dist`. Если вы используете Git, вам следует добавить их в файл `.gitignore`. Эти места также могут быть [сконфигурированы](../reference/site-config#outdir).\n:::\n\n### Конфигурационный файл {#the-config-file}\n\nФайл конфигурации (`.vitepress/config.js`) позволяет настраивать различные аспекты сайта VitePress, самыми основными из которых являются название и описание сайта:\n\n```js [.vitepress/config.js]\nexport default {\n  // параметры сайта\n  title: 'Заголовок сайта',\n  description: 'Описание сайта.',\n\n  themeConfig: {\n    // параметры темы\n  }\n}\n```\n\nВы также можете настроить поведение темы с помощью опции `themeConfig`. Загляните в главу [Конфигурация сайта](../reference/site-config) для получения подробной информации обо всех настраиваемых параметрах.\n\n### Исходные файлы {#source-files}\n\nФайлы Markdown за пределами директории `.vitepress` считаются **исходными файлами**.\n\nVitePress использует **маршрутизацию на основе файлов**: Каждый файл `.md` компилируется в соответствующий файл `.html` с тем же путём. Например, `index.md` будет скомпилирован в `index.html`, и его можно будет посетить по корневому пути `/` результирующего сайта VitePress.\n\nVitePress также предоставляет возможность генерировать чистые URL-адреса, переписывать пути и динамически генерировать страницы. Всё это будет рассмотрено в [Руководстве по маршрутизации](./routing).\n\n## Скрипты запуска {#up-and-running}\n\nМастер настройки также должен был внедрить следующие скрипты npm в ваш `package.json`, если вы разрешили ему это сделать в процессе установки:\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\nСкрипт `docs:dev` запустит локальный dev-сервер с мгновенными горячими обновлениями. Выполните следующую команду:\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\nВместо npm-скриптов вы также можете вызывать VitePress напрямую с помощью:\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\nБолее подробная информация об использовании командной строки описана в главе [Командная строка](../reference/cli).\n\nDev-сервер должен быть запущен по адресу `http://localhost:5173`. Перейдите по URL-адресу в браузере, чтобы увидеть новый сайт в действии!\n\n## Что дальше? {#what-s-next}\n\n- Чтобы лучше понять, как Markdown-файлы сопоставляются с генерируемым HTML, перейдите к [Руководству по маршрутизации](./routing).\n\n- Чтобы узнать больше о том, что вы можете делать на странице, например, писать содержимое в формате Markdown или использовать компоненты Vue, обратитесь к разделу «Написание». Начать стоит с изучения главы [Расширения Markdown](./markdown).\n\n- Чтобы изучить возможности, предоставляемые темой документации по умолчанию, ознакомьтесь с главой [Настройка темы по умолчанию](../reference/default-theme-config).\n\n- Если вы хотите ещё больше изменить внешний вид своего сайта, изучите главы [Расширение темы по умолчанию](./extending-default-theme) или [Пользовательская тема](./custom-theme).\n\n- Как только ваш сайт документации обретёт форму, обязательно прочитайте [Руководство по развёртыванию](./deploy).\n"
  },
  {
    "path": "docs/ru/guide/i18n.md",
    "content": "# Интернационализация {#internationalization}\n\nЧтобы использовать встроенные функции i18n, необходимо создать следующую структуру каталогов:\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ ru/\n│  ├─ foo.md\n├─ foo.md\n```\n\nЗатем в `docs/.vitepress/config.ts`:\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // общие свойства и другие вещи верхнего уровня...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    ru: {\n      label: 'Русский',\n      lang: 'ru', // необязательный, будет добавлен как атрибут `lang` в тег `html`\n      link: '/ru/guide' // по умолчанию /ru/ -- ссылка в меню переводов на панели навигации, может быть внешней\n\n      // другие свойства, специфичные для локали...\n    }\n  }\n})\n```\n\nСледующие свойства могут быть переопределены для каждой локали (включая корневую):\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // будут объединены с существующими записями в заголовке, дублирующие метатеги будут автоматически удалены\n  themeConfig?: ThemeConfig // будут неглубоко объединены, общие вещи можно поместить в запись themeConfig верхнего уровня\n}\n```\n\nПодробнее о настройке текстов-заготовок темы по умолчанию см. в интерфейсе [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts). Не переопределяйте `themeConfig.algolia` или `themeConfig.carbonAds` на локальном уровне. Использование многоязычного поиска описано в главе [Поиск Algolia](../reference/default-theme-search#algolia-search-i18n).\n\n**Совет:** Конфигурационный файл можно хранить и в `docs/.vitepress/config/index.ts`. Это может помочь вам организовать работу, создав конфигурационный файл для каждой локали, а затем объединить и экспортировать их из `index.ts`.\n\n## Отдельный каталог для каждой локали {#separate-directory-for-each-locale}\n\nПример многоязычной структуры:\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ ru/\n   ├─ foo.md\n```\n\nОднако по умолчанию VitePress не будет перенаправлять `/` на `/en/`. Для этого вам нужно будет настроить свой сервер. Например, в Netlify вы можете добавить файл `docs/public/_redirects` следующим образом:\n\n```\n/*  /es/:splat  302  Language=es\n/*  /ru/:splat  302  Language=ru\n/*  /en/:splat  302\n```\n\n**Совет:** Если вы используете описанный выше подход, вы можете использовать куки `nf_lang`, чтобы сохранить выбор языка пользователя:\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## Поддержка RTL (экспериментально) {#rtl-support-experimental}\n\nДля поддержки языков с написанием справа налево укажите `dir: 'rtl'` в конфиге и используйте какой-нибудь плагин RTLCSS PostCSS, например <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> или <https://github.com/elchininet/postcss-rtlcss>. Вам нужно настроить плагин PostCSS на использование `:where([dir=\"ltr\"])` и `:where([dir=\"rtl\"])` в качестве префиксов, чтобы избежать проблем со спецификой CSS.\n"
  },
  {
    "path": "docs/ru/guide/markdown.md",
    "content": "# Расширения Markdown {#markdown-extensions}\n\nVitePress поставляется со встроенными расширениями Markdown.\n\n## Якоря заголовков {#header-anchors}\n\nК заголовкам автоматически применяются якорные ссылки. Отрисовку якорей можно настроить с помощью опции `markdown.anchor`.\n\n### Пользовательские якоря {#custom-anchors}\n\nЧтобы указать пользовательский тег якоря для заголовка, а не использовать автоматически сгенерированный, добавьте суффикс к заголовку:\n\n```\n# Использование пользовательских якорей {#мой-якорь}\n```\n\nЭто позволит вам ссылаться на заголовок как `#мой-якорь` вместо стандартного `#использование-пользовательских-якорей`.\n\n## Ссылки {#links}\n\nОсобое внимание уделяется как внутренним, так и внешним ссылкам.\n\n### Внутренние ссылки {#internal-links}\n\nВнутренние ссылки преобразуются в ссылки маршрутизатора для навигации SPA. Кроме того, каждый `index.md`, содержащийся в каждом подкаталоге, будет автоматически преобразован в `index.html`, с соответствующим URL `/`.\n\nНапример, при следующей структуре каталогов:\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nИ при условии, что вы находитесь в `foo/one.md`:\n\n```md\n[Home](/) <!-- отправляет пользователя в корневой index.md -->\n[foo](/foo/) <!-- отправляет пользователя на страницу index.html из каталога foo -->\n[foo heading](./#heading) <!-- привязывает пользователя к заголовку в индексном файле foo -->\n[bar - three](../bar/three) <!-- вы можете опустить расширение -->\n[bar - three](../bar/three.md) <!-- вы можете добавить .md -->\n[bar - four](../bar/four.html) <!-- или вы можете добавить .html -->\n```\n\n### Суффикс страницы {#page-suffix}\n\nСтраницы и внутренние ссылки по умолчанию генерируются с суффиксом `.html`.\n\n### Внешние ссылки {#external-links}\n\nИсходящие ссылки автоматически получают значение `target=\"_blank\" rel=\"noreferrer\"`:\n\n- [vuejs.org](https://vuejs.org)\n- [VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## Метаданные {#frontmatter}\n\n[Метаданные YAML](https://jekyllrb.com/docs/front-matter/) поддерживаются из коробки:\n\n```yaml\n---\ntitle: Веду блог как хакер\nlang: ru-RU\n---\n```\n\nЭти данные будут доступны остальной части страницы, а также всем пользовательским и тематическим компонентам.\n\nБолее подробную информацию можно найти в главе [Метаданные](../reference/frontmatter-config).\n\n## Таблицы в стиле GitHub {#github-style-tables}\n\n**Разметка**\n\n```md\n| Таблицы          |           это            | круто |\n| ---------------- | :----------------------: | ----: |\n| столбец 3        | выровнен по правому краю | $1600 |\n| столбец 2        |       отцентрован        |   $12 |\n| полосатые строки |   как полоски у зебры    |    $1 |\n```\n\n**Результат**\n\n| Таблицы          |           это            |  круто |\n| ---------------- | :----------------------: | -----: |\n| столбец 3        | выровнен по правому краю | \\$1600 |\n| столбец 2        |       отцентрован        |   \\$12 |\n| полосатые строки |   как полоски у зебры    |    \\$1 |\n\n## Эмодзи :tada: {#emoji}\n\n**Разметка**\n\n```\n:tada: :100:\n```\n\n**Результат**\n\n:tada: :100:\n\n[Список всех эмодзи](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs).\n\n## Оглавление {#table-of-contents}\n\n**Разметка**\n\n```\n[[toc]]\n```\n\n**Результат**\n\n[[toc]]\n\nОтрисовка TOC может быть настроена с помощью опции `markdown.toc`.\n\n## Пользовательские контейнеры {#custom-containers}\n\nПользовательские контейнеры можно определить по их типам, заголовкам и содержимому.\n\n### Заголовок по умолчанию {#default-title}\n\n**Разметка**\n\n```md\n::: info\nЭто информация.\n:::\n\n::: tip\nЭто совет.\n:::\n\n::: warning\nЭто предупреждение.\n:::\n\n::: danger\nЭто сигнал об опасности.\n:::\n\n::: details\nЭто блок-спойлер.\n:::\n```\n\n**Результат**\n\n::: info\nЭто информация.\n:::\n\n::: tip\nЭто совет.\n:::\n\n::: warning\nЭто предупреждение.\n:::\n\n::: danger\nЭто сигнал об опасности.\n:::\n\n::: details\nЭто блок-спойлер.\n:::\n\n### Пользовательский заголовок {#custom-title}\n\nВы можете задать собственный заголовок, добавив текст сразу после «типа» контейнера.\n\n**Разметка**\n\n````md\n::: danger СТОП\nОпасная зона, остановитесь\n:::\n\n::: details Нажмите на меня, чтобы переключить код\n\n```js\nconsole.log('Привет, VitePress!')\n```\n\n:::\n````\n\n**Результат**\n\n::: danger СТОП\nОпасная зона, остановитесь\n:::\n\n::: details Нажмите на меня, чтобы переключить код\n\n```js\nconsole.log('Привет, VitePress!')\n```\n\n:::\n\nКроме того, можно установить пользовательские заголовки глобально, добавив следующее содержимое в конфигурацию сайта, полезное, если вы пишете не на английском языке:\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: 'СОВЕТ',\n      warningLabel: 'ПРЕДУПРЕЖДЕНИЕ',\n      dangerLabel: 'ОПАСНОСТЬ',\n      infoLabel: 'ИНФОРМАЦИЯ',\n      detailsLabel: 'Подробная информация'\n    }\n  }\n  // ...\n})\n```\n\n### Дополнительные атрибуты {#additional-attributes}\n\nВы можете добавить дополнительные атрибуты к пользовательским контейнерам. Мы используем [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) для этой функции, и она поддерживается почти для всех элементов Markdown. Например, можно установить атрибут `open`, чтобы сделать блок подробностей открытым по умолчанию:\n\n**Разметка**\n\n````md\n::: details Нажмите на меня, чтобы переключить код {open}\n```js\nconsole.log('Привет, VitePress!')\n```\n:::\n````\n\n**Результат**\n\n::: details Нажмите на меня, чтобы переключить код {open}\n```js\nconsole.log('Привет, VitePress!')\n```\n:::\n\n### `raw` {#raw}\n\nЭто специальный контейнер, который можно использовать для предотвращения конфликтов стилей и маршрутизаторов с VitePress. Это особенно полезно при документировании библиотек компонентов. Вы также можете посмотреть [whyframe](https://whyframe.dev/docs/integrations/vitepress) для лучшей изоляции.\n\n**Синтаксис**\n\n```md\n::: raw\nЗаворачивается в `<div class=\"vp-raw\">`\n:::\n```\n\nКласс `vp-raw` можно использовать и непосредственно на элементах. Изоляция стиля в настоящее время осуществляется по желанию:\n\n- Установите `postcss` с помощью предпочитаемого менеджера пакетов:\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- Создайте файл с именем `docs/postcss.config.mjs` и добавьте в него следующее:\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  Вы можете передать ему параметры следующим образом:\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // по умолчанию [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## Оповещения в стиле GitHub {#github-flavored-alerts}\n\nVitePress также поддерживает [Оповещения в стиле GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) для отображения в виде вставок. Они будут отображаться так же, как и [пользовательские контейнеры](#custom-containers).\n\n```md\n> [!NOTE]\n> Выделяет информацию, на которую пользователи должны обратить внимание, даже при беглом просмотре.\n\n> [!TIP]\n> Дополнительная информация, которая поможет пользователю добиться большего успеха.\n\n> [!IMPORTANT]\n> Важнейшая информация, необходимая пользователям для достижения успеха.\n\n> [!WARNING]\n> Критический контент, требующий немедленного внимания пользователей из-за потенциальных рисков.\n\n> [!CAUTION]\n> Негативные потенциальные последствия того или иного действия.\n```\n\n> [!NOTE]\n> Выделяет информацию, на которую пользователи должны обратить внимание, даже при беглом просмотре.\n\n> [!TIP]\n> Дополнительная информация, которая поможет пользователю добиться большего успеха.\n\n> [!IMPORTANT]\n> Важнейшая информация, необходимая пользователям для достижения успеха.\n\n> [!WARNING]\n> Критический контент, требующий немедленного внимания пользователей из-за потенциальных рисков.\n\n> [!CAUTION]\n> Негативные потенциальные последствия того или иного действия.\n\n## Подсветка синтаксиса в блоках кода {#syntax-highlighting-in-code-blocks}\n\nVitePress использует [Shiki](https://github.com/shikijs/shiki) для выделения синтаксиса языка в блоках кода Markdown с помощью цветного текста. Shiki поддерживает широкий спектр языков программирования. Всё, что вам нужно сделать, это добавить правильный псевдоним языка к начальным обратным кавычкам блока кода:\n\n**Разметка**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**Результат**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">{{ todo.text }}</li>\n</ul>\n```\n\n[Список всех поддерживаемых языков](https://shiki.style/languages).\n\nВы также можете настроить тему подсветки синтаксиса в конфигурации приложения. Более подробную информацию см. в секции [`markdown`](../reference/site-config#markdown).\n\n## Выделение строк в блоках кода {#line-highlighting-in-code-blocks}\n\n**Разметка**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Подсвечено!'\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Подсвечено!'\n    }\n  }\n}\n```\n\nПомимо одной строки, можно указать несколько отдельных строк, диапазонов или и то, и другое:\n\n- Диапазоны строк, например: `{5-8}`, `{3-10}`, `{10-17}`\n- Несколько одиночных строк, например: `{4,7,9}`\n- Диапазоны строк и отдельные строки, например: `{4,7-13,16,23-27,40}`\n\n**Разметка**\n\n````\n```js{1,4,6-8}\nexport default { // Подсвечено\n  data () {\n    return {\n      msg: `Подсвечено!\n      Эта строка не выделена,\n      но эта и две следующих - да.`,\n      motd: 'VitePress - это потрясающе',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js{1,4,6-8}\nexport default { // Подсвечено\n  data () {\n    return {\n      msg: `Подсвечено!\n      Эта строка не выделена,\n      но эта и две следующих - да.`,\n      motd: 'VitePress - это потрясающе',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\nКроме того, можно выделять непосредственно в строке, используя комментарий `// [!code highlight]`.\n\n**Разметка**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Подсвечено!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Подсвечено!' // [!code highlight]\n    }\n  }\n}\n```\n\n## Фокус в блоках кода {#focus-in-code-blocks}\n\nДобавление комментария `// [!code focus]` к строке сфокусирует её и размоет остальные части кода.\n\nКроме того, вы можете задать количество строк для фокусировки с помощью `// [!code focus:<lines>]`.\n\n**Разметка**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Фокус!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Фокус!' // [!code focus]\n    }\n  }\n}\n```\n\n## Подсветка различий в блоках кода {#colored-diffs-in-code-blocks}\n\nДобавление в строку комментариев `// [!code --]` или `// [!code ++]` подсветит различие этой строки от другой, сохраняя цвета блока кода.\n\n**Разметка**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Удалено' // [!!code --]\n      msg: 'Добавлено' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Удалено' // [!code --]\n      msg: 'Добавлено' // [!code ++]\n    }\n  }\n}\n```\n\n## Ошибки и предупреждения в блоках кода {#errors-and-warnings-in-code-blocks}\n\nДобавление в строку комментариев `// [!code warning]` или `// [!code error]` окрасит её соответствующим образом.\n\n**Разметка**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Ошибка', // [!!code error]\n      msg: 'Предупреждение' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**Результат**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Ошибка', // [!code error]\n      msg: 'Предупреждение' // [!code warning]\n    }\n  }\n}\n```\n\n## Номера строк {#line-numbers}\n\nВы можете включить нумерацию строк для каждого блока кода в конфигурации:\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\nБолее подробную информацию см. в секции [`markdown`](../reference/site-config#markdown).\n\nВы можете добавить метки `:line-numbers` / `:no-line-numbers` в ваши изолированные блоки кода, чтобы переопределить значение, установленное в конфиге.\n\nВы также можете настроить номер начальной строки, добавив `=` после `:line-numbers`. Например, `:line-numbers=2` означает, что нумерация строк в блоках кода будет начинаться с `2`.\n\n**Разметка**\n\n````md\n```ts {1}\n// опция line-numbers по умолчанию отключена\nconst line2 = 'Строка 2'\nconst line3 = 'Строка 3'\n```\n\n```ts:line-numbers {1}\n// опция line-numbers включена\nconst line2 = 'Строка 2'\nconst line3 = 'Строка 3'\n```\n\n```ts:line-numbers=2 {1}\n// опция line-numbers включена, нумерация начинается с 2\nconst line3 = 'Строка 3'\nconst line4 = 'Строка 4'\n```\n````\n\n**Результат**\n\n```ts {1}\n// опция line-numbers по умолчанию отключена\nconst line2 = 'Строка 2'\nconst line3 = 'Строка 3'\n```\n\n```ts:line-numbers {1}\n// опция line-numbers включена\nconst line2 = 'Строка 2'\nconst line3 = 'Строка 3'\n```\n\n```ts:line-numbers=2 {1}\n// опция line-numbers включена, нумерация начинается с 2\nconst line3 = 'Строка 3'\nconst line4 = 'Строка 4'\n```\n\n## Импорт фрагментов кода {#import-code-snippets}\n\nВы можете импортировать фрагменты кода из существующих файлов, используя следующий синтаксис:\n\n```md\n<<< @/filepath\n```\n\n[Выделение строк](#line-highlighting-in-code-blocks) тоже поддерживается:\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**Разметка**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**Файл с кодом**\n\n<<< @/snippets/snippet.js\n\n**Результат**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip СОВЕТ\nЗначение `@` соответствует корню источника. По умолчанию это корень проекта VitePress, если не настроен параметр `srcDir`. Альтернативно вы также можете импортировать из относительных путей:\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\nВы также можете использовать [регион VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding), чтобы включить только соответствующую часть файла кода. Имя пользовательского региона начинается с `#` после пути к файлу:\n\n**Разметка**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**Файл с кодом**\n\n<<< @/snippets/snippet-with-region.js\n\n**Результат**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\nКроме того, можно указать язык внутри фигурных скобок (`{}`) следующим образом:\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- с подсветкой строк: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- с номерами строк: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\nЭто полезно, если исходный язык нельзя определить по расширению вашего файла.\n\n## Группы кодов {#code-groups}\n\nМожно сгруппировать несколько блоков кода следующим образом:\n\n**Разметка**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**Результат**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\nВы также можете [импортировать фрагменты](#import-code-snippets) в группы кода:\n\n**Разметка**\n\n```md\n::: code-group\n\n<!-- по умолчанию в качестве заголовка используется имя файла -->\n\n<<< @/snippets/snippet.js\n\n<!-- но можно предоставить и индивидуальный вариант -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [фрагмент с регионом]\n\n:::\n```\n\n**Результат**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [фрагмент с регионом]\n\n:::\n\n## Включение файла Markdown {#markdown-file-inclusion}\n\nВы можете включить файл Markdown в другой файл Markdown, даже вложенный.\n\n::: tip СОВЕТ\nВы также можете добавить префикс `@` к пути Markdown, и он будет считаться корневой папкой исходников. По умолчанию корневая папка исходников совпадает с корнем проекта VitePress, если не настроен параметр `srcDir`.\n:::\n\nНапример, вы можете включить относительный файл Markdown следующим образом:\n\n**Разметка**\n\n```md\n# Документация\n\n## Основы\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**Файл части** (`parts/basics.md`)\n\n```md\nНекоторые вещи для начала.\n\n### Конфигурация\n\nМожет быть создана с помощью `.foorc.json`.\n```\n\n**Эквивалентный код**\n\n```md\n# Документация\n\n## Основы\n\nНекоторые вещи для начала.\n\n### Конфигурация\n\nМожет быть создана с помощью `.foorc.json`.\n```\n\nОн также поддерживает выбор диапазона строк:\n\n**Разметка**\n\n```md\n# Документация\n\n## Основы\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**Файл части** (`parts/basics.md`)\n\n```md\nНекоторые вещи для начала.\n\n### Конфигурация\n\nМожет быть создана с помощью `.foorc.json`.\n```\n\n**Соответствующий код**\n\n```md\n# Документация\n\n## Основы\n\n### Конфигурация\n\nМожет быть создана с помощью `.foorc.json`.\n```\n\nФормат выбранного диапазона строк может быть следующим: `{3,}`, `{,10}`, `{1,10}`\n\nВы также можете использовать [блоки кода VS Code](https://code.visualstudio.com/docs/editor/codebasics#_folding), чтобы включить только соответствующую часть файла. Можно указать пользовательское имя блока после `#`, следующего за путём к файлу:\n\n**Разметка**\n\n```md\n# Документация\n\n## Основы\n\n<!--@@include: ./parts/basics.md#basic-usage{,2}-->\n<!--@@include: ./parts/basics.md#basic-usage{5,}-->\n```\n\n**Часть файла** (`parts/basics.md`)\n\n```md\n<!-- #region basic-usage -->\n## Используемая строка 1\n\n## Используемая строка 2\n\n## Используемая строка 3\n<!-- #endregion basic-usage -->\n```\n\n**Соответствующий код**\n\n```md\n# Документация\n\n## Основы\n\n## Используемая строка 1\n\n## Используемая строка 3\n```\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nОбратите внимание, что это не приводит к ошибкам, если ваш файл отсутствует. Поэтому при использовании этой функции убедитесь, что содержимое отображается так, как ожидается.\n:::\n\nВместо регионов VS Code вы также можете использовать якоря заголовков, чтобы включить определённый раздел файла. Например, если у вас есть заголовок в вашем markdown-файле, например:\n\n```md\n## Мой основной раздел\n\nКакой-то контент здесь.\n\n### Мой подраздел\n\nЕщё немного контента здесь.\n\n## Другой раздел\n\nКонтент вне `Моего основного раздела`.\n```\n\nВы можете включить раздел `Мой основной раздел` следующим образом:\n\n```md\n## Мой дополнительный раздел\n<!--@@include: ./parts/basics.md#мои-основнои-раздел-->\n```\n\n**Соответствующий код**\n\n```md\n## Мой дополнительный раздел\n\nКакой-то контент здесь.\n\n### Мой подраздел\n\nЕщё немного контента здесь.\n```\n\nЗдесь `мои-основнои-раздел` — это сгенерированный идентификатор элемента заголовка. Если его нелегко угадать, вы можете открыть файл в браузере и нажать на якорь заголовка (символ `#` слева от заголовка при наведении), чтобы увидеть идентификатор в адресной строке. Или используйте инструменты разработчика браузера для проверки элемента. Кроме того, вы также можете указать идентификатор для файла части следующим образом:\n\n```md\n## Мой основной раздел {#custom-id}\n```\n\nи включить его следующим образом:\n\n```md\n<!--@@include: ./parts/basics.md#custom-id-->\n```\n\n## Математические уравнения {#math-equations}\n\nВ настоящее время эта фича предоставляется по желанию. Чтобы включить её, вам нужно установить `markdown-it-mathjax3` и установить значение `true` для опции `markdown.math` в вашем файле конфигурации:\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**Разметка**\n\n```md\nКогда $a \\ne 0$, существует два решения $(ax^2 + bx + c = 0)$:\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Уравнения Максвелла:**\n\n| уравнение                                                                                                                                                                 | описание                                                                             |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | дивергенция $\\vec{\\mathbf{B}}$ равна нулю                                            |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | искривление $\\vec{\\mathbf{E}}$ пропорционально скорости изменения $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _что?_                                                                               |\n```\n\n**Результат**\n\nКогда $a \\ne 0$, существует два решения $(ax^2 + bx + c = 0)$:\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Уравнения Максвелла:**\n\n| уравнение                                                                                                                                                                 | описание                                                                             |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | дивергенция $\\vec{\\mathbf{B}}$ равна нулю                                            |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | искривление $\\vec{\\mathbf{E}}$ пропорционально скорости изменения $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _что?_                                                                               |\n\n## Ленивая загрузка изображений {#image-lazy-loading}\n\nВы можете включить ленивую загрузку для каждого изображения, добавленного через markdown, установив значение `true` для опции `lazyLoading` в вашем файле конфигурации:\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // ленивая загрузка изображений отключена по умолчанию\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## Расширенная конфигурация {#advanced-configuration}\n\nVitePress использует [markdown-it](https://github.com/markdown-it/markdown-it) для отрисовки Markdown. Многие из вышеперечисленных расширений реализованы с помощью пользовательских плагинов. Вы можете дополнительно настроить экземпляр `markdown-it` с помощью опции `markdown` в файле `.vitepress/config.js`:\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // опции для markdown-it-anchor\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n\n    // опции для @mdit-vue/plugin-toc\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n\n    config: (md) => {\n      // используйте любые плагины для markdown-it!\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\nПолный список настраиваемых свойств см. в секции [`markdown`](../reference/site-config#markdown).\n"
  },
  {
    "path": "docs/ru/guide/migration-from-vitepress-0.md",
    "content": "# Переход с VitePress 0.x\n\nЕсли вы переходите с версии VitePress 0.x, то в ней есть несколько изменений, связанных с новыми функциями и улучшениями. Следуйте этому руководству, чтобы узнать, как перенести ваше приложение на последнюю версию VitePress.\n\n## Конфигурация приложения\n\n- Функция интернационализации ещё не реализована.\n\n## Конфигурация темы\n\n- Опция `sidebar` изменила свою структуру.\n  - Ключ `children` теперь называется `items`.\n  - Элемент верхнего уровня может не содержать `link` в данный момент. Мы планируем вернуть его обратно.\n- `repo`, `repoLabel`, `docsDir`, `docsBranch`, `editLinks`, `editLinkText` удалены в пользу более гибкого api.\n  - Для добавления ссылки GitHub с иконкой в навигацию используйте функцию [Социальные ссылки](../reference/default-theme-nav#navigation-links).\n  - Для добавления ссылки «Редактировать эту страницу» используйте функцию [Ссылка для редактирования](../reference/default-theme-edit-link).\n- Опция `lastUpdated` теперь разделена на `config.lastUpdated` и `themeConfig.lastUpdatedText`.\n- Опция `carbonAds.carbon` заменена на `carbonAds.code`.\n\n## Конфигурация метаданных\n\n- Опция `home: true` заменена на `layout: home`. Кроме того, многие настройки, связанные с главной страницей, были изменены для обеспечения дополнительных возможностей. Подробности см. в разделе [Главная страница](../reference/default-theme-home-page).\n- Опция `footer` перенесена в [`themeConfig.footer`](../reference/default-theme-config#footer).\n"
  },
  {
    "path": "docs/ru/guide/migration-from-vuepress.md",
    "content": "# Переход с VuePress\n\n## Конфигурация\n\n### Сайдбар\n\nБоковая панель больше не заполняется автоматически из метаданных. Вы можете [самостоятельно прочитать вступление](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225), чтобы научиться динамически заполнять боковую панель. [Дополнительные утилиты для этого](https://github.com/vuejs/vitepress/issues/96) могут быть предоставлены в будущем.\n\n## Markdown\n\n### Изображения\n\nВ отличие от VuePress, VitePress автоматически обрабатывает опцию [`base`](./asset-handling#base-url) вашего конфига, когда вы используете статическое изображение.\n\nТаким образом, теперь вы можете выводить изображения без тега `img`.\n\n```diff\n- <img :src=\"$withBase('/foo.png')\" alt=\"foo\">\n+ ![foo](/foo.png)\n```\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nДля динамических изображений вам всё ещё нужно использовать `withBase`, как показано в [Руководстве по базовому URL](./asset-handling#base-url).\n:::\n\nИспользуйте регулярное выражение `<img.*withBase\\('(.*)'\\).*alt=\"([^\"]*)\".*>` для поиска всех изображений с синтаксисом `![](...)` и замены на `![$2]($1)`.\n\n---\n\nпродолжение следует...\n"
  },
  {
    "path": "docs/ru/guide/mpa-mode.md",
    "content": "# Режим MPA <Badge type=\"warning\" text=\"экспериментально\" /> {#mpa-mode}\n\nРежим MPA (Multi-Page Application — «Многостраничное приложение») можно включить через командную строку с помощью команды `vitepress build --mpa`, или через конфигурацию с помощью опции `mpa: true`.\n\nВ режиме MPA все страницы по умолчанию отображаются без включенного JavaScript. В результате производственный сайт, скорее всего, получит более высокую оценку эффективности первых посещений с помощью инструментов аудита.\n\nОднако из-за отсутствия навигации SPA межстраничные ссылки будут приводить к полной перезагрузке страницы. После загрузки навигация в режиме MPA будет не такой мгновенной, как в режиме SPA.\n\nТакже обратите внимание, что «no-JS-by-default» («без JS по умолчанию») означает, что вы используете Vue исключительно как серверный язык шаблонов. Никаких обработчиков событий в браузере не будет, как и интерактивности. Чтобы загрузить JavaScript со стороны клиента, вам нужно использовать специальный тег `<script client>`:\n\n```html\n<script client>\n  document.querySelector('h1').addEventListener('click', () => {\n    console.log('JavaScript на стороне клиента!')\n  })\n</script>\n\n# Привет\n```\n\n`<script client>` — это функция только для VitePress, а не для Vue. Она работает как в файлах `.md`, так и в файлах `.vue`, но только в режиме MPA. Клиентские скрипты во всех компонентах темы будут объединены вместе, в то время как клиентский скрипт для конкретной страницы будет разделён только для этой страницы.\n\nОбратите внимание, что `<script client>` **не оценивается как код компонента Vue**: он обрабатывается как обычный модуль JavaScript. По этой причине режим MPA следует использовать только в том случае, если ваш сайт требует абсолютно минимальной интерактивности на стороне клиента.\n"
  },
  {
    "path": "docs/ru/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# Маршрутизация {#routing}\n\n## Маршрутизация на основе файлов {#file-based-routing}\n\nVitePress использует маршрутизацию на основе файлов, что означает, что сгенерированные HTML-страницы отображаются на основе структуры папок исходных файлов Markdown. Например, при следующей структуре папок:\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\nСгенерированные HTML-страницы будут выглядеть так:\n\n```\nindex.md                  -->  /index.html (доступна по адресу /)\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html (доступна по адресу /guide/)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\nПолученный HTML можно разместить на любом веб-сервере, который может обслуживать статические файлы.\n\n## Корневая директория и директория с исходными файлами {#root-and-source-directory}\n\nВ файловой структуре проекта VitePress есть два важных понятия: **корень проекта** и **директория с исходными файлами**.\n\n### Корень проекта {#project-root}\n\nКорень проекта — это место, где VitePress будет пытаться искать специальный каталог `.vitepress`. Директория `.vitepress` — это зарезервированное место для конфигурационного файла VitePress, кэша dev-сервера, результатов сборки и дополнительного кода настройки темы.\n\nКогда вы запускаете `vitepress dev` или `vitepress build` из командной строки, VitePress будет использовать текущий рабочий каталог в качестве корня проекта. Чтобы указать подкаталог в качестве корневого, нужно передать команде относительный путь. Например, если ваш проект VitePress находится в папке `./docs`, вам следует выполнить команду `vitepress dev docs`:\n\n```\n.\n├─ docs                    # корень проекта\n│  ├─ .vitepress           # директория с настройками\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\nВ результате получится следующее сопоставление источника с HTML:\n\n```\ndocs/index.md            -->  /index.html (доступна по адресу /)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### Директория с исходными файлами {#source-directory}\n\nДиректория с исходными файлами — это место, где хранятся ваши исходные файлы Markdown. По умолчанию она совпадает с корнем проекта. Однако вы можете настроить её с помощью параметра [`srcDir`](../reference/site-config#srcdir).\n\nОпция `srcDir` разрешается относительно корня проекта. Например, с помощью `srcDir: 'src'`, ваша файловая структура будет выглядеть следующим образом:\n\n```\n.                          # корень проекта\n├─ .vitepress              # директория с настройками\n└─ src                     # директория с исходными файлами\n   ├─ getting-started.md\n   └─ index.md\n```\n\nИтоговое сопоставление исходного кода с HTML:\n\n```\nsrc/index.md            -->  /index.html (доступна по адресу /)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## Связи между страницами {#linking-between-pages}\n\nПри создании ссылок между страницами можно использовать как абсолютные, так и относительные пути. Обратите внимание, что хотя расширения `.md` и `.html` будут работать, лучше всего опускать расширения файлов, чтобы VitePress мог генерировать конечные URL на основе вашего конфига.\n\n```md\n<!-- Будут работать -->\n[Первые шаги](./getting-started)\n[Первые шаги](../guide/getting-started)\n\n<!-- Не будут работать -->\n[Первые шаги](./getting-started.md)\n[Первые шаги](./getting-started.html)\n```\n\nУзнайте больше о ссылках на такие ресурсы, как изображения, в главе [Обработка ресурсов](./asset-handling).\n\n### Ссылки на страницы, не принадлежащие VitePress {#linking-to-non-vitepress-pages}\n\nЕсли вы хотите создать ссылку на страницу вашего сайта, которая не создана VitePress, вам нужно будет либо использовать полный URL-адрес (откроется в новой вкладке), либо явно указать цель:\n\n**Разметка**\n\n```md\n[Ссылка на pure.html](/pure.html){target=\"_self\"}\n```\n\n**Результат**\n\n[Ссылка на pure.html](/pure.html){target=\"_self\"}\n\n::: tip Примечание\n\nВ ссылках Markdown к URL-адресу автоматически добавляется значение параметра `base`. Это означает, что если вы хотите создать ссылку на страницу за пределами `base`, вам понадобится что-то вроде `../../pure.html` в ссылке (разрешаемой браузером относительно текущей страницы).\n\nАльтернативно можно напрямую использовать синтаксис тега ссылки:\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Ссылка на pure.html</a>\n```\n\n:::\n\n## Создание чистых URL-адресов {#generating-clean-urls}\n\n::: warning Требуется поддержка сервера\nДля обслуживания чистых URL-адресов с помощью VitePress требуется поддержка на стороне сервера.\n:::\n\nПо умолчанию VitePress разрешает входящие ссылки на URL-адреса, заканчивающиеся на `.html`. Однако некоторые пользователи могут предпочесть «Чистые URL-адреса» без расширения `.html` — например, `example.com/path` вместо `example.com/path.html`.\n\nНекоторые серверы или хостинговые платформы (например, Netlify, Vercel, GitHub Pages) предоставляют возможность сопоставлять URL-адрес типа `/foo` с `/foo.html`, если он существует, без перенаправления:\n\n- Страницы Netlify и GitHub поддерживают это по умолчанию.\n- Vercel требует включить [опцию `cleanUrls` в `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls).\n\nЕсли эта функция вам доступна, вы также можете включить собственную опцию конфигурации VitePress [`cleanUrls`](../reference/site-config#cleanurls), чтобы обеспечить следующее поведение:\n\n- Входящие ссылки между страницами генерируются без расширения `.html`.\n- Если текущий путь заканчивается на `.html`, маршрутизатор выполнит перенаправление на стороне клиента на путь без расширений.\n\nОднако если вы не можете настроить свой сервер с такой поддержкой, вам придётся вручную прибегнуть к следующей структуре каталогов:\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## Перезапись маршрутов {#route-rewrites}\n\nВы можете настроить сопоставление между структурой исходного каталога и создаваемыми страницами. Это полезно, когда у вас сложная структура проекта. Допустим, у вас есть монорепо с несколькими пакетами, и вы хотите поместить документацию вместе с исходными файлами, как это сделано здесь:\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ foo.md\n│  │      └─ index.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ bar.md\n│         └─ index.md\n```\n\nИ вы хотите, чтобы страницы VitePress генерировались следующим образом:\n\n```\npackages/pkg-a/src/index.md  -->  /pkg-a/index.html\npackages/pkg-a/src/foo.md    -->  /pkg-a/foo.html\npackages/pkg-b/src/index.md  -->  /pkg-b/index.html\npackages/pkg-b/src/bar.md    -->  /pkg-b/bar.html\n```\n\nЭтого можно добиться, настроив опцию [`rewrites`](../reference/site-config#rewrites) следующим образом:\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/index.md': 'pkg-a/index.md',\n    'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',\n    'packages/pkg-b/src/index.md': 'pkg-b/index.md',\n    'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'\n  }\n}\n```\n\nОпция `rewrites` также поддерживает динамические параметры маршрута. В приведённом выше примере, если у вас много пакетов, перечислять все пути было бы скучно. Учитывая, что все они имеют одинаковую структуру файлов, можно упростить конфигурацию следующим образом:\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/:slug*': ':pkg/:slug*'\n  }\n}\n```\n\nПути перезаписи компилируются с помощью пакета `path-to-regexp` — обратитесь к [его документации](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters) за более сложным синтаксисом.\n\n`rewrites` также может быть функцией, которая получает исходный путь и возвращает новый:\n\n```ts\nexport default {\n  rewrites(id) {\n    return id.replace(/^packages\\/([^/]+)\\/src\\//, '$1/')\n  }\n}\n```\n\n::: warning Относительные ссылки с переписыванием\n\nКогда переписывание включено, **относительные ссылки должны быть основаны на переписанных путях**. Например, чтобы создать относительную ссылку с `packages/pkg-a/src/pkg-a-code.md` на `packages/pkg-b/src/pkg-b-code.md`, нужно использовать:\n\n```md\n[Ссылка на PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## Динамические маршруты {#dynamic-routes}\n\nВы можете создать множество страниц, используя один файл Markdown и динамические данные. Например, вы можете создать файл `packages/[pkg].md`, который будет генерировать соответствующую страницу для каждого пакета в проекте. Здесь сегмент `[pkg]` является **параметром** маршрута, который отличает каждую страницу от других.\n\n### Файл загрузчика путей {#paths-loader-file}\n\nПоскольку VitePress — это генератор статических сайтов, возможные пути страниц должны быть определены во время сборки. Поэтому динамическая маршрутная страница **должна** сопровождаться **файлом загрузчика путей**. Для `packages/[pkg].md` нам понадобится `packages/[pkg].paths.js` (`.ts` также поддерживается):\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # шаблон маршрута\n   └─ [pkg].paths.js   # загрузчик путей маршрута\n```\n\nЗагрузчик путей должен предоставлять объект с методом `paths` в качестве экспорта по умолчанию. Метод `paths` должен возвращать массив объектов со свойством `params`. Для каждого из этих объектов будет создана соответствующая страница.\n\nДан следующий массив `paths`:\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\nСгенерированные HTML-страницы будут выглядеть так:\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### Типобезопасный загрузчик с `defineRoutes` {#type-safe-loader-with-defineroutes}\n\nЕсли вы используете TypeScript, вы можете обернуть загрузчик функцией `defineRoutes` из `vitepress`, чтобы получить подсказки типов для хуков маршрутов, таких как `paths`, `watch` и `transformPageData`:\n\n```ts\n// packages/[pkg].paths.ts\nimport { defineRoutes } from 'vitepress'\n\nexport default defineRoutes({\n  watch: ['../data/**/*.json'],\n  async paths() {\n    return [\n      { params: { pkg: 'foo' } },\n      { params: { pkg: 'bar' } }\n    ]\n  },\n  async transformPageData(pageData) {\n    pageData.title = `${pageData.title} · Packages`\n  }\n})\n```\n\n`defineRoutes` является необязательной, но рекомендуется при создании файлов `.paths.ts`.\n\n### Несколько параметров {#multiple-params}\n\nДинамический маршрут может содержать несколько параметров:\n\n**Структура файлов**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**Загрузчик путей**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' } },\n    { params: { pkg: 'foo', version: '2.0.0' } },\n    { params: { pkg: 'bar', version: '1.0.0' } },\n    { params: { pkg: 'bar', version: '2.0.0' } }\n  ]\n}\n```\n\n**Результат**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### Динамически генерируемые пути {#dynamically-generating-paths}\n\nМодуль загрузчика путей запускается в Node.js и выполняется только во время сборки. Вы можете динамически генерировать массив путей, используя любые данные, как локальные, так и удалённые.\n\nГенерация путей из локальных файлов:\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\nГенерация путей из удалённых данных:\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### Отслеживание файлов шаблонов и данных {#watching-template-and-data-files}\n\nПри создании содержимого страниц на основе шаблонов или внешних источников данных вы можете использовать опцию `watch` для автоматической пересборки страниц при изменении этих файлов в процессе разработки:\n\n```js\n// posts/[slug].paths.js\nimport fs from 'node:fs'\nimport { renderTemplate } from './templates/renderer.js'\n\nexport default {\n  // Отслеживание изменений в файлах шаблонов и источниках данных\n  watch: [\n    './templates/**/*.njk',     // Файлы шаблонов\n    '../data/**/*.json'         // Файлы данных\n  ],\n\n  paths(watchedFiles) {\n    // watchedFiles будет массивом абсолютных путей найденных файлов\n    // Чтение файлов данных для генерации маршрутов\n    const dataFiles = watchedFiles.filter(file => file.endsWith('.json'))\n\n    return dataFiles.map(file => {\n      const data = JSON.parse(fs.readFileSync(file, 'utf-8'))\n\n      return {\n        params: { slug: data.slug },\n        content: renderTemplate(data)  // Использование шаблона для генерации контента\n      }\n    })\n  }\n}\n```\n\nОпция `watch` работает так же, как и в [загрузчиках данных](./data-loading#data-from-local-files):\n\n- Принимает [glob-шаблоны](https://github.com/mrmlnc/fast-glob#pattern-syntax) для сопоставления файлов\n- Шаблоны указываются относительно самого файла `.paths.js`\n- Изменения в отслеживаемых файлах вызывают перегенерацию страниц и HMR во время разработки\n- В продакшен-сборках все страницы генерируются один раз, независимо от конфигурации `watch`\n\n### Доступ к параметрам на странице {#accessing-params-in-page}\n\nВы можете использовать параметры для передачи дополнительных данных на каждую страницу. Файл маршрута Markdown может получить доступ к параметрам текущей страницы в выражениях Vue через глобальное свойство `$params`:\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n\nВы также можете получить доступ к параметрам текущей страницы через Runtime API [`useData`](../reference/runtime-api#usedata). Это доступно как в файлах Markdown, так и в компонентах Vue:\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params — это ref-ссылка Vue\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### Рендеринг необработанного содержимого {#rendering-raw-content}\n\nПараметры, передаваемые странице, будут сериализованы в полезной нагрузке клиентского JavaScript, поэтому вам следует избегать передачи в параметрах больших объемов данных, например, необработанного Markdown или HTML-контента, полученного из удалённой CMS.\n\nВместо этого вы можете передавать такое содержимое на каждую страницу с помощью свойства `content` каждого объекта path:\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // необработанный Markdown или HTML\n      }\n    })\n  }\n}\n```\n\nЗатем используйте следующий специальный синтаксис, чтобы отобразить содержимое как часть самого файла Markdown:\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/ru/guide/sitemap-generation.md",
    "content": "# Генерация карты сайта {#sitemap-generation}\n\nVitePress поставляется с готовой поддержкой генерации файла `sitemap.xml` для вашего сайта. Чтобы включить её, добавьте следующее в файл `.vitepress/config.js`:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\nЧтобы теги `<lastmod>` присутствовали в вашем файле `sitemap.xml`, вы можете включить опцию [`lastUpdated`](../reference/default-theme-last-updated).\n\n## Параметры {#options}\n\nПоддержка карты сайта осуществляется с помощью модуля [`sitemap`](https://www.npmjs.com/package/sitemap). Вы можете передать любые поддерживаемые им параметры в опцию `sitemap` в вашем конфигурационном файле. Они будут переданы непосредственно в конструктор `SitemapStream`. Более подробную информацию см. в документации [`sitemap`](https://www.npmjs.com/package/sitemap#options-you-can-pass). Пример:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\nПри использовании параметра `base` в своей конфигурации обязательно добавьте его в адрес `hostname`:\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## Хук `transformItems` {#transformitems-hook}\n\nВы можете использовать хук `sitemap.transformItems` для изменения элементов карты сайта перед их записью в файл `sitemap.xml`. Этот хук вызывается с массивом элементов sitemap и ожидает возвращения массива элементов sitemap. Пример:\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // добавляем новые элементы или изменяем/фильтруем существующие\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ru/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# Совместимость с SSR {#ssr-compatibility}\n\nVitePress предварительно рендерит приложение в Node.js во время производственной сборки, используя возможности Vue по рендерингу на стороне сервера (SSR). Это означает, что весь пользовательский код в компонентах темы подлежит проверке на совместимость с SSR.\n\nГлава [Рендеринг на стороне сервера](https://ru.vuejs.org/guide/scaling-up/ssr.html) в документации Vue содержит более подробную информацию о том, что такое SSR, взаимосвязь между SSR и SSG, а также общие указания по написанию кода, дружественного к SSR. Правило заключается в том, чтобы обращаться к API браузера / DOM только в хуках `beforeMount` или `mounted` компонентов Vue.\n\n## `<ClientOnly>` {#clientonly}\n\nЕсли вы используете или демонстрируете компоненты, которые не являются SSR-дружественными (например, содержат пользовательские директивы), вы можете обернуть их внутри встроенного компонента `<ClientOnly>`:\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## Библиотеки, обращающиеся к API браузера при импорте {#libraries-that-access-browser-api-on-import}\n\nНекоторые компоненты или библиотеки получают доступ к API браузера **при импорте**. Чтобы использовать код, предполагающий наличие среды браузера при импорте, необходимо динамически импортировать их.\n\n### Импорт в хуке `onMounted` {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // используем код\n  })\n})\n</script>\n```\n\n### Условный импорт {#conditional-import}\n\nВы также можете условно импортировать зависимость с помощью флага `import.meta.env.SSR` (часть [env-переменных Vite](https://vitejs.dev/guide/env-and-mode.html#env-variables)):\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // используем код\n  })\n}\n```\n\nПоскольку [`Theme.enhanceApp`](./custom-theme#theme-interface) может быть асинхронным, вы можете условно импортировать и регистрировать плагины Vue, которые получают доступ к API браузера при импорте:\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\nЕсли вы используете TypeScript:\n\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent` {#defineclientcomponent}\n\nVitePress предоставляет удобный помощник для импорта компонентов Vue, которые получают доступ к API браузера при импорте.\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nВы также можете передавать параметры/дочерние элементы/слоты целевому компоненту:\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // args передаются в функцию h() - https://ru.vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'default slot',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'one'), h('span', 'two')]\n    }\n  ],\n\n  // обратный вызов после загрузки компонента, может быть асинхронным\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\nЦелевой компонент будет импортирован только в смонтированный хук компонента-обёртки.\n"
  },
  {
    "path": "docs/ru/guide/using-vue.md",
    "content": "# Использование Vue в Markdown {#using-vue-in-markdown}\n\nВ VitePress каждый Markdown-файл компилируется в HTML, а затем обрабатывается как [однофайловый компонент Vue](https://ru.vuejs.org/guide/scaling-up/sfc.html). Это означает, что вы можете использовать любые возможности Vue внутри Markdown, включая динамический шаблонизатор, использование компонентов Vue или произвольную логику компонентов Vue на странице, добавив тег `<script>`.\n\nСтоит отметить, что VitePress использует компилятор Vue для автоматического обнаружения и оптимизации чисто статических частей контента в формате Markdown. Статичное содержимое оптимизируется в отдельные узлы-заполнители и исключается из полезной нагрузки JavaScript страницы при первых посещениях. Они также пропускаются при гидратации на стороне клиента. Короче говоря, вы платите только за динамические части на каждой конкретной странице.\n\n::: tip Совместимость с SSR\nВсё, что используется в Vue, должно быть совместимо с SSR. Подробности и общие обходные пути см. в главе [Совместимость с SSR](./ssr-compat).\n:::\n\n## Шаблонизация {#templating}\n\n### Интерполяция {#interpolation}\n\nКаждый файл Markdown сначала компилируется в HTML, а затем передается в качестве компонента Vue в конвейер процесса Vite. Это означает, что вы можете использовать интерполяцию в стиле Vue в тексте:\n\n**Разметка**\n\n```md\n{{ 1 + 1 }}\n```\n\n**Результат**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### Директивы {#directives}\n\nДирективы также работают (обратите внимание, что по замыслу необработанный HTML также допустим в Markdown):\n\n**Разметка**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**Результат**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` и `<style>` {#script-and-style}\n\nТеги корневого уровня `<script>` и `<style>` в Markdown-файлах работают так же, как и в Vue SFC, включая `<script setup>`, `<style module>` и т. д. Главное отличие заключается в отсутствии тега `<template>`: всё остальное содержимое корневого уровня — Markdown. Также обратите внимание, что все теги должны располагаться **после** метаданных:\n\n```html\n---\nhello: world\n---\n\n<script setup>\n  import { ref } from 'vue'\n\n  const count = ref(0)\n</script>\n\n## Содержание в формате Markdown. Счётчик: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Увеличить</button>\n\n<style module>\n  .button {\n    color: red;\n    font-weight: bold;\n  }\n</style>\n```\n\n::: warning Избегайте `<style scoped>` в Markdown\nПри использовании в Markdown `<style scoped>` требует добавления специальных атрибутов к каждому элементу на текущей странице, что значительно увеличивает размер страницы. `<style module>` предпочтительнее, когда на странице требуется локально копируемый стиль.\n:::\n\nУ вас также есть доступ к runtime API VitePress, например, к [хелперу `useData`](../reference/runtime-api#usedata), который предоставляет доступ к метаданным текущей страницы:\n\n**Разметка**\n\n```html\n<script setup>\n  import { useData } from 'vitepress'\n\n  const { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**Результат**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"Использование Vue в Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## Использование компонентов {#using-components}\n\nВы можете импортировать и использовать компоненты Vue непосредственно в файлах Markdown.\n\n### Импорт в Markdown {#importing-in-markdown}\n\nЕсли компонент используется только на нескольких страницах, рекомендуется явно импортировать его туда, где он используется. Это позволяет правильно разделить их по коду и загружать только при показе соответствующих страниц:\n\n```md\n<script setup>\nimport CustomComponent from '../components/CustomComponent.vue'\n</script>\n\n# Документация\n\nЭто .md с использованием пользовательского компонента\n\n<CustomComponent />\n\n## Другая документация\n\n...\n```\n\n### Глобальная регистрация компонентов {#registering-components-globally}\n\nЕсли компонент будет использоваться на большинстве страниц, его можно зарегистрировать глобально, настроив экземпляр приложения Vue. Пример смотрите в соответствующей главе [Расширение темы по умолчанию](./extending-default-theme#registering-global-components).\n\n::: warning ВАЖНО\nУбедитесь, что имя пользовательского компонента содержит дефис или написано в PascalCase. В противном случае он будет рассматриваться как встроенный элемент и заключен в тег `<p>`, что приведёт к несоответствию гидратации, поскольку `<p>` не позволяет размещать внутри него блочные элементы.\n:::\n\n### Использование компонентов в заголовках <ComponentInHeader /> {#using-components-in-headers}\n\nВы можете использовать компоненты Vue в заголовках, но обратите внимание на разницу между следующими синтаксисами:\n\n| Markdown                                                 | Итоговый HTML                              | Разобранный заголовок |\n| -------------------------------------------------------- | ------------------------------------------ | --------------------- |\n| <pre v-pre><code> # текст &lt;Tag/&gt; </code></pre>     | `<h1>текст <Tag/></h1>`                    | `текст`               |\n| <pre v-pre><code> # текст \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>текст <code>&lt;Tag/&gt;</code></h1>` | `текст <Tag/>`        |\n\nHTML, обёрнутый `<code>`, будет отображаться как есть; только тот HTML, который **не** обёрнут, будет разобран Vue.\n\n::: tip ПРИМЕЧАНИЕ\nВывод HTML осуществляется с помощью [Markdown-it](https://github.com/Markdown-it/Markdown-it), а парсинг заголовков обрабатывается VitePress (и используется как для боковой панели, так и для заголовка документа).\n:::\n\n## Экранирование {#escaping}\n\nВы можете избежать интерполяций Vue, обернув их в `<span>` или другие элементы с помощью директивы `v-pre`:\n\n**Разметка**\n\n```md\nЭто <span v-pre>{{ будет отображаться как есть }}</span>.\n```\n\n**Результат**\n\n<div class=\"escape-demo\">\n  <p>Это <span v-pre>{{ будет отображаться как есть }}</span></p>\n</div>\n\nВ качестве альтернативы вы можете обернуть весь абзац в пользовательский контейнер `v-pre`:\n\n```md\n::: v-pre\n{{ Это будет отображаться как есть }}\n:::\n```\n\n**Результат**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ Это будет отображаться как есть }}\n:::\n\n</div>\n\n## Отключение экранирования в блоках кода {#unescape-in-code-blocks}\n\nПо умолчанию все изолированные блоки кода автоматически оборачиваются `v-pre`, поэтому внутри них не будет обрабатываться синтаксис Vue. Чтобы включить интерполяцию в стиле Vue внутри фигурных скобок, можно добавить к языку суффикс `-vue`, например `js-vue`:\n\n**Разметка**\n\n````md\n```js-vue\nПривет, {{ 1 + 1 }}\n```\n````\n\n**Результат**\n\n```js-vue\nПривет, {{ 1 + 1 }}\n```\n\nОбратите внимание, что при этом некоторые лексемы могут не выделяться синтаксисом должным образом.\n\n## Использование препроцессоров CSS {#using-css-pre-processors}\n\nVitePress имеет [встроенную поддержку](https://vitejs.dev/guide/features.html#css-pre-processors) для препроцессоров CSS: файлы `.scss`, `.sass`, `.less`, `.styl` и `.stylus`. Для них не нужно устанавливать специфические для Vite плагины, но сам соответствующий препроцессор должен быть установлен:\n\n::: code-group\n\n```sh [npm]\n# .scss и .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl и .stylus\nnpm install -D stylus\n```\n\n```sh [pnpm]\n# .scss и .sass\npnpm add -D sass\n\n# .less\npnpm add -D less\n\n# .styl и .stylus\npnpm add -D stylus\n```\n\n```sh [yarn]\n# .scss и .sass\nyarn add -D sass\n\n# .less\nyarn add -D less\n\n# .styl и .stylus\nyarn add -D stylus\n```\n\n```sh [bun]\n# .scss и .sass\nbun add -D sass\n\n# .less\nbun add -D less\n\n# .styl и .stylus\nbun add -D stylus\n```\n:::\n\nЗатем вы можете использовать соответствующий атрибут `lang` в Markdown и компонентах темы:\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## Использование телепортов {#using-teleports}\n\nВ настоящее время VitePress поддерживает SSG только для телепортов к элементу `body`. Для других целей вы можете обернуть их внутри встроенного компонента `<ClientOnly>` или внедрить разметку телепортации в нужное место HTML конечной страницы через [хук `postRender`](../reference/site-config#postrender).\n\n<ModalDemo />\n\n::: details Исходный код\n<<< @/ru/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n\n\n## Поддержка VS Code IntelliSense\n\n<!-- Based on https://github.com/vuejs/language-tools/pull/4321 -->\n\nVue предоставляет поддержку IntelliSense из коробки через [официальный плагин Vue для VS Code](https://marketplace.visualstudio.com/items?itemName=Vue.volar). Однако, чтобы включить её для файлов `.md`, вам нужно внести некоторые изменения в файлы конфигурации.\n\n1. Добавьте шаблон `.md` в параметры `include` и `vueCompilerOptions.vitePressExtensions` в файле tsconfig/jsconfig:\n\n::: code-group\n```json [tsconfig.json]\n{\n  \"include\": [\n    \"docs/**/*.ts\",\n    \"docs/**/*.vue\",\n    \"docs/**/*.md\",\n  ],\n  \"vueCompilerOptions\": {\n    \"vitePressExtensions\": [\".md\"],\n  },\n}\n```\n:::\n\n2. Добавьте `markdown` в параметр `vue.server.includeLanguages` в настройках VS Code:\n\n::: code-group\n```json [.vscode/settings.json]\n{\n  \"vue.server.includeLanguages\": [\"vue\", \"markdown\"]\n}\n```\n:::\n"
  },
  {
    "path": "docs/ru/guide/what-is-vitepress.md",
    "content": "# Что такое VitePress? {#what-is-vitepress}\n\nVitePress — это [Генератор статических сайтов](https://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B_%D1%81%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2) (ГСС), предназначенный для быстрого создания сайтов, ориентированных на контент. В двух словах, VitePress берёт ваш исходный контент, написанный на [Markdown](https://ru.wikipedia.org/wiki/Markdown), применяет к нему тему и генерирует статические HTML-страницы, которые можно легко развернуть в любом месте.\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\nХотите попробовать прямо сейчас? Перейдите к главе [Первые шаги](./getting-started).\n\n</div>\n\n## Примеры использования {#use-cases}\n\n- **Документация**\n\n  VitePress поставляется с темой по умолчанию, предназначенной для технической документации. Именно она обеспечивает работу этой страницы, которую вы сейчас читаете, а также документации для [Vite](https://vite-docs.ru/), [Rollup](https://rollupjs.org/), [Pinia](https://pinia-ru.netlify.app), [VueUse](https://vueuse.org/), [Vitest](https://vitest.dev/), [D3](https://d3js.org/), [UnoCSS](https://unocss.dev/), [Iconify](https://iconify.design/) и [многих других](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code).\n\n  [Официальная документация Vue.js](https://vuejs.org/) также основана на VitePress, но использует кастомную тему, общую для нескольких переводов.\n\n- **Блоги, портфолио и маркетинговые сайты**\n\n  VitePress поддерживает [полностью кастомизированные темы](./custom-theme), при этом разработчики могут использовать стандартное приложение Vite + Vue. То, что он построен на базе Vite, также означает, что вы можете напрямую использовать плагины Vite из его богатой экосистемы. Кроме того, VitePress предоставляет гибкие API для [загрузки данных](./data-loading) (локальной или удалённой) и [динамической генерации маршрутов](./routing#dynamic-routes). С его помощью можно построить практически всё, что угодно, если данные могут быть определены во время сборки.\n\n  Официальный [блог Vue.js](https://blog.vuejs.org/) — это простой блог, который генерирует свою индексную страницу на основе локального контента.\n\n## Опыт разработчика {#developer-experience}\n\nVitePress стремится обеспечить отличные возможности для разработчиков при работе с содержимым в формате Markdown.\n\n- **[На базе Vite:](https://vitejs.dev/)** мгновенный запуск сервера, правки всегда отражаются мгновенно (<100 мс) без перезагрузки страницы.\n\n- **[Встроенные расширения Markdown:](./markdown)** Frontmatter, таблицы, подсветка синтаксиса... называйте как хотите. В частности, VitePress предоставляет множество расширенных возможностей для работы с блоками кода, что делает его идеальным для создания технической документации.\n\n- **[Markdown с возможностями Vue:](./using-vue)** каждая Markdown-страница также является [однофайловым компонентом](https://ru.vuejs.org/guide/scaling-up/sfc.html) Vue, благодаря 100% синтаксической совместимости шаблона Vue с HTML. Вы можете внедрить интерактивность в статический контент, используя шаблонизаторы Vue или импортированные компоненты Vue.\n\n## Производительность {#performance}\n\nВ отличие от многих традиционных ГСС, где каждая навигация приводит к полной перезагрузке страницы, сайт, созданный VitePress, обслуживает статический HTML при первом посещении, но становится [Одностраничным приложением](https://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5) (SPA) для последующей навигации по сайту. Эта модель, на наш взгляд, обеспечивает оптимальный баланс производительности:\n\n- **Быстрая начальная загрузка**\n\n  При первом посещении любой страницы будет использоваться статичный, предварительно отрендеренный HTML для быстрой загрузки и оптимального SEO. Затем на страницу загружается пакет JavaScript, который превращает страницу в Vue SPA («гидратация»). Вопреки распространённому мнению о медленной гидратации SPA, этот процесс на самом деле чрезвычайно быстр благодаря высокой производительности Vue 3 и оптимизациям компилятора. По данным [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F), типичные сайты VitePress достигают почти идеальных показателей производительности даже на мобильных устройствах с низкой скоростью передачи данных.\n\n- **Быстрая навигация после загрузки**\n\n  Что ещё более важно, модель SPA приводит к улучшению пользовательского опыта **после** первоначальной загрузки. Последующая навигация по сайту больше не будет приводить к полной перезагрузке страницы. Вместо этого содержимое входящей страницы будет получено и динамически обновлено. VitePress также автоматически выполняет предварительную выборку фрагментов страницы для ссылок, которые находятся в пределах области просмотра. В большинстве случаев навигация после загрузки будет ощущаться мгновенно.\n\n- **Интерактивность без штрафов**\n\n  Для того чтобы динамические части Vue, встроенные в статический Markdown, могли работать в режиме гидратации, каждая страница Markdown обрабатывается как компонент Vue и компилируется в JavaScript. Это может показаться неэффективным, но компилятор Vue достаточно умён, чтобы разделить статическую и динамическую части, минимизируя как стоимость гидратации, так и размер полезной нагрузки. При первоначальной загрузке страницы статические части автоматически исключаются из полезной нагрузки JavaScript и пропускаются во время гидратации.\n\n## Что насчёт VuePress? {#what-about-vuepress}\n\nVitePress — это духовный наследник VuePress 1. Оригинальный VuePress 1 основывался на Vue 2 и webpack. Благодаря Vue 3 и Vite под капотом, VitePress обеспечивает значительно лучший опыт разработки (DX), более высокую производительность в продакшене, более отполированную тему по умолчанию и более гибкий API для кастомизации.\n\nРазличия в API между VitePress и VuePress 1 в основном касаются тем и настройки. Если вы используете VuePress 1 с темой по умолчанию, миграция на VitePress должна пройти относительно просто.\n\nПоддерживать два SSG параллельно нецелесообразно, поэтому команда Vue решила сосредоточиться на VitePress как на основном рекомендуемом SSG в долгосрочной перспективе. Теперь VuePress 1 объявлен устаревшим, а VuePress 2 передан команде сообщества VuePress для дальнейшей разработки и поддержки.\n"
  },
  {
    "path": "docs/ru/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Генератор статических сайтов на основе Vite и Vue\n  tagline: Преобразуйте Markdown в красивую документацию за минуты\n  actions:\n    - theme: brand\n      text: Что такое VitePress?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: Первые шаги\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n    src: /vitepress-logo-large.svg\n    alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: Сосредоточьтесь на своем контенте\n    details: Легко создавайте красивые сайты с документацией, используя только Markdown.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: Наслаждайтесь опытом разработчиков Vite\n    details: Мгновенный запуск сервера, молниеносные горячие обновления и использование плагинов экосистемы Vite.\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: Настройка с помощью Vue\n    details: Используйте синтаксис Vue и компоненты прямо в Markdown или создавайте собственные темы с помощью Vue.\n  - icon: 🚀\n    title: Быстрый запуск веб-сайтов\n    details: Быстрая начальная загрузка с помощью статического HTML, быстрая навигация после загрузки с помощью маршрутизации на стороне клиента.\n---\n"
  },
  {
    "path": "docs/ru/reference/cli.md",
    "content": "# Интерфейс командной строки {#command-line-interface}\n\n## `vitepress dev` {#vitepress-dev}\n\nЗапуск сервера разработки VitePress, с использованием указанного каталога в качестве корневого. По умолчанию используется текущий каталог. Команду `dev` также можно опустить при работе в текущем каталоге.\n\n### Использование {#usage}\n\n```sh\n# запуск в текущем каталоге, опускаем `dev`\nvitepress\n\n# запуск в подкаталоге\nvitepress dev [root]\n```\n\n### Параметры {#options}\n\n| Параметр        | Описание                                                                       |\n| --------------- | ------------------------------------------------------------------------------ |\n| `--open [path]` | Открытие браузера при запуске (`boolean \\| string`)                            |\n| `--port <port>` | Номер порта (`number`)                                                         |\n| `--base <path>` | Публичный базовый путь (по умолчанию: `/`) (`string`)                          |\n| `--cors`        | Включить CORS                                                                  |\n| `--strictPort`  | Выйти, если указанный порт уже используется (`boolean`)                        |\n| `--force`       | Заставить оптимизатор игнорировать кэш и повторно объединять файлы (`boolean`) |\n\n## `vitepress build` {#vitepress-build}\n\nСоздание производственной сборки текущего сайта VitePress.\n\n### Использование {#usage-1}\n\n```sh\nvitepress build [root]\n```\n\n### Параметры {#options-1}\n\n| Параметр                       | Описание                                                                                                                            |\n| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |\n| `--mpa` (экспериментально)     | Сборка в режиме [MPA](../guide/mpa-mode) без гидратации на стороне клиента (`boolean`)                                              |\n| `--base <path>`                | Публичный базовый путь (по умолчанию: `/`) (`string`)                                                                               |\n| `--target <target>`            | Транспилировать цель (по умолчанию: `\"modules\"`) (`string`)                                                                         |\n| `--outDir <dir>`               | Выходной каталог относительно **cwd** (по умолчанию: `<root>/.vitepress/dist`) (`string`)                                           |\n| `--assetsInlineLimit <number>` | Статический встроенный порог ресурса base64 в байтах (по умолчанию: `4096`) (`number`)                                              |\n\n## `vitepress preview` {#vitepress-preview}\n\nЛокальный предварительный просмотр производственной сборки.\n\n### Использование {#usage-2}\n\n```sh\nvitepress preview [root]\n```\n\n### Параметры {#options-2}\n\n| Параметр        | Описание                                              |\n| --------------- | ----------------------------------------------------- |\n| `--base <path>` | Публичный базовый путь (по умолчанию: `/`) (`string`) |\n| `--port <port>` | Номер порта (`number`)                                |\n\n## `vitepress init` {#vitepress-init}\n\nЗапуск [Мастера настройки](../guide/getting-started#setup-wizard) в текущем каталоге.\n\n### Использование {#usage-3}\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-badge.md",
    "content": "# Значки {#badge}\n\nС помощью значков удобно добавлять статус к заголовкам. Например, может быть полезно указать тип раздела или поддерживаемую версию.\n\n## Использование {#usage}\n\nВы можете использовать компонент `Badge`, который доступен глобально.\n\n```html\n### Заголовок <Badge type=\"info\" text=\"по умолчанию\" /> ### Заголовок\n<Badge type=\"tip\" text=\"^1.9.0\" /> ### Заголовок\n<Badge type=\"warning\" text=\"beta\" /> ### Заголовок\n<Badge type=\"danger\" text=\"осторожно\" />\n```\n\nПриведённый выше код даёт такой результат:\n\n### Заголовок <Badge type=\"info\" text=\"по умолчанию\" /> {#title}\n\n### Заголовок <Badge type=\"tip\" text=\"^1.9.0\" /> {#title-1}\n\n### Заголовок <Badge type=\"warning\" text=\"beta\" /> {#title-2}\n\n### Заголовок <Badge type=\"danger\" text=\"осторожно\" /> {#title-3}\n\n## Дочерние элементы {#custom-children}\n\n`<Badge>` принимает параметр `children`, который будет отображаться внутри значка.\n\n```html\n### Заголовок <Badge type=\"info\">вложенный элемент</Badge>\n```\n\n### Заголовок <Badge type=\"info\">вложенный элемент</Badge>\n\n## Настройка стиля значков {#customize-type-color}\n\nВы можете настроить стиль значков, переопределив переменные CSS. Ниже приведены значения по умолчанию:\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>` {#badge-1}\n\nКомпонент `<Badge>` принимает следующие параметры:\n\n```ts\ninterface Props {\n  // Когда передается `<slot>`, это значение игнорируется.\n  text?: string\n\n  // По умолчанию: `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-carbon-ads.md",
    "content": "# Carbon Ads {#carbon-ads}\n\nVitePress имеет встроенную поддержку [Carbon Ads](https://www.carbonads.net/). Определив в конфиге учётные данные Carbon Ads, VitePress будет отображать рекламу на странице.\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'код-рекламы',\n      placement: 'место-размещения-рекламы'\n    }\n  }\n}\n```\n\nЭти значения используются для вызова сценария Carbon CDN, как показано ниже:\n\n```js\n;`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\nЧтобы узнать больше о настройке Carbon Ads, посетите [веб-сайт Carbon Ads](https://www.carbonads.net/).\n"
  },
  {
    "path": "docs/ru/reference/default-theme-config.md",
    "content": "# Настройка темы по умолчанию {#default-theme-config}\n\nКонфигурация темы позволяет настроить её под себя. Вы можете настроить тему с помощью опции `themeConfig` в файле конфигурации:\n\n```ts\nexport default {\n  lang: 'ru-RU',\n  title: 'VitePress',\n  description: 'Генератор статического сайта на базе Vite и Vue.',\n\n  // Конфигурации, связанные с темой.\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**Параметры, описанные на этой странице, применимы только к теме по умолчанию.** Разные темы предполагают разные конфигурации темы. При использовании пользовательской темы объект конфигурации темы будет передан теме, чтобы она могла определить условное поведение на его основе.\n\n## i18nRouting\n\n- Тип: `boolean`\n\nПри смене локали на `ru` URL изменится с `/foo` (или `/en/foo/`) на `/ru/foo`. Вы можете отключить это поведение, установив для параметра `themeConfig.i18nRouting` значение `false`.\n\n## logo\n\n- Тип: `ThemeableImage`\n\nФайл логотипа для отображения в навигационной панели, прямо перед заголовком сайта. Принимает строку пути или объект, чтобы установить другой логотип для светлого/тёмного режима.\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- Тип: `string | false`\n\nВы можете настроить этот элемент для замены стандартного заголовка сайта (`title` в конфигурации приложения) в nav. При установке значения `false` заголовок в панели навигации будет отключен. Пригодится, если у вас есть `logo`, который уже содержит текст названия сайта.\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Привет, мир'\n  }\n}\n```\n\n## nav\n\n- Тип: `NavItem`\n\nКонфигурация для пункта навигационного меню. Подробнее в главе [Тема по умолчанию: Навигация](./default-theme-nav#navigation-links).\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Руководство', link: '/guide' },\n      {\n        text: 'Выпадающее меню',\n        items: [\n          { text: 'Пункт A', link: '/item-1' },\n          { text: 'Пункт B', link: '/item-2' },\n          { text: 'Пункт C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- Тип: `Sidebar`\n\nКонфигурация для пунктов меню боковой панели. Подробнее в главе [Тема по умолчанию: Сайдбар](./default-theme-sidebar).\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Руководство',\n        items: [\n          { text: 'Введение', link: '/introduction' },\n          { text: 'Первые шаги', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n}\n\nexport type SidebarItem = {\n  /**\n   * Текстовая метка элемента\n   */\n  text?: string\n\n  /**\n   * Ссылка на элемент\n   */\n  link?: string\n\n  /**\n   * Потомки элемента\n   */\n  items?: SidebarItem[]\n\n  /**\n   * Если не указано, группа не будет сворачиваться\n   *\n   * Если `true`, то группа будет сворачиваться и разворачиваться по умолчанию\n   *\n   * Если `false`, группа сворачивается, но по умолчанию разворачивается\n   */\n  collapsed?: boolean\n\n  /**\n   * Базовый путь для дочерних элементов\n   */\n  base?: string\n\n  /**\n   * Настройте текст, который отображается в футере предыдущей/следующей страницы\n   */\n  docFooterText?: string\n\n  rel?: string\n  target?: string\n}\n```\n\n## aside\n\n- Тип: `boolean | 'left'`\n- По умолчанию: `true`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#aside)\n\nУстановка этого значения в `false` предотвращает отрисовку контейнера сайдбара.\\\nУстановка этого значения в `true` приведёт к отображению сайдбара справа.\\\nУстановка этого значения в `left` приведёт к отображению сайдбара слева.\n\nЕсли вы хотите отключить его для всех режимов просмотра, используйте `aside: false`.\n\n## outline\n\n- Тип: `Outline | Outline['level'] | false`\n- Уровень можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#outline)\n\nУстановка этого значения в `false` предотвращает отрисовку оглавления. Для получения более подробной информации обратитесь к этому интерфейсу:\n\n```ts\ninterface Outline {\n  /**\n   * Уровни заголовков, которые будут отображаться в оглавлении.\n   * Одиночное число означает, что будут отображаться только заголовки этого уровня.\n   * Если передается кортеж, то первое число — это минимальный уровень, а второе — максимальный.\n   * `'deep'` то же самое, что `[2, 6]`, что означает, что будут отображены все заголовки от `<h2>` до `<h6>`.\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * Заголовок, который будет отображаться в оглавлении.\n   *\n   * @default 'На этой странице'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- Тип: `SocialLink[]`\n\nВы можете задать эту опцию, чтобы показывать ссылки на ваши социальные аккаунты с помощью иконок в панели навигации.\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      // Можно добавить любую иконку из simple-icons (https://simpleicons.org/):\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // Можно добавить пользовательские иконки, передав SVG в виде строки:\n      {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // Можно включить пользовательский ярлык для доступности (необязательно, но рекомендуется):\n        ariaLabel: 'классная ссылка'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- Тип: `Footer`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#footer)\n\nНастройка футера. Вы можете разместить в футере сообщение или текст об авторских правах, однако он будет отображаться только в том случае, если страница не содержит боковой панели. Это объясняется соображениями дизайна.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Опубликовано под лицензией MIT.',\n      copyright: '© 2019 – настоящее время, Эван Ю'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- Тип: `EditLink`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#editlink)\n\nСсылка для редактирования позволяет отобразить ссылку для редактирования страницы на сервисах управления Git, таких как GitHub или GitLab. См. секцию [Тема по умолчанию: Ссылка для редактирования](./default-theme-edit-link) для получения более подробной информации.\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Редактировать эту страницу на GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- Тип: `LastUpdatedOptions`\n\nПозволяет настраивать текст и формат даты последнего обновления.\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Обновлено',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- Тип: `AlgoliaSearch`\n\nОпция для поддержки поиска на вашем сайте документации с помощью [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Подробнее в главе [Тема по умолчанию: Поиск](./default-theme-search)\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\nПосмотреть все доступные опции можно [здесь](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts).\n\n## carbonAds {#carbon-ads}\n\n- Тип: `CarbonAdsOptions`\n\nВозможность отображения [Carbon Ads](https://www.carbonads.net/).\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'код-рекламы',\n      placement: 'место-размещения-рекламы'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\nПодробнее в главе [Тема по умолчанию: Carbon Ads](./default-theme-carbon-ads)\n\n## docFooter\n\n- Тип: `DocFooter`\n\nМожно использовать для настройки текста, отображаемого над ссылками на предыдущую и следующую страницы. Полезно, если вы не пишете документы только на английском языке. Также можно использовать для глобального отключения подобных ссылок. Если вы хотите выборочно включить/выключить эти ссылки на отдельной странице, воспользуйтесь [метаданными](./default-theme-prev-next-links).\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Предыдущая страница',\n      next: 'Следующая страница'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- Тип: `string`\n- По умолчанию: `Appearance`\n\nМожно использовать для настройки надписи переключателя тёмного режима. Этот ярлык отображается только в мобильном представлении.\n\n## lightModeSwitchTitle\n\n- Тип: `string`\n- По умолчанию: `Switch to light theme`\n\nМожет использоваться для настройки заголовка переключателя светлого режима, который появляется при наведении курсора.\n\n## darkModeSwitchTitle\n\n- Тип: `string`\n- По умолчанию: `Switch to dark theme`\n\nМожно использовать для настройки заголовка переключателя тёмного режима, который появляется при наведении курсора.\n\n## sidebarMenuLabel\n\n- Тип: `string`\n- По умолчанию: `Menu`\n\nМожет использоваться для настройки метки бокового меню. Эта метка отображается только в мобильном представлении.\n\n## returnToTopLabel\n\n- Тип: `string`\n- По умолчанию: `Return to top`\n\nМожет использоваться для настройки метки кнопки возврата наверх. Эта метка отображается только в мобильном представлении.\n\n## langMenuLabel\n\n- Тип: `string`\n- По умолчанию: `Change language`\n\nМожно использовать для настройки aria-метки кнопки переключения языка в панели навигации. Применяется только в том случае, если вы используете [i18n](../guide/i18n).\n\n## skipToContentLabel\n\n- Тип: `string`\n- По умолчанию: `Skip to content`\n\nМожно использовать для настройки метки ссылки перехода к содержимому. Эта ссылка отображается, когда пользователь перемещается по сайту с помощью клавиатуры.\n\n## externalLinkIcon\n\n- Тип: `boolean`\n- По умолчанию: `false`\n\nОтображать ли значок внешней ссылки рядом с внешними ссылками в Markdown.\n\n## `useLayout` <Badge type=\"info\" text=\"composable\" />\n\nВозвращает данные, относящиеся к макету. Возвращаемый объект имеет следующий тип:\n\n```ts\ninterface {\n  isHome: ComputedRef<boolean>\n\n  sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>\n  sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>\n  hasSidebar: ComputedRef<boolean>\n  isSidebarEnabled: ComputedRef<boolean>\n\n  hasAside: ComputedRef<boolean>\n  leftAside: ComputedRef<boolean>\n\n  headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>\n  hasLocalNav: ComputedRef<boolean>\n}\n```\n\n**Пример:**\n\n```vue\n<script setup>\nimport { useLayout } from 'vitepress/theme'\n\nconst { hasSidebar } = useLayout()\n</script>\n\n<template>\n  <div v-if=\"hasSidebar\">Отображается только если есть боковая панель</div>\n</template>\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-edit-link.md",
    "content": "# Ссылка для редактирования {#edit-link}\n\n## Настройка в файле конфигурации {#site-level-config}\n\nСсылка на редактирование позволяет отобразить ссылку для редактирования страницы на сервисах управления Git, таких как GitHub или GitLab. Чтобы включить её, добавьте опции `themeConfig.editLink` в свой конфиг:\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\nПараметр `pattern` задает структуру URL для ссылки, а `:path` будет заменён на путь к странице.\n\nВы также можете поместить чистую функцию, которая принимает [`PageData`](./runtime-api#usedata) в качестве аргумента и возвращает строку URL.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\nОна не должна иметь побочных эффектов или доступа к чему-либо за пределами своей области, поскольку будет сериализована и выполнена в браузере.\n\nПо умолчанию это добавит текст ссылки «Редактировать страницу» в нижней части документа. Вы можете настроить этот текст, определив опцию `text`.\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Редактировать эту страницу на GitHub'\n    }\n  }\n}\n```\n\n## Настройка в метаданных {#frontmatter-config}\n\nЭту ссылку можно отключить на конкретной странице с помощью опции `editLink` в метаданных:\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-footer.md",
    "content": "# Футер {#footer}\n\nVitePress будет отображать блок футера внизу страницы, если присутствует объект `themeConfig.footer`.\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Опубликовано под лицензией MIT.',\n      copyright: '© 2019 – настоящее время, Эван Ю'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // Сообщение, отображаемое прямо перед копирайтом.\n  message?: string\n\n  // Уведомление об авторских правах.\n  copyright?: string\n}\n```\n\nПриведённая выше конфигурация также поддерживает строки HTML. Так, например, если вы хотите разместить в футере несколько ссылок, можно настроить конфигурацию следующим образом:\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message:\n        'Опубликовано под <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">лицензией MIT</a>.',\n      copyright:\n        '© 2019 – настоящее время, <a href=\"https://github.com/yyx990803\">Эван Ю</a>'\n    }\n  }\n}\n```\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nВ `message` и `copyright` можно использовать только встроенные элементы, поскольку они отображаются внутри элемента `<p>`. Если вы хотите добавить блочные элементы, рассмотрите возможность использования слота [`layout-bottom`](../guide/extending-default-theme#layout-slots).\n:::\n\nОбратите внимание, что футер не будет отображаться, если виден [Сайдбар](./default-theme-sidebar).\n\n## Настройка в метаданных {#frontmatter-config}\n\nОтображение футера можно отключить на конкретной странице с помощью опции `footer` в метаданных:\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-home-page.md",
    "content": "# Главная страница {#home-page}\n\nТема VitePress по умолчанию предоставляет макет главной страницы, который вы также можете увидеть на [главной странице этого сайта](../). Вы можете использовать его на любой из своих страниц, указав `layout: home` в [метаданных](./frontmatter-config) страницы.\n\n```yaml\n---\nlayout: home\n---\n```\n\nОднако сам по себе этот вариант мало что даст. Вы можете добавить несколько различных готовых «секций» на главную страницу, установив дополнительные опции, такие как `hero` и `features`.\n\n## Секция `hero` {#hero-section}\n\nСекция `hero` находится в верхней части главной страницы. Вот как можно её настроить:\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Генератор статических сайтов на основе Vite и Vue.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: Начать\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: Посмотреть на GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // Строка, отображаемая поверх `text`. Поставляется в фирменном цвете и,\n  // как ожидается, будет короткой — например, название продукта\n  name?: string\n\n  // Основной текст секции. Будет использоваться внутри тега `h1`\n  text: string\n\n  // Заголовок, отображаемый под `text`\n  tagline?: string\n\n  // Изображение отображается рядом с `text` и `tagline`\n  image?: ThemeableImage\n\n  // Кнопки действий для отображения в секции\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // Цветовая тема кнопки. По умолчанию принимает значение `brand`.\n  theme?: 'brand' | 'alt'\n\n  // Метка кнопки.\n  text: string\n\n  // Ссылка назначения кнопки.\n  link: string\n\n  // Атрибут цели ссылки.\n  target?: string\n\n  // Атрибут rel ссылки.\n  rel?: string\n}\n```\n\n### Настройка цвета заголовка секции {#customizing-the-name-color}\n\nVitePress использует фирменный цвет (`--vp-c-brand-1`) для атрибута `name` в секции `hero`. Однако вы можете настроить этот цвет, переопределив переменную `--vp-home-hero-name-color`.\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\nТакже вы можете настроить его ещё больше, комбинируя `--vp-home-hero-name-background`, чтобы придать `name` градиентный цвет.\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(\n    120deg,\n    #bd34fe,\n    #41d1ff\n  );\n}\n```\n\n## Секция `features` {#features-section}\n\nВ секции `features` можно перечислить любое количество функций, которые вы хотели бы показать сразу после секции `hero`. Чтобы настроить её, передайте опцию `features` в метаданных страницы.\n\nДля каждой функции можно указать иконку, который может быть эмодзи или любым другим изображением. Если настраиваемая иконка представляет собой изображение (svg, png, jpeg...), вы должны предоставить ей соответствующую ширину и высоту. При необходимости можно указать описание, собственный размер, а также варианты для тёмной и светлой темы.\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Просто и минималистично, всегда\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Ещё одна интересная функция\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Ещё одна интересная функция\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // Иконка\n  icon?: FeatureIcon\n\n  // Заголовок фичи\n  title: string\n\n  // Описание фичи\n  details: string\n\n  // Ссылка при нажатии на компонент функции. Ссылка может быть как внутренней, так и внешней.\n  //\n  // например, `guide/reference/default-theme-home-page` или `https://example.com`\n  link?: string\n\n  // Текст ссылки, который будет отображаться внутри компонента функции. Лучше всего использовать с опцией `link`.\n  //\n  // например, `Узнать подробнее`, `Посетить страницу` и т. д.\n  linkText?: string\n\n  // Атрибут rel для опции `link`\n  //\n  // например, `external`\n  rel?: string\n\n  // Атрибут target для опции `link`\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## Содержимое Markdown {#markdown-content}\n\nВы можете добавить дополнительный контент на главную страницу вашего сайта, просто добавив Markdown под разделителем `---`.\n\n````md\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Генератор статических сайтов на основе Vite и Vue.\n---\n\n## Начало работы\n\nВы можете начать использовать VitePress прямо сейчас, используя `npx`!\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n\n::: info ПРИМЕЧАНИЕ\nVitePress не всегда автоматически стилизовал дополнительный контент страницы с макетом `layout: home`. Чтобы вернуться к старому поведению, добавьте `markdownStyles: false` в метаданных.\n:::\n"
  },
  {
    "path": "docs/ru/reference/default-theme-last-updated.md",
    "content": "# Последнее обновление {#last-updated}\n\nВремя последнего обновления содержимого будет отображаться в правом нижнем углу страницы. Чтобы включить его, добавьте опцию `lastUpdated` в свой конфиг.\n\n::: info ПРИМЕЧАНИЕ\nVitePress отображает время «последнего обновления» на основе временной метки последнего Git-коммита для каждого файла. Для работы этой функции Markdown-файл должен быть закоммичен в Git.\n\nВнутри VitePress выполняет команду `git log -1 --pretty=\"%ai\"` для каждого файла, чтобы получить его временную метку. Если все страницы показывают одинаковое время обновления, вероятно, это связано с поверхностным клонированием (часто встречается в CI-средах), которое ограничивает историю Git.\n\nЧтобы исправить это в **GitHub Actions**, добавьте следующее в ваш workflow-файл:\n\n```yaml{4}\n- name: Checkout\n  uses: actions/checkout@v5\n  with:\n    fetch-depth: 0\n```\n\nДругие CI/CD-платформы имеют аналогичные настройки.\n\nЕсли такие опции недоступны, вы можете добавить принудительный fetch перед командой `docs:build` в вашем `package.json`:\n\n```json\n\"docs:build\": \"git fetch --unshallow && vitepress build docs\"\n```\n:::\n\n## Настройка в файле конфигурации {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## Настройка в метаданных {#frontmatter-config}\n\nЭту информацию можно отключить на конкретной странице с помощью опции `lastUpdated` в метаданных:\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\nТакже смотрите [Тема по умолчанию: `lastUpdated`](./default-theme-config#lastupdated) для получения более подробной информации. Любое истинное значение на уровне темы также включит функцию, если только она не будет явно отключена на уровне сайта или страницы.\n"
  },
  {
    "path": "docs/ru/reference/default-theme-layout.md",
    "content": "# Макет {#layout}\n\nВы можете выбрать макет страницы, установив опцию `layout` в [метаданных](./frontmatter-config). Изначально есть 3 макета: `doc`, `page` и `home`. Если ничего не указано, то страница будет использовать макет `doc`.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## Макет `doc` {#doc-layout}\n\nВариант `doc` — это макет по умолчанию, который стилизует всё содержимое Markdown в виде «документации». Он работает, оборачивая весь контент в CSS-класс `vp-doc` и применяя стили к вложенным элементам.\n\nПочти все общие элементы, такие как `p` или `h2`, получают специальную стилизацию. Поэтому имейте в виду, что если вы добавите какой-либо пользовательский HTML внутри Markdown-контента, то он также будет подвержен влиянию этих стилей.\n\nКроме того, в нём предусмотрены специальные функции, перечисленные ниже. Эти функции включены только в данном макете.\n\n- Ссылка «Редактировать»\n- Ссылки предыдущая/следующая\n- Оглавление\n- Реклама [Carbon Ads](./default-theme-carbon-ads)\n\n## Макет `page` {#page-layout}\n\nВариант `page` сгенерирует «пустую страницу». Markdown всё равно будет разобран, и все [расширения Markdown](../guide/markdown) будут работать так же, как и с макетом `doc`, но никаких стилей по умолчанию применено не будет.\n\nМакет `page` позволит вам оформить всё самостоятельно, без влияния темы VitePress на разметку. Это удобно, когда вы хотите создать свою собственную страницу.\n\nОбратите внимание, что даже при таком раскладе сайдбар всё равно будет отображаться, если у страницы есть соответствующая конфигурация сайдбара.\n\n## Макет `home` {#home-layout}\n\nВариант `home` сгенерирует шаблонную «домашнюю страницу». В этом макете вы можете установить дополнительные параметры, такие как `hero` и `features`, для дальнейшей настройки контента. Посетите секцию [Тема по умолчанию: Домашняя страница](./default-theme-home-page) для получения более подробной информации.\n\n## Без макета {#no-layout}\n\nЕсли вам не нужен макет, вы можете указать `layout: false` в метаданных. Этот параметр полезен, если вам нужна полностью настраиваемая целевая страница (по умолчанию без сайдбара, панели навигации или футера).\n\n## Свой макет {#custom-layout}\n\nВы также можете использовать собственный макет:\n\n```md\n---\nlayout: foo\n---\n```\n\nБудет выполнен поиск компонента с именем `foo`, зарегистрированного в контексте. Например, вы можете зарегистрировать свой компонент глобально в `.vitepress/theme/index.ts`:\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-nav.md",
    "content": "# Навигация {#nav}\n\nКлюч `nav` в конфигурации — это панель навигации, отображаемая в верхней части страницы. Она содержит заголовок сайта, ссылки глобального меню и т. д.\n\n## Название и логотип сайта {#site-title-and-logo}\n\nПо умолчанию навигация отображает название сайта, ссылаясь на значение [`config.title`](./site-config#title). Если вы хотите изменить то, что отображается в панели навигации, задайте пользовательский текст в опции `themeConfig.siteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'Мой заголовок'\n  }\n}\n```\n\nЕсли у вас есть логотип для вашего сайта, вы можете отобразить его, передав путь к изображению. Вы должны поместить логотип непосредственно в директорию `public` и указать абсолютный путь к нему.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\nПри добавлении логотипа он отображается вместе с названием сайта. Если вам нужен только логотип и вы хотите скрыть текст заголовка сайта, установите `false` для параметра `SiteTitle`.\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\nВы также можете передать объект в качестве логотипа, если хотите добавить атрибут `alt` или настроить его в зависимости от тёмного/светлого режима. Подробности смотрите в [`themeConfig.logo`](./default-theme-config#logo).\n\n## Навигационные ссылки {#navigation-links}\n\nВы можете определить опцию `themeConfig.nav`, чтобы добавить ссылки в панель навигации:\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Руководство', link: '/guide' },\n      { text: 'Настройка', link: '/config' },\n      { text: 'Изменения', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` — это текст, отображаемый в навигации, а `link` — это ссылка, на которую будет осуществлён переход при нажатии на текст. Для ссылки задайте путь к фактическому файлу без префикса `.md` и всегда начинайте с `/`.\n\n`link` также может быть функцией, которая принимает [`PageData`](./runtime-api#usedata) в качестве аргумента и возвращает путь.\n\nНавигационные ссылки также могут быть выпадающими меню. Для этого установите ключ `items` вместо ключа `link`:\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Руководство', link: '/guide' },\n      {\n        text: 'Выпадающее меню',\n        items: [\n          { text: 'Пункт A', link: '/item-1' },\n          { text: 'Пункт B', link: '/item-2' },\n          { text: 'Пункт C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nОбратите внимание, что заголовок выпадающего меню (`Выпадающее меню` в примере выше) не может иметь свойство `link`, так как он становится кнопкой для открытия выпадающего диалога.\n\nВы можете добавить «секции» в пункты выпадающего меню, передавая больше вложенных элементов:\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Руководство', link: '/guide' },\n      {\n        text: 'Выпадающее меню',\n        items: [\n          {\n            // Заголовок секции\n            text: 'Секция A',\n            items: [\n              { text: 'Пункт A в секции A', link: '...' },\n              { text: 'Пункт B в секции A', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Выпадающее меню',\n        items: [\n          {\n            // Заголовок можно опустить\n            items: [\n              { text: 'Пункт A в секции A', link: '...' },\n              { text: 'Пункт B в секции A', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Настройка «активного» состояния ссылки {#customize-link-s-active-state}\n\nПункты меню навигации будут выделены, если текущая страница находится под соответствующим путём. Если вы хотите настроить сопоставление путей, определите свойство `activeMatch` и регулярное выражение в качестве строкового значения.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // Эта ссылка получает активное состояние, когда пользователь\n      // переходит по пути `/config/`.\n      {\n        text: 'Руководство',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nОжидается, что `activeMatch` будет регулярным выражением, но вы должны определить его как строку. Мы не можем использовать здесь реальный объект RegExp, потому что он не сериализуется во время сборки.\n:::\n\n### Настройка атрибутов «target» и «rel» {#customize-link-s-target-and-rel-attributes}\n\nПо умолчанию VitePress автоматически определяет атрибуты `target` и `rel` в зависимости от того, является ли ссылка внешней. Но при желании их можно настроить и вручную.\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Товары',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## Социальные ссылки {#social-links}\n\nСм. [`socialLinks`](./default-theme-config#sociallinks).\n\n## Пользовательские компоненты\n\nВы можете добавить пользовательские компоненты в панель навигации с помощью опции `component`. Ключ `component` должен быть именем компонента Vue и должен быть зарегистрирован глобально с помощью [Theme.enhanceApp](../guide/custom-theme#theme-interface).\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Мое меню',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // Необязательные параметры для передачи компоненту\n            props: {\n              title: 'Мой пользовательский компонент'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\nЗатем необходимо зарегистрировать компонент глобально:\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\nВаш компонент будет отображаться на панели навигации. VitePress предоставляет следующие дополнительные параметры компонента:\n\n- `screenMenu`: необязательное булево значение, указывающее, находится ли компонент внутри мобильного навигационного меню\n\nПример можно посмотреть в тестах e2e [здесь](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress).\n"
  },
  {
    "path": "docs/ru/reference/default-theme-prev-next-links.md",
    "content": "# Предыдущая и следующая страницы {#prev-next-links}\n\nВы можете настроить текст и ссылку для предыдущей и следующей страниц (отображаются в нижней части страницы). Это полезно, если вы хотите, чтобы текст отличался от того, что находится в сайдбаре. Кроме того, вы можете счесть полезным отключить футер или ссылку на страницу, которая не включена в сайдбар.\n\n## prev {#prev}\n\n- Тип: `string | false | { text?: string; link?: string }`\n\n- Подробности:\n\n  Указывает текст/ссылку, который должен отображаться при переходе на предыдущую страницу. Если вы не зададите это в метаданных, текст/ссылка будет определяться из конфигурации сайдбара.\n\n- Примеры:\n\n  - Для настройки только текста:\n\n    ```yaml\n    ---\n    prev: 'Начать | Markdown'\n    ---\n    ```\n\n  - Для настройки текста и ссылки:\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - Для скрытия предыдущей страницы:\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next {#next}\n\nАналогично параметру `prev`, но для следующей страницы.\n"
  },
  {
    "path": "docs/ru/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# Поиск {#search}\n\n## Локальный поиск {#local-search}\n\nVitePress поддерживает нечёткий полнотекстовый поиск с использованием внутрибраузерного индекса благодаря [MiniSearch](https://github.com/lucaong/minisearch/). Чтобы включить эту функцию, просто установите значение `'local'` для опции `themeConfig.search.provider` в файле `.vitepress/config.ts`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\nПример результата:\n\n![скриншот модального окна поиска](/search.png)\n\nВ качестве альтернативы можно использовать [Algolia DocSearch](#algolia-search) или некоторые плагины сообщества, например:\n\n- <https://www.npmjs.com/package/vitepress-plugin-search>\n- <https://www.npmjs.com/package/vitepress-plugin-pagefind>\n- <https://www.npmjs.com/package/@orama/plugin-vitepress>\n- <https://www.npmjs.com/package/vitepress-plugin-typesense>\n\n### i18n {#local-search-i18n}\n\nПример конфигурации для использования многоязычного поиска:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          ru: { // используйте `root`, если хотите перевести локаль по умолчанию\n            translations: {\n              button: {\n                buttonText: 'Поиск',\n                buttonAriaLabel: 'Поиск'\n              },\n              modal: {\n                displayDetails: 'Показать подробный список',\n                resetButtonTitle: 'Сбросить поиск',\n                backButtonTitle: 'Закрыть поиск',\n                noResultsText: 'Нет результатов',\n                footer: {\n                  selectText: 'Выбрать',\n                  selectKeyAriaLabel: 'Enter',\n                  navigateText: 'Навигация',\n                  navigateUpKeyAriaLabel: 'Стрелка вверх',\n                  navigateDownKeyAriaLabel: 'Стрелка вниз',\n                  closeText: 'Закрыть',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### Параметры MiniSearch {#minisearch-options}\n\nВы можете настроить MiniSearch следующим образом:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nПодробнее в [документации MiniSearch](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html).\n\n### Пользовательский рендерер содержимого {#custom-content-renderer}\n\nВы можете настроить функцию, используемую для отображения содержимого в формате Markdown перед его индексацией:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // вернуть строку HTML\n        }\n      }\n    }\n  }\n})\n```\n\nЭта функция будет очищена от данных сайта на стороне клиента, поэтому вы можете использовать в ней API Node.js.\n\n#### Пример: Исключение страниц из поиска {#example-excluding-pages-from-search}\n\nВы можете исключить страницы из поиска, добавив `search: false` в блок метаданных страницы. Альтернативный вариант:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning ПРИМЕЧАНИЕ\nВ случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.renderAsync`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого.\n:::\n\n#### Пример: Преобразование содержимого - добавление якорей {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Поиск Algolia {#algolia-search}\n\nVitePress поддерживает поиск в вашей документации с помощью [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Обратитесь к руководству по началу работы. В файле `.vitepress/config.ts` вам нужно будет указать, по крайней мере, следующее, чтобы всё работало:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\nПример конфигурации для использования многоязычного поиска:\n\n<details>\n<summary>Нажмите, чтобы развернуть</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\nПодробности см. в [официальной документации Algolia](https://docsearch.algolia.com/docs/api#translations). Чтобы быстрее начать, можно также скопировать переводы, используемые на этом сайте, из [нашего репозитория GitHub](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code).\n\n### Поддержка Ask AI в Algolia {#ask-ai}\n\nЕсли вы хотите добавить функцию **Ask AI**, передайте параметр `askAi` (или любые из его отдельных полей) внутри объекта `options`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"ВАШ-ID-АССИСТЕНТА\"\n        // ИЛИ\n        askAi: {\n          // как минимум нужно указать assistantId, полученный от Algolia\n          assistantId: 'XXXYYY',\n          // необязательные переопределения — если их нет, используются значения appId/apiKey/indexName верхнего уровня\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning Примечание\nЕсли вы хотите использовать обычный поиск по ключевым словам без Ask AI, просто не указывайте свойство `askAi`\n:::\n\n### Боковая панель Ask AI {#ask-ai-side-panel}\n\nDocSearch v4.5+ поддерживает опциональную **боковую панель Ask AI**. Когда она включена, её можно открыть с помощью **Ctrl/Cmd+I** по умолчанию. [Справочник API боковой панели](https://docsearch.algolia.com/docs/sidepanel/api-reference) содержит полный список опций.\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // Отражает API @docsearch/sidepanel-js SidepanelProps\n            panel: {\n              variant: 'floating', // или 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nЕсли вам нужно отключить сочетание клавиш, используйте опцию `keyboardShortcuts` боковой панели:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### Режим (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\nВы можете опционально контролировать, как VitePress интегрирует поиск по ключевым словам и Ask AI:\n\n- `mode: 'auto'` (по умолчанию): выводит `hybrid`, когда настроен поиск по ключевым словам, иначе `sidePanel`, когда настроена боковая панель Ask AI.\n- `mode: 'sidePanel'`: принудительно использовать только боковую панель (скрывает кнопку поиска по ключевым словам).\n- `mode: 'hybrid'`: включает модальное окно поиска по ключевым словам + боковую панель Ask AI (требует настройки поиска по ключевым словам).\n- `mode: 'modal'`: сохраняет Ask AI внутри модального окна DocSearch (даже если вы настроили боковую панель).\n\n#### Только Ask AI (без поиска по ключевым словам) {#ask-ai-only}\n\nЕсли вы хотите использовать **только боковую панель Ask AI**, вы можете опустить конфигурацию поиска по ключевым словам верхнего уровня и предоставить учётные данные в `askAi`:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### Конфигурация поискового робота {#crawler-config}\n\nВот пример конфигурации, основанной на той, что используется на этом сайте:\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/ru/reference/default-theme-sidebar.md",
    "content": "# Сайдбар {#sidebar}\n\nСайдбар (боковая панель) — основной навигационный блок вашей документации. Меню боковой панели можно настроить в секции [`themeConfig.sidebar`](./default-theme-config#sidebar).\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Руководство',\n        items: [\n          { text: 'Введение', link: '/ru/introduction' },\n          { text: 'Первые шаги', link: '/ru/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Основы {#the-basics}\n\nПростейшая форма сайдбара — это передача массива ссылок. Элемент первого уровня определяет «секцию» сайдбара. Он должен содержать `text`, который является заголовком секции, и `items`, которые являются фактическими навигационными ссылками.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Заголовок секции A',\n        items: [\n          { text: 'Пункт A', link: '/item-a' },\n          { text: 'Пункт B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Заголовок секции B',\n        items: [\n          { text: 'Пункт C', link: '/item-c' },\n          { text: 'Пункт D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\nКаждый элемент `link` должен указывать путь к фактическому файлу, начинающийся с `/`. Если добавить в конец ссылки косую черту, то будет показан `index.md` соответствующего каталога.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Руководство',\n        items: [\n          // Ссылка на страницу `/ru/guide/index.md`\n          { text: 'Введение', link: '/ru/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\nВы можете вложить элементы боковой панели на 6 уровней вглубь, считая от корневого уровня. Обратите внимание, что более 6 уровней вложенных элементов будут игнорироваться и не отображаться на боковой панели.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Уровень 1',\n        items: [\n          {\n            text: 'Уровень 2',\n            items: [\n              {\n                text: 'Уровень 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Несколько сайдбаров {#multiple-sidebars}\n\nВы можете показывать разные боковые панели в зависимости от текущего маршрута. Например, как показано на этом сайте, вы можете создать в документации отдельные разделы, например, «Руководство» и «Настройка».\n\nДля этого сначала организуйте страницы в каталоги для каждого нужного раздела:\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\nЗатем обновите конфигурацию, чтобы определить боковую панель для каждого раздела. На этот раз вместо массива нужно передать объект.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // Эта боковая панель отображается, когда пользователь находится в директории `guide`\n      '/guide/': [\n        {\n          text: 'Руководство',\n          items: [\n            { text: 'Index', link: '/guide/' },\n            { text: 'One', link: '/guide/one' },\n            { text: 'Two', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // Эта боковая панель отображается, когда пользователь находится в директории `config`\n      '/config/': [\n        {\n          text: 'Настройка',\n          items: [\n            { text: 'Index', link: '/config/' },\n            { text: 'Three', link: '/config/three' },\n            { text: 'Four', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## Сворачиваемые группы {#collapsible-sidebar-groups}\n\nДобавив опцию `collapsed` внутри группы `sidebar`, вы увидите кнопку переключения для скрытия/показа каждой секции.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Заголовок секции A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\nВсе секции «развёрнуты» по умолчанию. Если вы хотите, чтобы они были «свёрнуты» при первоначальной загрузке страницы, установите для опции `collapsed` значение `true`.\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Заголовок секции A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/ru/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Эван Ю',\n    title: 'Создатель',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Киа Кинг Исии',\n    title: 'Разработчик',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# Страница команды {#team-page}\n\nЕсли вы хотите представить свою команду, вы можете использовать компоненты Team для создания страницы команды. Есть два варианта использования этих компонентов. Один из вариантов — встроить их в страницу с макетом `doc`, а другой — создать полноценную страницу команды.\n\n## Отображение членов команды на странице {#show-team-members-in-a-page}\n\nВы можете использовать компонент `<VPTeamMembers>`, доступный из `vitepress/theme`, для отображения списка членов команды на любой странице.\n\n```html\n<script setup>\n  import { VPTeamMembers } from 'vitepress/theme'\n\n  const members = [\n    {\n      avatar: 'https://www.github.com/yyx990803.png',\n      name: 'Эван Ю',\n      title: 'Создатель',\n      links: [\n        { icon: 'github', link: 'https://github.com/yyx990803' },\n        { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n      ]\n    },\n    ...\n  ]\n</script>\n\n# Поприветствуйте нашу замечательную команду\n\n<VPTeamMembers size=\"small\" :members />\n```\n\nВышеуказанное отобразит члена команды в виде карточки. Должно отобразиться что-то похожее на то, что показано ниже.\n\n<VPTeamMembers size=\"small\" :members />\n\nКомпонент `<VPTeamMembers>` поставляется в двух различных размерах, `small` и `medium`. Хотя это зависит от ваших предпочтений, обычно размер `small` лучше подходит для использования на странице с макетом `doc`. Кроме того, вы можете добавить дополнительные свойства для карточки члена команды, например, добавить «описание» или кнопку «спонсировать». Подробнее об этом в секции [`<VPTeamMembers>`](#vpteammembers).\n\nВстраивание членов команды в страницу документа хорошо подходит для небольших команд, где наличие полной страницы команды может быть слишком большим, или для представления частичных членов команды в качестве ссылки на контекст документации.\n\nЕсли у вас большое количество участников или вы просто хотите иметь больше места для отображения членов команды, подумайте о [создании отдельной страницы команды](#create-a-full-team-page).\n\n## Создание отдельной страницы команды {#create-a-full-team-page}\n\nВместо того чтобы добавлять членов команды на страницу с макетом `doc`, вы можете создать полноценную страницу команды, подобно созданию пользовательской [главной страницы](./default-theme-home-page).\n\nЧтобы создать страницу команды, сначала создайте новый md-файл. Имя файла не имеет значения, но здесь мы назовем его `team.md`. В этом файле установите в блоке метаданных параметр `layout: page`, а затем вы можете организовать структуру страницы, используя компоненты `TeamPage`.\n\n```html\n---\nlayout: page\n---\n\n<script setup>\n  import {\n    VPTeamPage,\n    VPTeamPageTitle,\n    VPTeamMembers\n  } from 'vitepress/theme'\n\n  const members = [\n    {\n      avatar: 'https://www.github.com/yyx990803.png',\n      name: 'Эван Ю',\n      title: 'Создатель',\n      links: [\n        { icon: 'github', link: 'https://github.com/yyx990803' },\n        { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n      ]\n    },\n    ...\n  ]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title> Наша команда </template>\n    <template #lead>\n      Разработкой VitePress руководит международная команда, некоторые члены\n      которой представлены ниже.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\nПри создании полной страницы команды не забудьте обернуть все компоненты компонентом `<VPTeamPage>`. Этот компонент обеспечит всем вложенным компонентам, связанным с командой, правильную структуру макета, например, расстояние между ними.\n\nКомпонент `<VPPageTitle>` добавляет блок заголовка страницы. Заголовок — это тег `<h1>`. Используйте слоты `#title` и `#lead`, чтобы рассказать о своей команде.\n\n`<VPMembers>` работает так же, как и при использовании в doc-странице. Отобразится список участников.\n\n### Добавление секций для разделения членов команды {#add-sections-to-divide-team-members}\n\nВы можете добавить «секции» на страницу команды. Например, у вас могут быть разные типы членов команды, такие как члены основной команды и партнёры сообщества. Вы можете разделить этих членов на секции, чтобы лучше объяснить роли каждой группы.\n\nДля этого добавьте компонент `<VPTeamPageSection>` в файл `team.md`, который мы создали ранее.\n\n```html\n---\nlayout: page\n---\n\n<script setup>\n  import {\n    VPTeamPage,\n    VPTeamPageTitle,\n    VPTeamMembers,\n    VPTeamPageSection\n  } from 'vitepress/theme'\n\n  const coreMembers = [...]\n  const partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Наша команда</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Партнёры</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\nКомпонент `<VPTeamPageSection>` может иметь слоты `#title` и `#lead`, аналогичные компоненту `VPTeamPageTitle`, а также слот `#members` для отображения членов команды.\n\nНе забудьте поместить компонент `<VPTeamMembers>` в слот `#members`.\n\n## `<VPTeamMembers>` {#vpteammembers}\n\nКомпонент `<VPTeamMembers>` отображает заданный список членов команды.\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // Размер карточки каждого члена команды. По умолчанию `medium`.\n  size?: 'small' | 'medium'\n\n  // Список членов команды для отображения.\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // Изображение аватара.\n  avatar: string\n\n  // Имя члена команды.\n  name: string\n\n  // Заголовок, отображаемый под именем члена команды.\n  // например: разработчик, инженер-программист и т. д.\n  title?: string\n\n  // Организация, в которой состоит текущий член команды.\n  org?: string\n\n  // URL-адрес сайта организации.\n  orgLink?: string\n\n  // Описание члена команды.\n  desc?: string\n\n  // Социальные ссылки: GitHub, Twitter и т. д.\n  // Могут быть переданы в виде объекта.\n  // См. https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // URL-адрес спонсорской страницы члена команды.\n  sponsor?: string\n\n  // Текст спонсорской ссылки. По умолчанию 'Sponsor'.\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>` {#vpteampage}\n\nКорневой компонент при создании отдельной страницы команды. Принимает только один слот. Он будет стилизовать все передаваемые компоненты, связанные с командой.\n\n## `<VPTeamPageTitle>` {#vpteampagetitle}\n\nДобавляет блок «заголовка» страницы. Лучше всего использовать в самом начале внутри `<VPTeamPage>`. Принимает слоты `#title` и `#lead`.\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title> Наша команда </template>\n    <template #lead>\n      Разработкой VitePress руководит международная команда, некоторые члены\n      которой представлены ниже.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>` {#vpteampagesection}\n\nСоздает «секцию» на странице команды. Принимает слоты `#title`, `#lead` и `#members`. Внутри `<VPTeamPage>` вы можете добавить столько секций, сколько захотите.\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Партнёры</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/ru/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# Конфигурация метаданных {#frontmatter-config}\n\nМетаданные обеспечивают настройку отдельных страниц. В каждом файле Markdown можно использовать метаданные, чтобы переопределить параметры конфигурации сайта или темы. Кроме того, есть параметры конфигурации, которые можно задать только через метаданные.\n\nПример использования:\n\n```md\n---\ntitle: Документация с VitePress\neditLink: true\n---\n```\n\nВы можете получить доступ к метаданным через глобальный объект `$frontmatter` в выражениях Vue:\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- Тип: `string`\n\nЗаголовок страницы. Это то же самое, что [config.title](./site-config#title), и оно переопределяет конфигурацию сайта.\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- Тип: `string | boolean`\n\nСуффикс для названия. Это то же самое, что и [config.titleTemplate](./site-config#titletemplate), и оно переопределяет конфигурацию сайта.\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Генератор статических сайтов на основе Vite и Vue\n---\n```\n\n## description\n\n- Тип: `string`\n\nОписание для страницы. Это то же самое, что и [config.description](./site-config#description), и оно переопределяет конфигурацию сайта.\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- Тип: `HeadConfig[]`\n\nУкажите дополнительные теги, которые будут выводиться для текущей страницы. Они будут добавляться после других тегов внутри блока head, введённых в конфигурации сайта.\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: привет\n  - - meta\n    - name: keywords\n      content: супер-пупер SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## Только для темы по умолчанию {#default-theme-only}\n\nСледующие параметры метаданных применимы только при использовании темы по умолчанию.\n\n### layout\n\n- Тип: `doc | home | page`\n- По умолчанию: `doc`\n\nОпределяет макет страницы.\n\n- `doc` - Применяет стили документации по умолчанию к содержимому Markdown.\n- `home` - Вы можете добавить дополнительные параметры, такие как `hero` и `features`, чтобы быстро создать красивую целевую страницу.\n- `page` - Ведет себя аналогично `doc`, но не применяет стили к содержимому. Полезно, если вы хотите создать полностью настраиваемую страницу.\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"только для страниц с макетом home\" />\n\nОпределяет содержимое секции `hero`, когда `layout` имеет значение `home`. Подробнее в главе [Тема по умолчанию: Главная страница](./default-theme-home-page).\n\n### features <Badge type=\"info\" text=\"только для страниц с макетом home\" />\n\nОпределяет элементы для отображения в секции `features`, когда `layout` имеет значение `home`. Подробнее в главе [Тема по умолчанию: Главная страница](./default-theme-home-page).\n\n### navbar\n\n- Тип: `boolean`\n- По умолчанию: `true`\n\nОтображать ли [панель навигации](./default-theme-nav).\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- Тип: `boolean`\n- По умолчанию: `true`\n\nОтображать ли [сайдбар](./default-theme-sidebar).\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- Тип: `boolean | 'left'`\n- По умолчанию: `true`\n\nОпределяет расположение компонента aside в макете `doc`.\n\nУстановка этого значения в `false` предотвращает отрисовку контейнера сайдбара.\\\nУстановка этого значения в `true` приведёт к отображению сайдбара справа.\\\nУстановка этого значения в `left` приведёт к отображению сайдбара слева.\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- Тип: `number | [number, number] | 'deep' | false`\n- По умолчанию: `2`\n\nУровни заголовков в оглавлении для отображения на странице. Это то же самое, что и [config.themeConfig.outline.level](./default-theme-config#outline), и оно переопределяет значение, установленное в конфигурации сайта.\n\n```yaml\n---\noutline: [2, 4]\n---\n```\n\n### lastUpdated\n\n- Тип: `boolean | Date`\n- По умолчанию: `true`\n\nОтображать ли текст [Обновлено](./default-theme-last-updated) в футере текущей страницы. Если указано время даты, оно будет отображаться вместо временной метки последнего изменения git.\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- Тип: `boolean`\n- По умолчанию: `true`\n\nОтображать ли [ссылку для редактирования](./default-theme-edit-link) в футере текущей страницы.\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- Тип: `boolean`\n- По умолчанию: `true`\n\nОтображать ли [футер](./default-theme-footer).\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- Тип: `string`\n\nДобавьте дополнительное имя класса на определённую страницу.\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\nВы также можете настроить стили этой конкретной страницы в файле `.vitepress/theme/custom.css`:\n\n```css\n.custom-page-class {\n  /* стили для конкретной страницы */\n}\n```\n\n### isHome\n\n- Тип: `boolean`\n\nСтандартная тема полагается на проверки типа `frontmatter.layout === 'home'`, чтобы определить, является ли текущая страница домашней (главной).\\\nЭто полезно, когда вы хотите принудительно показывать элементы домашней страницы в пользовательском макете.\n\n```yaml\n---\nisHome: true\n---\n```\n"
  },
  {
    "path": "docs/ru/reference/runtime-api.md",
    "content": "# Runtime API {#runtime-api}\n\nVitePress предлагает несколько встроенных API, позволяющих получить доступ к данным приложения. VitePress также поставляется с несколькими встроенными компонентами, которые можно использовать глобально.\n\nВспомогательные методы глобально импортируются из `vitepress` и обычно используются в компонентах Vue для пользовательских тем. Однако их можно использовать и внутри страниц `.md`, так как файлы markdown компилируются в [однофайловые компоненты](https://ru.vuejs.org/guide/scaling-up/sfc.html) Vue.\n\nМетоды, начинающиеся с `use*`, указывают на то, что это функция [Vue 3 Composition API](https://ru.vuejs.org/guide/introduction.html#composition-api) («композабл»), которая может быть использована только внутри `setup()` или `<script setup>`.\n\n## `useData` <Badge type=\"info\" text=\"композабл\" /> {#usedata}\n\nВозвращает данные, относящиеся к конкретной странице. Возвращаемый объект имеет следующий тип:\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * Метаданные на уровне сайта\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig из .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Метаданные на уровне страницы\n   */\n  page: Ref<PageData>\n  /**\n   * Метаданные страницы\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * Параметры динамического маршрута\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  /**\n   * Текущий хеш адреса\n   */\n  hash: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**Пример:**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"композабл\" /> {#useroute}\n\nВозвращает текущий объект маршрута со следующим типом:\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"композабл\" /> {#userouter}\n\nВозвращает экземпляр маршрутизатора VitePress, чтобы вы могли программно перейти на другую страницу.\n\n```ts\ninterface Router {\n  /**\n   * Текущий маршрут.\n   */\n  route: Route\n  /**\n   * Переход к новому URL-адресу.\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * Вызывается перед изменением маршрута. Верните `false`, чтобы отменить навигацию.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Вызывается перед загрузкой компонента страницы (после того, как состояние истории\n   * обновлено). Верните `false`, чтобы отменить навигацию.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Вызывается после загрузки компонента страницы (перед обновлением компонента страницы).\n   */\n  onAfterPageLoad?: (to: string) => Awaitable<void>\n  /**\n   * Вызывается после изменения маршрута.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"хелпер\" /> {#withbase}\n\n- **Тип**: `(path: string) => string`\n\nДобавляет настроенный [`base`](./site-config#base) к заданному URL-пути. Также смотрите секцию [Базовый URL](../guide/asset-handling#base-url).\n\n## `<Content />` <Badge type=\"info\" text=\"компонент\" /> {#content}\n\nКомпонент `<Content />` отображает отрисованное содержимое Markdown. Полезно [при создании собственной темы](../guide/custom-theme).\n\n```vue\n<template>\n  <h1>Пользовательский макет!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"компонент\" /> {#clientonly}\n\nКомпонент `<ClientOnly />` отображает свой слот только на стороне клиента.\n\nПоскольку приложения VitePress при генерации статических сборок рендерятся в Node.js, любое использование Vue должно соответствовать универсальным требованиям к коду. Короче говоря, убедитесь, что доступ к API Browser / DOM осуществляется только в хуках `beforeMount` или `mounted`.\n\nЕсли вы используете или демонстрируете компоненты, которые не являются SSR-дружественными (например, содержат пользовательские директивы), вы можете обернуть их внутри компонента `ClientOnly`.\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- См. также: [Совместимость с SSR](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"глобальный шаблон\" /> {#frontmatter}\n\nПрямой доступ к [метаданным](../guide/frontmatter) текущей страницы в выражениях Vue.\n\n```md\n---\ntitle: Привет\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"глобальный шаблон\" /> {#params}\n\nПрямой доступ к параметрам [динамических маршрутов](../guide/routing#dynamic-routes) текущей страницы в выражениях Vue.\n\n```md\n- имя пакета: {{ $params.pkg }}\n- версия: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/ru/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# Конфигурация сайта {#site-config}\n\nКонфигурация сайта — это место, где вы можете определить глобальные настройки сайта. Параметры конфигурации приложения определяют настройки, которые применяются к каждому сайту VitePress, независимо от того, какая тема на нем используется. Например, базовый каталог или название сайта.\n\n## Обзор {#overview}\n\n### Разрешение конфигурации {#config-resolution}\n\nКонфигурация всегда считывается из файла `<root>/.vitepress/config.[ext]`, где `<root>` — это корень вашего [проекта](../guide/routing#root-and-source-directory) VitePress, а `[ext]` — одно из поддерживаемых расширений файла. TypeScript поддерживается из коробки. Поддерживаемые расширения включают `.js`, `.ts`, `.mjs` и `.mts`.\n\nВ файлах конфигурации рекомендуется использовать синтаксис ES-модулей. Файл конфигурации должен по умолчанию экспортировать объект:\n\n```ts\nexport default {\n  // параметры конфигурации на уровне приложения\n  lang: 'ru-RU',\n  title: 'VitePress',\n  description: 'Генератор статических сайтов на основе Vite и Vue.',\n  ...\n}\n```\n\n::: details Динамическая (асинхронная) конфигурация\n\nЕсли вам нужно генерировать конфигурацию динамически, вы также можете экспортировать функцию по умолчанию. Например:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // параметры конфигурации на уровне приложения\n    lang: 'ru-RU',\n    title: 'VitePress',\n    description: 'Генератор статических сайтов на основе Vite и Vue.',\n\n    // параметры конфигурации на уровне темы\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\nВы также можете использовать `await` верхнего уровня. Например:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // параметры конфигурации на уровне приложения\n  lang: 'ru-RU',\n  title: 'VitePress',\n  description: 'Генератор статических сайтов на основе Vite и Vue.',\n\n  // параметры конфигурации на уровне темы\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### Интеллектуальная настройка {#config-intellisense}\n\nИспользование помощника `defineConfig` обеспечит интеллектуальный анализ опций конфигурации на основе TypeScript. Если ваша IDE поддерживает эту функцию, она должна работать как в JavaScript, так и в TypeScript.\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### Типизированная конфигурация темы {#typed-theme-config}\n\nПо умолчанию помощник `defineConfig` ожидает тип конфигурации темы из темы по умолчанию:\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // Тип `DefaultTheme.Config`\n  }\n})\n```\n\nЕсли вы используете пользовательскую тему и хотите проверять типы для конфигурации темы, вам нужно использовать `defineConfigWithTheme`, и передавать тип конфигурации для вашей пользовательской темы через общий аргумент:\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // Tип `ThemeConfig`\n  }\n})\n```\n\n### Настройка Vite, Vue и Markdown {#vite-vue-markdown-config}\n\n- **Vite**\n\n  Вы можете настроить базовый экземпляр Vite с помощью опции [vite](#vite) в конфигурации VitePress. Нет необходимости создавать отдельный файл конфигурации Vite.\n\n- **Vue**\n\n  VitePress уже включает в себя официальный плагин Vue для Vite ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue)). Вы можете настроить его параметры с помощью опции [vue](#vue) в конфигурации VitePress.\n\n- **Markdown**\n\n  Вы можете настроить базовый экземпляр [Markdown-It](https://github.com/markdown-it/markdown-it) с помощью опции [markdown](#markdown) в конфигурации VitePress.\n\n## Метаданные сайта {#site-metadata}\n\n### title {#title}\n\n- Тип: `string`\n- По умолчанию: `VitePress`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#title)\n\nНазвание для сайта. При использовании темы по умолчанию оно будет отображаться в панели навигации.\n\nОно также будет использоваться в качестве суффикса по умолчанию для всех заголовков отдельных страниц, если не определен [`titleTemplate`](#titletemplate). Окончательный заголовок отдельной страницы будет представлять собой текстовое содержимое её первого заголовка `<h1>`, объединённое с глобальным `title` в качестве суффикса. Например, со следующей конфигурацией и содержимым страницы:\n\n```ts\nexport default {\n  title: 'Мой замечательный сайт'\n}\n```\n\n```md\n# Привет\n```\n\nЗаголовок страницы будет таким: `Привет | Мой замечательный сайт`.\n\n### titleTemplate {##titletemplate}\n\n- Тип: `string | boolean`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#titletemplate)\n\nПозволяет настраивать суффикс заголовка каждой страницы или весь заголовок. Например:\n\n```ts\nexport default {\n  title: 'Мой замечательный сайт',\n  titleTemplate: 'Пользовательский суффикс'\n}\n```\n\n```md\n# Привет\n```\n\nЗаголовок страницы будет таким: `Привет | Пользовательский суффикс`.\n\nЧтобы полностью настроить отображение заголовка, вы можете использовать символ `:title` в `titleTemplate`:\n\n```ts\nexport default {\n  titleTemplate: ':title - Пользовательский суффикс'\n}\n```\n\nЗдесь `:title` будет заменён текстом, выведенным из первого заголовка страницы `<h1>`. Заголовок страницы предыдущего примера будет `Привет - Пользовательский суффикс`.\n\nОпция может быть установлена в значение `false`, чтобы отключить суффиксы заголовков.\n\n### description {#description}\n\n- Тип: `string`\n- По умолчанию: `A VitePress site`\n- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#description)\n\nОписание для сайта. Это будет отображаться как тег `<meta>` в HTML-странице.\n\n```ts\nexport default {\n  description: 'A VitePress site'\n}\n```\n\n### head {#head}\n\n- Тип: `HeadConfig[]`\n- По умолчанию: `[]`\n- Можно добавлять на страницу через [метаданные](./frontmatter-config#head)\n\nДополнительные элементы для отображения в теге `<head>` в HTML-странице. Добавленные пользователем теги выводятся перед закрывающим тегом `head`, после тегов VitePress.\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### Пример: Добавление значка сайта {#example-adding-a-favicon}\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // поместите favicon.ico в публичную директорию; если установлен параметр base, используйте /base/favicon.ico\n\n/* Отрисуется так:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### Пример: Добавление шрифтов Google {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      {\n        href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',\n        rel: 'stylesheet'\n      }\n    ]\n  ]\n}\n\n/* Отрисуется так:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### Пример: Регистрация сервис-воркера {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* Отрисуется так:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### Пример: Использование Google Analytics {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* Отрисуется так:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang {#lang}\n\n- Тип: `string`\n- По умолчанию: `en-US`\n\nАтрибут lang для сайта. Будет выглядеть как тег `<html lang=\"en-US\">` в HTML-странице.\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base {#base}\n\n- Тип: `string`\n- По умолчанию: `/`\n\nБазовый URL-адрес, по которому будет развёрнут сайт. Этот параметр необходимо задать, если вы планируете развернуть свой сайт по подпути, например, для страниц GitHub. Если вы планируете развернуть свой сайт на `https://foo.github.io/bar/`, то вам следует установить base на `'/bar/'`. Он всегда должен начинаться и заканчиваться косой чертой.\n\nПараметр `base` автоматически добавляется ко всем URL, которые начинаются с `/` в других опциях, поэтому вам нужно указать его только один раз.\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## Маршрутизация {#routing}\n\n### cleanUrls {#cleanurls}\n\n- Тип: `boolean`\n- По умолчанию: `false`\n\nЕсли установить значение `true`, VitePress будет удалять из URL-адресов завершающий `.html`. Также смотрите [Создание чистых URL-адресов](../guide/routing#generating-clean-urls).\n\n::: warning Требуется поддержка сервера\nДля включения этой функции может потребоваться дополнительная настройка на вашей хостинговой платформе. Чтобы это сработало, ваш сервер должен быть способен обслуживать `/foo.html` при посещении `/foo` **без редиректа**.\n:::\n\n### rewrites {#rewrites}\n\n- Тип: `Record<string, string>`\n\nОпределяет сопоставление пользовательских каталогов с URL-адресами. Дополнительную информацию см. в секции [Маршрутизация: перезапись маршрутов](../guide/routing#route-rewrites).\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## Сборка {#build}\n\n### srcDir {#srcdir}\n\n- Тип: `string`\n- По умолчанию: `.`\n\nКаталог, в котором хранятся ваши страницы в формате Markdown, относительно корня проекта. Также смотрите [Корневая директория и директория с исходными файлами](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude {#srcexclude}\n\n- Тип: `string[]`\n- По умолчанию: `undefined`\n\n[Шаблон](https://github.com/mrmlnc/fast-glob#pattern-syntax) для поиска файлов, которые должны быть исключены из исходного содержимого.\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir {#outdir}\n\n- Тип: `string`\n- По умолчанию: `./.vitepress/dist`\n\nРасположение вывода сборки для сайта, относительно [корня проекта](../guide/routing#root-and-source-directory).\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir {#assetsdir}\n\n- Тип: `string`\n- По умолчанию: `assets`\n\nУкажите каталог, в котором будут храниться сгенерированные ресурсы. Путь должен находиться внутри [`outDir`](#outdir) и разрешается относительно него.\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir {#cachedir}\n\n- Тип: `string`\n- По умолчанию: `./.vitepress/cache`\n\nКаталог для файлов кэша, относительно [корня проекта](../guide/routing#root-and-source-directory). См. также: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir).\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks {#ignoredeadlinks}\n\n- Тип: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- По умолчанию: `false`\n\nЕсли установлено значение `true`, VitePress не будет завершать сборку из-за неработающих ссылок.\n\nЕсли установить значение `'localhostLinks'`, сборка будет завершаться при наличии неработающих ссылок, но не будет проверять ссылки `localhost`.\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\nЭто также может быть массив точных строк url, шаблонов regex или пользовательских функций фильтрации.\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // игнорировать url \"/playground\"\n    '/playground',\n    // игнорировать все ссылки на localhost\n    /^https?:\\/\\/localhost/,\n    // игнорировать все ссылки, включающие \"/repl/\"\"\n    /\\/repl\\//,\n    // пользовательская функция, игнорирует все ссылки, включающие \"ignore\"\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"экспериментально\" /> {#metachunk}\n\n- Тип: `boolean`\n- По умолчанию: `false`\n\nЕсли установлено значение `true`, метаданные страницы извлекаются в отдельный фрагмент JavaScript, а не вставляются в исходный HTML. Это уменьшает полезную нагрузку HTML каждой страницы и делает метаданные страниц кэшируемыми, что позволяет снизить пропускную способность сервера при наличии большого количества страниц на сайте.\n\n### mpa <Badge type=\"warning\" text=\"экспериментально\" /> {#mpa}\n\n- Тип: `boolean`\n- По умолчанию: `false`\n\nЕсли установлено значение `true`, производственное приложение будет создано в [режиме MPA](../guide/mpa-mode). В режиме MPA по умолчанию используется 0 КБ JavaScript, что приводит к отключению навигации на стороне клиента и требует явного согласия на интерактивность.\n\n## Тема {#theming}\n\n### appearance {#appearance}\n\n- Тип: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions`\n- По умолчанию: `true`\n\nВключать ли тёмный режим (путём добавления класса `.dark` к элементу `<html>`).\n\n- Если опция имеет значение `true`, тема по умолчанию будет определяться цветовой гаммой, предпочитаемой пользователем.\n- Если опция имеет значение `dark`, тема по умолчанию будет тёмной, если пользователь не переключит её вручную.\n- Если установить значение `false`, пользователи не смогут переключать тему.\n- Если для опции установлено значение `force-dark`, тема всегда будет темной, и пользователи не смогут её переключать.\n- Если для опции установлено значение `force-auto`, тема всегда будет определяться предпочитаемой пользователем цветовой схемой, и пользователи не смогут её переключать.\n\nЭта опция вставляет встроенный скрипт, который восстанавливает настройки пользователей из локального хранилища с помощью ключа `vitepress-theme-appearance`. Это гарантирует, что класс `.dark` будет применён до отрисовки страницы, чтобы избежать мерцания.\n\n`appearance.initialValue` может быть только `'dark' | undefined`. Ссылки или геттеры не поддерживаются.\n\n### lastUpdated {#lastupdated}\n\n- Тип: `boolean`\n- По умолчанию: `false`\n\nПолучать ли временную метку последнего обновления для каждой страницы с помощью Git. Временная метка будет включена в данные каждой страницы, доступные через [`useData`](./runtime-api#usedata).\n\nПри использовании темы по умолчанию включение этой опции приведёт к отображению времени последнего обновления каждой страницы. Вы можете настроить текст с помощью опции [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext).\n\n## Кастомизация {#customization}\n\n### markdown {#markdown}\n\n- Тип: `MarkdownOption`\n\nНастройте параметры парсера Markdown. VitePress использует [Markdown-it](https://github.com/markdown-it/markdown-it) в качестве парсера и [Shiki](https://github.com/shikijs/shiki) для подсветки синтаксиса языка. Внутри этой опции вы можете передать различные параметры, связанные с Markdown, в соответствии с вашими потребностями.\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\nПроверьте [объявление типа и jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) на наличие всех доступных опций.\n\n### vite {#vite}\n\n- Тип: `import('vite').UserConfig`\n\nПередаёт необработанную [конфигурацию Vite](https://vitejs.dev/config/) внутреннему серверу разработки / сборщику Vite.\n\n```js\nexport default {\n  vite: {\n    // параметры конфигурации Vite\n  }\n}\n```\n\n### vue {#vue}\n\n- Тип: `import('@vitejs/plugin-vue').Options`\n\nПередаёт необработанные [параметры `@vitejs/plugin-vue`](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options) внутреннему экземпляру плагина.\n\n```js\nexport default {\n  vue: {\n    // параметры @vitejs/plugin-vue\n  }\n}\n```\n\n## Хуки сборки {#build-hooks}\n\nХуки для сборки VitePress позволяют добавлять на сайт новую функциональность и поведение:\n\n- Карта сайта\n- Поисковая индексация\n- PWA\n- Телепорты\n\n### buildEnd {#buildend}\n\n- Тип: `(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd` — это хук CLI сборки, который будет запущен после завершения сборки (SSG), но до выхода из процесса VitePress CLI.\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender {#postrender}\n\n- Тип: `(context: SSGContext) => Awaitable<SSGContext | void>`\n\n`postRender` — это хук сборки, вызываемый после завершения рендеринга SSG. Это позволит вам обрабатывать содержимое телепортов во время SSG.\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead {#transformhead}\n\n- Тип: `(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` — это хук сборки для преобразования заголовка перед генерацией каждой страницы. Это позволит вам добавить в конфигурацию VitePress записи, которые не могут быть добавлены статически. Вам нужно только вернуть дополнительные записи, они будут автоматически объединены с существующими.\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nНе мутируйте ничего внутри `context`.\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // например, index.md (относительно srcDir)\n  assets: string[] // все ресурсы, не относящиеся к js/css, в виде полностью разрешённых публичных URL-адресов\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\nОбратите внимание, что этот хук вызывается только при статической генерации сайта. Он не вызывается во время разработки. Если вам нужно добавить динамические записи в голову во время разработки, вместо этого вы можете использовать хук [`transformPageData`](#transformpagedata):\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `VitePress`\n            : `${pageData.title} | VitePress`\n      }\n    ])\n  }\n}\n```\n\n#### Пример: Добавление канонического URL-адреса `<link>` {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml {#transformhtml}\n\n- Тип: `(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml` — это хук сборки для преобразования содержимого каждой страницы перед сохранением на диск.\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nНе мутируйте ничего внутри `контекста`. Кроме того, изменение html-содержимого может вызвать проблемы с гидратацией во время выполнения.\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData {#transformpagedata}\n\n- Тип: `(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` — это хук для преобразования `pageData` каждой страницы. Вы можете напрямую изменять `pageData` или возвращать изменённые значения, которые будут объединены с данными страницы.\n\n::: warning ПРЕДУПРЕЖДЕНИЕ\nНе мутируйте ничего внутри `context` и будьте осторожны, это может повлиять на производительность dev-сервера, особенно если у вас есть некоторые сетевые запросы или тяжёлые вычисления (например, генерация изображений) в хуке. Вы можете проверить `process.env.NODE_ENV === 'production'` для условной логики.\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // или возвращаем данные для объединения\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "docs/snippets/algolia-crawler.js",
    "content": "new Crawler({\n  appId: '...',\n  apiKey: '...',\n  rateLimit: 8,\n  startUrls: ['https://vitepress.dev/'],\n  renderJavaScript: false,\n  sitemaps: [],\n  exclusionPatterns: [],\n  ignoreCanonicalTo: false,\n  discoveryPatterns: ['https://vitepress.dev/**'],\n  schedule: 'at 05:10 on Saturday',\n  actions: [\n    {\n      indexName: 'vitepress',\n      pathsToMatch: ['https://vitepress.dev/**'],\n      recordExtractor: ({ $, helpers }) => {\n        return helpers.docsearch({\n          recordProps: {\n            lvl1: '.content h1',\n            content: '.content p, .content li',\n            lvl0: {\n              selectors: 'section.has-active div h2',\n              defaultValue: 'Documentation'\n            },\n            lvl2: '.content h2',\n            lvl3: '.content h3',\n            lvl4: '.content h4',\n            lvl5: '.content h5'\n          },\n          indexHeadings: true\n        })\n      }\n    }\n  ],\n  initialIndexSettings: {\n    vitepress: {\n      attributesForFaceting: ['type', 'lang'],\n      attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'],\n      attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'],\n      attributesToSnippet: ['content:10'],\n      camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'],\n      searchableAttributes: [\n        'unordered(hierarchy_radio_camel.lvl0)',\n        'unordered(hierarchy_radio.lvl0)',\n        'unordered(hierarchy_radio_camel.lvl1)',\n        'unordered(hierarchy_radio.lvl1)',\n        'unordered(hierarchy_radio_camel.lvl2)',\n        'unordered(hierarchy_radio.lvl2)',\n        'unordered(hierarchy_radio_camel.lvl3)',\n        'unordered(hierarchy_radio.lvl3)',\n        'unordered(hierarchy_radio_camel.lvl4)',\n        'unordered(hierarchy_radio.lvl4)',\n        'unordered(hierarchy_radio_camel.lvl5)',\n        'unordered(hierarchy_radio.lvl5)',\n        'unordered(hierarchy_radio_camel.lvl6)',\n        'unordered(hierarchy_radio.lvl6)',\n        'unordered(hierarchy_camel.lvl0)',\n        'unordered(hierarchy.lvl0)',\n        'unordered(hierarchy_camel.lvl1)',\n        'unordered(hierarchy.lvl1)',\n        'unordered(hierarchy_camel.lvl2)',\n        'unordered(hierarchy.lvl2)',\n        'unordered(hierarchy_camel.lvl3)',\n        'unordered(hierarchy.lvl3)',\n        'unordered(hierarchy_camel.lvl4)',\n        'unordered(hierarchy.lvl4)',\n        'unordered(hierarchy_camel.lvl5)',\n        'unordered(hierarchy.lvl5)',\n        'unordered(hierarchy_camel.lvl6)',\n        'unordered(hierarchy.lvl6)',\n        'content'\n      ],\n      distinct: true,\n      attributeForDistinct: 'url',\n      customRanking: [\n        'desc(weight.pageRank)',\n        'desc(weight.level)',\n        'asc(weight.position)'\n      ],\n      ranking: [\n        'words',\n        'filters',\n        'typo',\n        'attribute',\n        'proximity',\n        'exact',\n        'custom'\n      ],\n      highlightPreTag: '<span class=\"algolia-docsearch-suggestion--highlight\">',\n      highlightPostTag: '</span>',\n      minWordSizefor1Typo: 3,\n      minWordSizefor2Typos: 7,\n      allowTyposOnNumericTokens: false,\n      minProximity: 1,\n      ignorePlurals: true,\n      advancedSyntax: true,\n      attributeCriteriaComputedByMinProximity: true,\n      removeWordsIfNoResults: 'allOptional'\n    }\n  }\n})\n"
  },
  {
    "path": "docs/snippets/algolia-i18n.ts",
    "content": "import { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        locales: {\n          zh: {\n            translations: {\n              button: {\n                buttonText: '搜索',\n                buttonAriaLabel: '搜索'\n              },\n              modal: {\n                searchBox: {\n                  clearButtonTitle: '清除',\n                  clearButtonAriaLabel: '清除查询',\n                  closeButtonText: '关闭',\n                  closeButtonAriaLabel: '关闭',\n                  placeholderText: '搜索文档或向 AI 提问',\n                  placeholderTextAskAi: '再问一个问题...',\n                  placeholderTextAskAiStreaming: '正在回答...',\n                  searchInputLabel: '搜索',\n                  backToKeywordSearchButtonText: '返回关键词搜索',\n                  backToKeywordSearchButtonAriaLabel: '返回关键词搜索',\n                  newConversationPlaceholder: '提问',\n                  conversationHistoryTitle: '我的对话历史',\n                  startNewConversationText: '开始新的对话',\n                  viewConversationHistoryText: '对话历史',\n                  threadDepthErrorPlaceholder: '对话已达上限'\n                },\n                newConversation: {\n                  newConversationTitle: '我今天能帮你什么？',\n                  newConversationDescription:\n                    '我会搜索你的文档，快速帮你找到设置指南、功能细节和故障排除提示。'\n                },\n                footer: {\n                  selectText: '选择',\n                  submitQuestionText: '提交问题',\n                  selectKeyAriaLabel: '回车键',\n                  navigateText: '导航',\n                  navigateUpKeyAriaLabel: '向上箭头',\n                  navigateDownKeyAriaLabel: '向下箭头',\n                  closeText: '关闭',\n                  backToSearchText: '返回搜索',\n                  closeKeyAriaLabel: 'Esc 键',\n                  poweredByText: '由…提供支持'\n                },\n                errorScreen: {\n                  titleText: '无法获取结果',\n                  helpText: '你可能需要检查网络连接。'\n                },\n                startScreen: {\n                  recentSearchesTitle: '最近',\n                  noRecentSearchesText: '暂无最近搜索',\n                  saveRecentSearchButtonTitle: '保存此搜索',\n                  removeRecentSearchButtonTitle: '从历史记录中移除此搜索',\n                  favoriteSearchesTitle: '收藏',\n                  removeFavoriteSearchButtonTitle: '从收藏中移除此搜索',\n                  recentConversationsTitle: '最近对话',\n                  removeRecentConversationButtonTitle: '从历史记录中移除此对话'\n                },\n                noResultsScreen: {\n                  noResultsText: '未找到相关结果',\n                  suggestedQueryText: '尝试搜索',\n                  reportMissingResultsText: '认为此查询应该有结果？',\n                  reportMissingResultsLinkText: '告诉我们。'\n                },\n                resultsScreen: {\n                  askAiPlaceholder: '询问 AI：',\n                  noResultsAskAiPlaceholder: '文档里没找到？让 Ask AI 帮忙：'\n                },\n                askAiScreen: {\n                  disclaimerText: '回答由 AI 生成，可能会出错。请核实。',\n                  relatedSourcesText: '相关来源',\n                  thinkingText: '思考中...',\n                  copyButtonText: '复制',\n                  copyButtonCopiedText: '已复制！',\n                  copyButtonTitle: '复制',\n                  likeButtonTitle: '喜欢',\n                  dislikeButtonTitle: '不喜欢',\n                  thanksForFeedbackText: '感谢你的反馈！',\n                  preToolCallText: '搜索中...',\n                  duringToolCallText: '搜索中...',\n                  afterToolCallText: '已搜索',\n                  stoppedStreamingText: '你已停止此回复',\n                  errorTitleText: '聊天错误',\n                  threadDepthExceededMessage: '为保持回答准确，此对话已关闭。',\n                  startNewConversationButtonText: '开始新的对话'\n                }\n              }\n            },\n            askAi: {\n              sidePanel: {\n                button: {\n                  translations: {\n                    buttonText: '询问 AI',\n                    buttonAriaLabel: '询问 AI'\n                  }\n                },\n                panel: {\n                  translations: {\n                    header: {\n                      title: '询问 AI',\n                      conversationHistoryTitle: '我的对话历史',\n                      newConversationText: '开始新的对话',\n                      viewConversationHistoryText: '对话历史'\n                    },\n                    promptForm: {\n                      promptPlaceholderText: '提问',\n                      promptAnsweringText: '正在回答...',\n                      promptAskAnotherQuestionText: '再问一个问题',\n                      promptDisclaimerText: '回答由 AI 生成，可能会出错。',\n                      promptLabelText: '按回车发送，Shift+回车换行。',\n                      promptAriaLabelText: '问题输入'\n                    },\n                    conversationScreen: {\n                      preToolCallText: '搜索中...',\n                      searchingText: '搜索中...',\n                      toolCallResultText: '已搜索',\n                      conversationDisclaimer:\n                        '回答由 AI 生成，可能会出错。请核实。',\n                      reasoningText: '推理中...',\n                      thinkingText: '思考中...',\n                      relatedSourcesText: '相关来源',\n                      stoppedStreamingText: '你已停止此回复',\n                      copyButtonText: '复制',\n                      copyButtonCopiedText: '已复制！',\n                      likeButtonTitle: '喜欢',\n                      dislikeButtonTitle: '不喜欢',\n                      thanksForFeedbackText: '感谢你的反馈！',\n                      errorTitleText: '聊天错误'\n                    },\n                    newConversationScreen: {\n                      titleText: '我今天能帮你什么？',\n                      introductionText:\n                        '我会搜索你的文档，快速帮你找到设置指南、功能细节和故障排除提示。'\n                    },\n                    logo: {\n                      poweredByText: '由…提供支持'\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n"
  },
  {
    "path": "docs/snippets/init.ansi",
    "content": "\u001b[90m┌\u001b[39m  \u001b[1m\u001b[36mWelcome to VitePress!\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mWhere should VitePress initialize the config?\u001b[0m\n\u001b[90m│\u001b[39m  ./docs\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mWhere should VitePress look for your markdown files?\u001b[0m\n\u001b[90m│\u001b[39m  ./docs\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mSite title:\u001b[0m\n\u001b[90m│\u001b[39m  My Awesome Project\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mSite description:\u001b[0m\n\u001b[90m│\u001b[39m  A VitePress Site\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mTheme:\u001b[0m\n\u001b[90m│\u001b[39m  Default Theme\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mUse TypeScript for config and theme files?\u001b[0m\n\u001b[90m│\u001b[39m  Yes\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mAdd VitePress npm scripts to package.json?\u001b[0m\n\u001b[90m│\u001b[39m  Yes\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mAdd a prefix for VitePress npm scripts?\u001b[0m\n\u001b[90m│\u001b[39m  Yes\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[1mPrefix for VitePress npm scripts:\u001b[0m\n\u001b[90m│\u001b[39m  docs\u001b[0m\n\u001b[90m│\u001b[39m\n\u001b[90m└\u001b[39m  \u001b[1mDone! Now run \u001b[36mpnpm run docs:dev\u001b[39m and start writing.\u001b[0m"
  },
  {
    "path": "docs/snippets/snippet-with-region.js",
    "content": "// #region snippet\nfunction foo() {\n  // ..\n}\n// #endregion snippet\n\nexport default foo\n"
  },
  {
    "path": "docs/snippets/snippet.js",
    "content": "export default function () {\n  // ..\n}\n"
  },
  {
    "path": "docs/zh/config.ts",
    "content": "import { createRequire } from 'module'\nimport { defineAdditionalConfig, type DefaultTheme } from 'vitepress'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('vitepress/package.json')\n\nexport default defineAdditionalConfig({\n  description: '由 Vite 和 Vue 驱动的静态站点生成器',\n\n  themeConfig: {\n    nav: nav(),\n\n    search: { options: searchOptions() },\n\n    sidebar: {\n      '/zh/guide/': { base: '/zh/guide/', items: sidebarGuide() },\n      '/zh/reference/': { base: '/zh/reference/', items: sidebarReference() }\n    },\n\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: '在 GitHub 上编辑此页面'\n    },\n\n    footer: {\n      message: '基于 MIT 许可发布',\n      copyright: '版权所有 © 2019-至今 尤雨溪'\n    },\n\n    docFooter: {\n      prev: '上一页',\n      next: '下一页'\n    },\n\n    outline: {\n      label: '页面导航'\n    },\n\n    lastUpdated: {\n      text: '最后更新于'\n    },\n\n    notFound: {\n      title: '页面未找到',\n      quote:\n        '但如果你不改变方向，并且继续寻找，你可能最终会到达你所前往的地方。',\n      linkLabel: '前往首页',\n      linkText: '带我回首页'\n    },\n\n    langMenuLabel: '多语言',\n    returnToTopLabel: '回到顶部',\n    sidebarMenuLabel: '菜单',\n    darkModeSwitchLabel: '主题',\n    lightModeSwitchTitle: '切换到浅色模式',\n    darkModeSwitchTitle: '切换到深色模式',\n    skipToContentLabel: '跳转到内容'\n  }\n})\n\nfunction nav(): DefaultTheme.NavItem[] {\n  return [\n    {\n      text: '指南',\n      link: '/zh/guide/what-is-vitepress',\n      activeMatch: '/zh/guide/'\n    },\n    {\n      text: '参考',\n      link: '/zh/reference/site-config',\n      activeMatch: '/zh/reference/'\n    },\n    {\n      text: pkg.version,\n      items: [\n        {\n          text: '1.6.4',\n          link: 'https://vuejs.github.io/vitepress/v1/zh/'\n        },\n        {\n          text: '更新日志',\n          link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md'\n        },\n        {\n          text: '参与贡献',\n          link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md'\n        }\n      ]\n    }\n  ]\n}\n\nfunction sidebarGuide(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '简介',\n      collapsed: false,\n      items: [\n        { text: '什么是 VitePress？', link: 'what-is-vitepress' },\n        { text: '快速开始', link: 'getting-started' },\n        { text: '路由', link: 'routing' },\n        { text: '部署', link: 'deploy' }\n      ]\n    },\n    {\n      text: '写作',\n      collapsed: false,\n      items: [\n        { text: 'Markdown 扩展', link: 'markdown' },\n        { text: '资源处理', link: 'asset-handling' },\n        { text: 'frontmatter', link: 'frontmatter' },\n        { text: '在 Markdown 使用 Vue', link: 'using-vue' },\n        { text: '国际化', link: 'i18n' }\n      ]\n    },\n    {\n      text: '自定义',\n      collapsed: false,\n      items: [\n        { text: '自定义主题', link: 'custom-theme' },\n        { text: '扩展默认主题', link: 'extending-default-theme' },\n        { text: '构建时数据加载', link: 'data-loading' },\n        { text: 'SSR 兼容性', link: 'ssr-compat' },\n        { text: '连接 CMS', link: 'cms' }\n      ]\n    },\n    {\n      text: '实验性功能',\n      collapsed: false,\n      items: [\n        { text: 'MPA 模式', link: 'mpa-mode' },\n        { text: 'sitemap 生成', link: 'sitemap-generation' }\n      ]\n    },\n    { text: '配置和 API 参考', base: '/zh/reference/', link: 'site-config' }\n  ]\n}\n\nfunction sidebarReference(): DefaultTheme.SidebarItem[] {\n  return [\n    {\n      text: '参考',\n      items: [\n        { text: '站点配置', link: 'site-config' },\n        { text: 'frontmatter 配置', link: 'frontmatter-config' },\n        { text: '运行时 API', link: 'runtime-api' },\n        { text: 'CLI', link: 'cli' },\n        {\n          text: '默认主题',\n          base: '/zh/reference/default-theme-',\n          items: [\n            { text: '概览', link: 'config' },\n            { text: '导航栏', link: 'nav' },\n            { text: '侧边栏', link: 'sidebar' },\n            { text: '主页', link: 'home-page' },\n            { text: '页脚', link: 'footer' },\n            { text: '布局', link: 'layout' },\n            { text: '徽章', link: 'badge' },\n            { text: '团队页', link: 'team-page' },\n            { text: '上下页链接', link: 'prev-next-links' },\n            { text: '编辑链接', link: 'edit-link' },\n            { text: '最后更新时间戳', link: 'last-updated' },\n            { text: '搜索', link: 'search' },\n            { text: 'Carbon Ads', link: 'carbon-ads' }\n          ]\n        }\n      ]\n    }\n  ]\n}\n\nfunction searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {\n  return {\n    translations: {\n      button: {\n        buttonText: '搜索',\n        buttonAriaLabel: '搜索'\n      },\n      modal: {\n        searchBox: {\n          clearButtonTitle: '清除',\n          clearButtonAriaLabel: '清除查询',\n          closeButtonText: '关闭',\n          closeButtonAriaLabel: '关闭',\n          placeholderText: '搜索文档或向 AI 提问',\n          placeholderTextAskAi: '再问一个问题...',\n          placeholderTextAskAiStreaming: '正在回答...',\n          searchInputLabel: '搜索',\n          backToKeywordSearchButtonText: '返回关键词搜索',\n          backToKeywordSearchButtonAriaLabel: '返回关键词搜索',\n          newConversationPlaceholder: '提问',\n          conversationHistoryTitle: '我的对话历史',\n          startNewConversationText: '开始新的对话',\n          viewConversationHistoryText: '对话历史',\n          threadDepthErrorPlaceholder: '对话已达上限'\n        },\n        newConversation: {\n          newConversationTitle: '我今天能帮你什么？',\n          newConversationDescription:\n            '我会搜索你的文档，快速帮你找到设置指南、功能细节和故障排除提示。'\n        },\n        footer: {\n          selectText: '选择',\n          submitQuestionText: '提交问题',\n          selectKeyAriaLabel: '回车键',\n          navigateText: '导航',\n          navigateUpKeyAriaLabel: '向上箭头',\n          navigateDownKeyAriaLabel: '向下箭头',\n          closeText: '关闭',\n          backToSearchText: '返回搜索',\n          closeKeyAriaLabel: 'Esc 键',\n          poweredByText: '由…提供支持'\n        },\n        errorScreen: {\n          titleText: '无法获取结果',\n          helpText: '你可能需要检查网络连接。'\n        },\n        startScreen: {\n          recentSearchesTitle: '最近',\n          noRecentSearchesText: '暂无最近搜索',\n          saveRecentSearchButtonTitle: '保存此搜索',\n          removeRecentSearchButtonTitle: '从历史记录中移除此搜索',\n          favoriteSearchesTitle: '收藏',\n          removeFavoriteSearchButtonTitle: '从收藏中移除此搜索',\n          recentConversationsTitle: '最近对话',\n          removeRecentConversationButtonTitle: '从历史记录中移除此对话'\n        },\n        noResultsScreen: {\n          noResultsText: '未找到相关结果',\n          suggestedQueryText: '尝试搜索',\n          reportMissingResultsText: '认为此查询应该有结果？',\n          reportMissingResultsLinkText: '告诉我们。'\n        },\n        resultsScreen: {\n          askAiPlaceholder: '询问 AI：',\n          noResultsAskAiPlaceholder: '文档里没找到？让 Ask AI 帮忙：'\n        },\n        askAiScreen: {\n          disclaimerText: '回答由 AI 生成，可能会出错。请核实。',\n          relatedSourcesText: '相关来源',\n          thinkingText: '思考中...',\n          copyButtonText: '复制',\n          copyButtonCopiedText: '已复制！',\n          copyButtonTitle: '复制',\n          likeButtonTitle: '喜欢',\n          dislikeButtonTitle: '不喜欢',\n          thanksForFeedbackText: '感谢你的反馈！',\n          preToolCallText: '搜索中...',\n          duringToolCallText: '搜索中...',\n          afterToolCallText: '已搜索',\n          stoppedStreamingText: '你已停止此回复',\n          errorTitleText: '聊天错误',\n          threadDepthExceededMessage: '为保持回答准确，此对话已关闭。',\n          startNewConversationButtonText: '开始新的对话'\n        }\n      }\n    },\n    askAi: {\n      sidePanel: {\n        button: {\n          translations: {\n            buttonText: '询问 AI',\n            buttonAriaLabel: '询问 AI'\n          }\n        },\n        panel: {\n          translations: {\n            header: {\n              title: '询问 AI',\n              conversationHistoryTitle: '我的对话历史',\n              newConversationText: '开始新的对话',\n              viewConversationHistoryText: '对话历史'\n            },\n            promptForm: {\n              promptPlaceholderText: '提问',\n              promptAnsweringText: '正在回答...',\n              promptAskAnotherQuestionText: '再问一个问题',\n              promptDisclaimerText: '回答由 AI 生成，可能会出错。',\n              promptLabelText: '按回车发送，Shift+回车换行。',\n              promptAriaLabelText: '问题输入'\n            },\n            conversationScreen: {\n              preToolCallText: '搜索中...',\n              searchingText: '搜索中...',\n              toolCallResultText: '已搜索',\n              conversationDisclaimer: '回答由 AI 生成，可能会出错。请核实。',\n              reasoningText: '推理中...',\n              thinkingText: '思考中...',\n              relatedSourcesText: '相关来源',\n              stoppedStreamingText: '你已停止此回复',\n              copyButtonText: '复制',\n              copyButtonCopiedText: '已复制！',\n              likeButtonTitle: '喜欢',\n              dislikeButtonTitle: '不喜欢',\n              thanksForFeedbackText: '感谢你的反馈！',\n              errorTitleText: '聊天错误'\n            },\n            newConversationScreen: {\n              titleText: '我今天能帮你什么？',\n              introductionText:\n                '我会搜索你的文档，快速帮你找到设置指南、功能细节和故障排除提示。'\n            },\n            logo: {\n              poweredByText: '由…提供支持'\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/zh/guide/asset-handling.md",
    "content": "# 资源处理 {#asset-handling}\n\n## 引用静态资源 {#referencing-static-assets}\n\n所有的 Markdown 文件都会被编译成 Vue 组件，并由 [Vite](https://cn.vitejs.dev/guide/assets.html) 处理。可以**并且应该**使用相对路径来引用资源：\n\n```md\n![An image](./image.png)\n```\n\n可以在 Markdown 文件、主题中的 `*.vue` 组件、样式和普通的 `.css` 文件中引用静态资源，可以使用绝对路径 (基于项目根目录) 或者相对路径 (基于文件系统)。后者类似于 Vite、Vue CLI 或者 webpack 的 `file-loader` 的行为。\n\n常见的图像，媒体和字体文件会被自动检测并视作资源。\n\n::: tip 通过链接引用的文件不会视作资源\n在 Markdown 内，通过链接引用的 PDF 或者其他文档不会被自动视作资源。要使这些文件可用，你必须手动将其放在项目的 [`public`](#the-public-directory) 目录内。\n:::\n\n所有引用的资源，包括那些使用绝对路径的，都会在生产构建过程中被复制到输出目录，并使用哈希文件名。从未使用过的资源将不会被复制。小于 4kb 的图像资源将会采用 base64 内联——这可以通过 [`vite`](../reference/site-config#vite) 配置选项进行配置。\n\n所有**静态**路径引用，包括绝对路径，都应基于你的工作目录的结构。\n\n## public 目录 {#the-public-directory}\n\n有时可能需要一些静态资源，但这些资源没有直接被 Markdown 或主题组件直接引用，或者你可能想以原始文件名提供某些文件，像 `robots.txt`，favicons 和 PWA 图标这样的文件。\n\n可以将这些文件放置在[源目录](./routing#source-directory)的 `public` 目录中。例如，如果项目根目录是 `./docs`，并且使用默认源目录位置，那么 public 目录将是 `./docs/public`。\n\n放置在 `public` 中的资源将按原样复制到输出目录的根目录中。\n\n请注意，应使用根绝对路径来引用放置在 `public` 中的文件——例如，`public/icon.png` 应始终在源代码中使用 `/icon.png` 引用。\n\n## 根 URL {#base-url}\n\n如果站点没有部署在根 URL 上，则需要在 `.vitepress/config.js` 中设置 `base` 选项。例如，如果计划将站点部署到 `https://foo.github.io/bar/`，则 `base` 应设置为 `'/bar/'`(它应始终以斜杠开头和结尾)。\n\n所有静态资源路径都会被自动处理，来适应不同的 `base` 配置值。例如，如果 markdown 中有一个对 `public` 中的资源的绝对引用：\n\n```md\n![An image](/image-inside-public.png)\n```\n\n在这种情况下，更改 `base` 配置值时，**无需**更新该引用。\n\n但是如果你正在编写一个主题组件，它动态地链接到资源，例如一个图片，它的 `src` 基于主题配置：\n\n```vue\n<img :src=\"theme.logoPath\" />\n```\n\n在这种情况下，建议使用 VitePress 提供的 [`withBase` helper](../reference/runtime-api#withbase) 来包括路径：\n\n```vue\n<script setup>\nimport { withBase, useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <img :src=\"withBase(theme.logoPath)\" />\n</template>\n```\n"
  },
  {
    "path": "docs/zh/guide/cms.md",
    "content": "---\noutline: deep\n---\n\n# 连接到 CMS {#connecting-to-a-cms}\n\n## 一般的工作流 {#general-workflow}\n\n将 VitePress 连接到 CMS 主要围绕[动态路由](./routing#dynamic-routes)展开。在继续阅读之前，请确保了解它的工作原理。\n\n由于每个 CMS 的工作方式都不同，因此我们只能提供一个通用的工作流，你需要根据具体情况进行调整。\n\n1. 如果你的 CMS 需要身份验证，请创建一个 `.env` 文件来存储你的 API token：\n\n    ```js\n    // posts/[id].paths.js\n    import { loadEnv } from 'vitepress'\n\n    const env = loadEnv('', process.cwd())\n    ```\n\n2. 从 CMS 获取必要的数据并将其格式调整为合适的路径数据：\n\n   ```js\n    export default {\n      async paths() {\n        // 如有需要，使用相应的 CMS 客户端库\n        const data = await (await fetch('https://my-cms-api', {\n          headers: {\n            // 如有必要，可使用 token\n          }\n        })).json()\n\n        return data.map(entry => {\n          return {\n            params: { id: entry.id, /* title, authors, date 等 */ },\n            content: entry.content\n          }\n        })\n      }\n    }\n    ```\n\n3. 在页面中渲染内容：\n\n    ```md\n    # {{ $params.title }}\n\n    - by {{ $params.author }} on {{ $params.date }}\n\n    <!-- @content -->\n    ```\n\n## 整合指南 {#integration-guides}\n\n如果你已经写了一篇关于如何将 VitePress 与特定的 CMS 集成的指南，请点击下面的“在 GitHub 上编辑此页面”链接将它提交到这里！\n"
  },
  {
    "path": "docs/zh/guide/custom-theme.md",
    "content": "# 自定义主题 {#using-a-custom-theme}\n\n## 解析主题 {#theme-resolving}\n\n可以通过创建一个 `.vitepress/theme/index.js` 或 `.vitepress/theme/index.ts` 文件 (即“主题入口文件”) 来启用自定义主题：\n\n```\n.\n├─ docs                # 项目根目录\n│  ├─ .vitepress\n│  │  ├─ theme\n│  │  │  └─ index.js   # 主题入口\n│  │  └─ config.js     # 配置文件\n│  └─ index.md\n└─ package.json\n```\n\n当检测到存在主题入口文件时，VitePress 总会使用自定义主题而不是默认主题。但你可以[扩展默认主题](./extending-default-theme)来在其基础上实现更高级的自定义。\n\n## 主题接口 {#theme-interface}\n\nVitePress 自定义主题是一个对象，该对象具有如下接口：\n\n```ts\ninterface Theme {\n  /**\n   * 每个页面的根布局组件\n   * @required\n   */\n  Layout: Component\n  /**\n   * 增强 Vue 应用实例\n   * @optional\n   */\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  /**\n   * 扩展另一个主题，在我们的主题之前调用它的 `enhanceApp`\n   * @optional\n   */\n  extends?: Theme\n}\n\ninterface EnhanceAppContext {\n  app: App // Vue 应用实例\n  router: Router // VitePress 路由实例\n  siteData: Ref<SiteData> // 站点级元数据\n}\n```\n\n主题入口文件需要将主题作为默认导出来导出：\n\n```js [.vitepress/theme/index.js]\n\n// 可以直接在主题入口导入 Vue 文件\n// VitePress 已预先配置 @vitejs/plugin-vue\nimport Layout from './Layout.vue'\n\nexport default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}\n```\n\n默认导出是自定义主题的唯一方式，并且只有 `Layout` 属性是必须的。所以从技术上讲，一个 VitePress 主题可以是一个单独的 Vue 组件。\n\n在组件内部，它的工作方式就像是一个普通的 Vite + Vue 3 应用。请注意，主题还需要保证 [SSR 兼容](./ssr-compat)。\n\n## 构建布局 {#building-a-layout}\n\n最基本的布局组件需要包含一个 [`<Content />`](../reference/runtime-api#content) 组件：\n\n```vue [.vitepress/theme/Layout.vue]\n<template>\n  <h1>Custom Layout!</h1>\n\n  <!-- 此处将渲染 markdown 内容 -->\n  <Content />\n</template>\n```\n\n上面的布局只是将每个页面的 markdown 渲染为 HTML。我们添加的第一个改进是处理 404 错误：\n\n```vue{1-4,9-12}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <Content v-else />\n</template>\n```\n\n[`useData()`](../reference/runtime-api#usedata) 为我们提供了所有的运行时数据，以便我们根据不同条件渲染不同的布局。我们可以访问的另一个数据是当前页面的 frontmatter。通过利用这个数据，可以让用户单独控制每个页面的布局。例如，用户可以指定一个页面是否使用特殊的主页布局：\n\n```md\n---\nlayout: home\n---\n```\n\n并且我们可以调整主题进行处理：\n\n```vue{3,12-14}\n<script setup>\nimport { useData } from 'vitepress'\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <div v-if=\"page.isNotFound\">\n    Custom 404 page!\n  </div>\n  <div v-if=\"frontmatter.layout === 'home'\">\n    Custom home page!\n  </div>\n  <Content v-else />\n</template>\n```\n\n当然你可以将布局切分为不同的组件：\n\n```vue{3-5,12-15}\n<script setup>\nimport { useData } from 'vitepress'\nimport NotFound from './NotFound.vue'\nimport Home from './Home.vue'\nimport Page from './Page.vue'\n\nconst { page, frontmatter } = useData()\n</script>\n\n<template>\n  <h1>Custom Layout!</h1>\n\n  <NotFound v-if=\"page.isNotFound\" />\n  <Home v-if=\"frontmatter.layout === 'home'\" />\n  <Page v-else /> <!-- <Page /> renders <Content /> -->\n</template>\n```\n\n请查看[运行时 API 参考](../reference/runtime-api)获取主题组件中所有可用内容。此外，可以利用[构建时数据加载](./data-loading)来生成数据驱动布局——例如，一个列出当前项目中所有博客文章的页面。\n\n## 分发自定义主题 {#distributing-a-custom-theme}\n\n分发自定义主题最简单的方式是通过将其作为 [GitHub 模版仓库](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository)。\n\n如果你希望将主题作为 npm 包来分发，请按照下面的步骤操作：\n\n1. 在包入口将主题对象使用默认导出。\n\n2. 如果合适的话，将主题配置类型定义作为 `ThemeConfig` 导出。\n\n3. 如果主题需要调整 VitePress 配置，请在包的子路径下 (例如 `my-theme/config`) 下导出该配置，以便用户扩展。\n\n4. 记录主题配置选项 (通过配置文件和 frontmatter)。\n\n5. 提供清晰的说明，告诉用户如何使用主题 (见下文)。\n\n## 使用自定义主题 {#consuming-a-custom-theme}\n\n要使用外部主题，请导入它并重新导出：\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default Theme\n```\n\n如果主题需要扩展：\n\n```js [.vitepress/theme/index.js]\nimport Theme from 'awesome-vitepress-theme'\n\nexport default {\n  extends: Theme,\n  enhanceApp(ctx) {\n    // ...\n  }\n}\n```\n\n如果主题需要特殊的 VitePress 配置，也需要在配置中扩展：\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\n\nexport default {\n  // 扩展主题的基本配置（如需要）\n  extends: baseConfig\n}\n```\n\n最后，如果主题为其主题配置提供了类型：\n\n```ts [.vitepress/config.ts]\nimport baseConfig from 'awesome-vitepress-theme/config'\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'awesome-vitepress-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  extends: baseConfig,\n  themeConfig: {\n    // 类型为 `ThemeConfig`\n  }\n})\n```\n"
  },
  {
    "path": "docs/zh/guide/data-loading.md",
    "content": "# 构建时数据加载 {#build-time-data-loading}\n\nVitePress 提供了**数据加载**的功能，它允许加载任意数据并从页面或组件中导入它。数据加载**只在构建时**执行：最终的数据将被序列化为 JavaScript 包中的 JSON。\n\n数据加载可以被用于获取远程数据，也可以基于本地文件生成元数据。例如，可以使用数据加载来解析所有本地 API 页面并自动生成所有 API 入口的索引。\n\n## 基本用法 {#basic-usage}\n\n一个用于数据加载的文件必须以 `.data.js` 或 `.data.ts` 结尾。该文件应该提供一个默认导出的对象，该对象具有 `load()` 方法：\n\n```js [example.data.js]\nexport default {\n  load() {\n    return {\n      hello: 'world'\n    }\n  }\n}\n```\n\n数据加载模块只在 Node.js 中执行，因此可以按需导入 Node API 和 npm 依赖。\n\n然后，可以在 `.md` 页面和 `.vue` 组件中使用 `data` 具名导出从该文件中导入数据：\n\n```vue\n<script setup>\nimport { data } from './example.data.js'\n</script>\n\n<pre>{{ data }}</pre>\n```\n\n输出：\n\n```json\n{\n  \"hello\": \"world\"\n}\n```\n\n你会注意到 data loader 本身并没有导出 `data`。这是因为 VitePress 在后台调用了 `load()` 方法，并通过名为 `data` 的具名导出隐式地暴露了结果。\n\n即使它是异步的，这也是有效的：\n\n```js\nexport default {\n  async load() {\n    // 获取远程数据\n    return (await fetch('...')).json()\n  }\n}\n```\n\n## 使用本地文件生成数据 {#data-from-local-files}\n\n当需要基于本地文件生成数据时，需要在 data loader 中使用 `watch` 选项，以便这些文件改动时可以触发热更新。\n\n`watch` 选项也很方便，因为可以使用 [glob 模式](https://github.com/mrmlnc/fast-glob#pattern-syntax) 匹配多个文件。模式可以相对于数据加载文件本身，`load()` 函数将接收匹配文件的绝对路径。\n\n下面的例子展示了如何使用 [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) 加载 CSV 文件并将其转换为 JSON。因为此文件仅在构建时执行，因此不会将 CSV 解析器发送到客户端。\n\n```js\nimport fs from 'node:fs'\nimport { parse } from 'csv-parse/sync'\n\nexport default {\n  watch: ['./data/*.csv'],\n  load(watchedFiles) {\n    // watchFiles 是一个所匹配文件的绝对路径的数组。\n    // 生成一个博客文章元数据数组\n    // 可用于在主题布局中呈现列表。\n    return watchedFiles.map((file) => {\n      return parse(fs.readFileSync(file, 'utf-8'), {\n        columns: true,\n        skip_empty_lines: true\n      })\n    })\n  }\n}\n```\n\n## `createContentLoader`\n\n当构建一个内容为主的站点时，我们经常需要创建一个“归档”或“索引”页面：一个我们可以列出内容中的所有可用条目的页面，例如博客文章或 API 页面。我们**可以**直接使用数据加载 API 实现这一点，但由于这会经常使用，VitePress 还提供了一个 `createContentLoader` 辅助函数来简化这个过程：\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', /* options */)\n```\n\n该辅助函数接受一个相对于[源目录](./routing#source-directory)的 glob 模式，并返回一个 `{ watch, load }` 数据加载对象，该对象可以用作数据加载文件中的默认导出。它还基于文件修改时间戳实现了缓存以提高开发性能。\n\n请注意，数据加载仅适用于 Markdown 文件——匹配的非 Markdown 文件将被跳过。\n\n加载的数据将是一个类型为 `ContentData[]` 的数组：\n\n```ts\ninterface ContentData {\n  // 页面的映射 URL，如 /posts/hello.html（不包括 base）\n  // 手动迭代或使用自定义 `transform` 来标准化路径\n  url: string\n  // 页面的 frontmatter 数据\n  frontmatter: Record<string, any>\n\n  // 只有启用了相关选项，才会出现以下内容\n  // 我们将在下面讨论它们\n  src: string | undefined\n  html: string | undefined\n  excerpt: string | undefined\n}\n```\n\n默认情况下只提供 `url` 和 `frontmatter`。这是因为加载的数据将作为 JSON 内联在客户端 bundle 中，我们需要谨慎考虑其大小。下面的例子展示了如何使用数据构建最小的博客索引页面：\n\n```vue\n<script setup>\nimport { data as posts } from './posts.data.js'\n</script>\n\n<template>\n  <h1>All Blog Posts</h1>\n  <ul>\n    <li v-for=\"post of posts\">\n      <a :href=\"post.url\">{{ post.frontmatter.title }}</a>\n      <span>by {{ post.frontmatter.author }}</span>\n    </li>\n  </ul>\n</template>\n```\n\n### 选项 {#options}\n\n默认数据可能不适合所有需求——可以选择使用选项转换数据：\n\n```js [posts.data.js]\nimport { createContentLoader } from 'vitepress'\n\nexport default createContentLoader('posts/*.md', {\n  includeSrc: true, // 包含原始 markdown 源?\n  render: true,     // 包含渲染的整页 HTML?\n  excerpt: true,    // 包含摘录?\n  transform(rawData) {\n    // 根据需要对原始数据进行 map、sort 或 filter\n    // 最终的结果是将发送给客户端的内容\n    return rawData.sort((a, b) => {\n      return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)\n    }).map((page) => {\n      page.src     // 原始 markdown 源\n      page.html    // 渲染的整页 HTML\n      page.excerpt // 渲染的摘录 HTML（第一个 `---` 上面的内容）\n      return {/* ... */}\n    })\n  }\n})\n```\n\n查看它在 [Vue.js 博客](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts)中是如何使用的。\n\n`createContentLoader` API 也可以在[构建钩子](../reference/site-config#build-hooks)中使用：\n\n```js [.vitepress/config.js]\nexport default {\n  async buildEnd() {\n    const posts = await createContentLoader('posts/*.md').load()\n    // 根据 posts 元数据生成文件，如 RSS 订阅源\n  }\n}\n```\n\n**类型**\n\n```ts\ninterface ContentOptions<T = ContentData[]> {\n  /**\n   * 包含 src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * 将 src 渲染为 HTML 并包含在数据中?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * 如果为 `boolean`，是否解析并包含摘录? (呈现为 HTML)\n   *\n   * 如果为 `function`，则控制如何从内容中提取摘录\n   *\n   * 如果为 `string`，则定义用于提取摘录的自定义分隔符\n   * 如果 `excerpt` 为 `true`，则默认分隔符为 `---`\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void)\n    | string\n\n  /**\n   * 转换数据。请注意，如果从组件或 Markdown 文件导入，数据将以 JSON 形式内联到客户端包中\n   */\n  transform?: (data: ContentData[]) => T | Promise<T>\n}\n```\n\n## 为 data loader 导出类型 {#typed-data-loaders}\n\n当使用 TypeScript 时，可以像这样为 loader 和 `data` 导出类型：\n\n```ts\nimport { defineLoader } from 'vitepress'\n\nexport interface Data {\n  // data 类型\n}\n\ndeclare const data: Data\nexport { data }\n\nexport default defineLoader({\n  // 类型检查加载器选项\n  watch: ['...'],\n  async load(): Promise<Data> {\n    // ...\n  }\n})\n```\n\n## 配置 {#configuration}\n\n要获取 data loader 中的配置信息，可以使用如下代码：\n\n```ts\nimport type { SiteConfig } from 'vitepress'\n\nconst config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG\n```\n"
  },
  {
    "path": "docs/zh/guide/deploy.md",
    "content": "---\noutline: deep\n---\n\n# 部署 VitePress 站点 {#deploy-your-vitepress-site}\n\n以下指南基于一些前提：\n\n- VitePress 站点位于项目的 `docs` 目录中。\n- 你使用的是默认的生成输出目录 （`.vitepress/dist`）。\n- VitePress 作为本地依赖项安装在项目中，并且你已在 `package.json` 中设置以下脚本：\n\n  ```json [package.json]\n  {\n    \"scripts\": {\n      \"docs:build\": \"vitepress build docs\",\n      \"docs:preview\": \"vitepress preview docs\"\n    }\n  }\n  ```\n\n## 本地构建与测试 {#build-and-test-locally}\n\n1. 可以运行以下命令来构建文档：\n\n   ```sh\n   $ npm run docs:build\n   ```\n\n2. 构建文档后，通过运行以下命令可以在本地预览它：\n\n   ```sh\n   $ npm run docs:preview\n   ```\n\n   `preview` 命令将启动一个本地静态 Web 服务 `http://localhost:4173`，该服务以 `.vitepress/dist` 作为源文件。这是检查生产版本在本地环境中是否正常的一种简单方法。\n\n3. 可以通过传递 `--port` 作为参数来配置服务器的端口。\n\n   ```json\n   {\n     \"scripts\": {\n       \"docs:preview\": \"vitepress preview docs --port 8080\"\n     }\n   }\n   ```\n\n   现在 `docs:preview` 方法将会在 `http://localhost:8080` 启动服务。\n\n## 设定 public 根目录 {#setting-a-public-base-path}\n\n默认情况下，我们假设站点将部署在域名 (`/`) 的根路径上。如果站点在子路径中提供服务，例如 `https://mywebsite.com/blog/`，则需要在 VitePress 配置中将 [`base`](../reference/site-config#base) 选项设置为 `'/blog/'`。\n\n**例**：如果你使用的是 Github（或 GitLab）页面并部署到 `user.github.io/repo/`，请将 `base` 设置为 `/repo/`。\n\n## HTTP 缓存标头 {#http-cache-headers}\n\n如果可以控制生产服务器上的 HTTP 标头，则可以配置 `cache-control` 标头以在重复访问时获得更好的性能。\n\n生产版本对静态资源 (JavaScript、CSS 和其他非 `public` 目录中的导入资源) 使用哈希文件名。如果你使用浏览器开发工具的网络选项卡查看生产预览，你将看到类似 `app.4f283b18.js` 的文件。\n\n此哈希 `4f283b18` 是从此文件的内容生成的。相同的哈希 URL 保证提供相同的文件内容——如果内容更改，URL 也会更改。这意味着你可以安全地为这些文件使用最强的缓存标头。所有此类文件都将放置在输出目录的 `assets/` 中，因此你可以为它们配置以下标头：\n\n```\nCache-Control: max-age=31536000,immutable\n```\n\n::: details Netlify 示例 `_headers` 文件\n\n```\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n```\n\n注意：该 `_headers` 文件应放置在 [public 目录](./asset-handling#the-public-directory)中 (在我们的例子中是 `docs/public/_headers`)，以便将其逐字复制到输出目录。\n\n[Netlify 自定义标头文档](https://docs.netlify.com/routing/headers/)\n\n:::\n\n::: details Vercel 配置示例 `vercel.json`\n\n```json\n{\n  \"headers\": [\n    {\n      \"source\": \"/assets/(.*)\",\n      \"headers\": [\n        {\n          \"key\": \"Cache-Control\",\n          \"value\": \"max-age=31536000, immutable\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n注意：`vercel.json` 文件应放在存储库的根目录中。\n\n[Vercel 关于标头配置的文档](https://vercel.com/docs/concepts/projects/project-configuration#headers)\n\n:::\n\n## 各平台部署指南 {#platform-guides}\n\n### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic}\n\n使用仪表板创建新项目并更改这些设置：\n\n- **构建命令：** `npm run docs:build`\n- **输出目录：** `docs/.vitepress/dist`\n- **node 版本：** `20` (或更高版本)\n\n::: warning\n不要为 HTML 代码启用 _Auto Minify_ 等选项。它将从输出中删除对 Vue 有意义的注释。如果被删除，你可能会看到激活不匹配错误。\n:::\n\n### GitHub Pages\n\n1. 在项目的 `.github/workflows` 目录中创建一个名为 `deploy.yml` 的文件，其中包含这样的内容：\n\n   ```yaml [.github/workflows/deploy.yml]\n   # 构建 VitePress 站点并将其部署到 GitHub Pages 的示例工作流程\n   #\n   name: Deploy VitePress site to Pages\n\n   on:\n     # 在针对 `main` 分支的推送上运行。如果你\n     # 使用 `master` 分支作为默认分支，请将其更改为 `master`\n     push:\n       branches: [main]\n\n     # 允许你从 Actions 选项卡手动运行此工作流程\n     workflow_dispatch:\n\n   # 设置 GITHUB_TOKEN 的权限，以允许部署到 GitHub Pages\n   permissions:\n     contents: read\n     pages: write\n     id-token: write\n\n   # 只允许同时进行一次部署，跳过正在运行和最新队列之间的运行队列\n   # 但是，不要取消正在进行的运行，因为我们希望允许这些生产部署完成\n   concurrency:\n     group: pages\n     cancel-in-progress: false\n\n   jobs:\n     # 构建工作\n     build:\n       runs-on: ubuntu-latest\n       steps:\n         - name: Checkout\n           uses: actions/checkout@v5\n           with:\n             fetch-depth: 0 # 如果未启用 lastUpdated，则不需要\n         # - uses: pnpm/action-setup@v4 # 如果使用 pnpm，请取消此区域注释\n         #   with:\n         #     version: 9\n         # - uses: oven-sh/setup-bun@v1 # 如果使用 Bun，请取消注释\n         - name: Setup Node\n           uses: actions/setup-node@v6\n           with:\n             node-version: 24\n             cache: npm # 或 pnpm / yarn\n         - name: Setup Pages\n           uses: actions/configure-pages@v4\n         - name: Install dependencies\n           run: npm ci # 或 pnpm install / yarn install / bun install\n         - name: Build with VitePress\n           run: npm run docs:build # 或 pnpm docs:build / yarn docs:build / bun run docs:build\n         - name: Upload artifact\n           uses: actions/upload-pages-artifact@v3\n           with:\n             path: docs/.vitepress/dist\n\n     # 部署工作\n     deploy:\n       environment:\n         name: github-pages\n         url: ${{ steps.deployment.outputs.page_url }}\n       needs: build\n       runs-on: ubuntu-latest\n       name: Deploy\n       steps:\n         - name: Deploy to GitHub Pages\n           id: deployment\n           uses: actions/deploy-pages@v4\n   ```\n\n   ::: warning\n   确保 VitePress 中的 `base` 选项配置正确。有关更多详细信息，请参阅[设置根路径](#setting-a-public-base-path)。\n   :::\n\n2. 在存储库设置中的“Pages”菜单项下，选择“Build and deployment > Source > GitHub Actions”。\n\n3. 将更改推送到 `main` 分支并等待 GitHub Action 工作流完成。你应该看到站点部署到 `https://<username>.github.io/[repository]/` 或 `https://<custom-domain>/`，这取决于你的设置。你的站点将在每次推送到 `main` 分支时自动部署。\n\n### GitLab Pages\n\n1. 如果你想部署到 `https://<username> .gitlab.io/<repository> /`，将 VitePress 配置中的 `outDir` 设置为 `../public`。将 `base` 选项配置为 `'/<repository>/'`。如果你部署到自定义域名、用户或组织页面，或在 GitLab 中启用了“Use unique domain”设置，则不需要 `base`。\n\n2. 在项目的根目录中创建一个名为 `.gitlab-ci.yml` 的文件，其中包含以下内容。每当你更改内容时，这都会构建和部署你的站点：\n\n   ```yaml [.gitlab-ci.yml]\n   image: node:24\n   pages:\n     cache:\n       paths:\n         - node_modules/\n     script:\n       # - apk add git # 如果你使用的是像 alpine 这样的小型 docker 镜像，并且启用了 lastUpdated，请取消注释\n       - npm install\n       - npm run docs:build\n     artifacts:\n       paths:\n         - public\n     only:\n       - main\n   ```\n\n### Azure\n\n1. 参考[官方文档](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration)。\n\n2. 在配置文件中设置这些值 (并删除不需要的值，如 `api_location`)：\n\n   - **`app_location`**: `/`\n   - **`output_location`**: `docs/.vitepress/dist`\n   - **`app_build_command`**: `npm run docs:build`\n\n### CloudRay\n\n你可以按照这些[说明](https://cloudray.io/articles/how-to-deploy-vitepress-site)使用 [CloudRay](https://cloudray.io/) 部署你的 VitePress 项目。\n\n### Firebase\n\n1. 在项目的根目录下创建 `firebase.json` 和 `.firebaserc`：\n\n   `firebase.json`:\n\n   ```json [firebase.json]\n   {\n     \"hosting\": {\n       \"public\": \"docs/.vitepress/dist\",\n       \"ignore\": []\n     }\n   }\n   ```\n\n   `.firebaserc`:\n\n   ```json [.firebaserc]\n   {\n     \"projects\": {\n       \"default\": \"<YOUR_FIREBASE_ID>\"\n     }\n   }\n   ```\n\n2. 运行 `npm run docs:build` 后，运行此命令进行部署：\n\n   ```sh\n   firebase deploy\n   ```\n\n### Heroku\n\n1. 参考 [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) 中给出的文档和指南。\n\n2. 使用以下内容在项目的根目录中创建一个名为 `static.json` 的文件：\n\n   ```json [static.json]\n   {\n     \"root\": \"docs/.vitepress/dist\"\n   }\n   ```\n\n### Hostinger\n\n你可以按照这些[说明](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/)使用 [Hostinger](https://www.hostinger.com/web-apps-hosting) 部署你的 VitePress 项目。在配置构建设置时，选择 VitePress 作为框架，并将根目录调整为 `./docs`。\n\n### Kinsta\n\n你可以按照这些[说明](https://kinsta.com/docs/vitepress-static-site-example/) 在 [Kinsta](https://kinsta.com/static-site-hosting/) 上部署 VitePress 站点。\n\n### Stormkit\n\n你可以按照这些[说明](https://stormkit.io/blog/how-to-deploy-vitepress)将你的 VitePress 项目部署到 [Stormkit](https://www.stormkit.io)。\n\n### Surge\n\n1. 运行 `npm run docs:build` 后，运行此命令进行部署：\n\n   ```sh\n   npx surge docs/.vitepress/dist\n   ```\n\n### Nginx\n\n下面是一个 Nginx 服务器块配置示例。此配置包括对基于文本的常见资源的 gzip 压缩、使用适当缓存头为 VitePress 站点静态文件提供服务的规则以及处理 `cleanUrls: true` 的方法。\n\n```nginx\nserver {\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;\n\n    listen 80;\n    server_name _;\n    index index.html;\n\n    location / {\n        # 内容位置\n        root /app;\n\n        # 完全匹配 -> 反向清理 url -> 文件夹 -> 没有发现    \n        try_files $uri $uri.html $uri/ =404;\n\n        # 不存在的页面\n        error_page 404 /404.html;\n\n        # 在此设置中，如果文件夹没有 index.html，就会引发 403 错误\n        error_page 403 /404.html;\n\n        # 调整缓存标头\n        # assets 文件夹中的文件都有哈希文件名\n        location ~* ^/assets/ {\n            expires 1y;\n            add_header Cache-Control \"public, immutable\";\n        }\n    }\n}\n```\n\n本配置默认已构建的 VitePress 站点位于服务器上的 `/app` 目录中。如果站点文件位于其他位置，请相应调整 `root` 指令。\n\n::: warning 不要默认为 index.html\ntry_files 解析不能像其他 Vue 应用那样默认为 index.html。这会导致页面状态处于无效。\n:::\n\n更多信息请参见 [nginx 官方文档](https://nginx.org/en/docs/)、这些 GitHub Issue [#2837](https://github.com/vuejs/vitepress/discussions/2837)、[#3235](https://github.com/vuejs/vitepress/issues/3235)以及 Mehdi Merah 发表的[博客](https://blog.mehdi.cc/articles/vitepress-cleanurls-on-nginx-environment#readings)。\n"
  },
  {
    "path": "docs/zh/guide/extending-default-theme.md",
    "content": "---\noutline: deep\n---\n\n# 扩展默认主题 {#extending-the-default-theme}\n\nVitePress 默认的主题已经针对文档进行了优化，并且可以进行自定义。请参考[默认主题配置概览](../reference/default-theme-config)获取完整的选项列表。\n\n但是有一些情况仅靠配置是不够的。例如：\n\n1. 需要调整 CSS 样式；\n2. 需要修改 Vue 应用实例，例如注册全局组件；\n3. 需要通过 layout 插槽将自定义内容注入到主题中；\n\n这些高级自定义配置将需要使用自定义主题来“拓展”默认主题。\n\n::: tip\n在继续之前，请确保首先阅读[自定义主题](./custom-theme)以了解其工作原理。\n:::\n\n## 自定义 CSS {#customizing-css}\n\n可以通过覆盖根级别的 CSS 变量来自定义默认主题的 CSS：\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/custom.css */\n:root {\n  --vp-c-brand-1: #646cff;\n  --vp-c-brand-2: #747bff;\n}\n```\n\n查看[默认主题 CSS 变量](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css)来获取可以被覆盖的变量。\n\n## 使用自定义字体 {#using-different-fonts}\n\nVitePress 使用 [Inter](https://rsms.me/inter/) 作为默认字体，并且将其包含在生成的输出中。该字体在生产环境中也会自动预加载。但是如果要使用不同的字体，这可能不是很好。\n\n为了避免在生成后的输出中包含 Inter 字体，请从 `vitepress/theme-without-fonts` 中导入主题：\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme-without-fonts'\nimport './my-fonts.css'\n\nexport default DefaultTheme\n```\n\n```css\n/* .vitepress/theme/my-fonts.css */\n:root {\n  --vp-font-family-base: /* 普通文本字体 */\n  --vp-font-family-mono: /* 代码字体 */\n}\n```\n\n::: warning\n如果你在使用像是[团队页](../reference/default-theme-team-page)这样的组件，请确保也从 `vitepress/theme-without-fonts` 中导入它们！\n:::\n\n如果字体是通过 `@font-face` 引用的本地文件，它将会被作为资源被包含在 `.vitepress/dist/asset` 目录下，并且使用哈希后的文件名。为了预加载这个文件，请使用 [transformHead](../reference/site-config#transformhead) 构建钩子：\n\n```js [.vitepress/config.js]\nexport default {\n  transformHead({ assets }) {\n    // 相应地调整正则表达式以匹配字体\n    const myFontFile = assets.find(file => /font-name\\.[\\w-]+\\.woff2/.test(file))\n    if (myFontFile) {\n      return [\n        [\n          'link',\n          {\n            rel: 'preload',\n            href: myFontFile,\n            as: 'font',\n            type: 'font/woff2',\n            crossorigin: ''\n          }\n        ]\n      ]\n    }\n  }\n}\n```\n\n## 注册全局组件 {#registering-global-components}\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 注册自定义全局组件\n    app.component('MyGlobalComponent' /* ... */)\n  }\n}\n```\n\n如果使用 TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    // 注册自定义全局组件\n    app.component('MyGlobalComponent' /* ... */)\n  }\n} satisfies Theme\n```\n\n因为我们使用 Vite，还可以利用 Vite 的 [glob 导入功能](https://cn.vitejs.dev/guide/features.html#glob-import)来自动注册一个组件目录。\n\n## 布局插槽 {#layout-slots}\n\n默认主题的 `<Layout/>` 组件有一些插槽，能够被用来在页面的特定位置注入内容。下面这个例子展示了将一个组件注入到 outline 之前：\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\nimport MyLayout from './MyLayout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  // 使用注入插槽的包装组件覆盖 Layout\n  Layout: MyLayout\n}\n```\n\n```vue [.vitepress/theme/MyLayout.vue]\n<script setup>\nimport DefaultTheme from 'vitepress/theme'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #aside-outline-before>\n      My custom sidebar top content\n    </template>\n  </Layout>\n</template>\n```\n\n也可以使用渲染函数。\n\n```js [.vitepress/theme/index.js]\nimport { h } from 'vue'\nimport DefaultTheme from 'vitepress/theme'\nimport MyComponent from './MyComponent.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout() {\n    return h(DefaultTheme.Layout, null, {\n      'aside-outline-before': () => h(MyComponent)\n    })\n  }\n}\n```\n\n默认主题布局的全部可用插槽如下：\n\n- 当 `layout: 'doc'` (默认) 在 frontmatter 中被启用时：\n  - `doc-top`\n  - `doc-bottom`\n  - `doc-footer-before`\n  - `doc-before`\n  - `doc-after`\n  - `sidebar-nav-before`\n  - `sidebar-nav-after`\n  - `aside-top`\n  - `aside-bottom`\n  - `aside-outline-before`\n  - `aside-outline-after`\n  - `aside-ads-before`\n  - `aside-ads-after`\n- 当 `layout: 'home'` 在 frontmatter 中被启用时:\n  - `home-hero-before`\n  - `home-hero-info-before`\n  - `home-hero-info`\n  - `home-hero-info-after`\n  - `home-hero-actions-before-actions`\n  - `home-hero-actions-after`\n  - `home-hero-image`\n  - `home-hero-after`\n  - `home-features-before`\n  - `home-features-after`\n- 当 `layout: 'page'` 在 frontmatter 中被启用时:\n  - `page-top`\n  - `page-bottom`\n- 当未找到页面 (404) 时:\n  - `not-found`\n- 总是启用:\n  - `layout-top`\n  - `layout-bottom`\n  - `nav-bar-title-before`\n  - `nav-bar-title-after`\n  - `nav-bar-content-before`\n  - `nav-bar-content-after`\n  - `nav-screen-content-before`\n  - `nav-screen-content-after`\n\n## 使用视图过渡 API\n\n### 关于外观切换 {#on-appearance-toggle}\n\n可以扩展默认主题以在切换颜色模式时提供自定义过渡动画。例如：\n\n```vue [.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport { useData } from 'vitepress'\nimport DefaultTheme from 'vitepress/theme'\nimport { nextTick, provide } from 'vue'\n\nconst { isDark } = useData()\n\nconst enableTransitions = () =>\n  'startViewTransition' in document &&\n  window.matchMedia('(prefers-reduced-motion: no-preference)').matches\n\nprovide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {\n  if (!enableTransitions()) {\n    isDark.value = !isDark.value\n    return\n  }\n\n  const clipPath = [\n    `circle(0px at ${x}px ${y}px)`,\n    `circle(${Math.hypot(\n      Math.max(x, innerWidth - x),\n      Math.max(y, innerHeight - y)\n    )}px at ${x}px ${y}px)`\n  ]\n\n  await document.startViewTransition(async () => {\n    isDark.value = !isDark.value\n    await nextTick()\n  }).ready\n\n  document.documentElement.animate(\n    { clipPath: isDark.value ? clipPath.reverse() : clipPath },\n    {\n      duration: 300,\n      easing: 'ease-in',\n      fill: 'forwards',\n      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`\n    }\n  )\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n\n<style>\n::view-transition-old(root),\n::view-transition-new(root) {\n  animation: none;\n  mix-blend-mode: normal;\n}\n\n::view-transition-old(root),\n.dark::view-transition-new(root) {\n  z-index: 1;\n}\n\n::view-transition-new(root),\n.dark::view-transition-old(root) {\n  z-index: 9999;\n}\n\n.VPSwitchAppearance {\n  width: 22px !important;\n}\n\n.VPSwitchAppearance .check {\n  transform: none !important;\n}\n</style>\n```\n\n结果（**注意！**：画面闪烁、快速闪现、强光刺激）:\n\n<details>\n<summary>Demo</summary>\n\n![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp)\n\n</details>\n\n有关视图过渡动画的更多详细信息，请参阅 [Chrome 文档](https://developer.chrome.com/docs/web-platform/view-transitions/)。\n\n### 路由切换时 {#on-route-change}\n\n即将到来。\n\n## 重写内部组件 {#overriding-internal-components}\n\n可以使用 Vite 的 [aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) 来用自定义组件替换默认主题的组件：\n\n```ts\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  vite: {\n    resolve: {\n      alias: [\n        {\n          find: /^.*\\/VPNavBar\\.vue$/,\n          replacement: fileURLToPath(\n            new URL('./components/CustomNavBar.vue', import.meta.url)\n          )\n        }\n      ]\n    }\n  }\n})\n```\n\n想要了解组件的确切名称请参考我们的[源代码](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components)。因为组件是内部的，因此在小版本更迭中，它们名字改动的可能性很小。\n"
  },
  {
    "path": "docs/zh/guide/frontmatter.md",
    "content": "# frontmatter\n\n## 用法 {#usage}\n\nVitePress 支持在所有 Markdown 文件中使用 YAML frontmatter，并使用 [gray-matter](https://github.com/jonschlinkert/gray-matter) 解析。frontmatter 必须位于 Markdown 文件的顶部 (在任何元素之前，包括 `<script>` 标签)，并且需要在三条虚线之间采用有效的 YAML 格式。例如：\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\n许多站点或默认主题配置选项在 frontmatter 中都有相应的选项。可以使用 frontmatter 来覆盖当前页面的特定行为。详细信息请参见 [frontmatter 配置参考](../reference/frontmatter-config)。\n\n还可以定义自己的 frontmatter 数据，以在页面上的动态 Vue 表达式中使用。\n\n## 访问 frontmatter 数据 {#accessing-frontmatter-data}\n\nfrontmatter 数据可以通过特殊的 `$frontmatter` 全局变量来访问：\n\n下面的例子展示了应该如何在 Markdown 文件中使用它：\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n\n# {{ $frontmatter.title }}\n\nGuide content\n```\n\n还可以使用 [`useData()`](../reference/runtime-api#usedata) 辅助函数在 `<script setup>` 中访问当前页面的 frontmatter。\n\n## 其他 frontmatter 格式 {#alternative-frontmatter-formats}\n\nVitePress 也支持 JSON 格式的 frontmatter，以花括号开始和结束：\n\n```json\n---\n{\n  \"title\": \"Blogging Like a Hacker\",\n  \"editLink\": true\n}\n---\n```\n"
  },
  {
    "path": "docs/zh/guide/getting-started.md",
    "content": "# 快速开始 {#getting-started}\n\n## 在线尝试 {#try-it-online}\n\n可以直接在 [StackBlitz](https://vitepress.new) 上进行在线尝试。\n\n## 安装 {#installation}\n\n### 前置准备 {#prerequisites}\n\n- [Node.js](https://nodejs.org/) 20 及以上版本。\n- 通过命令行界面 (CLI) 访问 VitePress 的终端。\n- 支持 [Markdown](https://en.wikipedia.org/wiki/Markdown) 语法的编辑器。\n  - 推荐 [VSCode](https://code.visualstudio.com/) 及其[官方 Vue 扩展](https://marketplace.visualstudio.com/items?itemName=Vue.volar)。\n\nVitePress 可以单独使用，也可以安装到现有项目中。在这两种情况下，都可以使用以下方式安装它：\n\n::: code-group\n\n```sh [npm]\n$ npm add -D vitepress@next\n```\n\n```sh [pnpm]\n$ pnpm add -D vitepress@next\n```\n\n```sh [yarn]\n$ yarn add -D vitepress@next vue\n```\n\n```sh [bun]\n$ bun add -D vitepress@next\n```\n\n:::\n\n::: tip 注意\n\nVitePress 是仅 ESM 的软件包。不要使用 `require()` 导入它，并确保最新的 `package.json` 包含 `\"type\": \"module\"`，或者更改相关文件的文件扩展名，例如 `.vitepress/config.js` 到 `.mjs`/`.mts`。更多详情请参考 [Vite 故障排除指南](http://vitejs.dev/guide/troubleshooting.html#this-package-is-esm-only)。此外，在异步 CJS 上下文中，可以使用 `await import('vitepress')` 代替。\n\n:::\n\n### 安装向导 {#setup-wizard}\n\nVitePress 附带一个命令行设置向导，可以帮助你构建一个基本项目。安装后，通过运行以下命令启动向导：\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress init\n```\n\n```sh [pnpm]\n$ pnpm vitepress init\n```\n\n```sh [yarn]\n$ yarn vitepress init\n```\n\n```sh [bun]\n$ bun vitepress init\n```\n\n:::\n\n将需要回答几个简单的问题：\n\n<<< @/snippets/init.ansi\n\n::: tip Vue 作为 peer dependency\n如果打算使用 Vue 组件或 API 进行自定义，还应该明确地将 `vue` 安装为 dependency。\n:::\n\n## 文件结构 {#file-structure}\n\n如果正在构建一个独立的 VitePress 站点，可以在当前目录 (`./`) 中搭建站点。但是，如果在现有项目中与其他源代码一起安装 VitePress，建议将站点搭建在嵌套目录 (例如 `./docs`) 中，以便它与项目的其余部分分开。\n\n假设选择在 `./docs` 中搭建 VitePress 项目，生成的文件结构应该是这样的：\n\n```\n.\n├─ docs\n│  ├─ .vitepress\n│  │  └─ config.js\n│  ├─ api-examples.md\n│  ├─ markdown-examples.md\n│  └─ index.md\n└─ package.json\n```\n\n `docs` 目录作为 VitePress 站点的项目**根目录**。`.vitepress` 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的位置。\n\n::: tip\n默认情况下，VitePress 将其开发服务器缓存存储在 `.vitepress/cache` 中，并将生产构建输出存储在 `.vitepress/dist` 中。如果使用 Git，应该将它们添加到 `.gitignore` 文件中。也可以手动[配置](../reference/site-config#outdir)这些位置。\n:::\n\n### 配置文件 {#the-config-file}\n\n配置文件 (`.vitepress/config.js`) 让你能够自定义 VitePress 站点的各个方面，最基本的选项是站点的标题和描述：\n\n```js [.vitepress/config.js]\nexport default {\n  // 站点级选项\n  title: 'VitePress',\n  description: 'Just playing around.',\n\n  themeConfig: {\n    // 主题级选项\n  }\n}\n```\n\n还可以通过 `themeConfig` 选项配置主题的行为。有关所有配置选项的完整详细信息，请参见[配置参考](../reference/site-config)。\n\n### 源文件 {#source-files}\n\n`.vitepress` 目录之外的 Markdown 文件被视为**源文件**。\n\nVitePress 使用 **基于文件的路由**：每个 `.md` 文件将在相同的路径被编译成为 `.html` 文件。例如，`index.md` 将会被编译成 `index.html`，可以在生成的 VitePress 站点的根路径 `/` 进行访问。\n\nVitePress 还提供了生成简洁 URL、重写路径和动态生成页面的能力。这些将在[路由指南](./routing)中进行介绍。\n\n## 启动并运行 {#up-and-running}\n\n该工具还应该将以下 npm 脚本注入到 `package.json` 中：\n\n```json [package.json]\n{\n  ...\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  ...\n}\n```\n\n`docs:dev` 脚本将启动具有即时热更新的本地开发服务器。使用以下命令运行它：\n\n::: code-group\n\n```sh [npm]\n$ npm run docs:dev\n```\n\n```sh [pnpm]\n$ pnpm run docs:dev\n```\n\n```sh [yarn]\n$ yarn docs:dev\n```\n\n```sh [bun]\n$ bun run docs:dev\n```\n\n:::\n\n除了 npm 脚本，还可以直接调用 VitePress：\n\n::: code-group\n\n```sh [npm]\n$ npx vitepress dev docs\n```\n\n```sh [pnpm]\n$ pnpm vitepress dev docs\n```\n\n```sh [yarn]\n$ yarn vitepress dev docs\n```\n\n```sh [bun]\n$ bun vitepress dev docs\n```\n\n:::\n\n更多的命令行用法请参见 [CLI 参考](../reference/cli)。\n\n开发服务应该会运行在 `http://localhost:5173` 上。在浏览器中访问 URL 以查看新站点的运行情况吧！\n\n## 下一步 {#what-s-next}\n\n- 想要进一步了解 Markdown 文件是怎么映射到对应的 HTML，请继续阅读[路由指南](./routing)。\n\n- 要了解有关可以在页面上执行的操作的更多信息，例如编写 Markdown 内容或使用 Vue 组件，请参见指南的“编写”部分。一个很好的起点是了解 [Markdown 扩展](./markdown)。\n\n- 要探索默认文档主题提供的功能，请查看[默认主题配置参考](../reference/default-theme-config)。\n\n- 如果想进一步自定义站点的外观，参见[扩展默认主题](./extending-default-theme)或者[构建自定义主题](./custom-theme)。\n\n- 文档成形以后，务必阅读[部署指南](./deploy)。\n"
  },
  {
    "path": "docs/zh/guide/i18n.md",
    "content": "# 国际化 {#internationalization}\n\n要使用内置的 i18n (国际化) 功能，需要创建类似于下面的目录结构：\n\n```\ndocs/\n├─ es/\n│  ├─ foo.md\n├─ fr/\n│  ├─ foo.md\n├─ foo.md\n```\n\n然后在 `docs/.vitepress/config.ts` 中：\n\n```ts [docs/.vitepress/config.ts]\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // 共享属性和其他顶层内容...\n\n  locales: {\n    root: {\n      label: 'English',\n      lang: 'en'\n    },\n    fr: {\n      label: 'French',\n      lang: 'fr', // 可选，将作为 `lang` 属性添加到 `html` 标签中\n      link: '/fr/guide' // 默认 /fr/ -- 显示在导航栏翻译菜单上，可以是外部的\n\n      // 其余 locale 特定属性...\n    }\n  }\n})\n```\n\n下面的属性能够被每个 locale 覆盖 (包括 root)：\n\n```ts\ninterface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[] // 将与现有的头部条目合并，重复的元标签将自动删除\n  themeConfig?: ThemeConfig // 会进行浅层合并，常见内容可放在顶层的 themeConfig 属性中\n}\n```\n\n有关自定义默认主题的文本占位符的信息，请参考 [`DefaultTheme.Config`](https://github.com/vuejs/vitepress/blob/main/types/default-theme.d.ts) 接口。不要在 locale 级别覆盖 `themeConfig.algolia` 或 `themeConfig.carbonAds`。想获取多语言搜索的信息，请参考 [Algolia 文档](../reference/default-theme-search#i18n)。\n\n**提示**：配置文件也可以是 `docs/.vitepress/config/index.ts`。通过为每个语言环境创建一个配置文件，然后从 `index.ts` 合并并导出它们，可以更好的组织文件。\n\n## 为本地化设置子目录 {#separate-directory-for-each-locale}\n\n下面是一个组织良好的结构：\n\n```\ndocs/\n├─ en/\n│  ├─ foo.md\n├─ es/\n│  ├─ foo.md\n├─ fr/\n   ├─ foo.md\n```\n\n但是，VitePress 默认不会将 `/` 重定向到 `/en/`。需要配置服务器来实现这一点。例如，在使用 Netlify 时，可以添加一个 `docs/public/_redirects` 文件，如下所示：\n\n```\n/*  /es/:splat  302  Language=es\n/*  /fr/:splat  302  Language=fr\n/*  /en/:splat  302\n```\n\n**提示：** 如果使用上述的方法，可以使用`nf_lang` cookie 来保存用户的语言选择。例如，可以在主题中添加以下代码：\n\n```ts [docs/.vitepress/theme/index.ts]\nimport DefaultTheme from 'vitepress/theme'\nimport Layout from './Layout.vue'\n\nexport default {\n  extends: DefaultTheme,\n  Layout\n}\n```\n\n```vue [docs/.vitepress/theme/Layout.vue]\n<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport { useData, inBrowser } from 'vitepress'\nimport { watchEffect } from 'vue'\n\nconst { lang } = useData()\nwatchEffect(() => {\n  if (inBrowser) {\n    document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2030 00:00:00 UTC; path=/`\n  }\n})\n</script>\n\n<template>\n  <DefaultTheme.Layout />\n</template>\n```\n\n## RTL 支持 (实验性功能) {#rtl-support-experimental}\n\n支持 RTL 需要在配置中指定 `dir: 'rtl'` 并且使用一些 RTLCSS PostCSS 插件，例如 <https://github.com/MohammadYounes/rtlcss>, <https://github.com/vkalinichev/postcss-rtl> 或者 <https://github.com/elchininet/postcss-rtlcss>。需要配置 PostCSS 插件，使用 `:where([dir=\"ltr\"])` 和 `:where([dir=\"rtl\"])` 作为前缀，以防止 CSS 特异性问题。\n"
  },
  {
    "path": "docs/zh/guide/markdown.md",
    "content": "# Markdown 扩展 {#markdown-extensions}\n\nVitePress 带有内置的 Markdown 扩展。\n\n## 标题锚点 {#header-anchors}\n\n标题会自动应用锚点。可以使用 `markdown.anchor` 选项配置锚点的渲染。\n\n### 自定义锚点 {#custom-anchors}\n\n要为标题指定自定义锚点而不是使用自动生成的锚点，请向标题添加后缀：\n\n```\n# 使用自定义锚点 {#my-anchor}\n```\n\n这允许将标题链接为 `#my-anchor`，而不是默认的 `#使用自定义锚点`。\n\n## 链接 {#links}\n\n内部和外部链接都会被特殊处理。\n\n### 内部链接 {#internal-links}\n\n内部链接将转换为单页导航的路由链接。此外，子目录中包含的每个 `index.md` 都会自动转换为 `index.html`，并带有相应的 URL `/`。\n\n例如，给定以下目录结构：\n\n```\n.\n├─ index.md\n├─ foo\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ bar\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\n假设现在处于 `foo/one.md` 文件中：\n\n```md\n[Home](/) <!-- 将用户导航至根目录下的 index.html -->\n[foo](/foo/) <!-- 将用户导航至目录 foo 下的 index.html -->\n[foo heading](./#heading) <!-- 将用户锚定到目录 foo 下的index文件中的一个标题上 -->\n[bar - three](../bar/three) <!-- 可以省略扩展名 -->\n[bar - three](../bar/three.md) <!-- 可以添加 .md -->\n[bar - four](../bar/four.html) <!-- 或者可以添加 .html -->\n```\n\n### 页面后缀 {#page-suffix}\n\n默认情况下，生成的页面和内部链接带有 `.html` 后缀。\n\n### 外部链接 {#external-links}\n\n外部链接带有 `target=\"_blank\" rel=\"noreferrer\"`：\n\n- [vuejs.org](https://cn.vuejs.org)\n- [VitePress on GitHub](https://github.com/vuejs/vitepress)\n\n## frontmatter {#frontmatter}\n\n[YAML 格式的 frontmatter](https://jekyllrb.com/docs/front-matter/) 开箱即用：\n\n```yaml\n---\ntitle: Blogging Like a Hacker\nlang: en-US\n---\n```\n\n此数据将可用于页面的其余部分，以及所有自定义和主题组件。\n\n更多信息，参见 [frontmatter](../reference/frontmatter-config)。\n\n## GitHub 风格的表格 {#github-style-tables}\n\n**输入**\n\n```\n| Tables        |      Are      |  Cool |\n| ------------- | :-----------: | ----: |\n| col 3 is      | right-aligned | $1600 |\n| col 2 is      |   centered    |   $12 |\n| zebra stripes |   are neat    |    $1 |\n```\n\n**输出**\n\n| Tables        |      Are      |   Cool |\n| ------------- | :-----------: | -----: |\n| col 3 is      | right-aligned | \\$1600 |\n| col 2 is      |   centered    |   \\$12 |\n| zebra stripes |   are neat    |    \\$1 |\n\n## Emoji :tada:\n\n**输入**\n\n```\n:tada: :100:\n```\n\n**输出**\n\n:tada: :100:\n\n这里可以找到[所有支持的 emoji 列表](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs)。\n\n## 目录表 (TOC) {#table-of-contents}\n\n**输入**\n\n```\n[[toc]]\n```\n\n**输出**\n\n[[toc]]\n\n可以使用 `markdown.toc` 选项配置 TOC 的呈现效果。\n\n## 自定义容器 {#custom-containers}\n\n自定义容器可以通过它们的类型、标题和内容来定义。\n\n### 默认标题 {#default-title}\n\n**输入**\n\n```md\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n```\n\n**输出**\n\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n\n### 自定义标题 {#custom-title}\n\n可以通过在容器的 \"type\" 之后附加文本来设置自定义标题。\n\n**输入**\n\n````md\n::: danger STOP\n危险区域，请勿继续\n:::\n\n::: details 点我查看代码\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n````\n\n**输出**\n\n::: danger STOP\n危险区域，请勿继续\n:::\n\n::: details 点我查看代码\n```js\nconsole.log('Hello, VitePress!')\n```\n:::\n\n此外，可以通过在站点配置中添加以下内容来全局设置自定义标题，如果不是用英语书写，这会很有帮助：\n\n```ts\n// config.ts\nexport default defineConfig({\n  // ...\n  markdown: {\n    container: {\n      tipLabel: '提示',\n      warningLabel: '警告',\n      dangerLabel: '危险',\n      infoLabel: '信息',\n      detailsLabel: '详细信息'\n    }\n  }\n  // ...\n})\n```\n\n### `raw`\n\n这是一个特殊的容器，可以用来防止与 VitePress 的样式和路由冲突。这在记录组件库时特别有用。可能还想查看 [whyframe](https://whyframe.dev/docs/integrations/vitepress) 以获得更好的隔离。\n\n**语法**\n\n```md\n::: raw\nWraps in a `<div class=\"vp-raw\">`\n:::\n```\n\n`vp-raw` class 也可以直接用于元素。样式隔离目前是可选的：\n\n- 使用喜欢的包管理器来安装需要的依赖项：\n\n  ```sh\n  $ npm add -D postcss\n  ```\n\n- 创建 `docs/postcss.config.mjs` 文件并将以下内容添加到其中：\n\n  ```js\n  import { postcssIsolateStyles } from 'vitepress'\n\n  export default {\n    plugins: [postcssIsolateStyles()]\n  }\n  ```\n\n  你可以像这样传递它的选项：\n\n  ```js\n  postcssIsolateStyles({\n    includeFiles: [/custom\\.css/] // 默认为 [/vp-doc\\.css/, /base\\.css/]\n  })\n  ```\n\n## GitHub 风格的警报 {#github-flavored-alerts}\n\nVitePress 同样支持以标注的方式渲染 [GitHub 风格的警报](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)。它们和[自定义容器](#custom-containers)的渲染方式相同。\n\n```md\n> [!NOTE]\n> 强调用户在快速浏览文档时也不应忽略的重要信息。\n\n> [!TIP]\n> 有助于用户更顺利达成目标的建议性信息。\n\n> [!IMPORTANT]\n> 对用户达成目标至关重要的信息。\n\n> [!WARNING]\n> 因为可能存在风险，所以需要用户立即关注的关键内容。\n\n> [!CAUTION]\n> 行为可能带来的负面影响。\n```\n\n> [!NOTE]\n> 强调用户在快速浏览文档时也不应忽略的重要信息。\n\n> [!TIP]\n> 有助于用户更顺利达成目标的建议性信息。\n\n> [!IMPORTANT]\n> 对用户达成目标至关重要的信息。\n\n> [!WARNING]\n> 因为可能存在风险，所以需要用户立即关注的关键内容。\n\n> [!CAUTION]\n> 行为可能带来的负面影响。\n\n## 代码块中的语法高亮 {#syntax-highlighting-in-code-blocks}\n\nVitePress 使用 [Shiki](https://github.com/shikijs/shiki) 在 Markdown 代码块中使用彩色文本实现语法高亮。Shiki 支持多种编程语言。需要做的就是将有效的语言别名附加到代码块的开头：\n\n**输入**\n\n````\n```js\nexport default {\n  name: 'MyComponent',\n  // ...\n}\n```\n````\n\n````\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n````\n\n**输出**\n\n```js\nexport default {\n  name: 'MyComponent'\n  // ...\n}\n```\n\n```html\n<ul>\n  <li v-for=\"todo in todos\" :key=\"todo.id\">\n    {{ todo.text }}\n  </li>\n</ul>\n```\n\n在 Shiki 的代码仓库中，可以找到[合法的编程语言列表](https://shiki.style/languages)。\n\n还可以在全局配置中自定义语法高亮主题、配置语言别名和自定义语言标签。有关详细信息，参见 [`markdown` 选项](../reference/site-config#markdown)得到更多信息。\n\n## 在代码块中实现行高亮 {#line-highlighting-in-code-blocks}\n\n**输入**\n\n````\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n\n除了单行之外，还可以指定多个单行、多行，或两者均指定：\n\n- 多行：例如 `{5-8}`、`{3-10}`、`{10-17}`\n- 多个单行：例如 `{4,7,9}`\n- 多行与单行：例如 `{4,7-13,16,23-27,40}`\n\n**输入**\n\n````\n```js{1,4,6-8}\nexport default { // Highlighted\n  data () {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum'\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js{1,4,6-8}\nexport default { // Highlighted\n  data () {\n    return {\n      msg: `Highlighted!\n      This line isn't highlighted,\n      but this and the next 2 are.`,\n      motd: 'VitePress is awesome',\n      lorem: 'ipsum',\n    }\n  }\n}\n```\n\n也可以使用 `// [!code highlight]` 注释实现行高亮。\n\n**输入**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!' // [!!code highlight]\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Highlighted!' // [!code highlight]\n    }\n  }\n}\n```\n\n## 代码块中聚焦 {#focus-in-code-blocks}\n\n在某一行上添加 `// [!code focus]` 注释将聚焦它并模糊代码的其他部分。\n\n此外，可以使用 `// [!code focus:<lines>]` 定义要聚焦的行数。\n\n**输入**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Focused!' // [!!code focus]\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Focused!' // [!code focus]\n    }\n  }\n}\n```\n\n## 代码块中的颜色差异 {#colored-diffs-in-code-blocks}\n\n在某一行添加 `// [!code --]` 或 `// [!code ++]` 注释将会为该行创建 diff，同时保留代码块的颜色。\n\n**输入**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!!code --]\n      msg: 'Added' // [!!code ++]\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Removed' // [!code --]\n      msg: 'Added' // [!code ++]\n    }\n  }\n}\n```\n\n## 高亮“错误”和“警告” {#errors-and-warnings-in-code-blocks}\n\n在某一行添加 `// [!code warning]` 或 `// [!code error]` 注释将会为该行相应的着色。\n\n**输入**\n\n````\n```js\nexport default {\n  data () {\n    return {\n      msg: 'Error', // [!!code error]\n      msg: 'Warning' // [!!code warning]\n    }\n  }\n}\n```\n````\n\n**输出**\n\n```js\nexport default {\n  data() {\n    return {\n      msg: 'Error', // [!code error]\n      msg: 'Warning' // [!code warning]\n    }\n  }\n}\n```\n\n## 行号 {#line-numbers}\n\n可以通过以下配置为每个代码块启用行号：\n\n```js\nexport default {\n  markdown: {\n    lineNumbers: true\n  }\n}\n```\n\n查看 [`markdown` 选项](../reference/site-config#markdown) 获取更多信息。\n\n可以在代码块中添加 `:line-numbers` / `:no-line-numbers` 标记来覆盖在配置中的设置。\n\n还可以通过在 `:line-numbers` 之后添加 `=` 来自定义起始行号，例如 `:line-numbers=2` 表示代码块中的行号从 2 开始。\n\n**输入**\n\n````md\n```ts {1}\n// 默认禁用行号\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// 启用行号\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// 行号已启用，并从 2 开始\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n````\n\n**输出**\n\n```ts {1}\n// 默认禁用行号\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers {1}\n// 启用行号\nconst line2 = 'This is line 2'\nconst line3 = 'This is line 3'\n```\n\n```ts:line-numbers=2 {1}\n// 行号已启用，并从 2 开始\nconst line3 = 'This is line 3'\nconst line4 = 'This is line 4'\n```\n\n## 导入代码片段 {#import-code-snippets}\n\n可以通过下面的语法来从现有文件中导入代码片段：\n\n```md\n<<< @/filepath\n```\n\n此语法同时支持[行高亮](#line-highlighting-in-code-blocks)：\n\n```md\n<<< @/filepath{highlightLines}\n```\n\n**输入**\n\n```md\n<<< @/snippets/snippet.js{2}\n```\n\n**Code file**\n\n<<< @/snippets/snippet.js\n\n**输出**\n\n<<< @/snippets/snippet.js{2}\n\n::: tip\n`@` 的值对应于源代码根目录，默认情况下是 VitePress 项目根目录，除非配置了 `srcDir`。或者也可以从相对路径导入：\n\n```md\n<<< ../snippets/snippet.js\n```\n\n:::\n\n也可以使用 [VS Code region](https://code.visualstudio.com/docs/editor/codebasics#_folding) 来只包含代码文件的相应部分。可以在文件目录后面的 `#` 符号后提供一个自定义的区域名：\n\n**输入**\n\n```md\n<<< @/snippets/snippet-with-region.js#snippet{1}\n```\n\n**Code file**\n\n<<< @/snippets/snippet-with-region.js\n\n**输出**\n\n<<< @/snippets/snippet-with-region.js#snippet{1}\n\n也可以像这样在大括号内(`{}`)指定语言：\n\n```md\n<<< @/snippets/snippet.cs{c#}\n\n<!-- 带行高亮: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#}\n\n<!-- 带行号: -->\n\n<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers}\n```\n\n如果无法从文件扩展名推测出源语言，这将会很有帮助\n\n## 代码组 {#code-groups}\n\n可以像这样对多个代码块进行分组：\n\n**输入**\n\n````md\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n````\n\n**输出**\n\n::: code-group\n\n```js [config.js]\n/**\n * @type {import('vitepress').UserConfig}\n */\nconst config = {\n  // ...\n}\n\nexport default config\n```\n\n```ts [config.ts]\nimport type { UserConfig } from 'vitepress'\n\nconst config: UserConfig = {\n  // ...\n}\n\nexport default config\n```\n\n:::\n\n也可以在代码组中[导入代码片段](#import-code-snippets)：\n\n**输入**\n\n```md\n::: code-group\n\n<!-- 文件名默认用作标题 -->\n\n<<< @/snippets/snippet.js\n\n<!-- 也可以提供定制的代码组 -->\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n```\n\n**输出**\n\n::: code-group\n\n<<< @/snippets/snippet.js\n\n<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [snippet with region]\n\n:::\n\n## 包含 markdown 文件 {#markdown-file-inclusion}\n\n可以像这样在一个 markdown 文件中包含另一个 markdown 文件，甚至是内嵌的。\n\n::: tip\n也可以使用 `@`，它的值对应于源代码根目录，默认情况下是 VitePress 项目根目录，除非配置了 `srcDir`。\n:::\n\n例如，可以这样用相对路径包含 Markdown 文件：\n\n**输入**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md-->\n```\n\n**Part file** (`parts/basics.md`)\n\n```md\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**等价代码**\n\n```md\n# Docs\n\n## Basics\n\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n它还支持选择行范围：\n\n**输入**\n\n```md\n# Docs\n\n## Basics\n\n<!--@@include: ./parts/basics.md{3,}-->\n```\n\n**Part file** (`parts/basics.md`)\n\n```md\nSome getting started stuff.\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n**等价代码**\n\n```md\n# Docs\n\n## Basics\n\n### Configuration\n\nCan be created using `.foorc.json`.\n```\n\n所选行范围的格式可以是： `{3,}`、 `{,10}`、`{1,10}`\n\n::: warning\n如果指定的文件不存在，这将不会产生错误。因此，在使用这个功能的时候请保证内容按预期呈现。\n:::\n\n## 数学方程 {#math-equations}\n\n现在这是可选的。要启用它，需要安装 `markdown-it-mathjax3`，在配置文件中设置`markdown.math` 为 `true`：\n\n```sh\nnpm add -D markdown-it-mathjax3@^4\n```\n\n```ts [.vitepress/config.ts]\nexport default {\n  markdown: {\n    math: true\n  }\n}\n```\n\n**输入**\n\n```md\nWhen $a \\ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Maxwell's equations:**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | divergence of $\\vec{\\mathbf{B}}$ is zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl of $\\vec{\\mathbf{E}}$ is proportional to the rate of change of $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                                 |\n```\n\n**输出**\n\nWhen $a \\ne 0$, there are two solutions to $(ax^2 + bx + c = 0)$ and they are\n$$ x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a} $$\n\n**Maxwell's equations:**\n\n| equation                                                                                                                                                                  | description                                                                            |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| $\\nabla \\cdot \\vec{\\mathbf{B}}  = 0$                                                                                                                                      | divergence of $\\vec{\\mathbf{B}}$ is zero                                               |\n| $\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t}  = \\vec{\\mathbf{0}}$                                                          | curl of $\\vec{\\mathbf{E}}$ is proportional to the rate of change of $\\vec{\\mathbf{B}}$ |\n| $\\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} = \\frac{4\\pi}{c}\\vec{\\mathbf{j}}    \\nabla \\cdot \\vec{\\mathbf{E}} = 4 \\pi \\rho$ | _wha?_                                                                                 |\n\n## 图片懒加载 {#image-lazy-loading}\n\n通过在配置文件中将 `lazyLoading` 设置为 `true`，可以为通过 markdown 添加的每张图片启用懒加载。\n\n```js\nexport default {\n  markdown: {\n    image: {\n      // 默认禁用；设置为 true 可为所有图片启用懒加载。\n      lazyLoading: true\n    }\n  }\n}\n```\n\n## 高级配置 {#advanced-configuration}\n\nVitePress 使用 [markdown-it](https://github.com/markdown-it/markdown-it) 作为 Markdown 渲染器。上面提到的很多扩展功能都是通过自定义插件实现的。可以使用 `.vitepress/config.js` 中的 `markdown` 选项来进一步自定义 `markdown-it` 实例。\n\n```js\nimport { defineConfig } from 'vitepress'\nimport markdownItAnchor from 'markdown-it-anchor'\nimport markdownItFoo from 'markdown-it-foo'\n\nexport default defineConfig({\n  markdown: {\n    // markdown-it-anchor 的选项\n    // https://github.com/valeriangalliat/markdown-it-anchor#usage\n    anchor: {\n      permalink: markdownItAnchor.permalink.headerLink()\n    },\n    // @mdit-vue/plugin-toc 的选项\n    // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options\n    toc: { level: [1, 2] },\n    config: (md) => {\n      // 使用更多的 Markdown-it 插件！\n      md.use(markdownItFoo)\n    }\n  }\n})\n```\n\n请查看[配置参考：站点配置](../reference/site-config#markdown)来获取完整的可配置属性列表。\n"
  },
  {
    "path": "docs/zh/guide/migration-from-vitepress-0.md",
    "content": "n# 从 VitePress 0.x 迁移 {#migration-from-vitepress-0-x}\n\n如果你来自 VitePress 0.x 版本，VitePress 有了一些重大更改。请按照本指南了解如何将应用程序迁移到最新的 VitePress。\n\n## 应用配置 {#app-config}\n\n- 国际化功能尚未实现。\n\n## 主题配置 {#theme-config}\n\n- `sidebar` 选项改变了它的结构。\n  - `children` 现在命名为 `items`。\n  - 顶级侧边栏不包含 `link`。我们打算把它改回来。\n- 删除了 `repo`、`repoLabel`、`docsDir`、`docsBranch`、`editLinks`、`editLinkText`，以支持更灵活的api。\n  - 要将带有图标的 GitHub 链接添加到导航，请使用 [社交链接](../reference/default-theme-config#nav) 功能。\n  - 要添加“编辑此页面”功能，请使用 [编辑链接](../reference/default-theme-edit-link) 功能。\n- `lastUpdated` 选项现在分为` config.lastUpdated` 和 `themeConfig.lastUpdatedText`。\n- `carbonAds.carbon` 更改为 `carbonAds.code`.\n\n## frontmatter 配置 {#frontmatter-config}\n\n- `home: true` 选项已更改为 `layout: home`。此外，还修改了许多与主页相关的设置以提供附加功能。详情请参阅 [主页指南](../reference/default-theme-home-page)。\n- `footer` 选项移至 [`themeConfig.footer`](../reference/default-theme-footer).\n"
  },
  {
    "path": "docs/zh/guide/migration-from-vuepress.md",
    "content": "# 从 VuePress 迁移 {#migration-from-vuepress}\n\n## 配置 {#config}\n\n### 侧边栏 {#sidebar}\n\n侧边栏不再从 frontmatter 中自动获取。你可以自行阅读 [`frontmatter`](https://github.com/vuejs/vitepress/issues/572#issuecomment-1170116225) 来动态填充侧边栏。[迁移工具](https://github.com/vuejs/vitepress/issues/96)将来可能会提供。\n\n## Markdown {#markdown}\n\n### 图片 {#images}\n\n与 VuePress 不同，在使用静态图片时，VitePress 会根据配置自动处理这些 [`base`](./asset-handling#base-url)。\n\n因此，现在可以在没有 `img` 标签的情况下渲染图像。\n\n```diff\n- <img :src=\"$withBase('/foo.png')\" alt=\"foo\">\n+ ![foo](/foo.png)\n```\n\n::: warning\n对于动态图像，仍然需要 `withBase`，如 [Base URL](./asset-handling#base-url) 中所示。\n:::\n\n使用 `<img.*withBase\\('(.*)'\\).*alt=\"([^\"]*)\".*>` 正则表达式查找并替换为 `![$2]($1)` 用 `![](...)` 语法替换所有图像。\n\n---\n\n更多请继续关注...\n"
  },
  {
    "path": "docs/zh/guide/mpa-mode.md",
    "content": "# MPA 模式 <Badge type=\"warning\" text=\"experimental\" /> {#mpa-mode}\n\n可以通过命令行输入 `vitepress build --mpa` 或在配置文件中指定 `mpa: true` 配置选项来启用 MPA (Multi-Page Application) 模式。\n\n在 MPA 模式下，所有页面都默认不会包含任何 JavaScript。因此，站点也许可以在评估工具中获得更好的初始访问性能分数。\n\n但是，由于缺少 SPA 路由，在 MPA 模式下切换页面时会重新加载整个页面，而不会像 SPA 模式那样立即响应。\n\n同时请注意，默认情况下不使用 JavaScript 意味着你实际上只是将 Vue 作为服务器端模板语言。浏览器不会附加任何事件处理程序，因此将不会有任何交互性。要加载客户端 JavaScript，需要使用特殊的 `<script client>` 标签：\n\n```html\n<script client>\ndocument.querySelector('h1').addEventListener('click', () => {\n  console.log('client side JavaScript!')\n})\n</script>\n\n# Hello\n```\n\n`<script client>` 是 VitePress 独有的功能，而不是 Vue 的功能。它可以在 `.md` 和 `.vue` 文件中使用，但只能在 MPA 模式下使用。所有主题组件中的客户端脚本将被打包在一起，而特定页面的客户端脚本将会分开处理。\n\n请注意，`<script client>` **不会被视为 Vue 组件代码**，它只是普通的 JavaScript 模块。因此，只有在站点需要极少的客户端交互时，才应该使用 MPA 模式。\n"
  },
  {
    "path": "docs/zh/guide/routing.md",
    "content": "---\noutline: deep\n---\n\n# 路由 {#routing}\n\n## 基于文件的路由 {#file-based-routing}\n\nVitePress 使用基于文件的路由，这意味着生成的 HTML 页面是从源 Markdown 文件的目录结构映射而来的。例如，给定以下目录结构：\n\n```\n.\n├─ guide\n│  ├─ getting-started.md\n│  └─ index.md\n├─ index.md\n└─ prologue.md\n```\n\n生成的 HTML 页面会是这样：\n\n```\nindex.md                  -->  /index.html (可以通过 / 访问)\nprologue.md               -->  /prologue.html\nguide/index.md            -->  /guide/index.html (可以通过 /guide/ 访问)\nguide/getting-started.md  -->  /guide/getting-started.html\n```\n\n生成的 HTML 可以托管在任何支持静态文件的 Web 服务器上。\n\n## 根目录和源目录 {#root-and-source-directory}\n\nVitePress 项目的文件结构中有两个重要的概念：项目根目录 (**project root**) 和源目录 (**source directory**)。\n\n### 项目根目录 {#project-root}\n\n项目根目录是 VitePress 将尝试寻找 `.vitepress` 特殊目录的地方。`.vitepress` 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的预留位置。\n\n当从命令行运行 `vitepress dev` 或 `vitepress build` 时，VitePress 将使用当前工作目录作为项目根目录。要将子目录指定为根目录，需要将相对路径传递给命令。例如，如果 VitePress 项目位于 `./docs`，应该运行 `vitepress dev docs`：\n\n```\n.\n├─ docs                    # 项目根目录\n│  ├─ .vitepress           # 配置目录\n│  ├─ getting-started.md\n│  └─ index.md\n└─ ...\n```\n\n```sh\nvitepress dev docs\n```\n\n这将导致以下源代码到 HTML 的映射：\n\n```\ndocs/index.md            -->  /index.html (可以通过 / 访问)\ndocs/getting-started.md  -->  /getting-started.html\n```\n\n### 源目录 {#source-directory}\n\n源目录是 Markdown 源文件所在的位置。默认情况下，它与项目根目录相同。但是，可以通过 [`srcDir`](../reference/site-config#srcdir) 配置选项对其进行配置。\n\n`srcDir` 选项是相对于项目根目录解析的。例如，对于 `srcDir: 'src'`，文件结构将如下所示：\n\n```\n.                          # 项目根目录\n├─ .vitepress              # 配置目录\n└─ src                     # 源目录\n   ├─ getting-started.md\n   └─ index.md\n```\n\n生成的源代码到 HTML 的映射：\n\n```\nsrc/index.md            -->  /index.html (可以通过 / 访问)\nsrc/getting-started.md  -->  /getting-started.html\n```\n\n## 链接页面 {#linking-between-pages}\n\n在页面之间链接时，可以使用绝对路径和相对路径。请注意，虽然 `.md` 和 `.html` 扩展名都可以使用，但最佳做法是省略文件扩展名，以便 VitePress 可以根据配置生成最终的 URL。\n\n```md\n<!-- Do -->\n[Getting Started](./getting-started)\n[Getting Started](../guide/getting-started)\n\n<!-- Don't -->\n[Getting Started](./getting-started.md)\n[Getting Started](./getting-started.html)\n```\n\n在[资源处理](./asset-handling)中了解有关链接到资源（例如图像）的更多信息。\n\n### 链接到非 VitePress 页面 {#linking-to-non-vitepress-pages}\n\n如果想链接到站点中不是由 VitePress 生成的页面，需要使用完整的 URL（在新选项卡中打开）或明确指定 target：\n\n**输入**\n\n```md\n[Link to pure.html](/pure.html){target=\"_self\"}\n```\n\n**输出**\n\n[Link to pure.html](/pure.html){target=\"_self\"}\n\n::: tip 注意\n\n在 Markdown 链接中，`base` 会自动添加到 URL 前面。这意味着，如果想链接到 `base` 之外的页面，则链接中需要类似 `../../pure.html` 的内容（由浏览器相对于当前页面解析）。\n\n或者，可以直接使用锚标记语法：\n\n```md\n<a href=\"/pure.html\" target=\"_self\">Link to pure.html</a>\n```\n\n:::\n\n## 生成简洁的 URL {#generating-clean-urls}\n\n::: warning 需要服务器支持\n要使 VitePress 提供简洁 URL，需要服务器端支持。\n:::\n\n默认情况下，VitePress 将入站链接解析为以 `.html` 结尾的 URL。但是，一些用户可能更喜欢没有 .html 扩展名的“简洁 URL”——例如，`example.com/path` 而不是 `example.com/path.html`。\n\n某些服务器或托管平台 (例如 Netlify、Vercel 或 GitHub Pages) 提供将 `/foo` 之类的 URL 映射到 `/foo.html` (如果存在) 的功能，而无需重定向：\n\n- Netlify 和 GitHub Pages 是默认支持的。\n- Vercel 需要在 [vercel.json 中启用 cleanUrls 选项](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls)。\n\n如果可以使用此功能，还可以启用 VitePress 自己的 [`cleanUrls`](../reference/site-config#cleanurls) 配置选项，以便：\n\n- 页面之间的入站链接是在没有 `.html` 扩展名的情况下生成的。\n- 如果当前路径以 `.html` 结尾，路由器将执行客户端重定向到无扩展路径。\n\n但是，如果无法为服务器配置此类支持，则必须手动采用以下目录结构：\n\n```\n.\n├─ getting-started\n│  └─ index.md\n├─ installation\n│  └─ index.md\n└─ index.md\n```\n\n## 路由重写 {#route-rewrites}\n\n可以自定义源目录结构和生成页面之间的映射。当有一个复杂的项目结构时，它很有用。例如，假设有一个包含多个包的 monorepo，并且希望将文档与源文件一起放置，如下所示：\n\n```\n.\n├─ packages\n│  ├─ pkg-a\n│  │  └─ src\n│  │      ├─ pkg-a-code.ts\n│  │      └─ pkg-a-docs.md\n│  └─ pkg-b\n│     └─ src\n│         ├─ pkg-b-code.ts\n│         └─ pkg-b-docs.md\n```\n\n希望像这样生成 VitePress 页面：\n\n```\npackages/pkg-a/src/pkg-a-docs.md  -->  /pkg-a/index.html\npackages/pkg-b/src/pkg-b-docs.md  -->  /pkg-b/index.html\n```\n\n可以通过像这样配置 [`rewrites`](../reference/site-config#rewrites) 选项来实现此目的：\n\n```ts [.vitepress/config.js]\nexport default {\n  rewrites: {\n    'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',\n    'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'\n  }\n}\n```\n\n`rewrites` 选项还支持动态路由参数。在上面的示例中，如果有很多包，则列出所有路径会很冗长。鉴于它们都具有相同的文件结构，可以像这样简化配置：\n\n```ts\nexport default {\n  rewrites: {\n    'packages/:pkg/src/(.*)': ':pkg/index.md'\n  }\n}\n```\n\n重写路径是使用 `path-to-regexp` 包编译的——请参阅其[文档](https://github.com/pillarjs/path-to-regexp#parameters)以获取更多语法。\n\n::: warning 开启重写功能时使用相对链接\n\n启用重写后，**相对链接应基于重写的路径**。例如，为了创建从 `packages/pkg-a/src/pkg-a-code.md` 到 `packages/pkg-b/src/pkg-b-code.md` 的相对链接，应该使用：\n\n```md\n[Link to PKG B](../pkg-b/pkg-b-code)\n```\n:::\n\n## 动态路由 {#dynamic-routes}\n\n可以使用单个 Markdown 文件和动态数据生成许多页面。例如，可以创建一个 `packages/[pkg].md` 文件，为项目中的每个包生成相应的页面。这里，`[pkg]` 段是一个路由参数，用于区分每个页面。\n\n### 路径加载文件 {#paths-loader-file}\n\n由于 VitePress 是静态站点生成器，因此**必须**在构建时确定可能的页面路径。因此，动态路由页面必须伴随**路径加载文件**。对于 `packages/[pkg].md`，我们需要 `packages/[pkg].paths.js` (也支持 `.ts`)：\n\n```\n.\n└─ packages\n   ├─ [pkg].md         # 路由模板\n   └─ [pkg].paths.js   # 路由路径加载器\n```\n\n路径加载器应该提供一个带有 `paths` 方法的对象作为其默认导出。`paths` 方法应返回具有 `params` 属性的对象数组。这些对象中的每一个都将生成一个相应的页面。\n\n给定以下 `paths` 数组：\n\n```js\n// packages/[pkg].paths.js\nexport default {\n  paths() {\n    return [\n      { params: { pkg: 'foo' }},\n      { params: { pkg: 'bar' }}\n    ]\n  }\n}\n```\n\n生成的 HTML 页面将会是：\n\n```\n.\n└─ packages\n   ├─ foo.html\n   └─ bar.html\n```\n\n### 多参数 {#multiple-params}\n\n动态路由可以包含多个参数：\n\n**文件结构**\n\n```\n.\n└─ packages\n   ├─ [pkg]-[version].md\n   └─ [pkg]-[version].paths.js\n```\n\n**路径加载器**\n\n```js\nexport default {\n  paths: () => [\n    { params: { pkg: 'foo', version: '1.0.0' }},\n    { params: { pkg: 'foo', version: '2.0.0' }},\n    { params: { pkg: 'bar', version: '1.0.0' }},\n    { params: { pkg: 'bar', version: '2.0.0' }}\n  ]\n}\n```\n\n**输出**\n\n```\n.\n└─ packages\n   ├─ foo-1.0.0.html\n   ├─ foo-2.0.0.html\n   ├─ bar-1.0.0.html\n   └─ bar-2.0.0.html\n```\n\n### 动态生成路径 {#dynamically-generating-paths}\n\n路径加载器模块在 Node.js 中运行，并且仅在构建期间执行。可以使用本地或远程的任何数据动态生成路径数组。\n\n从本地文件生成路径：\n\n```js\nimport fs from 'fs'\n\nexport default {\n  paths() {\n    return fs\n      .readdirSync('packages')\n      .map((pkg) => {\n        return { params: { pkg }}\n      })\n  }\n}\n```\n\n从远程数据生成路径：\n\n```js\nexport default {\n  async paths() {\n    const pkgs = await (await fetch('https://my-api.com/packages')).json()\n\n    return pkgs.map((pkg) => {\n      return {\n        params: {\n          pkg: pkg.name,\n          version: pkg.version\n        }\n      }\n    })\n  }\n}\n```\n\n### 访问页面中的参数 {#accessing-params-in-page}\n\n可以使用参数将附加数据传递到每个页面。Markdown 路由文件可以通过 `$params` 全局属性访问 Vue 表达式中的当前页面参数：\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n\n还可以通过 [`useData`](../reference/runtime-api#usedata) 运行时 API 访问当前页面的参数。这在 Markdown 文件和 Vue 组件中都可用：\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\n// params 是一个 Vue ref\nconst { params } = useData()\n\nconsole.log(params.value)\n</script>\n```\n\n### 渲染原始内容 {#rendering-raw-content}\n\n传递给页面的参数将在客户端 JavaScript payload 中序列化，因此应该避免在参数中传递大量数据，例如从远程 CMS 获取的原始 Markdown 或 HTML 内容。\n\n相反，可以使用每个路径对象上的 `content` 属性将此类内容传递到每个页面：\n\n```js\nexport default {\n  async paths() {\n    const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n    return posts.map((post) => {\n      return {\n        params: { id: post.id },\n        content: post.content // 原始 Markdown 或 HTML\n      }\n    })\n  }\n}\n```\n\n然后，使用以下特殊语法将内容呈现为 Markdown 文件本身的一部分：\n\n```md\n<!-- @content -->\n```\n"
  },
  {
    "path": "docs/zh/guide/sitemap-generation.md",
    "content": "# 生成 sitemap {#sitemap-generation}\n\nVitePress 提供开箱即用的配置，为站点生成 `sitemap.xml` 文件。要启用它，请将以下内容添加到 `.vitepress/config.js` 中：\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com'\n  }\n}\n```\n\n要在 `sitemap.xml` 中包含 `<lastmod>` 标签，可以启用 [`lastUpdated`](../reference/default-theme-last-updated) 选项。\n\n## 选项 {#options}\n\nVitePress 的 sitemap 由 [`sitemap`](https://www.npmjs.com/package/sitemap) 模块提供支持。可以将该模块支持的选项传递给配置文件中的 `sitemap` 选项。这些选项将直接传递给 `SitemapStream` 构造函数。有关更多详细信息，请参阅 [`sitemap` 文档](https://www.npmjs.com/package/sitemap#options-you-can-pass)。例如：\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    lastmodDateOnly: false\n  }\n}\n```\n\n如果在配置中使用 `base`，则应将其追加到 `hostname` 选项中：\n\n```ts\nexport default {\n  base: '/my-site/',\n  sitemap: {\n    hostname: 'https://example.com/my-site/'\n  }\n}\n```\n\n## `transformItems` Hook\n\n在将 sitemap 写入 `sitemap.xml` 文件之前，可以使用 `sitemap.transformItems` 钩子来修改 sitemap。使用 sitemap 调用该钩子，应返回 sitemap 数组。例如：\n\n```ts\nexport default {\n  sitemap: {\n    hostname: 'https://example.com',\n    transformItems: (items) => {\n      // 添加新项目或修改/筛选现有选项\n      items.push({\n        url: '/extra-page',\n        changefreq: 'monthly',\n        priority: 0.8\n      })\n      return items\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/guide/ssr-compat.md",
    "content": "---\noutline: deep\n---\n\n# SSR 兼容性 {#ssr-compatibility}\n\n通过使用 Vue 的服务器端渲染 (SSR) 功能，VitePress 能够在生产构建期间在 Node.js 中预渲染应用程序。这意味着主题组件中的所有自定义代码都需要考虑 SSR 兼容性。\n\n[Vue 官方文档的 SSR 部分](https://cn.vuejs.org/guide/scaling-up/ssr.html)提供了更多有关 SSR 是什么，SSR / SSG 之间的关系以及编写 SSR 友好的代码的常见注意事项等信息。原则上只在 Vue 组件的 `beforeMount` 或 `mounted` 钩子中访问浏览器或 DOM API。\n\n## `<ClientOnly>`\n\n如果正在使用或演示不支持 SSR 的组件 (例如，包含自定义指令)，则可以将它们包装在内置的 `<ClientOnly>` 组件中：\n\n```md\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n## 在导入时访问浏览器 API 的库 {#libraries-that-access-browser-api-on-import}\n\n一些组件或库在**导入时**访问浏览器 API。要使用假定在导入时处于浏览器环境的代码，需要动态导入它们。\n\n### 在 mounted 钩子中导入 {#importing-in-mounted-hook}\n\n```vue\n<script setup>\nimport { onMounted } from 'vue'\n\nonMounted(() => {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // use code\n  })\n})\n</script>\n```\n\n### 条件导入 {#conditional-import}\n\n也可以使用 `import.meta.env.SSR` 标志 ([Vite 环境变量](https://cn.vitejs.dev/guide/env-and-mode.html#env-variables)的一部分) 来有条件地导入依赖项：\n\n```js\nif (!import.meta.env.SSR) {\n  import('./lib-that-access-window-on-import').then((module) => {\n    // use code\n  })\n}\n```\n\n因为 [`Theme.enhanceApp`](./custom-theme#theme-interface) 可以是异步的，所以可以有条件地导入并注册访问浏览器 API 的 Vue 插件：\n\n```js [.vitepress/theme/index.js]\n/** @type {import('vitepress').Theme} */\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n}\n```\n\n如果使用 TypeScript:\n```ts [.vitepress/theme/index.ts]\nimport type { Theme } from 'vitepress'\n\nexport default {\n  // ...\n  async enhanceApp({ app }) {\n    if (!import.meta.env.SSR) {\n      const plugin = await import('plugin-that-access-window-on-import')\n      app.use(plugin.default)\n    }\n  }\n} satisfies Theme\n```\n\n### `defineClientComponent`\n\nVitePress 为导入 Vue 组件提供了一个方便的辅助函数，该组件可以在导入时访问浏览器 API。\n\n```vue\n<script setup>\nimport { defineClientComponent } from 'vitepress'\n\nconst ClientComp = defineClientComponent(() => {\n  return import('component-that-access-window-on-import')\n})\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\n还可以将 props/children/slots 传递给目标组件：\n\n```vue\n<script setup>\nimport { ref } from 'vue'\nimport { defineClientComponent } from 'vitepress'\n\nconst clientCompRef = ref(null)\nconst ClientComp = defineClientComponent(\n  () => import('component-that-access-window-on-import'),\n\n  // 参数传递给 h() - https://cn.vuejs.org/api/render-function.html#h\n  [\n    {\n      ref: clientCompRef\n    },\n    {\n      default: () => 'default slot',\n      foo: () => h('div', 'foo'),\n      bar: () => [h('span', 'one'), h('span', 'two')]\n    }\n  ],\n\n  // 组件加载后的回调，可以是异步的\n  () => {\n    console.log(clientCompRef.value)\n  }\n)\n</script>\n\n<template>\n  <ClientComp />\n</template>\n```\n\n目标组件将仅在 wrapper 组件的 mounted 钩子中导入。\n"
  },
  {
    "path": "docs/zh/guide/using-vue.md",
    "content": "# 在 Markdown 使用 Vue {#using-vue-in-markdown}\n\n在 VitePress 中，每个 Markdown 文件都被编译成 HTML，而且将其作为 [Vue 单文件组件](https://cn.vuejs.org/guide/scaling-up/sfc.html)处理。这意味着可以在 Markdown 中使用任何 Vue 功能，包括动态模板、使用 Vue 组件或通过添加 `<script>` 标签为页面的 Vue 组件添加逻辑。\n\n值得注意的是，VitePress 利用 Vue 的编译器自动检测和优化 Markdown 内容的纯静态部分。静态内容被优化为单个占位符节点，并从页面的 JavaScript 负载中删除以供初始访问。在客户端激活期间也会跳过它们。简而言之，只需注意任何给定页面上的动态部分。\n\n::: tip SSR 兼容性\n所有的 Vue 用法都需要兼容 SSR。参见 [SSR 兼容性](./ssr-compat)获得更多信息和常见的解决方案。\n:::\n\n## 模板化 {#templating}\n\n### 插值语法 {#interpolation}\n\n每个 Markdown 文件首先被编译成 HTML，然后作为 Vue 组件传递给 Vite 流程管道。这意味着可以在文本中使用 Vue 的插值语法：\n\n**输入**\n\n```md\n{{ 1 + 1 }}\n```\n\n**输出**\n\n<div class=\"language-text\"><pre><code>{{ 1 + 1 }}</code></pre></div>\n\n### 指令 {#directives}\n\n也可以使用指令 (请注意，原始 HTML 在 Markdown 中也有效):\n\n**输入**\n\n```html\n<span v-for=\"i in 3\">{{ i }}</span>\n```\n\n**输出**\n\n<div class=\"language-text\"><pre><code><span v-for=\"i in 3\">{{ i }} </span></code></pre></div>\n\n## `<script>` 和 `<style>` {#script-and-style}\n\nMarkdown 文件中的根级 `<script>` 和 `<style>` 标签与 Vue SFC 中的一样，包括 `<script setup>`、`<style module>` 等。这里的主要区别是没有 `<template>` 标签：所有其他根级内容都是 Markdown。另请注意，所有标签都应放在 frontmatter **之后**：\n\n```html\n---\nhello: world\n---\n\n<script setup>\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n## Markdown Content\n\nThe count is: {{ count }}\n\n<button :class=\"$style.button\" @click=\"count++\">Increment</button>\n\n<style module>\n.button {\n  color: red;\n  font-weight: bold;\n}\n</style>\n```\n\n::: warning 避免在 Markdown 中使用 `<style scoped>`\n在 Markdown 中使用时，`<style scoped>` 需要为当前页面的每个元素添加特殊属性，这将显著增加页面的大小。当我们需要局部范围的样式时 `<style module>` 是首选。\n:::\n\n还可以访问 VitePress 的运行时 API，例如 [`useData` 辅助函数](../reference/runtime-api#usedata)，它提供了当前页面的元数据：\n\n**输入**\n\n```html\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { page } = useData()\n</script>\n\n<pre>{{ page }}</pre>\n```\n\n**输出**\n\n```json\n{\n  \"path\": \"/using-vue.html\",\n  \"title\": \"Using Vue in Markdown\",\n  \"frontmatter\": {},\n  ...\n}\n```\n\n## 使用组件 {#using-components}\n\n可以直接在 Markdown 文件中导入和使用 Vue 组件。\n\n### 在 Markdown 中导入组件 {#importing-in-markdown}\n\n如果一个组件只被几个页面使用，建议在使用它们的地方显式导入它们。这使它们可以正确地进行代码拆分，并且仅在显示相关页面时才加载：\n\n```md\n<script setup>\nimport CustomComponent from '../../components/CustomComponent.vue'\n</script>\n\n# Docs\n\nThis is a .md using a custom component\n\n<CustomComponent />\n\n## More docs\n\n...\n```\n\n### 注册全局组件 {#registering-components-globally}\n\n如果一个组件要在大多数页面上使用，可以通过自定义 Vue 实例来全局注册它们。有关示例，请参见[扩展默认主题](./extending-default-theme#registering-global-components)中的相关部分。\n\n::: warning 重要\n确保自定义组件的名称包含连字符或采用 PascalCase。否则，它将被视为内联元素并包裹在 `<p>` 标签内，这将导致激活不匹配，因为 `<p>` 不允许将块元素放置在其中。\n:::\n\n### 在标题中使用组件 <ComponentInHeader /> {#using-components-in-headers}\n\n可以在标题中使用 Vue 组件，但请注意以下语法之间的区别：\n\n| Markdown                                                | 输出的 HTML                               | 被解析的标题 |\n| ------------------------------------------------------- | ----------------------------------------- | ------------- |\n| <pre v-pre><code> # text &lt;Tag/&gt; </code></pre>     | `<h1>text <Tag/></h1>`                    | `text`        |\n| <pre v-pre><code> # text \\`&lt;Tag/&gt;\\` </code></pre> | `<h1>text <code>&lt;Tag/&gt;</code></h1>` | `text <Tag/>` |\n\n被 `<code>` 包裹的 HTML 将按原样显示，只有未包裹的 HTML 才会被 Vue 解析。\n\n::: tip\n输出 HTML 由 [Markdown-it](https://github.com/Markdown-it/Markdown-it) 完成，而解析的标题由 VitePress 处理 (并用于侧边栏和文档标题)。\n:::\n\n\n## 转义 {#escaping}\n\n可以通过使用 `v-pre` 指令将它们包裹在 `<span>` 或其他元素中来转义 Vue 插值：\n\n**输入**\n\n```md\nThis <span v-pre>{{ will be displayed as-is }}</span>\n```\n\n**输出**\n\n<div class=\"escape-demo\">\n  <p>This <span v-pre>{{ will be displayed as-is }}</span></p>\n</div>\n\n也可以将整个段落包装在 `v-pre` 自定义容器中：\n\n```md\n::: v-pre\n{{ This will be displayed as-is }}`\n:::\n```\n\n**输出**\n\n<div class=\"escape-demo\">\n\n::: v-pre\n{{ This will be displayed as-is }}\n:::\n\n</div>\n\n## 代码块中不转义 {#unescape-in-code-blocks}\n\n默认情况下，代码块是受到保护的，都会自动使用 `v-pre` 包装，因此内部不会处理任何 Vue 语法。要在代码块内启用 Vue 插值语法，可以在代码语言后附加 `-vue` 后缀，例如 `js-vue`：\n\n**输入**\n\n````md\n```js-vue\nHello {{ 1 + 1 }}\n```\n````\n\n**输出**\n\n```js-vue\nHello {{ 1 + 1 }}\n```\n\n请注意，这可能会让某些字符不能正确地进行语法高亮显示。\n\n## 使用 CSS 预处理器 {#using-css-pre-processors}\n\nVitePress [内置支持](https://cn.vitejs.dev/guide/features.html#css-pre-processors) CSS 预处理器：`.scss`、`.sass`、.`less`、`.styl` 和 `.stylus` 文件。无需为它们安装 Vite 专用插件，但必须安装相应的预处理器：\n\n```\n# .scss and .sass\nnpm install -D sass\n\n# .less\nnpm install -D less\n\n# .styl and .stylus\nnpm install -D stylus\n```\n\n然后可以在 Markdown 和主题组件中使用以下内容：\n\n```vue\n<style lang=\"sass\">\n.title\n  font-size: 20px\n</style>\n```\n\n## 使用 teleport 传递组件内容 {#using-teleports}\n\nVitePress 目前只有使用 teleport 传送到 body 的 SSG 支持。对于其他地方，可以将它们包裹在内置的 `<ClientOnly>` 组件中，或者通过 [postRender 钩子](../reference/site-config#postrender)将 teleport 标签注入到最终页面 HTML 中的正确位置。\n\n<ModalDemo />\n\n::: details\n<<< @/components/ModalDemo.vue\n:::\n\n```md\n<ClientOnly>\n  <Teleport to=\"#modal\">\n    <div>\n      // ...\n    </div>\n  </Teleport>\n</ClientOnly>\n```\n\n<script setup>\nimport ModalDemo from '../../components/ModalDemo.vue'\nimport ComponentInHeader from '../../components/ComponentInHeader.vue'\n</script>\n\n<style>\n.escape-demo {\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  padding: 0 20px;\n}\n</style>\n"
  },
  {
    "path": "docs/zh/guide/what-is-vitepress.md",
    "content": "# VitePress 是什么？ {#what-is-vitepress}\n\nVitePress 是一个[静态站点生成器](https://en.wikipedia.org/wiki/Static_site_generator) (SSG)，专为构建快速、以内容为中心的站点而设计。简而言之，VitePress 获取用 Markdown 编写的内容，对其应用主题，并生成可以轻松部署到任何地方的静态 HTML 页面。\n\n<div class=\"tip custom-block\" style=\"padding-top: 8px\">\n\n只是想尝试一下？跳到[快速开始](./getting-started)。\n\n</div>\n\n## 使用场景 {#use-cases}\n\n- **文档**\n\n  VitePress 附带一个专为技术文档设计的默认主题。你现在正在阅读的这个页面以及 [Vite](https://vitejs.dev/)、[Rollup](https://rollupjs.org/)、[Pinia](https://pinia.vuejs.org/)、[VueUse](https://vueuse.org/)、[Vitest](https://vitest.dev/)、[D3](https://d3js.org/)、[UnoCSS](https://unocss.dev/)、[Iconify](https://iconify.design/) [等](https://github.com/search?q=/%22vitepress%22:+/+path:/(?:package%7Cdeno)%5C.jsonc?$/+NOT+is:fork+NOT+is:archived&type=code)文档都是基于这个主题的。\n\n  [Vue.js 官方文档](https://cn.vuejs.org/)也是基于 VitePress 的。但是为了可以在不同的翻译文档之间切换，它自定义了自己的主题。\n\n- **博客、档案和营销网站**\n\n  VitePress 支持[完全的自定义主题](./custom-theme)，具有标准 Vite + Vue 应用程序的开发体验。基于 Vite 构建还意味着可以直接利用其生态系统中丰富的 Vite 插件。此外，VitePress 提供了灵活的 API 来[加载数据](./data-loading) (本地或远程)，也可以[动态生成路由](./routing#dynamic-routes)。只要可以在构建时确定数据，就可以使用它来构建几乎任何东西。\n\n  [Vue.js 官方博客](https://blog.vuejs.org/)是一个简单的博客页面，它根据本地内容生成其索引页面。\n\n## 开发体验 {#developer-experience}\n\nVitePress 旨在使用 Markdown 生成内容时提供出色的开发体验。\n\n- **[Vite 驱动](https://cn.vitejs.dev/)**：即时服务器启动，始终立即反映 (<100ms) 编辑变化，无需重新加载页面。\n\n- **[内置 Markdown 扩展](./markdown)**：frontmatter、表格、语法高亮……应有尽有。具体来说，VitePress 提供了许多用于处理代码块的高级功能，使其真正成为技术文档的理想选择。\n\n- **[Vue 增强的 Markdown](./using-vue)**：每个 Markdown 页面都是 Vue [单文件组件](https://cn.vuejs.org/guide/scaling-up/sfc.html)，这要归功于 Vue 模板与 HTML 的 100% 语法兼容性。可以使用 Vue 模板语法或导入的 Vue 组件在静态内容中嵌入交互性。\n\n## 性能 {#performance}\n\n与许多传统的 SSG 不同，每次导航都会导致页面完全重新加载，VitePress 生成的网站在初次访问时提供静态 HTML，但它变成了[单页应用程序](https://en.wikipedia.org/wiki/Single-page_application)（SPA）进行站点内的后续导航。我们认为，这种模式为性能提供了最佳平衡：\n\n- **快速的初始加载**\n\n  对任何页面的初次访问都将会是静态的、预呈现的 HTML，以实现极快的加载速度和最佳的 SEO。然后页面加载一个 JavaScript bundle，将页面变成 Vue SPA (这被称为“激活”)。与 SPA 激活缓慢的常见假设不同，由于 Vue 3 良好的原始性能和编译优化，这个过程实际上非常快。在 [PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F) 上，典型的 VitePress 站点即使在网络速度较慢的低端移动设备上也能获得近乎完美的性能分数。\n\n- **加载完成后可以快速切换**\n\n  更重要的是，SPA 模型在首次加载后能够提升用户体验。用户在站点内导航时，不会再触发整个页面的刷新。而是通过获取并动态更新页面的内容来实现切换。VitePress 还会自动预加载视口范围内链接对应的页面片段。这样一来，大部分情况下，用户在加载完成后就能立即浏览新页面。\n\n- **高效的交互**\n\n  为了能够嵌入静态 Markdown 中的动态 Vue 部分，每个 Markdown 页面都被处理为 Vue 组件并编译成 JavaScript。这听起来可能效率低下，但 Vue 编译器足够聪明，可以将静态和动态部分分开，从而最大限度地减少激活成本和有效负载大小。对于初始的页面加载，静态部分会自动从 JavaScript 有效负载中删除，并在激活期间跳过。\n\n## VuePress 又是什么？ {#what-about-vuepress}\n\nVitePress 灵感来源于 VuePress。最初的 VuePress 1 基于 Vue 2 和 webpack。VitePress 则基于 Vue 3 和 Vite 开发，提供了更好的开发体验、更好的生产性能、更精美的默认主题和更灵活的自定义 API。\n\nVitePress 和 VuePress 1 的 API 区别主要在于主题和自定义。如果你使用的是 VuePress 1 的默认主题，应该可以很方便地迁移到 VitePress。\n\n并行维护两个 SSG 是难以持续的，因此 Vue 团队决定将 VitePress 作为长期维护并推荐的 SSG。现在 VuePress 1 已被弃用，VuePress 2 已移交给 VuePress 社区团队进行进一步开发和维护。\n"
  },
  {
    "path": "docs/zh/index.md",
    "content": "---\nlayout: home\n\nhero:\n  name: VitePress\n  text: 由 Vite 和 Vue 驱动的静态站点生成器\n  tagline: 将 Markdown 变成优雅的文档，只需几分钟\n  actions:\n    - theme: brand\n      text: 什么是 VitePress?\n      link: ./guide/what-is-vitepress\n    - theme: alt\n      text: 快速开始\n      link: ./guide/getting-started\n    - theme: alt\n      text: GitHub\n      link: https://github.com/vuejs/vitepress\n  image:\n      src: /vitepress-logo-large.svg\n      alt: VitePress\n\nfeatures:\n  - icon: 📝\n    title: 专注内容\n    details: 只需 Markdown 即可轻松创建美观的文档站点。\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 256.32\"><defs><linearGradient id=\"a\" x1=\"-.828%\" x2=\"57.636%\" y1=\"7.652%\" y2=\"78.411%\"><stop offset=\"0%\" stop-color=\"#41D1FF\"/><stop offset=\"100%\" stop-color=\"#BD34FE\"/></linearGradient><linearGradient id=\"b\" x1=\"43.376%\" x2=\"50.316%\" y1=\"2.242%\" y2=\"89.03%\"><stop offset=\"0%\" stop-color=\"#FFEA83\"/><stop offset=\"8.333%\" stop-color=\"#FFDD35\"/><stop offset=\"100%\" stop-color=\"#FFA800\"/></linearGradient></defs><path fill=\"url(#a)\" d=\"M255.153 37.938 134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z\"/><path fill=\"url(#b)\" d=\"M185.432.063 96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028 72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z\"/></svg>\n    title: 享受 Vite 无可比拟的体验\n    details: 服务器即时启动，闪电般的热更新，还可以使用基于 Vite 生态的插件。\n  - icon: <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"30\" viewBox=\"0 0 256 220.8\"><path fill=\"#41B883\" d=\"M204.8 0H256L128 220.8 0 0h97.92L128 51.2 157.44 0h47.36Z\"/><path fill=\"#41B883\" d=\"m0 0 128 220.8L256 0h-51.2L128 132.48 50.56 0H0Z\"/><path fill=\"#35495E\" d=\"M50.56 0 128 133.12 204.8 0h-47.36L128 51.2 97.92 0H50.56Z\"/></svg>\n    title: 使用 Vue 自定义\n    details: 直接在 Markdown 中使用 Vue 语法和组件，或者使用 Vue 组件构建自定义主题。\n  - icon: 🚀\n    title: 速度真的很快！\n    details: 采用静态 HTML 实现快速的页面初次加载，使用客户端路由实现快速的页面切换导航。\n---\n"
  },
  {
    "path": "docs/zh/reference/cli.md",
    "content": "# 命令行接口 {#command-line-interface}\n\n## `vitepress dev`\n\n使用指定目录作为根目录来启动 VitePress 开发服务器。默认为当前目录。在当前目录下运行时也可以省略 `dev` 命令。\n\n### 用法\n\n```sh\n# 从当前目录启动，省略 `dev`\nvitepress\n\n# 从子目录启动\nvitepress dev [root]\n```\n\n### 选项 {#options}\n\n| 选项            | 说明                                       |\n| --------------- | ------------------------------------------ |\n| `--open [path]` | 启动时打开浏览器 (`boolean \\| string`)     |\n| `--port <port>` | 指定端口 (`number`)                        |\n| `--base <path>` | public base URL (默认值: `/`) (`string`)     |\n| `--cors`        | 启用 CORS                                  |\n| `--strictPort`  | 如果指定的端口已被占用则退出 (`boolean`)   |\n| `--force`       | 强制优化程序忽略缓存并重新绑定 (`boolean`) |\n\n## `vitepress build`\n\n构建用于生产环境的 VitePress 站点。\n\n### 用法\n\n```sh\nvitepress build [root]\n```\n\n### 选项\\\n\n| 选项                           | 说明                                                                                              |\n| ------------------------------ | ------------------------------------------------------------------------------------------------- |\n| `--mpa` (experimental)         | [MPA 模式](../guide/mpa-mode) 下构建，无需客户端激活 (`boolean`)                        |\n| `--base <path>`                | public base URL (默认值: `/`)  (`string`)                                                            |\n| `--target <target>`            | 转译目标 (默认值：`\"modules\"`) (`string`)                                                        |\n| `--outDir <dir>`               | 输出目录 (默认值：`.vitepress/dist`) (`string`)                                                  |\n| `--assetsInlineLimit <number>` | 静态资源 base64 内联阈值（以字节为单位）(默认值：`4096`) (`number`)                             |\n\n## `vitepress preview`\n\n在本地预览生产版本。\n\n### 用法\n\n```sh\nvitepress preview [root]\n```\n\n### 选项\n\n| 选项            | 说明                                   |\n| --------------- | -------------------------------------- |\n| `--base <path>` | public base URL (默认值: `/`) (`string`) |\n| `--port <port>` | 指定端口 (`number`)                    |\n\n## `vitepress init`\n\n在当前目录中启动[安装向导](../guide/getting-started#setup-wizard)。\n\n### 用法\n\n```sh\nvitepress init\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-badge.md",
    "content": "# 徽标 {#badge}\n\n徽标可让你为标题添加状态。例如，指定部分的类型或支持的版本可能很有用。\n\n## 用法 {#usage}\n\n可以使用全局组件 `Badge` 。\n\n```html\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n```\n\n上面的代码渲染如下：\n\n### Title <Badge type=\"info\" text=\"default\" />\n### Title <Badge type=\"tip\" text=\"^1.9.0\" />\n### Title <Badge type=\"warning\" text=\"beta\" />\n### Title <Badge type=\"danger\" text=\"caution\" />\n\n## 自定义子节点 {#custom-children}\n\n`<Badge>` 接受 `children`，这将显示在徽标中。\n\n```html\n### Title <Badge type=\"info\">custom element</Badge>\n```\n\n### Title <Badge type=\"info\">custom element</Badge>\n\n## 自定义不同类型徽标的背景色 {#customize-type-color}\n\n可以通过覆盖 css 来自定义不同类型 `<Badge />` 的样式。以下是默认值。\n\n```css\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-brand-1);\n  --vp-badge-tip-bg: var(--vp-c-brand-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n```\n\n## `<Badge>`\n\n`<Badge>` 组件接受以下属性：\n\n```ts\ninterface Props {\n  // 当传递 `<slot>` 时，该值将被忽略\n  text?: string\n\n  // 默认为 `tip`.\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-carbon-ads.md",
    "content": "# Carbon Ads {#carbon-ads}\n\nVitePress 内置了对 [Carbon Ads](https://www.carbonads.net/) 的原生支持。通过在配置中定义 Carbon Ads 凭据，VitePress 将在页面上显示广告。\n\n```js\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n这些值用于调用 carbon CDN 脚本，如下所示。\n\n```js\n`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}`\n```\n\n要了解有关 Carbon Ads 配置的更多信息，请访问 [Carbon Ads 站点](https://www.carbonads.net/)。\n"
  },
  {
    "path": "docs/zh/reference/default-theme-config.md",
    "content": "# 默认主题配置 {#default-theme-config}\n\n主题配置可以让你能够自定义主题。可以通过将 `themeConfig` 添加到配置文件来进行主题配置：\n\n```ts\nexport default {\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // 主题相关配置\n  themeConfig: {\n    logo: '/logo.svg',\n    nav: [...],\n    sidebar: { ... }\n  }\n}\n```\n\n**此页面上记录的选项仅适用于默认主题**。不同的主题需要不同的主题配置。使用自定义主题时，主题配置对象将传递给主题，以便主题可以基于它作出不同表现。\n\n## i18nRouting\n\n- 类型：`boolean`\n\n将本地语言更改为 `zh` 会将 URL 从 `/foo`（或 `/en/foo/`）更改为 `/zh/foo`。可以通过将 `themeConfig.i18nRouting` 设置为 `false` 来禁用此行为。\n\n## logo\n\n- 类型：`ThemeableImage`\n\n导航栏上显示的 Logo，位于站点标题前。可以接受一个路径字符串，或者一个对象来设置在浅色/深色模式下不同的 Logo。\n\n```ts\nexport default {\n  themeConfig: {\n    logo: '/logo.svg'\n  }\n}\n```\n\n```ts\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n```\n\n## siteTitle\n\n- 类型：`string | false`\n\n可以自定义此项以替换导航中的默认站点标题 (应用配置中的 `title`)。当设置为 `false` 时，导航中的标题将被禁用。这在当 `logo` 已经包含站点标题文本时很有用。\n\n```ts\nexport default {\n  themeConfig: {\n    siteTitle: 'Hello World'\n  }\n}\n```\n\n## nav\n\n- 类型：`NavItem`\n\n导航菜单项的配置。可以在[默认主题: 导航栏](./default-theme-nav#navigation-links) 了解更多详情。\n\n```ts\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\ntype NavItem = NavItemWithLink | NavItemWithChildren\n\ninterface NavItemWithLink {\n  text: string\n  link: string | ((payload: PageData) => string)\n  activeMatch?: string\n  target?: string\n  rel?: string\n  noIcon?: boolean\n}\n\ninterface NavItemChildren {\n  text?: string\n  items: NavItemWithLink[]\n}\n\ninterface NavItemWithChildren {\n  text?: string\n  items: (NavItemChildren | NavItemWithLink)[]\n  activeMatch?: string\n}\n```\n\n## sidebar\n\n- 类型：`Sidebar`\n\n侧边栏菜单项的配置。可以在[默认主题: 侧边栏](./default-theme-sidebar)了解更多详情。\n\n```ts\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n```ts\nexport type Sidebar = SidebarItem[] | SidebarMulti\n\nexport interface SidebarMulti {\n  [path: string]: SidebarItem[]\n}\n\nexport type SidebarItem = {\n  /**\n   * 侧边栏项的文本标签\n   */\n  text?: string\n\n  /**\n   * 侧边栏项的链接\n   */\n  link?: string\n\n  /**\n   * 侧边栏项的子项\n   */\n  items?: SidebarItem[]\n\n  /**\n   * 如果未指定，侧边栏组不可折叠\n   *\n   * 如果为 `true`，则侧边栏组可折叠并且默认折叠\n   *\n   * 如果为 `false`，则侧边栏组可折叠但默认展开\n   */\n  collapsed?: boolean\n}\n```\n\n## aside\n\n- 类型：`boolean | 'left'`\n- 默认值：`true`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#aside) 覆盖\n\n将此值设置为 `false` 可禁用 aside 容器。\\\n将此值设置为 `true` 将在页面右侧渲染。\\\n将此值设置为 `left` 将在页面左侧渲染。\n\n如果想对所有页面禁用它，应该使用 `outline: false`。\n\n## outline\n\n- 类型：`Outline | Outline['level'] | false`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#outline) 覆盖层级\n\n将此值设置为 `false` 可禁止渲染大纲容器。更多详情请参考该接口：\n\n```ts\ninterface Outline {\n  /**\n   * outline 中要显示的标题级别。\n   * 单个数字表示只显示该级别的标题。\n   * 如果传递的是一个元组，第一个数字是最小级别，第二个数字是最大级别。\n   * `'deep'` 与 `[2, 6]` 相同，将显示从 `<h2>` 到 `<h6>` 的所有标题。\n   *\n   * @default 2\n   */\n  level?: number | [number, number] | 'deep'\n\n  /**\n   * 显示在 outline 上的标题。\n   *\n   * @default 'On this page'\n   */\n  label?: string\n}\n```\n\n## socialLinks\n\n- 类型：`SocialLink[]`\n\n可以定义此选项以在导航栏中展示带有图标的社交帐户链接。\n\n```ts\nexport default {\n  themeConfig: {\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' },\n      { icon: 'twitter', link: '...' },\n      // 可以通过将 SVG 作为字符串传递来添加自定义图标：\n      {\n        icon: {\n          svg: '<svg role=\"img\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><title>Dribbble</title><path d=\"M12...6.38z\"/></svg>'\n        },\n        link: '...',\n        // 也可以为无障碍添加一个自定义标签 (可选但推荐):\n        ariaLabel: 'cool link'\n      }\n    ]\n  }\n}\n```\n\n```ts\ninterface SocialLink {\n  icon: string | { svg: string }\n  link: string\n  ariaLabel?: string\n}\n```\n\n## footer\n\n- 类型：`Footer`\n- 可以通过 [frontmatter](./frontmatter-config#footer) 进行覆盖。\n\n页脚配置。可以添加 message 和 copyright。由于设计原因，仅当页面不包含侧边栏时才会显示页脚。\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  message?: string\n  copyright?: string\n}\n```\n\n## editLink\n\n- 类型：`EditLink`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#editlink) 覆盖\n\n编辑链接可让显示链接以编辑 Git 管理服务 (例如 GitHub 或 GitLab) 上的页面。有关详细信息，请参阅[默认主题：编辑链接](./default-theme-edit-link)。\n\n```ts\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    }\n  }\n}\n```\n\n```ts\nexport interface EditLink {\n  pattern: string\n  text?: string\n}\n```\n\n## lastUpdated\n\n- 类型：`LastUpdatedOptions`\n\n允许自定义上次更新的文本和日期格式。\n\n```ts\nexport default {\n  themeConfig: {\n    lastUpdated: {\n      text: 'Updated at',\n      formatOptions: {\n        dateStyle: 'full',\n        timeStyle: 'medium'\n      }\n    }\n  }\n}\n```\n\n```ts\nexport interface LastUpdatedOptions {\n  /**\n   * @default 'Last updated'\n   */\n  text?: string\n\n  /**\n   * @default\n   * { dateStyle: 'short',  timeStyle: 'short' }\n   */\n  formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n}\n```\n\n## algolia\n\n- 类型：`AlgoliaSearch`\n\n支持使用 [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) 搜索站点文档。在[默认主题：搜索](./default-theme-search) 中了解更多信息。\n\n```ts\nexport interface AlgoliaSearchOptions extends DocSearchProps {\n  locales?: Record<string, Partial<DocSearchProps>>\n}\n```\n\n在[这里](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)查看完整配置。\n\n## carbonAds {#carbon-ads}\n\n- 类型：`CarbonAdsOptions`\n\n一个配置即可展示 [Carbon Ads](https://www.carbonads.net/)。\n\n```ts\nexport default {\n  themeConfig: {\n    carbonAds: {\n      code: 'your-carbon-code',\n      placement: 'your-carbon-placement'\n    }\n  }\n}\n```\n\n```ts\nexport interface CarbonAdsOptions {\n  code: string\n  placement: string\n}\n```\n\n在 [Default Theme: Carbon Ads](./default-theme-carbon-ads) 中了解更多信息。\n\n## docFooter\n\n- 类型：`DocFooter`\n\n可用于自定义出现在上一页和下一页链接上方的文本。如果不是用英语编写文档，这很有帮助。也可用于全局禁用上一页/下一页链接。如果想有选择地启用/禁用上一个/下一个链接，可以使用 [frontmatter](./default-theme-prev-next-links)。\n\n```ts\nexport default {\n  themeConfig: {\n    docFooter: {\n      prev: 'Pagina prior',\n      next: 'Proxima pagina'\n    }\n  }\n}\n```\n\n```ts\nexport interface DocFooter {\n  prev?: string | false\n  next?: string | false\n}\n```\n\n## darkModeSwitchLabel\n\n- 类型：`string`\n- 默认值：`Appearance`\n\n用于自定义深色模式开关标签，该标签仅在移动端视图中显示。\n\n## lightModeSwitchTitle\n\n- 类型：`string`\n- 默认值：`Switch to light theme`\n\n用于自定义悬停时显示的浅色模式开关标题。\n\n## darkModeSwitchTitle\n\n- 类型：`string`\n- 默认值：`Switch to dark theme`\n\n用于自定义悬停时显示的深色模式开关标题。\n\n## sidebarMenuLabel\n\n- 类型：`string`\n- 默认值：`Menu`\n\n用于自定义侧边栏菜单标签，该标签仅在移动端视图中显示。\n\n## returnToTopLabel\n\n- 类型：`string`\n- 默认值：`Return to top`\n\n用于自定义返回顶部按钮的标签，该标签仅在移动端视图中显示。\n\n## langMenuLabel\n\n- 类型：`string`\n- 默认值：`Change language`\n\n用于自定义导航栏中语言切换按钮的 aria-label，仅当使用 [i18n](../guide/i18n) 时才使用此选项。\n\n## externalLinkIcon\n\n- 类型：`boolean`\n- 默认值：`false`\n\n是否在 markdown 中的外部链接旁显示外部链接图标。\n"
  },
  {
    "path": "docs/zh/reference/default-theme-edit-link.md",
    "content": "# 编辑链接 {#edit-link}\n\n## 站点级配置 {#site-level-config}\n\n编辑链接让你可以显示一个链接，以在 GitHub 或 GitLab 等 Git 管理服务上编辑页面。要启用它，请将 `themeConfig.editLink` 选项添加到配置中。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n    }\n  }\n}\n```\n\n`pattern` 选项定义链接的 URL 结构，并且 `:path` 将被替换为页面路径。\n\n你还可以放置一个接受 [`PageData`](./runtime-api#usedata) 作为参数并返回 URL 字符串的纯函数。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: ({ filePath }) => {\n        if (filePath.startsWith('packages/')) {\n          return `https://github.com/acme/monorepo/edit/main/${filePath}`\n        } else {\n          return `https://github.com/acme/monorepo/edit/main/docs/${filePath}`\n        }\n      }\n    }\n  }\n}\n```\n\n它不应该有副作用，也不应该访问其范围之外的任何东西，因为它将在浏览器中被序列化和执行。\n\n默认情况下，这将在文档页面底部添加链接文本“Edit this page”。可以通过定义 `text` 选项来自定义此文本。\n\n```js\nexport default {\n  themeConfig: {\n    editLink: {\n      pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path',\n      text: 'Edit this page on GitHub'\n    }\n  }\n}\n```\n\n## frontmatter 配置 {#frontmatter-config}\n\n可以使用 frontmatter 上的 `editLink` 选项单独禁用某个页面的编辑链接：\n\n```yaml\n---\neditLink: false\n---\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-footer.md",
    "content": "# 页脚 {#footer}\n\n配置好 `themeConfig.footer`，VitePress 将在全局页面底部显示页脚。\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2019-present Evan You'\n    }\n  }\n}\n```\n\n```ts\nexport interface Footer {\n  // 版权前显示的信息\n  message?: string\n\n  // 实际的版权文本\n  copyright?: string\n}\n```\n\n上面的配置也支持 HTML 字符串。所以，例如，如果想配置页脚文本有一些链接，可以调整配置如下：\n\n```ts\nexport default {\n  themeConfig: {\n    footer: {\n      message: 'Released under the <a href=\"https://github.com/vuejs/vitepress/blob/main/LICENSE\">MIT License</a>.',\n      copyright: 'Copyright © 2019-present <a href=\"https://github.com/yyx990803\">Evan You</a>'\n    }\n  }\n}\n```\n\n::: warning\n只有内联元素可以在 `message` 和 `copyright` 中使用，因为它们渲染在 `<p>` 元素中。如果想添加块元素，请考虑使用 [`layout-bottom`](../guide/extending-default-theme#layout-slots) 插槽。\n:::\n\n请注意，当[侧边栏](./default-theme-sidebar)可见时，不会显示页脚。\n\n## frontmatter 配置 {#frontmatter-config}\n\n可以使用 frontmatter 上的 `footer` 选项在单独页面上禁用此功能：\n\n```yaml\n---\nfooter: false\n---\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-home-page.md",
    "content": "# 主页 {#home-page}\n\nVitePress 默认主题提供了一个首页布局，也可以在[此站点首页](../)看到。可以通过 [frontmatter](./frontmatter-config) 指定 `layout: home` 在任何页面上使用它\n\n```yaml\n---\nlayout: home\n---\n```\n\n但是，仅做这个配置不会有太大作用。可以通过设置其他选项 (例如 `hero` 和 `features`) 向主页添加几个不同的预设。\n\n## Hero 部分 {#hero-section}\n\nHero 部分位于主页顶部。以下是配置 Hero 的方法。\n\n```yaml\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n  tagline: Lorem ipsum...\n  image:\n    src: /logo.png\n    alt: VitePress\n  actions:\n    - theme: brand\n      text: Get Started\n      link: /guide/what-is-vitepress\n    - theme: alt\n      text: View on GitHub\n      link: https://github.com/vuejs/vitepress\n---\n```\n\n```ts\ninterface Hero {\n  // `text` 上方的字符，带有品牌颜色\n  // 预计简短，例如产品名称\n  name?: string\n\n  // hero 部分的主要文字，\n  // 被定义为 `h1` 标签\n  text: string\n\n  // `text` 下方的标语\n  tagline?: string\n\n  // text 和 tagline 区域旁的图片\n  image?: ThemeableImage\n\n  // 主页 hero 部分的操作按钮\n  actions?: HeroAction[]\n}\n\ntype ThemeableImage =\n  | string\n  | { src: string; alt?: string }\n  | { light: string; dark: string; alt?: string }\n\ninterface HeroAction {\n  // 按钮的颜色主题，默认为 `brand`\n  theme?: 'brand' | 'alt'\n\n  // 按钮的标签\n  text: string\n\n  // 按钮的目标链接\n  link: string\n\n  // 链接的 target 属性\n  target?: string\n\n  // 链接的 rel 属性\n  rel?: string\n}\n```\n\n### 自定义 name 的颜色 {#customizing-the-name-color}\n\nVitePress 通过 (`--vp-c-brand-1`) 设置 `name` 的颜色。但是，可以通过覆盖 `--vp-home-hero-name-color` 变量来自定义此颜色。\n\n```css\n:root {\n  --vp-home-hero-name-color: blue;\n}\n```\n\n也可以通过组合 `--vp-home-hero-name-background` 来进一步自定义 `name` 为渐变色。\n\n```css\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff);\n}\n```\n\n## Features 部分 {#features-section}\n\n在 Features 部分，可以在 Hero 部分之后列出任意数量的 Feature。可以在 frontmatter 中配置  `features`。\n\n可以为每个 feature 提供一个图标，可以是表情符号或任何类型的图像。当配置的图标是图片（svg, png, jpeg...）时，必须提供合适的宽度和高度的图标；还可以在需要时配置其描述、固有大小以及深色和浅色主题下的不同表现。\n\n```yaml\n---\nlayout: home\n\nfeatures:\n  - icon: 🛠️\n    title: Simple and minimal, always\n    details: Lorem ipsum...\n  - icon:\n      src: /cool-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n  - icon:\n      dark: /dark-feature-icon.svg\n      light: /light-feature-icon.svg\n    title: Another cool feature\n    details: Lorem ipsum...\n---\n```\n\n```ts\ninterface Feature {\n  // 在每个 feature 框中显示图标\n  icon?: FeatureIcon\n\n  // feature 的标题\n  title: string\n\n  // feature 的详情\n  details: string\n\n  // 点击 feature 组件时的链接，可以是内部链接，也可以是外部链接。\n  //\n  //\n  // 例如 `guide/reference/default-theme-home-page` 或 `https://example.com`\n  link?: string\n\n  // feature 组件内显示的链接文本，最好与 `link` 选项一起使用\n  //\n  //\n  // 例如 `Learn more`, `Visit page` 等\n  linkText?: string\n\n  // `link` 选项的链接 rel 属性\n  //\n  // 例如 `external`\n  rel?: string\n\n  // `link` 选项的链接 target 属性\n  target?: string\n}\n\ntype FeatureIcon =\n  | string\n  | { src: string; alt?: string; width?: string; height: string }\n  | {\n      light: string\n      dark: string\n      alt?: string\n      width?: string\n      height: string\n    }\n```\n\n## Markdown 内容 {#markdown-content}\n\n可以在 frontmatter 的分隔符 `---` 下方为站点主页添加额外的 Markdown 内容。\n\n````md\n---\nlayout: home\n\nhero:\n  name: VitePress\n  text: Vite & Vue powered static site generator.\n---\n\n## Getting Started\n\nYou can get started using VitePress right away using `npx`!\n\n```sh\nnpm init\nnpx vitepress init\n```\n````\n\n::: info\nVitePress 并不总是为 `layout: home` 页面里额外的内容自动添加样式。要回到以前的行为，可以在 frontmatter 中添加 `markdownStyles: false`。\n:::\n"
  },
  {
    "path": "docs/zh/reference/default-theme-last-updated.md",
    "content": "# 最后更新于 {#last-updated}\n\n最近一条内容的更新时间会显示在页面右下角。要启用它，请将 `lastUpdated` 选项添加到配置中。\n\n::: tip\nVitePress 通过每个文件最近一次 Git 提交的时间戳显示\"最后更新\"时间，因此你必须提交 markdown 文件才能看到最后更新时间。\n\n具体实现上，VitePress 会对每个文件执行`git log -1 --pretty=\"%ai\"`命令以获取时间戳。若所有页面显示相同的更新时间，可能是由于浅克隆（常见于 CI 环境）导致 Git 历史记录受限所致。\n\n在 **GitHub Actions** 中修复此问题，请在工作流中添加以下配置：\n\n```yaml{4}\n- name: Checkout\n  uses: actions/checkout@v5\n  with:\n    fetch-depth: 0\n```\n\n其他 CI/CD 平台也有类似设置。\n\n若上述选项不可用，可在 `package.json` 中的 `docs:build` 命令后手动添加获取操作：\n\n```json\n\"docs:build\": \"git fetch --unshallow && vitepress build docs\"\n```\n:::\n\n## 全局配置 {#site-level-config}\n\n```js\nexport default {\n  lastUpdated: true\n}\n```\n\n## frontmatter 配置 {#frontmatter-config}\n\n可以使用 frontmatter 上的 `lastUpdated` 选项单独禁用某个页面的最后更新展示：\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n另请参阅[默认主题：最后更新时间](./default-theme-config#lastupdated) 了解更多详细信息。主题级别的任何 [truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy) 值也将启用该功能，除非在站点或页面级别明确禁用。\n"
  },
  {
    "path": "docs/zh/reference/default-theme-layout.md",
    "content": "# 布局 {#layout}\n\n可以通过设置页面 [frontmatter](./frontmatter-config) 选项来选择页面布局。有 3 种布局选项 `doc`、`page` 和 `home`。如果未指定任何内容，则该页面将被视为 `doc` 页面。\n\n```yaml\n---\nlayout: doc\n---\n```\n\n## doc 布局 {#doc-layout}\n\n`doc` 是默认布局，它将整个 Markdown 内容设置为“documentation”外观。它的工作原理是将整个内容包装在 css `vp-doc` 类中，并将样式应用于它下面的元素。\n\n几乎所有通用元素，例如 `p`, 或 `h2` 都有特殊的样式。因此，请记住，如果在 Markdown 内容中添加任何自定义 HTML，这些内容也会受到这些样式的影响。\n\n它还提供下面列出的文档特定功能。这些功能仅在此布局中启用。\n\n- [编辑链接](./default-theme-edit-link)\n- [上下页链接](./default-theme-prev-next-links)\n- [大纲](./default-theme-config#outline)\n- [Carbon Ads](./default-theme-carbon-ads)\n\n## page 布局 {#page-layout}\n\n`page` 被视为“空白页”。Markdown 仍然会被解析，所有的 [Markdown 扩展](../guide/markdown) 都和 `doc` 布局一样运行，但它没有任何默认样式。\n\n`page` 布局将使可以自行设计所有内容，而不会受 VitePress 主题影响。当想要创建自己的自定义页面时，这很有用。\n\n请注意，即使在此布局中，如果页面具有匹配的侧边栏配置，侧边栏仍会显示。\n\n## home 布局 {#home-layout}\n\n`home` 将生成模板化的“主页”。在此布局中，可以设置额外的选项，例如 `hero` 和 `features` 以进一步自定义内容。请访问[默认主题: 主页](./default-theme-home-page)了解更多详情。\n\n## 无布局 {#no-layout}\n\n如果不想要任何布局，可以通过 frontmatter 传递 `layout: false`。如果想要一个完全可自定义的登录页面（默认情况下没有任何侧边栏、导航栏或页脚），此选项很有用。\n\n## 自定义布局 {#custom-layout}\n\n也可以使用自定义布局：\n\n```md\n---\nlayout: foo\n---\n```\n\n这将在上下文中查找注册名为 `foo` 的组件。例如，可以在 `.vitepress/theme/index.ts`中全局注册组件：\n\n```ts\nimport DefaultTheme from 'vitepress/theme'\nimport Foo from './Foo.vue'\n\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('foo', Foo)\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-nav.md",
    "content": "# 导航栏 {#nav}\n\nNav 是显示在页面顶部的导航栏。它包含站点标题、全局菜单链接等。\n\n## 站点标题和图标 {#site-title-and-logo}\n\n默认情况下，nav 显示 [`config.title`](./site-config#title) 作为站点的标题。如果想更改导航栏上显示的内容，可以在 `themeConfig.siteTitle` 选项中定义自定义文本。\n\n```js\nexport default {\n  themeConfig: {\n    siteTitle: 'My Custom Title'\n  }\n}\n```\n\n如果站点有图标，则可以通过传递图片路径来显示它。应该将图标直接放在 `public` 中，并赋值该绝对路径。\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg'\n  }\n}\n```\n\n添加图标时，它会与站点标题一起显示。如果只需要图标并且想要隐藏站点标题文本，请将 `siteTitle` 选项设置为 `false`。\n\n```js\nexport default {\n  themeConfig: {\n    logo: '/my-logo.svg',\n    siteTitle: false\n  }\n}\n```\n\n如果想添加 `alt` 属性或根据深色/浅色模式自定义，还可以将图标作为对象传递。有关详细信息，请参阅 [`themeConfig.logo`](./default-theme-config#logo)。\n\n## 导航链接 {#navigation-links}\n\n可以定义 `themeConfig.nav` 选项以将链接添加到导航栏。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      { text: 'Config', link: '/config' },\n      { text: 'Changelog', link: 'https://github.com/...' }\n    ]\n  }\n}\n```\n\n`text` 是 nav 中显示的实际文本，而 `link` 是单击文本时将导航到的链接。对于链接，将路径设置为不带 `.md` 后缀的实际文件，并且始终以 `/` 开头。\n\n`link` 也可以是一个函数，它接受 [`PageData`](./runtime-api#usedata) 作为参数并返回路径。\n\n导航链接也可以是下拉菜单。为此，请替换 `link` 选项，设置 `items` 数组。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          { text: 'Item A', link: '/item-1' },\n          { text: 'Item B', link: '/item-2' },\n          { text: 'Item C', link: '/item-3' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n请注意，下拉菜单标题 (上例中的 `Dropdown Menu`) 不能具有 `link` 属性，因为它是打开下拉对话框的按钮。\n\n还可以通过传入更多嵌套项来进一步向下拉菜单项添加“sections”。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      { text: 'Guide', link: '/guide' },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // 该部分的标题\n            text: 'Section A Title',\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      },\n      {\n        text: 'Dropdown Menu',\n        items: [\n          {\n            // 也可以省略标题\n            items: [\n              { text: 'Section A Item A', link: '...' },\n              { text: 'Section B Item B', link: '...' }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### 自定义链接的路由匹配状态 {#customize-link-s-active-state}\n\n当前页面位于匹配路径下时，导航菜单项将突出显示。如果想自定义要匹配的路径，请将 `activeMatch` 属性和正则表达式定义为字符串值。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      // 当用户位于 `/config/` 路径时，该链接处于激活状态\n      {\n        text: 'Guide',\n        link: '/guide',\n        activeMatch: '/config/'\n      }\n    ]\n  }\n}\n```\n\n::: warning\n`activeMatch` 应为正则表达式字符串，但必须将其定义为字符串。我们不能在这里使用实际的 RegExp 对象，因为它在构建期间不可序列化。\n:::\n\n### 自定义链接的“target”和“rel”属性 {#customize-link-s-target-and-rel-attributes}\n\n默认情况下，VitePress 会根据链接是否为外部链接自动判断 `target` 和 `rel` 属性。但如果愿意，也可以自定义它们。\n\n```js\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'Merchandise',\n        link: 'https://www.thegithubshop.com/',\n        target: '_self',\n        rel: 'sponsored'\n      }\n    ]\n  }\n}\n```\n\n## 社交链接 {#social-links}\n\n参考 [`socialLinks`](./default-theme-config#sociallinks)。\n\n## 自定义组件\n\n你可以通过使用 `component` 选项在导航栏中包含自定义组件。`component` 键对应的值应为 Vue 组件名，并且必须使用 [Theme.enhanceApp](../guide/custom-theme#theme-interface) 全局注册。\n\n```js [.vitepress/config.js]\nexport default {\n  themeConfig: {\n    nav: [\n      {\n        text: 'My Menu',\n        items: [\n          {\n            component: 'MyCustomComponent',\n            // 可选的 props 传递给组件\n            props: {\n              title: 'My Custom Component'\n            }\n          }\n        ]\n      },\n      {\n        component: 'AnotherCustomComponent'\n      }\n    ]\n  }\n}\n```\n\n然后，你需要全局注册该组件：\n\n```js [.vitepress/theme/index.js]\nimport DefaultTheme from 'vitepress/theme'\n\nimport MyCustomComponent from './components/MyCustomComponent.vue'\nimport AnotherCustomComponent from './components/AnotherCustomComponent.vue'\n\n/** @type {import('vitepress').Theme} */\nexport default {\n  extends: DefaultTheme,\n  enhanceApp({ app }) {\n    app.component('MyCustomComponent', MyCustomComponent)\n    app.component('AnotherCustomComponent', AnotherCustomComponent)\n  }\n}\n```\n\n你的组件将在导航栏中渲染。 VitePress 会向组件提供以下额外的 props：\n\n- `screenMenu`：一个可选的布尔值，指示组件是否在移动导航菜单内\n\n你可以在端到端测试中查看示例 [这里](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress)。\n"
  },
  {
    "path": "docs/zh/reference/default-theme-prev-next-links.md",
    "content": "# 上下页链接 {#prev-next-links}\n\n可以自定义上一页和下一页的文本和链接 (显示在文档页脚处)。如果要使其与侧边栏上的文本不同，这会很有帮助。此外，你可能会发现，要禁用未包含在侧边栏中的页面的页脚或链接时，这很有用。\n\n## prev\n\n- 类型：`string | false | { text?: string; link?: string }`\n\n- 说明：\n\n  指定要在指向上一页的链接上显示的文本/链接。如果没有在 frontmatter 中设置它，文本/链接将从侧边栏配置中推断出来。\n\n- 示例：\n\n  - 仅自定义文本：\n\n    ```yaml\n    ---\n    prev: 'Get Started | Markdown'\n    ---\n    ```\n\n  - 自定义文本和链接：\n\n    ```yaml\n    ---\n    prev:\n      text: 'Markdown'\n      link: '/guide/markdown'\n    ---\n    ```\n\n  - 隐藏上一页：\n\n    ```yaml\n    ---\n    prev: false\n    ---\n    ```\n\n## next\n\n与 `prev` 相同，但用于下一页。\n"
  },
  {
    "path": "docs/zh/reference/default-theme-search.md",
    "content": "---\noutline: deep\n---\n\n# 搜索 {#search}\n\n## 本地搜索 {#local-search}\n\n得益于 [minisearch](https://github.com/lucaong/minisearch/)，VitePress 支持使用浏览器内索引进行模糊全文搜索。要启用此功能，只需在 `.vitepress/config.ts` 文件中将 `themeConfig.search.provider` 选项设置为 `'local'` 即可：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local'\n    }\n  }\n})\n```\n\n示例结果：\n\n![搜索弹窗截图](/search.png)\n\n或者，你可以使用 [Algolia DocSearch](#algolia-search) 或一些社区插件，例如：<https://www.npmjs.com/package/vitepress-plugin-search> 或者 <https://www.npmjs.com/package/vitepress-plugin-pagefind>。\n\n### i18n {#local-search-i18n}\n\n你可以使用这样的配置来使用多语言搜索：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        locales: {\n          zh: { // 如果你想翻译默认语言，请将此处设为 `root`\n            translations: {\n              button: {\n                buttonText: '搜索',\n                buttonAriaLabel: '搜索'\n              },\n              modal: {\n                displayDetails: '显示详细列表',\n                resetButtonTitle: '重置搜索',\n                backButtonTitle: '关闭搜索',\n                noResultsText: '没有结果',\n                footer: {\n                  selectText: '选择',\n                  selectKeyAriaLabel: '输入',\n                  navigateText: '导航',\n                  navigateUpKeyAriaLabel: '上箭头',\n                  navigateDownKeyAriaLabel: '下箭头',\n                  closeText: '关闭',\n                  closeKeyAriaLabel: 'Esc'\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n### MiniSearch 配置项 {#minisearch-options}\n\n你可以像这样配置 MiniSearch ：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        miniSearch: {\n          /**\n           * @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}\n           */\n          options: {\n            /* ... */\n          },\n          /**\n           * @type {import('minisearch').SearchOptions}\n           * @default\n           * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }\n           */\n          searchOptions: {\n            /* ... */\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n参阅 [MiniSearch 文档](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html)了解更多信息。\n\n### 自定义渲染内容 {#custom-content-renderer}\n\n可以在索引之前自定义用于渲染 Markdown 内容的函数：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        /**\n         * @param {string} src\n         * @param {import('vitepress').MarkdownEnv} env\n         * @param {import('markdown-it-async')} md\n         */\n        async _render(src, env, md) {\n          // 返回 HTML 字符串\n        }\n      }\n    }\n  }\n})\n```\n\n该函数将从客户端站点数据中剥离，因此你可以在其中使用 Node.js API。\n\n#### 示例：从搜索中排除页面 {#example-excluding-pages-from-search}\n\n你可以通过将 `search: false` 添加到页面的 `frontmatter` 来从搜索中排除页面。或者：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.search === false) return ''\n          if (env.relativePath.startsWith('some/path')) return ''\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 注意\n如果提供了自定义的 `_render` 函数，你需要自己处理 `search: false` 的 frontmatter。此外，在调用 `md.renderAsync` 之前，`env` 对象不会完全填充，因此对可选 `env` 属性 (如 `frontmatter`) 的任何检查都应该在此之后完成。\n:::\n\n#### 示例：转换内容——添加锚点 {#example-transforming-content-adding-anchors}\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'local',\n      options: {\n        async _render(src, env, md) {\n          const html = await md.renderAsync(src, env)\n          if (env.frontmatter?.title)\n            return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html\n          return html\n        }\n      }\n    }\n  }\n})\n```\n\n## Algolia Search {#algolia-search}\n\nVitePress 支持使用 [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) 搜索文档站点。请参阅他们的入门指南。在你的 `.vitepress/config.ts` 中，你至少需要提供以下内容才能使其正常工作：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...'\n      }\n    }\n  }\n})\n```\n\n### i18n {#algolia-search-i18n}\n\n你可以使用这样的配置来使用多语言搜索：\n\n<details>\n<summary>点击展开</summary>\n\n<<< @/snippets/algolia-i18n.ts\n\n</details>\n\n更多信息请参考[官方 Algolia 文档](https://docsearch.algolia.com/docs/api#translations)。想要快速开始，你也可以从[我们的 GitHub 仓库](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code)复制此站点使用的翻译。\n\n### Algolia Ask AI 支持 {#ask-ai}\n\n如果需要启用 **Ask AI**，只需在 `options` 中添加 `askAi`：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        // askAi: \"你的助手ID\"\n        // 或\n        askAi: {\n          // 至少需要提供从 Algolia 获取的 assistantId\n          assistantId: 'XXXYYY',\n          // 可选覆盖 — 若省略，将复用顶层 appId/apiKey/indexName 的值\n          // apiKey: '...',\n          // appId: '...',\n          // indexName: '...'\n        }\n      }\n    }\n  }\n})\n```\n\n::: warning 提示\n若仅需关键词搜索，可省略 `askAi`。\n:::\n\n### Ask AI 侧边栏 {#ask-ai-side-panel}\n\nDocSearch v4.5+ 支持可选的 **Ask AI 侧边栏**。启用后，默认可通过 **Ctrl/Cmd+I** 打开。完整的选项列表请参阅[侧边栏 API 参考](https://docsearch.algolia.com/docs/sidepanel/api-reference)。\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            // 镜像 @docsearch/sidepanel-js SidepanelProps API\n            panel: {\n              variant: 'floating', // 或 'inline'\n              side: 'right',\n              width: '360px',\n              expandedWidth: '580px',\n              suggestedQuestions: true\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n如果需要禁用键盘快捷键，请使用侧边栏的 `keyboardShortcuts` 选项：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        appId: '...',\n        apiKey: '...',\n        indexName: '...',\n        askAi: {\n          assistantId: 'XXXYYY',\n          sidePanel: {\n            keyboardShortcuts: {\n              'Ctrl/Cmd+I': false\n            }\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### 模式 (auto / sidePanel / hybrid / modal) {#ask-ai-mode}\n\n你可以选择性地控制 VitePress 如何集成关键词搜索和 Ask AI：\n\n- `mode: 'auto'`（默认）：当配置了关键词搜索时推断为 `hybrid`，否则当配置了 Ask AI 侧边栏时推断为 `sidePanel`。\n- `mode: 'sidePanel'`：强制仅使用侧边栏（隐藏关键词搜索按钮）。\n- `mode: 'hybrid'`：启用关键词搜索模态框 + Ask AI 侧边栏（需要关键词搜索配置）。\n- `mode: 'modal'`：将 Ask AI 保留在 DocSearch 模态框内（即使你配置了侧边栏）。\n\n#### 仅 Ask AI（无关键词搜索） {#ask-ai-only}\n\n如果你想**仅使用 Ask AI 侧边栏**，可以省略顶级关键词搜索配置，并在 `askAi` 下提供凭据：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    search: {\n      provider: 'algolia',\n      options: {\n        mode: 'sidePanel',\n        askAi: {\n          assistantId: 'XXXYYY',\n          appId: '...',\n          apiKey: '...',\n          indexName: '...',\n          sidePanel: true\n        }\n      }\n    }\n  }\n})\n```\n\n### 爬虫配置 {#crawler-config}\n\n以下是基于此站点使用的示例配置：\n\n<<< @/snippets/algolia-crawler.js\n"
  },
  {
    "path": "docs/zh/reference/default-theme-sidebar.md",
    "content": "# 侧边栏 {#sidebar}\n\n侧边栏是文档的主要导航块。可以在 [`themeConfig.sidebar`](./default-theme-config#sidebar) 中配置侧边栏菜单。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          { text: 'Introduction', link: '/introduction' },\n          { text: 'Getting Started', link: '/getting-started' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 基本用法 {#the-basics}\n\n侧边栏菜单的最简单形式是传入一个链接数组。第一级项目定义侧边栏的“部分”。它应该包含作为小标题的 `text` 和作为实际导航链接的 `items`。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        items: [\n          { text: 'Item A', link: '/item-a' },\n          { text: 'Item B', link: '/item-b' },\n          ...\n        ]\n      },\n      {\n        text: 'Section Title B',\n        items: [\n          { text: 'Item C', link: '/item-c' },\n          { text: 'Item D', link: '/item-d' },\n          ...\n        ]\n      }\n    ]\n  }\n}\n```\n\n每个 `link` 都应指定以 `/` 开头的实际文件的路径。如果在链接末尾添加斜杠，它将显示相应目录的 `index.md`。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Guide',\n        items: [\n          // 显示的是 `/guide/index.md` 页面\n          { text: 'Introduction', link: '/guide/' }\n        ]\n      }\n    ]\n  }\n}\n```\n\n可以进一步将侧边栏项目嵌入到 6 级深度，从根级别上计数。请注意，深度超过 6 级将被忽略，并且不会在侧边栏上显示。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Level 1',\n        items: [\n          {\n            text: 'Level 2',\n            items: [\n              {\n                text: 'Level 3',\n                items: [\n                  ...\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## 多侧边栏 {#multiple-sidebars}\n\n可能会根据页面路径显示不同的侧边栏。例如，如本站点所示，可能希望在文档中创建单独的侧边栏，例如“指南”页面和“配置参考”页面。\n\n为此，首先将你的页面组织到每个所需部分的目录中：\n\n```\n.\n├─ guide/\n│  ├─ index.md\n│  ├─ one.md\n│  └─ two.md\n└─ config/\n   ├─ index.md\n   ├─ three.md\n   └─ four.md\n```\n\n然后，更新配置以定义每个部分的侧边栏。这一次，应该传递一个对象而不是数组。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: {\n      // 当用户位于 `guide` 目录时，会显示此侧边栏\n      '/guide/': [\n        {\n          text: 'Guide',\n          items: [\n            { text: 'Index', link: '/guide/' },\n            { text: 'One', link: '/guide/one' },\n            { text: 'Two', link: '/guide/two' }\n          ]\n        }\n      ],\n\n      // 当用户位于 `config` 目录时，会显示此侧边栏\n      '/config/': [\n        {\n          text: 'Config',\n          items: [\n            { text: 'Index', link: '/config/' },\n            { text: 'Three', link: '/config/three' },\n            { text: 'Four', link: '/config/four' }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n## 可折叠的侧边栏组 {#collapsible-sidebar-groups}\n\n通过向侧边栏组添加 `collapsed` 选项，它会显示一个切换按钮来隐藏/显示每个部分。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: false,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n\n默认情况下，所有部分都是“打开”的。如果希望它们在初始页面加载时“关闭”，请将 `collapsed` 选项设置为 `true`。\n\n```js\nexport default {\n  themeConfig: {\n    sidebar: [\n      {\n        text: 'Section Title A',\n        collapsed: true,\n        items: [...]\n      }\n    ]\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/reference/default-theme-team-page.md",
    "content": "<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  {\n    avatar: 'https://github.com/kiaking.png',\n    name: 'Kia King Ishii',\n    title: 'Developer',\n    links: [\n      { icon: 'github', link: 'https://github.com/kiaking' },\n      { icon: 'twitter', link: 'https://twitter.com/KiaKing85' }\n    ]\n  }\n]\n</script>\n\n# 团队页 {#team-page}\n\n如果你想介绍你的团队，你可以使用 Team components 来构建团队页面。有两种使用这些组件的方法。一种是将其嵌入文档页面，另一种是创建完整的团队页面。\n\n## 在页面中显示团队成员 {#show-team-members-in-a-page}\n\n你可以在任何页面上使用从 `vitepress/theme` 暴露出的公共组件 `<VPTeamMembers>` 显示团队成员。\n\n```html\n<script setup>\nimport { VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n# Our Team\n\nSay hello to our awesome team.\n\n<VPTeamMembers size=\"small\" :members />\n```\n\n以上将在卡片外观元素中显示团队成员。它应该显示类似于下面的内容。\n\n<VPTeamMembers size=\"small\" :members />\n\n`<VPTeamMembers>` 组件有 2 种不同的尺寸，`small` 和 `medium`。虽然它取决于你的偏好，但通常尺寸在文档页面中使用时 `small` 应该更适合。此外，你可以为每个成员添加更多属性，例如添加“描述”或“赞助”按钮。在 [`<VPTeamMembers>`](#vpteammembers) 中了解更多信息。\n\n在文档页面中嵌入团队成员对于小型团队来说非常有用，某种情况下，完整的贡献团队可能太大了，可以引入部分成员作为文档上下文的参考。\n\n如果你有大量成员，或者只是想有更多空间来展示团队成员，请考虑[创建一个完整的团队页面](#create-a-full-team-page)。\n\n## 创建一个完整的团队页面 {#create-a-full-team-page}\n\n除了将团队成员添加到 doc 页面，你还可以创建一个完整的团队页面，类似于创建自定义[默认主题：主页](./default-theme-home-page)的方式。\n\n要创建团队页面，首先，创建一个新的 md 文件。文件名无所谓，这里我们就叫它 `team.md` 吧。在这个文件中，在 frontmatter 设置 `layout: page`，然后你可以使用 `TeamPage` 组件来组成页面结构。\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers\n} from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/yyx990803.png',\n    name: 'Evan You',\n    title: 'Creator',\n    links: [\n      { icon: 'github', link: 'https://github.com/yyx990803' },\n      { icon: 'twitter', link: 'https://twitter.com/youyuxi' }\n    ]\n  },\n  ...\n]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n  <VPTeamMembers :members />\n</VPTeamPage>\n```\n\n创建完整的团队页面时，请记住用 `<VPTeamPage>` 组件包装所有团队相关组件，以获得正确的布局结构，如间距。\n\n`<VPPageTitle>` 组件添加页面标题部分。标题是 `<h1>` 标题。使用 `#title` 和 `#lead` 插槽来介绍你的团队。\n\n`<VPMembers>` 和在 doc 页面中使用时一样。它将显示成员列表。\n\n### 添加 section 以划分团队成员 {#add-sections-to-divide-team-members}\n\n你可以将“section”添加到团队页面。例如，你可能有不同类型的团队成员，例如核心团队成员和社区合作伙伴。你可以将这些成员分成几个部分，以更好地解释每组的角色。\n\n为此，将 `<VPTeamPageSection>` 组件添加到我们之前创建的 `team.md` 文件中。\n\n```html\n---\nlayout: page\n---\n<script setup>\nimport {\n  VPTeamPage,\n  VPTeamPageTitle,\n  VPTeamMembers,\n  VPTeamPageSection\n} from 'vitepress/theme'\n\nconst coreMembers = [...]\nconst partners = [...]\n</script>\n\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>Our Team</template>\n    <template #lead>...</template>\n  </VPTeamPageTitle>\n  <VPTeamMembers size=\"medium\" :members=\"coreMembers\" />\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>...</template>\n    <template #members>\n      <VPTeamMembers size=\"small\" :members=\"partners\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n\n`<VPTeamPageSection>` 组件可以有类似于 `VPTeamPageTitle` 组件的 `#title` 和 `#lead` 插槽，还有用于显示团队成员的 `#members` 插槽。\n\n请记住将 `<VPTeamMembers>` 组件放入 `#members` 插槽中。\n\n## `<VPTeamMembers>`\n\n`<VPTeamMembers>` 组件显示给定的成员列表。\n\n```html\n<VPTeamMembers\n  size=\"medium\"\n  :members=\"[\n    { avatar: '...', name: '...' },\n    { avatar: '...', name: '...' },\n    ...\n  ]\"\n/>\n```\n\n```ts\ninterface Props {\n  // 每个成员的大小，默认为 `medium`\n  size?: 'small' | 'medium'\n\n  // 显示的成员列表\n  members: TeamMember[]\n}\n\ninterface TeamMember {\n  // 成员的头像图像\n  avatar: string\n\n  // 成员的名称\n  name: string\n\n  // 成员姓名下方的标题\n  // 例如：Developer, Software Engineer, etc.\n  title?: string\n\n  // 成员所属的组织\n  org?: string\n\n  // 组织的 URL\n  orgLink?: string\n\n  // 成员的描述\n  desc?: string\n\n  // 社交媒体链接，例如 GitHub、Twitter 等，可以在此处传入 Social Links 对象\n  // 参见: https://vitepress.dev/reference/default-theme-config.html#sociallinks\n  links?: SocialLink[]\n\n  // 成员 sponsor 页面的 URL\n  sponsor?: string\n\n  // sponsor 链接的文本，默认为 'Sponsor'\n  actionText?: string\n}\n```\n\n## `<VPTeamPage>`\n\n创建完整团队页面时的根组件。它只接受一个插槽。它将设置所有传入的团队相关组件的样式。\n\n## `<VPTeamPageTitle>`\n\n添加页面的标题。最好在一开始就在 `<VPTeamPage>` 下使用。它接受 `#title` 和 `#lead` 插槽。\n\n```html\n<VPTeamPage>\n  <VPTeamPageTitle>\n    <template #title>\n      Our Team\n    </template>\n    <template #lead>\n      The development of VitePress is guided by an international\n      team, some of whom have chosen to be featured below.\n    </template>\n  </VPTeamPageTitle>\n</VPTeamPage>\n```\n\n## `<VPTeamPageSection>`\n\n在团队页面中创建一个“section”。它接受 `#title`、`#lead` 和 `#members` 插槽。你可以在 `<VPTeamPage>` 中添加任意数量的section。\n\n```html\n<VPTeamPage>\n  ...\n  <VPTeamPageSection>\n    <template #title>Partners</template>\n    <template #lead>Lorem ipsum...</template>\n    <template #members>\n      <VPTeamMembers :members=\"data\" />\n    </template>\n  </VPTeamPageSection>\n</VPTeamPage>\n```\n"
  },
  {
    "path": "docs/zh/reference/frontmatter-config.md",
    "content": "---\noutline: deep\n---\n\n# frontmatter 配置 {#frontmatter-config}\n\nfrontmatter 支持基于页面的配置。在每个 markdown 文件中，可以使用 frontmatter 配置来覆盖站点级别或主题级别的配置选项。此外，还有一些配置选项只能在 frontmatter 中定义。\n\n示例用法：\n\n```md\n---\ntitle: Docs with VitePress\neditLink: true\n---\n```\n\n可以通过 Vue 表达式中的 `$frontmatter` 全局变量访问 frontmatter 数据：\n\n```md\n{{ $frontmatter.title }}\n```\n\n## title\n\n- 类型：`string`\n\n页面的标题。它与 [config.title](./site-config#title) 相同，并且覆盖站点级配置。\n\n```yaml\n---\ntitle: VitePress\n---\n```\n\n## titleTemplate\n\n- 类型：`string | boolean`\n\n标题的后缀。它与 [config.titleTemplate](./site-config#titletemplate) 相同，它会覆盖站点级别的配置。\n\n```yaml\n---\ntitle: VitePress\ntitleTemplate: Vite & Vue powered static site generator\n---\n```\n\n## description\n\n- 类型：`string`\n\n页面的描述。它与 [config.description](./site-config#description) 相同，它会覆盖站点级别的配置。\n\n```yaml\n---\ndescription: VitePress\n---\n```\n\n## head\n\n- 类型：`HeadConfig[]`\n\n指定要为当前页面注入的额外 head 标签。将附加在站点级配置注入的头部标签之后。\n\n```yaml\n---\nhead:\n  - - meta\n    - name: description\n      content: hello\n  - - meta\n    - name: keywords\n      content: super duper SEO\n---\n```\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n## 仅默认主题 {#default-theme-only}\n\n以下 frontmatter 选项仅在使用默认主题时适用。\n\n### layout\n\n- 类型：`doc | home | page`\n- 默认值：`doc`\n\n指定页面的布局。\n\n- `doc`——它将默认文档样式应用于 markdown 内容。\n- `home`——“主页”的特殊布局。可以添加额外的选项，例如 `hero` 和 `features`，以快速创建漂亮的落地页。\n- `page`——表现类似于 `doc`，但它不对内容应用任何样式。当想创建一个完全自定义的页面时很有用。\n\n```yaml\n---\nlayout: doc\n---\n```\n\n### hero <Badge type=\"info\" text=\"home page only\" />\n\n当 `layout` 设置为 `home` 时，定义主页 hero 部分的内容。更多详细信息：[默认主题：主页](./default-theme-home-page)。\n\n### features <Badge type=\"info\" text=\"home page only\" />\n\n定义当`layout` 设置为 `home` 时要在 features 部分中显示的项目。更多详细信息：[默认主题：主页](./default-theme-home-page)。\n\n### navbar\n\n- 类型：`boolean`\n- 默认值：`true`\n\n是否显示[导航栏](./default-theme-nav)。\n\n```yaml\n---\nnavbar: false\n---\n```\n\n### sidebar\n\n- 类型：`boolean`\n- 默认值：`true`\n\n是否显示 [侧边栏](./default-theme-sidebar).\n\n```yaml\n---\nsidebar: false\n---\n```\n\n### aside\n\n- 类型：`boolean | 'left'`\n- 默认值：`true`\n\n定义侧边栏组件在 `doc` 布局中的位置。\n\n将此值设置为 `false` 可禁用侧边栏容器。\\\n将此值设置为 `true` 会将侧边栏渲染到右侧。\\\n将此值设置为 `left` 会将侧边栏渲染到左侧。\n\n```yaml\n---\naside: false\n---\n```\n\n### outline\n\n- 类型：`number | [number, number] | 'deep' | false`\n- 默认值：`2`\n\n大纲中显示的标题级别。它与 [config.themeConfig.outline.level](./default-theme-config#outline) 相同，它会覆盖站点级的配置。\n\n### lastUpdated\n\n- 类型：`boolean | Date`\n- 默认值：`true`\n\n是否在当前页面的页脚中显示[最后更新时间](./default-theme-last-updated)的文本。如果指定了日期时间，则会显示该日期时间而不是上次 git 修改的时间戳。\n\n```yaml\n---\nlastUpdated: false\n---\n```\n\n### editLink\n\n- 类型：`boolean`\n- 默认值：`true`\n\n是否在当前页的页脚显示[编辑链接](./default-theme-edit-link)。\n\n```yaml\n---\neditLink: false\n---\n```\n\n### footer\n\n- 类型：`boolean`\n- 默认值：`true`\n\n是否显示[页脚](./default-theme-footer)。\n\n```yaml\n---\nfooter: false\n---\n```\n\n### pageClass\n\n- 类型：`string`\n\n将额外的类名称添加到特定页面。\n\n```yaml\n---\npageClass: custom-page-class\n---\n```\n\n然后可以在 `.vitepress/theme/custom.css` 文件中自定义该特定页面的样式：\n\n```css\n.custom-page-class {\n  /* 特定页面的样式 */\n}\n```\n"
  },
  {
    "path": "docs/zh/reference/runtime-api.md",
    "content": "# 运行时 API {#runtime-api}\n\nVitePress 提供了几个内置的 API 来让你访问应用程序数据。VitePress 还附带了一些可以在全局范围内使用的内置组件。\n\n辅助函数可从 `vitepress` 全局导入，通常用于自定义主题 Vue 组件。但是，它们也可以在 `.md` 页面内使用，因为 markdown 文件被编译成 Vue [单文件组件](https://cn.vuejs.org/guide/scaling-up/sfc.html)。\n\n以 `use*` 开头的方法表示它是一个 [Vue 3 组合式 API](https://cn.vuejs.org/guide/introduction.html#composition-api) 函数，只能在 `setup()` 或 `<script setup>` 中使用。\n\n## `useData` <Badge type=\"info\" text=\"composable\" />\n\n返回特定页面的数据。返回的对象具有以下类型：\n\n```ts\ninterface VitePressData<T = any> {\n  /**\n   * 站点级元数据\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * .vitepress/config.js 中的 themeConfig\n   */\n  theme: Ref<T>\n  /**\n   * 页面级元数据\n   */\n  page: Ref<PageData>\n  /**\n   * 页面 frontmatter\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * 动态路由参数\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  isDark: Ref<boolean>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n}\n\ninterface PageData {\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  relativePath: string\n  filePath: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n```\n\n**示例：**\n\n```vue\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <h1>{{ theme.footer.copyright }}</h1>\n</template>\n```\n\n## `useRoute` <Badge type=\"info\" text=\"composable\" />\n\n返回具有以下类型的当前路由对象：\n\n```ts\ninterface Route {\n  path: string\n  data: PageData\n  component: Component | null\n}\n```\n\n## `useRouter` <Badge type=\"info\" text=\"composable\" />\n\n返回 VitePress 路由实例，以便可以以编程方式导航到另一个页面。\n\n```ts\ninterface Router {\n  /**\n   * 当前路由\n   */\n  route: Route\n  /**\n   * 导航到新的 URL\n   */\n  go: (to?: string) => Promise<void>\n  /**\n   * 在路由更改前调用。返回 `false` 表示取消导航\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * 在页面组件加载前（history 状态更新后）调用。返回 `false` 表示取消导航\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * 在页面组件加载后（页面组件实际更新前）调用\n   */\n  onAfterPageLoad?: (to: string) => Awaitable<void>\n  /**\n   * 在路由更改后调用\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n```\n\n## `withBase` <Badge type=\"info\" text=\"helper\" />\n\n- **Type**: `(path: string) => string`\n\n将配置的 [`base`](./site-config#base) 追加到给定的 URL 路径。另请参阅 [Base URL](../guide/asset-handling#base-url)。\n\n## `<Content />` <Badge type=\"info\" text=\"component\" />\n\n`<Content />` 组件显示渲染的 markdown 内容。在[创建自己的主题时](../guide/custom-theme)很有用。\n\n```vue\n<template>\n  <h1>Custom Layout!</h1>\n  <Content />\n</template>\n```\n\n## `<ClientOnly />` <Badge type=\"info\" text=\"component\" />\n\n`<ClientOnly />` 组件仅在客户端渲染其插槽。\n\n由于 VitePress 应用程序在生成静态构建时是在 Node.js 中服务器渲染的，因此任何 Vue 使用都必须符合通用代码要求。简而言之，确保仅在 beforeMount 或 mounted 钩子中访问 Browser/DOM API。\n\n如果正在使用或演示对 SSR 不友好的组件 (例如，包含自定义指令)，可以将它们包装在 `ClientOnly` 组件中。\n\n```vue-html\n<ClientOnly>\n  <NonSSRFriendlyComponent />\n</ClientOnly>\n```\n\n- 相关文档：[SSR 兼容性](../guide/ssr-compat)\n\n## `$frontmatter` <Badge type=\"info\" text=\"template global\" />\n\n在 Vue 表达式中直接访问当前页面的 [frontmatter](../guide/frontmatter) 数据。\n\n```md\n---\ntitle: Hello\n---\n\n# {{ $frontmatter.title }}\n```\n\n## `$params` <Badge type=\"info\" text=\"template global\" />\n\n在 Vue 表达式中直接访问当前页面的[动态路由参数](../guide/routing#dynamic-routes)。\n\n```md\n- package name: {{ $params.pkg }}\n- version: {{ $params.version }}\n```\n"
  },
  {
    "path": "docs/zh/reference/site-config.md",
    "content": "---\noutline: deep\n---\n\n# 站点配置 {#site-config}\n\n站点配置可以定义站点的全局设置。应用配置选项适用于每个 VitePress 站点，无论它使用什么主题。例如根目录或站点的标题。\n\n## 概览 {#overview}\n\n### 配置解析 {#config-resolution}\n\n配置文件总是从 `<root>/.vitepress/config.[ext]` 解析，其中 `<root>` 是 VitePress [项目根目录](../guide/routing#root-and-source-directory)，`[ext]` 是支持的文件扩展名之一。开箱即用地支持 TypeScript。支持的扩展名包括 `.js`、`.ts`、`.mjs` 和 `.mts`。\n\n建议在配置文件中使用 ES 模块语法。配置文件应该默认导出一个对象：\n\n```ts\nexport default {\n  // 应用级配置选项\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n  ...\n}\n```\n\n::: details 异步的动态配置\n\n如果需要动态生成配置，也可以默认导出一个函数，例如：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default async () => {\n  const posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\n  return defineConfig({\n    // 应用级配置选项\n    lang: 'en-US',\n    title: 'VitePress',\n    description: 'Vite & Vue powered static site generator.',\n\n    // 主题级配置选项\n    themeConfig: {\n      sidebar: [\n        ...posts.map((post) => ({\n          text: post.name,\n          link: `/posts/${post.name}`\n        }))\n      ]\n    }\n  })\n}\n```\n\n也可以在最外层使用 `await`。例如：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nconst posts = await (await fetch('https://my-cms.com/blog-posts')).json()\n\nexport default defineConfig({\n  // 应用级配置选项\n  lang: 'en-US',\n  title: 'VitePress',\n  description: 'Vite & Vue powered static site generator.',\n\n  // 主题级别配置选项\n  themeConfig: {\n    sidebar: [\n      ...posts.map((post) => ({\n        text: post.name,\n        link: `/posts/${post.name}`\n      }))\n    ]\n  }\n})\n```\n\n:::\n\n### 配置智能提示 {#config-intellisense}\n\n使用 `defineConfig` 辅助函数将为配置选项提供 TypeScript 支持的智能提示。假设 IDE 支持它，那么在 JavaScript 和 TypeScript 中都将触发智能提示。\n\n```js\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  // ...\n})\n```\n\n### 主题类型提示 {#typed-theme-config}\n\n默认情况下，`defineConfig` 辅助函数期望默认主题的主题配置数据类型为：\n\n```ts\nimport { defineConfig } from 'vitepress'\n\nexport default defineConfig({\n  themeConfig: {\n    // 类型为 `DefaultTheme.Config`\n  }\n})\n```\n\n如果使用自定义主题并希望对主题配置进行类型检查，则需要改用 `defineConfigWithTheme`，并通过通用参数传递自定义主题的配置类型：\n\n```ts\nimport { defineConfigWithTheme } from 'vitepress'\nimport type { ThemeConfig } from 'your-theme'\n\nexport default defineConfigWithTheme<ThemeConfig>({\n  themeConfig: {\n    // 类型为 `ThemeConfig`\n  }\n})\n```\n\n### Vite、Vue 和 Markdown 配置\n\n- **Vite**\n\n  可以使用 VitePress 配置中的 [vite](#vite) 选项配置底层 Vite 实例。无需创建单独的 Vite 配置文件。\n\n- **Vue**\n\n  VitePress 已经包含 Vite 的官方 Vue 插件 ([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue))，所以我们可以配置 VitePress 中的 [vue](#vue) 选项。\n\n- **Markdown**\n\n  可以使用 VitePress 配置中的 [markdown](#markdown) 选项配置底层的 [Markdown-It](https://github.com/markdown-it/markdown-it) 实例。\n\n## 站点元数据 {#site-metadata}\n\n### title\n\n- 类型：`string`\n- 默认值： `VitePress`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#title) 覆盖\n\n站点的标题。使用默认主题时，这将显示在导航栏中。\n\n它还将用作所有单独页面标题的默认后缀，除非定义了 [`titleTemplate`](#titletemplate)。单个页面的最终标题将是其第一个 `<h1>` 标题的文本内容加上的全局 `title`。例如使用以下配置和页面内容：\n\n```ts\nexport default {\n  title: 'My Awesome Site'\n}\n```\n\n```md\n# Hello\n```\n\n页面标题就是 `Hello | My Awesome Site`.\n\n### titleTemplate\n\n- 类型：`string | boolean`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#titletemplate) 覆盖\n\n允许自定义每个页面的标题后缀或整个标题。例如：\n\n```ts\nexport default {\n  title: 'My Awesome Site',\n  titleTemplate: 'Custom Suffix'\n}\n```\n\n```md\n# Hello\n```\n\n页面标题就是 `Hello | Custom Suffix`.\n\n要完全自定义标题的呈现方式，可以在 `titleTemplate` 中使用 `:title` 标识符：\n\n```ts\nexport default {\n  titleTemplate: ':title - Custom Suffix'\n}\n```\n\n这里的 `:title` 将替换为从页面的第一个 `<h1>` 标题推断出的文本。上一个示例页面的标题将是 `Hello - Custom Suffix`。\n\n该选项可以设置为 `false` 以禁用标题后缀。\n\n### description\n\n- 类型：`string`\n- 默认值： `A VitePress site`\n- 每个页面可以通过 [frontmatter](./frontmatter-config#description) 覆盖\n\n站点的描述。这将呈现为页面 HTML 中的 `<meta>` 标签。\n\n```ts\nexport default {\n  description: 'A VitePress site'\n}\n```\n\n### head\n\n- 类型：`HeadConfig[]`\n- 默认值： `[]`\n- 可以通过 [frontmatter](./frontmatter-config#head) 为每个页面追加\n\n要在页面 HTML 的 `<head>` 标签中呈现的其他元素。用户添加的标签在结束 `head` 标签之前呈现，在 VitePress 标签之后。\n\n```ts\ntype HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n```\n\n#### 示例：添加一个图标 {#example-adding-a-favicon}\n\n```ts\nexport default {\n  head: [['link', { rel: 'icon', href: '/favicon.ico' }]]\n} // 将 favicon.ico 放在公共目录中，如果设置了 base，则使用 /base/favicon.ico\n\n/* 渲染成:\n  <link rel=\"icon\" href=\"/favicon.ico\">\n*/\n```\n\n#### 示例：添加谷歌字体 {#example-adding-google-fonts}\n\n```ts\nexport default {\n  head: [\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.googleapis.com' }\n    ],\n    [\n      'link',\n      { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }\n    ],\n    [\n      'link',\n      { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' }\n    ]\n  ]\n}\n\n/* 渲染成:\n  <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n  <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n  <link href=\"https://fonts.googleapis.com/css2?family=Roboto&display=swap\" rel=\"stylesheet\">\n*/\n```\n\n#### 示例：添加一个 serviceWorker {#example-registering-a-service-worker}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { id: 'register-sw' },\n      `;(() => {\n        if ('serviceWorker' in navigator) {\n          navigator.serviceWorker.register('/sw.js')\n        }\n      })()`\n    ]\n  ]\n}\n\n/* 渲染成:\n  <script id=\"register-sw\">\n    ;(() => {\n      if ('serviceWorker' in navigator) {\n        navigator.serviceWorker.register('/sw.js')\n      }\n    })()\n  </script>\n*/\n```\n\n#### 示例：使用谷歌分析 {#example-using-google-analytics}\n\n```ts\nexport default {\n  head: [\n    [\n      'script',\n      { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' }\n    ],\n    [\n      'script',\n      {},\n      `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'TAG_ID');`\n    ]\n  ]\n}\n\n/* 渲染成:\n  <script async src=\"https://www.googletagmanager.com/gtag/js?id=TAG_ID\"></script>\n  <script>\n    window.dataLayer = window.dataLayer || [];\n    function gtag(){dataLayer.push(arguments);}\n    gtag('js', new Date());\n    gtag('config', 'TAG_ID');\n  </script>\n*/\n```\n\n### lang\n\n- 类型：`string`\n- 默认值： `en-US`\n\n站点的 lang 属性。这将呈现为页面 HTML 中的 `<html lang=\"en-US\">` 标签。\n\n```ts\nexport default {\n  lang: 'en-US'\n}\n```\n\n### base\n\n- 类型：`string`\n- 默认值： `/`\n\n站点将部署到的 base URL。如果计划在子路径例如 GitHub 页面下部署站点，则需要设置此项。如果计划将站点部署到 `https://foo.github.io/bar/`，那么应该将 `base` 设置为 `'/bar/'`。它应该始终以 `/` 开头和结尾。\n\nbase 会自动添加到其他选项中以 `/` 开头的所有 URL 前面，因此只需指定一次。\n\n```ts\nexport default {\n  base: '/base/'\n}\n```\n\n## 路由 {#routing}\n\n### cleanUrls\n\n- 类型：`boolean`\n- 默认值： `false`\n\n当设置为 `true` 时，VitePress 将从 URL 中删除 `.html` 后缀。另请参阅[生成简洁的 URL](../guide/routing#generating-clean-urls)。\n\n::: warning 需要服务器支持\n要启用此功能，可能需要在托管平台上进行额外配置。要使其正常工作，服务器必须能够在**不重定向的情况下**访问 `/foo` 时提供 `/foo.html`。\n:::\n\n### rewrites\n\n- 类型：`Record<string, string>`\n\n自定义目录 &lt;-&gt; URL 映射。详细信息请参阅[路由：路由重写](../guide/routing#route-rewrites)。\n\n```ts\nexport default {\n  rewrites: {\n    'source/:page': 'destination/:page'\n  }\n}\n```\n\n## 构建 {#build}\n\n### srcDir\n\n- 类型：`string`\n- 默认值： `.`\n\n相对于项目根目录的 markdown 文件所在的文件夹。另请参阅[根目录和源目录](../guide/routing#root-and-source-directory)。\n\n```ts\nexport default {\n  srcDir: './src'\n}\n```\n\n### srcExclude\n\n- 类型：`string`\n- 默认值： `undefined`\n\n用于匹配应排除作为源内容输出的 markdown 文件，语法详见 [glob pattern](https://github.com/mrmlnc/fast-glob#pattern-syntax)。\n\n```ts\nexport default {\n  srcExclude: ['**/README.md', '**/TODO.md']\n}\n```\n\n### outDir\n\n- 类型：`string`\n- 默认值： `./.vitepress/dist`\n\n项目的构建输出位置，相对于[项目根目录](../guide/routing#root-and-source-directory)。\n\n```ts\nexport default {\n  outDir: '../public'\n}\n```\n\n### assetsDir\n\n- 类型：`string`\n- 默认值： `assets`\n\n指定放置生成的静态资源的目录。该路径应位于 [`outDir`](#outdir) 内，并相对于它进行解析。\n\n```ts\nexport default {\n  assetsDir: 'static'\n}\n```\n\n### cacheDir\n\n- 类型：`string`\n- 默认值： `./.vitepress/cache`\n\n缓存文件的目录，相对于[项目根目录](../guide/routing#root-and-source-directory)。另请参阅：[cacheDir](https://vitejs.dev/config/shared-options.html#cachedir)。\n\n```ts\nexport default {\n  cacheDir: './.vitepress/.vite'\n}\n```\n\n### ignoreDeadLinks\n\n- 类型：`boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]`\n- 默认值： `false`\n\n当设置为 `true` 时，VitePress 不会因为死链而导致构建失败。\n\n当设置为 `'localhostLinks'` ，出现死链时构建将失败，但不会检查 `localhost` 链接。\n\n```ts\nexport default {\n  ignoreDeadLinks: true\n}\n```\n\n它也可以是一组精确的 url 字符串、正则表达式模式或自定义过滤函数。\n\n```ts\nexport default {\n  ignoreDeadLinks: [\n    // 忽略精确网址 \"/playground\"\n    '/playground',\n    // 忽略所有 localhost 链接\n    /^https?:\\/\\/localhost/,\n    // 忽略所有包含 \"/repl/\" 的链接\n    /\\/repl\\//,\n    // 自定义函数，忽略所有包含 \"ignore \"的链接\n    (url) => {\n      return url.toLowerCase().includes('ignore')\n    }\n  ]\n}\n```\n\n### metaChunk <Badge type=\"warning\" text=\"experimental\" />\n\n- 类型：`boolean`\n- 默认值：`false`\n\n当设置为 `true` 时，将页面元数据提取到单独的 JavaScript 块中，而不是内联在初始 HTML 中。这使每个页面的 HTML 负载更小，并使页面元数据可缓存，从而当站点中有很多页面时可以减少服务器带宽。\n\n### mpa <Badge type=\"warning\" text=\"experimental\" />\n\n- 类型：`boolean`\n- 默认值： `false`\n\n设置为 `true` 时，生产应用程序将在 [MPA 模式](../guide/mpa-mode)下构建。MPA 模式默认提供 零 JavaScript 支持，代价是禁用客户端导航，并且需要明确选择加入才能进行交互。\n\n## 主题 {#theming}\n\n### appearance\n\n- 类型：`boolean | 'dark' | 'force-dark' | import('@vueuse/core').UseDarkOptions`\n- 默认值： `true`\n\n是否启用深色模式 (通过将 `.dark` 类添加到 `<html>` 元素)。\n\n- 如果该选项设置为 `true`，则默认主题将由用户的首选配色方案决定。\n- 如果该选项设置为 `dark`，则默认情况下主题将是深色的，除非用户手动切换它。\n- 如果该选项设置为 `false`，用户将无法切换主题。\n\n此选项注入一个内联脚本，使用 `vitepress-theme-appearance` key 从本地存储恢复用户设置。这确保在呈现页面之前应用 `.dark` 类以避免闪烁。\n\n`appearance.initialValue` 只能是 `'dark' | undefined`。 不支持 Refs 或 getters。\n\n### lastUpdated\n\n- 类型：`boolean`\n- 默认值： `false`\n\n是否使用 Git 获取每个页面的最后更新时间戳。时间戳将包含在每个页面的页面数据中，可通过 [`useData`](./runtime-api#usedata) 访问。\n\n使用默认主题时，启用此选项将显示每个页面的最后更新时间。可以通过 [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) 选项自定义文本。\n\n## 自定义 {#customization}\n\n### markdown\n\n- 类型：`MarkdownOption`\n\n配置 Markdown 解析器选项。VitePress 使用 [Markdown-it](https://github.com/markdown-it/markdown-it) 作为解析器，使用 [Shiki](https://github.com/shikijs/shiki) 来高亮不同语言语法。在此选项中，可以传递各种 Markdown 相关选项以满足你的需要。\n\n```js\nexport default {\n  markdown: {...}\n}\n```\n\n查看[类型声明和 jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) 以获得所有可配置的选项。\n\n### vite\n\n- 类型：`import('vite').UserConfig`\n\n将原始 [Vite 配置](https://vitejs.dev/config/)传递给内部 Vite 开发服务器 / bundler。\n\n```js\nexport default {\n  vite: {\n    // Vite 配置选项\n  }\n}\n```\n\n### vue\n\n- 类型：`import('@vitejs/plugin-vue').Options`\n\n将原始的 [@vitejs/plugin-vue 选项](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue#options)传递给内部插件实例。\n\n```js\nexport default {\n  vue: {\n    // @vitejs/plugin-vue 选项\n  }\n}\n```\n\n## 构建钩子 {#build-hooks}\n\nVitePress 构建钩子允许向站点添加新功能和行为：\n\n- Sitemap\n- Search Indexing\n- PWA\n- Teleport\n\n### buildEnd\n\n- 类型：`(siteConfig: SiteConfig) => Awaitable<void>`\n\n`buildEnd` 是一个构建 CLI 钩子，它将在构建 SSG 完成后但在 VitePress CLI 进程退出之前运行。\n\n```ts\nexport default {\n  async buildEnd(siteConfig) {\n    // ...\n  }\n}\n```\n\n### postRender\n\n- 类型：`(context: SSGContext) => Awaitable<SSGContext | void>`\n\n `postRender` 是一个构建钩子，在 SSG 渲染完成时调用。它将允许在 SSG 期间处理传递的内容。\n\n```ts\nexport default {\n  async postRender(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface SSGContext {\n  content: string\n  teleports?: Record<string, string>\n  [key: string]: any\n}\n```\n\n### transformHead\n\n- 类型：`(context: TransformContext) => Awaitable<HeadConfig[]>`\n\n`transformHead` 是一个构建钩子，用于在生成每个页面之前转换 head。它将允许添加无法静态添加到 VitePress 配置中的 head entries。只需要返回额外的 entries，它们将自动与现有 entries 合并。\n\n::: warning\n不要改变 `context` 中的任何东西。\n:::\n\n```ts\nexport default {\n  async transformHead(context) {\n    // ...\n  }\n}\n```\n\n```ts\ninterface TransformContext {\n  page: string // 例如 index.md (相对于 srcDir)\n  assets: string[] // 所有非 js/css 资源均作为完全解析的公共 URL\n  siteConfig: SiteConfig\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n}\n```\n\n请注意，仅在静态生成站点时才会调用此钩子。在开发期间不会调用它。如果需要在开发期间添加动态 head 条目，可以使用 [`transformPageData`](#transformpagedata) 钩子来替代：\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'meta',\n      {\n        name: 'og:title',\n        content:\n          pageData.frontmatter.layout === 'home'\n            ? `VitePress`\n            : `${pageData.title} | VitePress`\n      }\n    ])\n  }\n}\n```\n\n#### 示例：添加 canonical URL `<link>` {#example-adding-a-canonical-url-link}\n\n```ts\nexport default {\n  transformPageData(pageData) {\n    const canonicalUrl = `https://example.com/${pageData.relativePath}`\n      .replace(/index\\.md$/, '')\n      .replace(/\\.md$/, '.html')\n\n    pageData.frontmatter.head ??= []\n    pageData.frontmatter.head.push([\n      'link',\n      { rel: 'canonical', href: canonicalUrl }\n    ])\n  }\n}\n```\n\n### transformHtml\n\n- 类型：`(code: string, id: string, context: TransformContext) => Awaitable<string | void>`\n\n`transformHtml` 是一个构建钩子，用于在保存到磁盘之前转换每个页面的内容。\n\n::: warning\n不要改变 `context` 中的任何东西。另外，修改 html 内容可能会导致运行时出现激活问题。\n:::\n\n```ts\nexport default {\n  async transformHtml(code, id, context) {\n    // ...\n  }\n}\n```\n\n### transformPageData\n\n- 类型：`(pageData: PageData, context: TransformPageContext) => Awaitable<Partial<PageData> | { [key: string]: any } | void>`\n\n`transformPageData` 是一个钩子，用于转换每个页面的 `pageData`。可以直接改变 `pageData` 或返回将合并到 `PageData` 中的更改值。\n\n::: warning\n不要改变 `context` 中的任何东西。请注意，这可能会影响开发服务器的性能，特别是当在钩子中有一些网络请求或大量计算 (例如生成图像) 时。可以通过判断 `process.env.NODE_ENV === 'production'` 匹配符合条件的情况。\n:::\n\n```ts\nexport default {\n  async transformPageData(pageData, { siteConfig }) {\n    pageData.contributors = await getPageContributors(pageData.relativePath)\n  }\n\n  // 或返回要合并的数据\n  async transformPageData(pageData, { siteConfig }) {\n    return {\n      contributors: await getPageContributors(pageData.relativePath)\n    }\n  }\n}\n```\n\n```ts\ninterface TransformPageContext {\n  siteConfig: SiteConfig\n}\n```\n"
  },
  {
    "path": "netlify.toml",
    "content": "[build.environment]\n  NODE_VERSION = \"24\"\n  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = \"1\"\n\n[build]\n  publish = \"docs/.vitepress/dist\"\n  command = \"pnpm docs:build && pnpm docs:lunaria:build\"\n\n[[headers]]\n  for = \"/assets/*\"\n  [headers.values]\n    cache-control = '''\n    max-age=31536000,\n    immutable'''\n\n[[headers]]\n  for = \"/_translations/*\"\n  [headers.values]\n    x-robots-tag = \"noindex\"\n\n[[redirects]]\n  from = \"https://vitepress.vuejs.org/*\"\n  to = \"https://vitepress.dev/:splat\"\n  force = true\n\n[[redirects]]\n  from = \"/guide/\"\n  to = \"/guide/getting-started\"\n\n[[redirects]]\n  from = \"/llms.md\"\n  status = 301\n  to = \"/llms.txt\"\n\n[[redirects]]\n  from = \"/llms-full.md\"\n  status = 301\n  to = \"/llms-full.txt\"\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vitepress\",\n  \"version\": \"2.0.0-alpha.17\",\n  \"description\": \"Vite & Vue powered static site generator\",\n  \"keywords\": [\n    \"vite\",\n    \"vue\",\n    \"vitepress\"\n  ],\n  \"homepage\": \"https://vitepress.dev/\",\n  \"bugs\": {\n    \"url\": \"https://github.com/vuejs/vitepress/issues\"\n  },\n  \"repository\": \"github:vuejs/vitepress\",\n  \"license\": \"MIT\",\n  \"author\": \"Evan You\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./types/index.d.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./dist/*\": \"./dist/*\",\n    \"./package.json\": \"./package.json\",\n    \"./client\": {\n      \"types\": \"./client.d.ts\",\n      \"default\": \"./dist/client/index.js\"\n    },\n    \"./theme\": {\n      \"types\": \"./theme.d.ts\",\n      \"default\": \"./dist/client/theme-default/index.js\"\n    },\n    \"./theme-without-fonts\": {\n      \"types\": \"./theme-without-fonts.d.ts\",\n      \"default\": \"./dist/client/theme-default/without-fonts.js\"\n    }\n  },\n  \"main\": \"dist/node/index.js\",\n  \"types\": \"types/index.d.ts\",\n  \"bin\": {\n    \"vitepress\": \"bin/vitepress.js\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\",\n    \"types\",\n    \"template\",\n    \"client.d.ts\",\n    \"theme.d.ts\",\n    \"theme-without-fonts.d.ts\",\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"clean\": \"node -e \\\"require('node:fs').rmSync('./dist',{recursive:!0,force:!0,maxRetries:10})\\\"\",\n    \"dev\": \"pnpm clean && pnpm dev:shared && pnpm dev:start\",\n    \"dev:start\": \"pnpm --stream '/^dev:(client|node|watch)$/'\",\n    \"dev:client\": \"tsc --sourcemap -w --preserveWatchOutput -p src/client\",\n    \"dev:node\": \"DEV=true pnpm build:node -w\",\n    \"dev:shared\": \"node scripts/copyShared\",\n    \"dev:watch\": \"node scripts/watchAndCopy\",\n    \"build\": \"pnpm build:prepare && pnpm build:client && pnpm build:node\",\n    \"build:prepare\": \"pnpm clean && node scripts/copyShared\",\n    \"build:client\": \"vue-tsc --noEmit -p src/client && tsc -p src/client && node scripts/copyClient\",\n    \"build:node\": \"tsc -p src/node --noEmit && rollup --config rollup.config.ts --configPlugin esbuild\",\n    \"test\": \"pnpm --aggregate-output --reporter=append-only '/^test:(unit|e2e|init)$/'\",\n    \"test:unit\": \"vitest run -r __tests__/unit\",\n    \"test:unit:watch\": \"vitest -r __tests__/unit\",\n    \"test:e2e\": \"pnpm test:e2e-dev && pnpm test:e2e-build\",\n    \"test:e2e:site:dev\": \"pnpm -F=tests-e2e site:dev\",\n    \"test:e2e:site:build\": \"pnpm -F=tests-e2e site:build\",\n    \"test:e2e:site:preview\": \"pnpm -F=tests-e2e site:preview\",\n    \"test:e2e-dev\": \"pnpm -F=tests-e2e test\",\n    \"test:e2e-dev:watch\": \"pnpm -F=tests-e2e watch\",\n    \"test:e2e-build\": \"VITE_TEST_BUILD=1 pnpm test:e2e-dev\",\n    \"test:e2e-build:watch\": \"VITE_TEST_BUILD=1 pnpm test:e2e-dev:watch\",\n    \"test:init\": \"pnpm -F=tests-init test\",\n    \"test:init:watch\": \"pnpm -F=tests-init watch\",\n    \"docs\": \"pnpm --stream '/^(docs:)?dev$/'\",\n    \"docs:dev\": \"wait-on -d 100 dist/node/cli.js && pnpm -F=docs dev\",\n    \"docs:debug\": \"NODE_OPTIONS='--inspect-brk' pnpm docs:dev\",\n    \"docs:build\": \"pnpm build && pnpm docs:build:only\",\n    \"docs:build:only\": \"pnpm -F=docs build\",\n    \"docs:preview\": \"pnpm -F=docs preview\",\n    \"docs:lunaria:build\": \"pnpm -F=docs lunaria:build\",\n    \"docs:lunaria:open\": \"pnpm -F=docs lunaria:open\",\n    \"format\": \"prettier --experimental-cli --write .\",\n    \"format:fail\": \"prettier --experimental-cli --check .\",\n    \"check\": \"pnpm format:fail && pnpm build && pnpm test\",\n    \"changelog\": \"conventional-changelog -p angular -i CHANGELOG.md -s\",\n    \"release\": \"node scripts/release.js\"\n  },\n  \"simple-git-hooks\": {\n    \"pre-commit\": \"pnpm lint-staged\"\n  },\n  \"lint-staged\": {\n    \"*\": \"prettier --experimental-cli --ignore-unknown --write\"\n  },\n  \"dependencies\": {\n    \"@docsearch/css\": \"^4.6.0\",\n    \"@docsearch/js\": \"^4.6.0\",\n    \"@docsearch/sidepanel-js\": \"^4.6.0\",\n    \"@iconify-json/simple-icons\": \"^1.2.74\",\n    \"@shikijs/core\": \"^4.0.2\",\n    \"@shikijs/transformers\": \"^4.0.2\",\n    \"@shikijs/types\": \"^4.0.2\",\n    \"@types/markdown-it\": \"^14.1.2\",\n    \"@vitejs/plugin-vue\": \"^6.0.5\",\n    \"@vue/devtools-api\": \"^8.1.0\",\n    \"@vue/shared\": \"^3.5.30\",\n    \"@vueuse/core\": \"^14.2.1\",\n    \"@vueuse/integrations\": \"^14.2.1\",\n    \"focus-trap\": \"^8.0.0\",\n    \"mark.js\": \"8.11.1\",\n    \"minisearch\": \"^7.2.0\",\n    \"shiki\": \"^4.0.2\",\n    \"vite\": \"^7.3.1\",\n    \"vue\": \"^3.5.30\"\n  },\n  \"devDependencies\": {\n    \"@clack/prompts\": \"^1.1.0\",\n    \"@iconify/utils\": \"^3.1.0\",\n    \"@mdit-vue/plugin-component\": \"^3.0.2\",\n    \"@mdit-vue/plugin-frontmatter\": \"^3.0.2\",\n    \"@mdit-vue/plugin-headers\": \"^3.0.2\",\n    \"@mdit-vue/plugin-sfc\": \"^3.0.2\",\n    \"@mdit-vue/plugin-title\": \"^3.0.2\",\n    \"@mdit-vue/plugin-toc\": \"^3.0.2\",\n    \"@mdit-vue/shared\": \"^3.0.2\",\n    \"@polka/compression\": \"^1.0.0-next.28\",\n    \"@rollup/plugin-alias\": \"^6.0.0\",\n    \"@rollup/plugin-commonjs\": \"^29.0.2\",\n    \"@rollup/plugin-json\": \"^6.1.0\",\n    \"@rollup/plugin-node-resolve\": \"^16.0.3\",\n    \"@rollup/plugin-replace\": \"^6.0.3\",\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/fs-extra\": \"^11.0.4\",\n    \"@types/lodash.template\": \"^4.5.3\",\n    \"@types/mark.js\": \"^8.11.12\",\n    \"@types/markdown-it-attrs\": \"^4.1.3\",\n    \"@types/markdown-it-container\": \"^4.0.0\",\n    \"@types/markdown-it-emoji\": \"^3.0.1\",\n    \"@types/minimist\": \"^1.2.5\",\n    \"@types/node\": \"^25.5.0\",\n    \"@types/picomatch\": \"^4.0.2\",\n    \"@types/prompts\": \"^2.4.9\",\n    \"chokidar\": \"^5.0.0\",\n    \"conventional-changelog\": \"^7.2.0\",\n    \"conventional-changelog-angular\": \"^8.3.0\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"esbuild\": \"^0.27.4\",\n    \"execa\": \"^9.6.1\",\n    \"fs-extra\": \"^11.3.4\",\n    \"get-port\": \"^7.1.0\",\n    \"gray-matter\": \"^4.0.3\",\n    \"lint-staged\": \"^16.4.0\",\n    \"lodash.template\": \"^4.5.0\",\n    \"lru-cache\": \"^11.2.7\",\n    \"markdown-it\": \"^14.1.1\",\n    \"markdown-it-anchor\": \"^9.2.0\",\n    \"markdown-it-async\": \"^2.2.0\",\n    \"markdown-it-attrs\": \"^4.3.1\",\n    \"markdown-it-cjk-friendly\": \"^2.0.2\",\n    \"markdown-it-container\": \"^4.0.0\",\n    \"markdown-it-emoji\": \"^3.0.0\",\n    \"markdown-it-mathjax3\": \"^4.3.2\",\n    \"minimist\": \"^1.2.8\",\n    \"nanoid\": \"^5.1.7\",\n    \"obug\": \"^2.1.1\",\n    \"ora\": \"^9.3.0\",\n    \"oxc-minify\": \"^0.98.0\",\n    \"p-map\": \"^7.0.4\",\n    \"package-directory\": \"^8.2.0\",\n    \"path-to-regexp\": \"^6.3.0\",\n    \"picocolors\": \"^1.1.1\",\n    \"picomatch\": \"^4.0.3\",\n    \"playwright-chromium\": \"^1.58.2\",\n    \"polka\": \"^1.0.0-next.28\",\n    \"postcss\": \"^8.5.6\",\n    \"postcss-selector-parser\": \"^7.1.1\",\n    \"prettier\": \"^3.8.1\",\n    \"prompts\": \"^2.4.2\",\n    \"punycode\": \"^2.3.1\",\n    \"rollup\": \"^4.59.0\",\n    \"rollup-plugin-dts\": \"6.1.1\",\n    \"rollup-plugin-esbuild\": \"^6.2.1\",\n    \"semver\": \"^7.7.4\",\n    \"simple-git-hooks\": \"^2.13.1\",\n    \"sirv\": \"^3.0.2\",\n    \"sitemap\": \"^9.0.1\",\n    \"tinyglobby\": \"^0.2.15\",\n    \"typescript\": \"^5.9.3\",\n    \"vitest\": \"4.0.0-beta.4\",\n    \"vue-tsc\": \"^3.2.6\",\n    \"wait-on\": \"^9.0.4\"\n  },\n  \"peerDependencies\": {\n    \"markdown-it-mathjax3\": \"^4\",\n    \"oxc-minify\": \"*\",\n    \"postcss\": \"^8\"\n  },\n  \"peerDependenciesMeta\": {\n    \"markdown-it-mathjax3\": {\n      \"optional\": true\n    },\n    \"postcss\": {\n      \"optional\": true\n    },\n    \"oxc-minify\": {\n      \"optional\": true\n    }\n  },\n  \"packageManager\": \"pnpm@10.32.1\"\n}\n"
  },
  {
    "path": "patches/@types__markdown-it-attrs.patch",
    "content": "diff --git a/index.d.ts b/index.d.ts\nindex 41d4a858c6ece5a61a2088733cf8b333b45603d8..2cb19bcd8fc76ae82ebe87af742916e17f49334b 100644\n--- a/index.d.ts\n+++ b/index.d.ts\n@@ -1,3 +1,15 @@\n-import MarkdownIt = require(\"markdown-it\");\n-declare function attrs(md: MarkdownIt): void;\n-export = attrs;\n+import type MarkdownIt from 'markdown-it'\n+\n+export interface MarkdownItAttrsOptions {\n+  /** left delimiter, default is `{`(left curly bracket) */\n+  leftDelimiter?: string\n+  /** right delimiter, default is `}`(right curly bracket) */\n+  rightDelimiter?: string\n+  /** rule of allowed attribute, empty means no limit */\n+  allowedAttributes?: (string | RegExp)[]\n+}\n+\n+export default function attrsPlugin(\n+  md: MarkdownIt,\n+  options?: MarkdownItAttrsOptions\n+): void\n"
  },
  {
    "path": "patches/@types__mdurl@2.0.0.patch",
    "content": "diff --git a/lib/parse.d.mts b/lib/parse.d.mts\nindex 2e0d8f2ea00a06c0971a68d34946e797b7f8152d..f61d4dd05c1b181bc6d2d8683153abcd10fe9ab9 100644\n--- a/lib/parse.d.mts\n+++ b/lib/parse.d.mts\n@@ -1,4 +1,4 @@\n-declare class Url {\n+declare class _Url {\n     protocol: string;\n     slashes: string;\n     auth: string;\n@@ -14,5 +14,7 @@ declare class Url {\n     parseHost(host: string): void;\n }\n \n+type Url = _Url;\n+\n export default function parse(url: string | Url, slashesDenoteHost?: boolean): Url;\n-export type { Url };\n+export { Url };\n"
  },
  {
    "path": "patches/markdown-it-anchor@9.2.0.patch",
    "content": "diff --git a/types/index.d.ts b/types/index.d.ts\nindex 40c25c0be1add8b0fc2c51489c25a423dbc49d2c..807bc1b0e434d660c6a298b1dee1c87935bfac86 100644\n--- a/types/index.d.ts\n+++ b/types/index.d.ts\n@@ -1,10 +1,8 @@\n import MarkdownIt from 'markdown-it';\n-import { default as MarkdownItToken } from 'markdown-it/lib/token.mjs';\n-import { default as MarkdownItState} from 'markdown-it/lib/rules_core/state_core.mjs';\n+import { default as Token } from 'markdown-it/lib/token.mjs';\n+import { default as State } from 'markdown-it/lib/rules_core/state_core.mjs';\n \n declare namespace anchor {\n-  export type Token = MarkdownItToken\n-  export type State = MarkdownItState\n   export type RenderHref = (slug: string, state: State) => string;\n   export type RenderAttrs = (slug: string, state: State) => Record<string, string | number>;\n \n"
  },
  {
    "path": "patches/markdown-it-attrs@4.3.1.patch",
    "content": "diff --git a/patterns.js b/patterns.js\nindex e56a3b785df29e726194f2b30e86bb19a78ef902..e1f6211b92cbb2bbbe2a3c317dd9e5f1f41ab8d1 100644\n--- a/patterns.js\n+++ b/patterns.js\n@@ -28,7 +28,8 @@ module.exports = options => {\n         {\n           shift: 0,\n           block: true,\n-          info: utils.hasDelimiters('end', options)\n+          info: utils.hasDelimiters('end', options),\n+          markup: (str) => !/^[`~]{3,}$/.test(str)\n         }\n       ],\n       transform: (tokens, i) => {\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - docs\n  - __tests__/*\n\nautoInstallPeers: false\n\nonlyBuiltDependencies:\n  - esbuild\n  - playwright-chromium\n  - simple-git-hooks\n\noverrides:\n  ora>string-width: ^5\n  vite: npm:rolldown-vite@latest\n\npatchedDependencies:\n  '@types/markdown-it-attrs': patches/@types__markdown-it-attrs.patch\n  '@types/mdurl@2.0.0': patches/@types__mdurl@2.0.0.patch\n  markdown-it-anchor@9.2.0: patches/markdown-it-anchor@9.2.0.patch\n  markdown-it-attrs@4.3.1: patches/markdown-it-attrs@4.3.1.patch\n\nshellEmulator: true\n"
  },
  {
    "path": "rollup.config.ts",
    "content": "import alias from '@rollup/plugin-alias'\nimport commonjs from '@rollup/plugin-commonjs'\nimport json from '@rollup/plugin-json'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\nimport replace from '@rollup/plugin-replace'\nimport * as fs from 'node:fs/promises'\nimport { builtinModules, createRequire } from 'node:module'\nimport { type RollupOptions, defineConfig } from 'rollup'\nimport dts from 'rollup-plugin-dts'\nimport esbuild from 'rollup-plugin-esbuild'\n\nconst require = createRequire(import.meta.url)\nconst pkg = require('./package.json')\n\nconst DEV = !!process.env.DEV\nconst PROD = !DEV\n\nconst external = [\n  ...Object.keys(pkg.dependencies),\n  ...Object.keys(pkg.peerDependencies),\n  ...builtinModules.flatMap((m) =>\n    m.includes('punycode') ? [] : [m, `node:${m}`]\n  )\n]\n\nconst plugins = [\n  alias({ entries: { 'readable-stream': 'stream' } }),\n  replace({\n    // polyfill broken browser check from bundled deps\n    'navigator.userAgentData': 'undefined',\n    'navigator.userAgent': 'undefined',\n    preventAssignment: true\n  }),\n  commonjs(),\n  nodeResolve({ preferBuiltins: false }),\n  esbuild({ target: 'node20' }),\n  json()\n]\n\nconst esmBuild: RollupOptions = {\n  input: ['src/node/index.ts', 'src/node/cli.ts'],\n  output: {\n    format: 'esm',\n    entryFileNames: `[name].js`,\n    chunkFileNames: 'chunk-[hash].js',\n    dir: 'dist/node',\n    sourcemap: DEV\n  },\n  external,\n  plugins,\n  onwarn(warning, warn) {\n    if (warning.code !== 'EVAL') warn(warning)\n  }\n}\n\nconst typesExternal = [\n  ...external,\n  /\\/vitepress\\/(?!(dist|node_modules|vitepress)\\/).*\\.d\\.ts$/,\n  /^markdown-it(?:\\/|$)/\n]\n\nconst dtsNode = dts({\n  respectExternal: true,\n  tsconfig: 'src/node/tsconfig.json',\n  compilerOptions: { preserveSymlinks: false }\n})\n\nconst nodeTypes: RollupOptions = {\n  input: 'src/node/index.ts',\n  output: {\n    format: 'esm',\n    file: 'dist/node/index.d.ts'\n  },\n  external: typesExternal,\n  plugins: [dtsNode]\n}\n\nconst clientTypes: RollupOptions = {\n  input: 'dist/client-types/index.d.ts',\n  output: {\n    format: 'esm',\n    file: 'dist/client/index.d.ts'\n  },\n  external: typesExternal,\n  plugins: [\n    dts({ respectExternal: true }),\n    {\n      name: 'cleanup',\n      async closeBundle() {\n        if (PROD) {\n          await fs.rm('dist/client-types', { recursive: true })\n        }\n      }\n    }\n  ]\n}\n\nexport default defineConfig([esmBuild, nodeTypes, clientTypes])\n"
  },
  {
    "path": "scripts/copyClient.js",
    "content": "import { copy } from 'fs-extra'\nimport { globSync } from 'tinyglobby'\n\nfunction toDest(file) {\n  return file.replace(/^src\\//, 'dist/')\n}\n\nglobSync(['src/client/**']).forEach((file) => {\n  if (/(\\.ts|tsconfig\\.json)$/.test(file)) return\n  copy(file, toDest(file))\n})\n"
  },
  {
    "path": "scripts/copyShared.js",
    "content": "import { copy } from 'fs-extra'\nimport { globSync } from 'tinyglobby'\n\nglobSync(['src/shared/**/*.ts']).forEach(async (file) => {\n  await Promise.all([\n    copy(file, file.replace(/^src\\/shared\\//, 'src/node/')),\n    copy(file, file.replace(/^src\\/shared\\//, 'src/client/'))\n  ])\n})\n"
  },
  {
    "path": "scripts/release.js",
    "content": "import { readFileSync, writeFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { createRequire } from 'node:module'\nimport c from 'picocolors'\nimport prompts from 'prompts'\nimport { execa } from 'execa'\nimport semver from 'semver'\n\nconst { version: currentVersion } = createRequire(import.meta.url)(\n  '../package.json'\n)\nconst { inc: _inc, valid } = semver\n\nconst versionIncrements = ['patch', 'minor', 'major']\n\nconst tags = ['latest', 'next']\n\nconst dir = fileURLToPath(new URL('.', import.meta.url))\nconst inc = (i) => _inc(currentVersion, i)\nconst run = (bin, args, opts = {}) =>\n  execa(bin, args, { stdio: 'inherit', ...opts })\nconst step = (msg) => console.log(c.cyan(msg))\n\nasync function main() {\n  let targetVersion\n\n  const versions = versionIncrements\n    .map((i) => `${i} (${inc(i)})`)\n    .concat(['custom'])\n\n  const { release } = await prompts({\n    type: 'select',\n    name: 'release',\n    message: 'Select release type',\n    choices: versions\n  })\n\n  if (release === 3) {\n    targetVersion = (\n      await prompts({\n        type: 'text',\n        name: 'version',\n        message: 'Input custom version',\n        initial: currentVersion\n      })\n    ).version\n  } else {\n    targetVersion = versions[release].match(/\\((.*)\\)/)[1]\n  }\n\n  if (!valid(targetVersion)) {\n    throw new Error(`Invalid target version: ${targetVersion}`)\n  }\n\n  const { tag } = await prompts({\n    type: 'select',\n    name: 'tag',\n    message: 'Select tag type',\n    choices: tags\n  })\n\n  const { yes: tagOk } = await prompts({\n    type: 'confirm',\n    name: 'yes',\n    message: `Releasing v${targetVersion} on ${tags[tag]}. Confirm?`\n  })\n\n  if (!tagOk) {\n    return\n  }\n\n  // Update the package version.\n  step('\\nUpdating the package version...')\n  updatePackage(targetVersion)\n\n  // Build the package.\n  step('\\nBuilding the package...')\n  await run('pnpm', ['build'])\n\n  // Generate the changelog.\n  step('\\nGenerating the changelog...')\n  await run('pnpm', ['changelog'])\n  await run('pnpm', ['prettier', '--write', 'CHANGELOG.md'])\n\n  const { yes: changelogOk } = await prompts({\n    type: 'confirm',\n    name: 'yes',\n    message: `Changelog generated. Does it look good?`\n  })\n\n  if (!changelogOk) {\n    return\n  }\n\n  // Commit changes to the Git and create a tag.\n  step('\\nCommitting changes...')\n  await run('git', ['add', 'CHANGELOG.md', 'package.json'])\n  await run('git', ['commit', '-m', `release: v${targetVersion}`])\n  await run('git', ['tag', `v${targetVersion}`])\n\n  // Publish the package.\n  step('\\nPublishing the package...')\n  await run('pnpm', [\n    'publish',\n    '--tag',\n    tags[tag],\n    '--ignore-scripts',\n    '--no-git-checks'\n  ])\n\n  // Push to GitHub.\n  step('\\nPushing to GitHub...')\n  await run('git', ['push', 'origin', `refs/tags/v${targetVersion}`])\n  await run('git', ['push'])\n}\n\nfunction updatePackage(version) {\n  const pkgPath = resolve(resolve(dir, '..'), 'package.json')\n  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n\n  pkg.version = version\n\n  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n')\n}\n\nmain().catch((err) => console.error(err))\n"
  },
  {
    "path": "scripts/watchAndCopy.js",
    "content": "import { watch } from 'chokidar'\nimport { copy, remove } from 'fs-extra'\nimport { normalizePath } from 'vite'\n\nfunction toClientAndNode(method, file) {\n  file = normalizePath(file)\n  if (method === 'copy') {\n    copy(file, file.replace(/^src\\/shared\\//, 'src/node/'))\n    copy(file, file.replace(/^src\\/shared\\//, 'src/client/'))\n  } else if (method === 'remove') {\n    remove(file.replace(/^src\\/shared\\//, 'src/node/'))\n    remove(file.replace(/^src\\/shared\\//, 'src/client/'))\n  }\n}\n\nfunction toDist(file) {\n  return normalizePath(file).replace(/^src\\//, 'dist/')\n}\n\n// copy shared files to the client and node directory whenever they change.\nwatch('src/shared', {\n  ignored: (path, stats) => stats?.isFile() && !path.endsWith('.ts')\n})\n  .on('change', (file) => toClientAndNode('copy', file))\n  .on('add', (file) => toClientAndNode('copy', file))\n  .on('unlink', (file) => toClientAndNode('remove', file))\n\n// copy non ts files, such as an html or css, to the dist directory whenever\n// they change.\nwatch('src/client', {\n  ignored: (path, stats) =>\n    stats?.isFile() && (path.endsWith('.ts') || path.endsWith('tsconfig.json'))\n})\n  .on('change', (file) => copy(file, toDist(file)))\n  .on('add', (file) => copy(file, toDist(file)))\n  .on('unlink', (file) => remove(toDist(file)))\n"
  },
  {
    "path": "src/client/app/components/ClientOnly.ts",
    "content": "import { defineComponent, onMounted, ref } from 'vue'\n\nexport const ClientOnly = defineComponent({\n  setup(_, { slots }) {\n    const show = ref(false)\n\n    onMounted(() => {\n      show.value = true\n    })\n\n    return () => (show.value && slots.default ? slots.default() : null)\n  }\n})\n"
  },
  {
    "path": "src/client/app/components/Content.ts",
    "content": "import { useData, useRoute } from 'vitepress'\nimport { defineComponent, h, watch } from 'vue'\nimport { contentUpdatedCallbacks } from '../utils'\n\nconst runCbs = () => contentUpdatedCallbacks.forEach((fn) => fn())\n\nexport const Content = defineComponent({\n  name: 'VitePressContent',\n  props: {\n    as: { type: [Object, String], default: 'div' }\n  },\n  setup(props) {\n    const route = useRoute()\n    const { frontmatter, site } = useData()\n    watch(frontmatter, runCbs, { deep: true, flush: 'post' })\n    return () =>\n      h(\n        props.as,\n        site.value.contentProps ?? { style: { position: 'relative' } },\n        [\n          route.component\n            ? h(route.component, {\n                onVnodeMounted: runCbs,\n                onVnodeUpdated: runCbs,\n                onVnodeUnmounted: runCbs\n              })\n            : '404 Page Not Found'\n        ]\n      )\n  }\n})\n"
  },
  {
    "path": "src/client/app/composables/codeGroups.ts",
    "content": "import { inBrowser, onContentUpdated } from 'vitepress'\n\nexport function useCodeGroups() {\n  if (import.meta.env.DEV) {\n    onContentUpdated(() => {\n      document.querySelectorAll('.vp-code-group > .blocks').forEach((el) => {\n        Array.from(el.children).forEach((child) => {\n          child.classList.remove('active')\n        })\n        activate(el.children[0])\n      })\n    })\n  }\n\n  if (inBrowser) {\n    window.addEventListener('click', (e) => {\n      const el = e.target as HTMLInputElement\n\n      if (el.matches('.vp-code-group input')) {\n        // input <- .tabs <- .vp-code-group\n        const group = el.parentElement?.parentElement\n        if (!group) return\n\n        const i = Array.from(group.querySelectorAll('input')).indexOf(el)\n        if (i < 0) return\n\n        const blocks = group.querySelector('.blocks')\n        if (!blocks) return\n\n        const current = Array.from(blocks.children).find((child) =>\n          child.classList.contains('active')\n        )\n        if (!current) return\n\n        const next = blocks.children[i]\n        if (!next || current === next) return\n\n        current.classList.remove('active')\n        activate(next)\n\n        const label = group?.querySelector(`label[for=\"${el.id}\"]`)\n        label?.scrollIntoView({ block: 'nearest' })\n      }\n    })\n  }\n}\n\nfunction activate(el: Element): void {\n  el.classList.add('active')\n  window.dispatchEvent(\n    new CustomEvent('vitepress:codeGroupTabActivate', { detail: el })\n  )\n}\n"
  },
  {
    "path": "src/client/app/composables/copyCode.ts",
    "content": "import { inBrowser } from 'vitepress'\nimport { isShell } from '../../shared'\n\nconst ignoredNodes = ['.vp-copy-ignore', '.diff.remove'].join(', ')\n\nexport function useCopyCode() {\n  if (inBrowser) {\n    const timeoutIdMap: WeakMap<HTMLElement, NodeJS.Timeout> = new WeakMap()\n    window.addEventListener('click', (e) => {\n      const el = e.target as HTMLElement\n      if (el.matches('div[class*=\"language-\"] > button.copy')) {\n        const parent = el.parentElement\n        const sibling = el.nextElementSibling?.nextElementSibling // <pre> tag\n        if (!parent || !sibling) {\n          return\n        }\n\n        // Clone the node and remove the ignored nodes\n        const clone = sibling.cloneNode(true) as HTMLElement\n        clone.querySelectorAll(ignoredNodes).forEach((node) => node.remove())\n        // remove extra newlines left after removing ignored nodes (affecting textContent because it is inside `<pre>`)\n        // doesn't affect the newlines already in the code because they are rendered as `\\n<span class=\"line\"></span>`\n        clone.innerHTML = clone.innerHTML.replace(/\\n+/g, '\\n')\n\n        let text = clone.textContent || ''\n\n        // NOTE: Any changes to this the code here may also need to update\n        // `transformerDisableShellSymbolSelect` in `src/node/markdown/plugins/highlight.ts`\n        const lang = /language-(\\w+)/.exec(parent.className)?.[1] || ''\n        if (isShell(lang)) {\n          text = text.replace(/^ *(\\$|>) /gm, '').trim()\n        }\n\n        copyToClipboard(text).then(() => {\n          el.classList.add('copied')\n          clearTimeout(timeoutIdMap.get(el))\n          const timeoutId = setTimeout(() => {\n            el.classList.remove('copied')\n            el.blur()\n            timeoutIdMap.delete(el)\n          }, 2000)\n          timeoutIdMap.set(el, timeoutId)\n        })\n      }\n    })\n  }\n}\n\nasync function copyToClipboard(text: string) {\n  try {\n    await navigator.clipboard.writeText(text)\n  } catch {\n    const element = document.createElement('textarea')\n    const previouslyFocusedElement = document.activeElement\n\n    element.value = text\n\n    // Prevent keyboard from showing on mobile\n    element.setAttribute('readonly', '')\n\n    element.style.contain = 'strict'\n    element.style.position = 'absolute'\n    element.style.left = '-9999px'\n    element.style.fontSize = '12pt' // Prevent zooming on iOS\n\n    const selection = document.getSelection()\n    const originalRange = selection\n      ? selection.rangeCount > 0 && selection.getRangeAt(0)\n      : null\n\n    document.body.appendChild(element)\n    element.select()\n\n    // Explicit selection workaround for iOS\n    element.selectionStart = 0\n    element.selectionEnd = text.length\n\n    document.execCommand('copy')\n    document.body.removeChild(element)\n\n    if (originalRange) {\n      selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy\n      selection!.addRange(originalRange)\n    }\n\n    // Get the focus back on the previously focused element, if any\n    if (previouslyFocusedElement) {\n      ;(previouslyFocusedElement as HTMLElement).focus()\n    }\n  }\n}\n"
  },
  {
    "path": "src/client/app/composables/head.ts",
    "content": "import { watchEffect, type Ref } from 'vue'\nimport {\n  createTitle,\n  mergeHead,\n  type HeadConfig,\n  type SiteData\n} from '../../shared'\nimport type { Route } from '../router'\n\nexport function useUpdateHead(route: Route, siteDataByRouteRef: Ref<SiteData>) {\n  let isFirstUpdate = true\n  let managedHeadElements: (HTMLElement | undefined)[] = []\n\n  const updateHeadTags = (newTags: HeadConfig[]) => {\n    if (import.meta.env.PROD && isFirstUpdate) {\n      // in production, the initial meta tags are already pre-rendered so we\n      // skip the first update.\n      isFirstUpdate = false\n      newTags.forEach((tag) => {\n        const headEl = createHeadElement(tag)\n        for (const el of document.head.children) {\n          if (el.isEqualNode(headEl)) {\n            managedHeadElements.push(el as HTMLElement)\n            return\n          }\n        }\n      })\n      return\n    }\n\n    const newElements: (HTMLElement | undefined)[] =\n      newTags.map(createHeadElement)\n\n    managedHeadElements.forEach((oldEl, oldIndex) => {\n      const matchedIndex = newElements.findIndex((newEl) =>\n        newEl?.isEqualNode(oldEl ?? null)\n      )\n      if (matchedIndex !== -1) {\n        delete newElements[matchedIndex]\n      } else {\n        oldEl?.remove()\n        delete managedHeadElements[oldIndex]\n      }\n    })\n\n    newElements.forEach((el) => el && document.head.appendChild(el))\n    managedHeadElements = [...managedHeadElements, ...newElements].filter(\n      Boolean\n    )\n  }\n\n  watchEffect(() => {\n    const pageData = route.data\n    const siteData = siteDataByRouteRef.value\n    const pageDescription = pageData && pageData.description\n    const frontmatterHead = (pageData && pageData.frontmatter.head) || []\n\n    // update title and description\n    const title = createTitle(siteData, pageData)\n    if (title !== document.title) {\n      document.title = title\n    }\n\n    const description = pageDescription || siteData.description\n    let metaDescriptionElement = document.querySelector(\n      `meta[name=description]`\n    )\n    if (metaDescriptionElement) {\n      if (metaDescriptionElement.getAttribute('content') !== description) {\n        metaDescriptionElement.setAttribute('content', description)\n      }\n    } else {\n      createHeadElement(['meta', { name: 'description', content: description }])\n    }\n\n    updateHeadTags(\n      mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead))\n    )\n  })\n}\n\nfunction createHeadElement([tag, attrs, innerHTML]: HeadConfig) {\n  const el = document.createElement(tag)\n  for (const key in attrs) {\n    el.setAttribute(key, attrs[key])\n  }\n  if (innerHTML) {\n    el.innerHTML = innerHTML\n  }\n  if (tag === 'script' && attrs.async == null) {\n    // async is true by default for dynamically created scripts\n    ;(el as HTMLScriptElement).async = false\n  }\n  return el\n}\n\nfunction isMetaDescription(headConfig: HeadConfig) {\n  return (\n    headConfig[0] === 'meta' &&\n    headConfig[1] &&\n    headConfig[1].name === 'description'\n  )\n}\n\nfunction filterOutHeadDescription(head: HeadConfig[]) {\n  return head.filter((h) => !isMetaDescription(h))\n}\n"
  },
  {
    "path": "src/client/app/composables/preFetch.ts",
    "content": "// Customized pre-fetch for page chunks based on\n// https://github.com/GoogleChromeLabs/quicklink\n\nimport { onMounted, onUnmounted, watch } from 'vue'\nimport { useRoute } from '../router'\nimport { inBrowser, pathToFile } from '../utils'\n\nconst hasFetched = new Set<string>()\nconst createLink = () => document.createElement('link')\n\nconst viaDOM = (url: string) => {\n  const link = createLink()\n  link.rel = `prefetch`\n  link.href = url\n  document.head.appendChild(link)\n}\n\nconst viaXHR = (url: string) => {\n  const req = new XMLHttpRequest()\n  req.open('GET', url, (req.withCredentials = true))\n  req.send()\n}\n\nlet link\nconst doFetch: (url: string) => void =\n  inBrowser &&\n  (link = createLink()) &&\n  link.relList &&\n  link.relList.supports &&\n  link.relList.supports('prefetch')\n    ? viaDOM\n    : viaXHR\n\nexport function usePrefetch() {\n  if (!inBrowser) {\n    return\n  }\n\n  if (!window.IntersectionObserver) {\n    return\n  }\n\n  let conn\n  if (\n    (conn = (navigator as any).connection) &&\n    (conn.saveData || /2g/.test(conn.effectiveType))\n  ) {\n    // Don't prefetch if using 2G or if Save-Data is enabled.\n    return\n  }\n\n  const rIC = window.requestIdleCallback || setTimeout\n  let observer: IntersectionObserver | null = null\n\n  const observeLinks = () => {\n    if (observer) {\n      observer.disconnect()\n    }\n\n    observer = new IntersectionObserver((entries) => {\n      entries.forEach((entry) => {\n        if (entry.isIntersecting) {\n          const link = entry.target as HTMLAnchorElement\n          observer!.unobserve(link)\n          const { pathname } = link\n          if (!hasFetched.has(pathname)) {\n            hasFetched.add(pathname)\n            const pageChunkPath = pathToFile(pathname)\n            if (pageChunkPath) doFetch(pageChunkPath)\n          }\n        }\n      })\n    })\n\n    rIC(() => {\n      document\n        .querySelectorAll<HTMLAnchorElement | SVGAElement>('#app a')\n        .forEach((link) => {\n          const { hostname, pathname } = new URL(\n            link.href instanceof SVGAnimatedString\n              ? link.href.animVal\n              : link.href,\n            link.baseURI\n          )\n          const extMatch = pathname.match(/\\.\\w+$/)\n          if (extMatch && extMatch[0] !== '.html') {\n            return\n          }\n\n          if (\n            // only prefetch same tab navigation, since a new tab will load\n            // the lean js chunk instead.\n            link.target !== '_blank' &&\n            // only prefetch inbound links\n            hostname === location.hostname\n          ) {\n            if (pathname !== location.pathname) {\n              observer!.observe(link)\n            } else {\n              // No need to prefetch chunk for the current page, but also mark\n              // it as already fetched. This is because the initial page uses its\n              // lean chunk, and if we don't mark it, navigation to another page\n              // with a link back to the first page will fetch its full chunk\n              // which isn't needed.\n              hasFetched.add(pathname)\n            }\n          }\n        })\n    })\n  }\n\n  onMounted(observeLinks)\n\n  const route = useRoute()\n  watch(() => route.path, observeLinks)\n\n  onUnmounted(() => {\n    observer && observer.disconnect()\n  })\n}\n"
  },
  {
    "path": "src/client/app/data.ts",
    "content": "import siteData from '@siteData'\nimport { useDark, usePreferredDark } from '@vueuse/core'\nimport {\n  computed,\n  inject,\n  readonly,\n  ref,\n  shallowRef,\n  watch,\n  type InjectionKey,\n  type Ref\n} from 'vue'\nimport {\n  APPEARANCE_KEY,\n  createTitle,\n  inBrowser,\n  resolveSiteDataByRoute,\n  type PageData,\n  type SiteData\n} from '../shared'\nimport type { Route } from './router'\n\nexport const dataSymbol: InjectionKey<VitePressData> = Symbol()\n\nexport interface VitePressData<T = any> {\n  /**\n   * Site-level metadata\n   */\n  site: Ref<SiteData<T>>\n  /**\n   * themeConfig from .vitepress/config.js\n   */\n  theme: Ref<T>\n  /**\n   * Page-level metadata\n   */\n  page: Ref<PageData>\n  /**\n   * page frontmatter data\n   */\n  frontmatter: Ref<PageData['frontmatter']>\n  /**\n   * dynamic route params\n   */\n  params: Ref<PageData['params']>\n  title: Ref<string>\n  description: Ref<string>\n  lang: Ref<string>\n  dir: Ref<string>\n  localeIndex: Ref<string>\n  isDark: Ref<boolean>\n  /**\n   * Current location hash\n   */\n  hash: Ref<string>\n}\n\n// site data is a singleton\nexport const siteDataRef: Ref<SiteData> = shallowRef(\n  readonly(siteData) as SiteData\n)\n\n// per-app data\nexport function initData(route: Route): VitePressData {\n  const site = computed(() =>\n    resolveSiteDataByRoute(siteDataRef.value, route.data.relativePath)\n  )\n\n  const appearance = site.value.appearance // fine with reactivity being lost here, config change triggers a restart\n  const isDark =\n    appearance === 'force-dark'\n      ? ref(true)\n      : appearance === 'force-auto'\n        ? usePreferredDark()\n        : appearance\n          ? useDark({\n              storageKey: APPEARANCE_KEY,\n              initialValue: () => (appearance === 'dark' ? 'dark' : 'auto'),\n              ...(typeof appearance === 'object' ? appearance : {})\n            })\n          : ref(false)\n\n  const hashRef = ref(inBrowser ? location.hash : '')\n\n  if (inBrowser) {\n    window.addEventListener('hashchange', () => {\n      hashRef.value = location.hash\n    })\n  }\n\n  watch(\n    () => route.data,\n    () => {\n      hashRef.value = inBrowser ? location.hash : ''\n    }\n  )\n\n  return {\n    site,\n    theme: computed(() => site.value.themeConfig),\n    page: computed(() => route.data),\n    frontmatter: computed(() => route.data.frontmatter),\n    params: computed(() => route.data.params),\n    lang: computed(() => site.value.lang),\n    dir: computed(() => route.data.frontmatter.dir || site.value.dir),\n    localeIndex: computed(() => site.value.localeIndex || 'root'),\n    title: computed(() => createTitle(site.value, route.data)),\n    description: computed(\n      () => route.data.description || site.value.description\n    ),\n    isDark,\n    hash: computed(() => hashRef.value)\n  }\n}\n\nexport function useData<T = any>(): VitePressData<T> {\n  const data = inject(dataSymbol)\n  if (!data) {\n    throw new Error('vitepress data not properly injected in app')\n  }\n  return data\n}\n"
  },
  {
    "path": "src/client/app/devtools.ts",
    "content": "import { setupDevToolsPlugin } from '@vue/devtools-api'\nimport type { App } from 'vue'\nimport type { VitePressData } from './data'\nimport type { Router } from './router'\n\nconst COMPONENT_STATE_TYPE = 'VitePress'\n\nexport const setupDevtools = (\n  app: App,\n  router: Router,\n  data: VitePressData\n): void => {\n  setupDevToolsPlugin(\n    {\n      // fix recursive reference\n      app: app as any,\n      id: 'org.vuejs.vitepress',\n      label: 'VitePress',\n      packageName: 'vitepress',\n      homepage: 'https://vitepress.dev',\n      componentStateTypes: [COMPONENT_STATE_TYPE]\n    },\n    (api) => {\n      api.on.inspectComponent((payload) => {\n        payload.instanceData.state.push({\n          type: COMPONENT_STATE_TYPE,\n          key: 'route',\n          value: router.route,\n          editable: false\n        })\n\n        payload.instanceData.state.push({\n          type: COMPONENT_STATE_TYPE,\n          key: 'data',\n          value: data,\n          editable: false\n        })\n      })\n    }\n  )\n}\n"
  },
  {
    "path": "src/client/app/index.ts",
    "content": "import RawTheme from '@theme/index'\nimport {\n  createApp as createClientApp,\n  createSSRApp,\n  defineComponent,\n  h,\n  onMounted,\n  watchEffect,\n  type App\n} from 'vue'\nimport { ClientOnly } from './components/ClientOnly'\nimport { Content } from './components/Content'\nimport { useCodeGroups } from './composables/codeGroups'\nimport { useCopyCode } from './composables/copyCode'\nimport { useUpdateHead } from './composables/head'\nimport { usePrefetch } from './composables/preFetch'\nimport { dataSymbol, initData, siteDataRef, useData } from './data'\nimport { RouterSymbol, createRouter, scrollTo, type Router } from './router'\nimport { inBrowser, pathToFile } from './utils'\n\nfunction resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme {\n  if (theme.extends) {\n    const base = resolveThemeExtends(theme.extends)\n    return {\n      ...base,\n      ...theme,\n      async enhanceApp(ctx) {\n        if (base.enhanceApp) await base.enhanceApp(ctx)\n        if (theme.enhanceApp) await theme.enhanceApp(ctx)\n      }\n    }\n  }\n  return theme\n}\n\nconst Theme = resolveThemeExtends(RawTheme)\n\nconst VitePressApp = defineComponent({\n  name: 'VitePressApp',\n  setup() {\n    const { site, lang, dir } = useData()\n\n    // change the language on the HTML element based on the current lang\n    onMounted(() => {\n      watchEffect(() => {\n        document.documentElement.lang = lang.value\n        document.documentElement.dir = dir.value\n      })\n    })\n\n    if (import.meta.env.PROD && site.value.router.prefetchLinks) {\n      // in prod mode, enable intersectionObserver based pre-fetch\n      usePrefetch()\n    }\n\n    // setup global copy code handler\n    useCopyCode()\n    // setup global code groups handler\n    useCodeGroups()\n\n    if (Theme.setup) Theme.setup()\n    return () => h(Theme.Layout!)\n  }\n})\n\nexport async function createApp() {\n  ;(globalThis as any).__VITEPRESS__ = true\n\n  const router = newRouter()\n\n  const app = newApp()\n\n  app.provide(RouterSymbol, router)\n\n  const data = initData(router.route)\n  app.provide(dataSymbol, data)\n\n  // install global components\n  app.component('Content', Content)\n  app.component('ClientOnly', ClientOnly)\n\n  // expose $frontmatter & $params\n  Object.defineProperties(app.config.globalProperties, {\n    $frontmatter: {\n      get() {\n        return data.frontmatter.value\n      }\n    },\n    $params: {\n      get() {\n        return data.page.value.params\n      }\n    }\n  })\n\n  if (Theme.enhanceApp) {\n    await Theme.enhanceApp({\n      app,\n      router,\n      siteData: siteDataRef\n    })\n  }\n\n  // setup devtools in dev mode\n  if (import.meta.env.DEV || __VUE_PROD_DEVTOOLS__) {\n    import('./devtools.js').then(({ setupDevtools }) =>\n      setupDevtools(app, router, data)\n    )\n  }\n\n  return { app, router, data }\n}\n\nfunction newApp(): App {\n  return import.meta.env.PROD\n    ? createSSRApp(VitePressApp)\n    : createClientApp(VitePressApp)\n}\n\nfunction newRouter(): Router {\n  let isInitialPageLoad = inBrowser\n\n  return createRouter((path) => {\n    let pageFilePath = pathToFile(path)\n    let pageModule = null\n\n    if (pageFilePath) {\n      // use lean build if this is the initial page load\n      if (isInitialPageLoad) {\n        pageFilePath = pageFilePath.replace(/\\.js$/, '.lean.js')\n      }\n\n      if (import.meta.env.DEV) {\n        pageModule = import(/*@vite-ignore*/ pageFilePath).catch((e) => {\n          // page load could fail for other reasons, don't swallow\n          console.error(e)\n          // try with/without trailing slash\n          // in prod this is handled in src/client/app/utils.ts#pathToFile\n          const url = new URL(pageFilePath!, 'http://a.com')\n          const path =\n            (url.pathname.endsWith('/index.md')\n              ? url.pathname.slice(0, -9) + '.md'\n              : url.pathname.slice(0, -3) + '/index.md') +\n            url.search +\n            url.hash\n          return import(/*@vite-ignore*/ path)\n        })\n      } else {\n        pageModule = import(/*@vite-ignore*/ pageFilePath)\n      }\n    }\n\n    if (inBrowser) {\n      isInitialPageLoad = false\n    }\n\n    return pageModule\n  }, Theme.NotFound)\n}\n\nif (inBrowser) {\n  createApp().then(({ app, router, data }) => {\n    // wait until page component is fetched before mounting\n    router.go(location.href, { initialLoad: true }).then(() => {\n      // dynamically update head tags\n      useUpdateHead(router.route, data.site)\n      app.mount('#app')\n\n      // scroll to hash on new tab during dev\n      if (import.meta.env.DEV && location.hash) {\n        scrollTo(location.hash)\n      }\n    })\n  })\n}\n"
  },
  {
    "path": "src/client/app/router.ts",
    "content": "import type { Component, InjectionKey } from 'vue'\nimport { inject, markRaw, nextTick, reactive, readonly } from 'vue'\nimport type { Awaitable, PageData, PageDataPayload } from '../shared'\nimport { notFoundPageData, treatAsHtml } from '../shared'\nimport { siteDataRef } from './data'\nimport { getScrollOffset, inBrowser, withBase } from './utils'\n\nexport interface Route {\n  path: string\n  hash: string\n  query: string\n  data: PageData\n  component: Component | null\n}\n\nexport interface Router {\n  /**\n   * Current route.\n   */\n  route: Route\n  /**\n   * Navigate to a new URL.\n   */\n  go: (\n    to: string,\n    options?: {\n      // @internal\n      initialLoad?: boolean\n      // Whether to smoothly scroll to the target position.\n      smoothScroll?: boolean\n      // Whether to replace the current history entry.\n      replace?: boolean\n    }\n  ) => Promise<void>\n  /**\n   * Called before the route changes. Return `false` to cancel the navigation.\n   */\n  onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Called before the page component is loaded (after the history state is\n   * updated). Return `false` to cancel the navigation.\n   */\n  onBeforePageLoad?: (to: string) => Awaitable<void | boolean>\n  /**\n   * Called after the page component is loaded (before the page component is updated).\n   */\n  onAfterPageLoad?: (to: string) => Awaitable<void>\n  /**\n   * Called after the route changes.\n   */\n  onAfterRouteChange?: (to: string) => Awaitable<void>\n}\n\nexport const RouterSymbol: InjectionKey<Router> = Symbol()\n\n// we are just using URL to parse the pathname and hash - the base doesn't\n// matter and is only passed to support same-host hrefs\nconst fakeHost = 'http://a.com'\n\nconst getDefaultRoute = (): Route => ({\n  path: '/',\n  hash: '',\n  query: '',\n  component: null,\n  data: notFoundPageData\n})\n\ninterface PageModule {\n  __pageData: PageData\n  default: Component\n}\n\nexport function createRouter(\n  loadPageModule: (path: string) => Awaitable<PageModule | null>,\n  fallbackComponent?: Component\n): Router {\n  const route = reactive(getDefaultRoute())\n\n  const router: Router = {\n    route,\n    async go(href, options) {\n      const { hash } = new URL(href, fakeHost)\n      const hasTextFragment =\n        inBrowser && document.fragmentDirective && hash.includes(':~:')\n      href = normalizeHref(href)\n      if ((await router.onBeforeRouteChange?.(href)) === false) return\n      if (\n        !inBrowser ||\n        (await changeRoute(href, { ...options, hasTextFragment }))\n      ) {\n        await loadPage(href, { initialLoad: !!options?.initialLoad })\n      }\n      if (hasTextFragment) {\n        // this will create a new history entry, but that's almost unavoidable\n        location.hash = hash\n      }\n      syncRouteQueryAndHash()\n      await router.onAfterRouteChange?.(href)\n    }\n  }\n\n  let latestPendingPath: string | null = null\n\n  async function loadPage(\n    href: string,\n    { scrollPosition = 0, isRetry = false, initialLoad = false } = {}\n  ) {\n    if ((await router.onBeforePageLoad?.(href)) === false) return\n\n    const targetLoc = new URL(href, fakeHost)\n    const pendingPath = (latestPendingPath = targetLoc.pathname)\n\n    try {\n      let page = await loadPageModule(pendingPath)\n      if (!page) throw new Error(`Page not found: ${pendingPath}`)\n\n      if (latestPendingPath === pendingPath) {\n        latestPendingPath = null\n\n        const { default: comp, __pageData } = page\n        if (!comp) throw new Error(`Invalid route component: ${comp}`)\n\n        await router.onAfterPageLoad?.(href)\n\n        route.path = inBrowser ? pendingPath : withBase(pendingPath)\n        route.component = markRaw(comp)\n        route.data = import.meta.env.PROD\n          ? markRaw(__pageData)\n          : (readonly(__pageData) as PageData)\n        syncRouteQueryAndHash(targetLoc)\n\n        if (inBrowser) {\n          nextTick(() => {\n            let actualPathname =\n              siteDataRef.value.base +\n              __pageData.relativePath.replace(/(?:(^|\\/)index)?\\.md$/, '$1')\n\n            if (!siteDataRef.value.cleanUrls && !actualPathname.endsWith('/')) {\n              actualPathname += '.html'\n            }\n\n            if (actualPathname !== targetLoc.pathname) {\n              targetLoc.pathname = actualPathname\n              href = actualPathname + targetLoc.search + targetLoc.hash\n              history.replaceState({}, '', href)\n            }\n\n            if (!initialLoad) scrollTo(targetLoc.hash, false, scrollPosition)\n          })\n        }\n      }\n    } catch (err: any) {\n      if (\n        !/fetch|Page not found/.test(err.message) &&\n        !/^\\/404(\\.html|\\/)?$/.test(href)\n      ) {\n        console.error(err)\n      }\n\n      // retry on fetch fail: the page to hash map may have been invalidated\n      // because a new deploy happened while the page is open. Try to fetch\n      // the updated pageToHash map and fetch again.\n      if (!isRetry) {\n        try {\n          const res = await fetch(siteDataRef.value.base + 'hashmap.json')\n          ;(window as any).__VP_HASH_MAP__ = await res.json()\n          await loadPage(href, { scrollPosition, isRetry: true, initialLoad })\n          return\n        } catch (e) {}\n      }\n\n      if (latestPendingPath === pendingPath) {\n        latestPendingPath = null\n        route.path = inBrowser ? pendingPath : withBase(pendingPath)\n        route.component = fallbackComponent ? markRaw(fallbackComponent) : null\n        const relativePath = inBrowser\n          ? route.path\n              .replace(/(^|\\/)$/, '$1index')\n              .replace(/(\\.html)?$/, '.md')\n              .slice(siteDataRef.value.base.length)\n          : '404.md'\n        route.data = { ...notFoundPageData, relativePath }\n        syncRouteQueryAndHash(targetLoc)\n      }\n    }\n  }\n\n  function syncRouteQueryAndHash(\n    loc: { search: string; hash: string } = inBrowser\n      ? location\n      : { search: '', hash: '' }\n  ) {\n    route.query = loc.search\n    route.hash = decodeURIComponent(loc.hash)\n  }\n\n  if (inBrowser) {\n    if (history.state === null) history.replaceState({}, '')\n    window.addEventListener(\n      'click',\n      (e) => {\n        if (\n          e.defaultPrevented ||\n          !(e.target instanceof Element) ||\n          e.target.closest('button') || // temporary fix for docsearch action buttons\n          e.button !== 0 ||\n          e.ctrlKey ||\n          e.shiftKey ||\n          e.altKey ||\n          e.metaKey\n        ) {\n          return\n        }\n\n        const link = e.target.closest<HTMLAnchorElement | SVGAElement>('a')\n        if (\n          !link ||\n          link.closest('.vp-raw') ||\n          link.hasAttribute('download') ||\n          link.hasAttribute('target')\n        ) {\n          return\n        }\n\n        const linkHref =\n          link.getAttribute('href') ??\n          (link instanceof SVGAElement ? link.getAttribute('xlink:href') : null)\n        if (linkHref == null) return\n\n        const { href, origin, pathname } = new URL(linkHref, link.baseURI)\n        const currentLoc = new URL(location.href) // copy to keep old data\n        // only intercept inbound html links\n        if (origin === currentLoc.origin && treatAsHtml(pathname)) {\n          e.preventDefault()\n          router.go(href, {\n            // use smooth scroll when clicking on header anchor links\n            smoothScroll: link.classList.contains('header-anchor')\n          })\n        }\n      },\n      { capture: true }\n    )\n\n    window.addEventListener('popstate', async (e) => {\n      if (e.state === null) return\n      const href = normalizeHref(location.href)\n      await loadPage(href, { scrollPosition: e.state.scrollPosition || 0 })\n      syncRouteQueryAndHash()\n      await router.onAfterRouteChange?.(href)\n    })\n\n    window.addEventListener('hashchange', (e) => {\n      e.preventDefault()\n      syncRouteQueryAndHash()\n    })\n  }\n\n  handleHMR(route)\n\n  return router\n}\n\nexport function useRouter(): Router {\n  const router = inject(RouterSymbol)\n  if (!router) throw new Error('useRouter() is called without provider.')\n  return router\n}\n\nexport function useRoute(): Route {\n  return useRouter().route\n}\n\nexport function scrollTo(hash: string, smooth = false, scrollPosition = 0) {\n  if (!hash || scrollPosition) {\n    window.scrollTo(0, scrollPosition)\n    return\n  }\n\n  let target: HTMLElement | null = null\n  try {\n    target = document.getElementById(decodeURIComponent(hash).slice(1))\n  } catch (e) {\n    console.warn(e)\n  }\n  if (!target) return\n\n  const targetTop =\n    window.scrollY +\n      target.getBoundingClientRect().top -\n      getScrollOffset() +\n      Number.parseInt(window.getComputedStyle(target).paddingTop, 10) || 0\n\n  const behavior = window.matchMedia('(prefers-reduced-motion)').matches\n    ? 'instant'\n    : // only smooth scroll if distance is smaller than screen height\n      smooth && Math.abs(targetTop - window.scrollY) <= window.innerHeight\n      ? 'smooth'\n      : 'auto'\n\n  const scrollToTarget = () => {\n    window.scrollTo({ left: 0, top: targetTop, behavior })\n\n    // focus the target element for better accessibility\n    target.focus({ preventScroll: true })\n\n    // return if focus worked\n    if (document.activeElement === target) return\n\n    // element has tabindex already, likely not focusable\n    // because of some other reason, bail out\n    if (target.hasAttribute('tabindex')) return\n\n    const restoreTabindex = () => {\n      target.removeAttribute('tabindex')\n      target.removeEventListener('blur', restoreTabindex)\n    }\n\n    // temporarily make the target element focusable\n    target.setAttribute('tabindex', '-1')\n    target.addEventListener('blur', restoreTabindex)\n\n    // try to focus again\n    target.focus({ preventScroll: true })\n\n    // remove tabindex and event listener if focus still not worked\n    if (document.activeElement !== target) restoreTabindex()\n  }\n\n  requestAnimationFrame(scrollToTarget)\n}\n\nfunction handleHMR(route: Route): void {\n  // update route.data on HMR updates of active page\n  if (import.meta.hot) {\n    // hot reload pageData\n    import.meta.hot.on('vitepress:pageData', (payload: PageDataPayload) => {\n      if (shouldHotReload(payload)) route.data = payload.pageData\n    })\n  }\n}\n\nfunction shouldHotReload(payload: PageDataPayload): boolean {\n  const payloadPath = payload.path.replace(/(?:(^|\\/)index)?\\.md$/, '$1')\n  const locationPath = location.pathname\n    .replace(/(?:(^|\\/)index)?\\.html$/, '')\n    .slice(siteDataRef.value.base.length - 1)\n  return payloadPath === locationPath\n}\n\nfunction normalizeHref(href: string): string {\n  const url = new URL(href, fakeHost)\n  url.pathname = url.pathname.replace(/(^|\\/)index(\\.html)?$/, '$1')\n  // ensure correct deep link so page refresh lands on correct files\n  if (siteDataRef.value.cleanUrls) {\n    url.pathname = url.pathname.replace(/\\.html$/, '')\n  } else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) {\n    url.pathname += '.html'\n  }\n  return url.pathname + url.search + url.hash.split(':~:')[0]\n}\n\nasync function changeRoute(\n  href: string,\n  {\n    smoothScroll = false,\n    initialLoad = false,\n    replace = false,\n    hasTextFragment = false\n  } = {}\n): Promise<boolean> {\n  const loc = normalizeHref(location.href)\n  const nextUrl = new URL(href, location.origin)\n  const currentUrl = new URL(loc, location.origin)\n\n  if (href === loc) {\n    if (!initialLoad) {\n      if (!hasTextFragment) scrollTo(nextUrl.hash, smoothScroll)\n      return false\n    }\n  } else {\n    if (replace) {\n      history.replaceState({}, '', href)\n    } else {\n      // save scroll position before changing URL\n      history.replaceState({ scrollPosition: window.scrollY }, '')\n      history.pushState({}, '', href)\n    }\n\n    if (nextUrl.pathname === currentUrl.pathname) {\n      // scroll between hash anchors on the same page, avoid duplicate entries\n      if (nextUrl.hash !== currentUrl.hash) {\n        window.dispatchEvent(\n          new HashChangeEvent('hashchange', {\n            oldURL: currentUrl.href,\n            newURL: nextUrl.href\n          })\n        )\n        if (!hasTextFragment) scrollTo(nextUrl.hash, smoothScroll)\n      }\n\n      return false\n    }\n  }\n\n  return true\n}\n"
  },
  {
    "path": "src/client/app/ssr.ts",
    "content": "// entry for SSR\nimport { renderToString } from 'vue/server-renderer'\nimport type { SSGContext } from '../shared'\nimport { createApp } from './index'\n\nexport async function render(path: string) {\n  const { app, router } = await createApp()\n  await router.go(path)\n  const ctx: SSGContext = { content: '', vpSocialIcons: new Set<string>() }\n  ctx.content = await renderToString(app, ctx)\n  return ctx\n}\n"
  },
  {
    "path": "src/client/app/theme.ts",
    "content": "import type { App, Component, Ref } from 'vue'\nimport type { Awaitable, SiteData } from '../shared'\nimport type { Router } from './router'\n\nexport interface EnhanceAppContext {\n  app: App\n  router: Router\n  siteData: Ref<SiteData>\n}\n\nexport interface Theme {\n  Layout?: Component\n  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>\n  extends?: Theme\n\n  /**\n   * @deprecated can be replaced by wrapping layout component\n   */\n  setup?: () => void\n\n  /**\n   * @deprecated Render not found page by checking `useData().page.value.isNotFound` in Layout instead.\n   */\n  NotFound?: Component\n}\n"
  },
  {
    "path": "src/client/app/utils.ts",
    "content": "import { tryOnUnmounted } from '@vueuse/core'\nimport { h, onMounted, shallowRef, type AsyncComponentLoader } from 'vue'\nimport {\n  EXTERNAL_URL_RE,\n  inBrowser,\n  sanitizeFileName,\n  type Awaitable\n} from '../shared'\nimport { siteDataRef } from './data'\n\nexport { escapeHtml as _escapeHtml, inBrowser } from '../shared'\n\n/**\n * Join two paths by resolving the slash collision.\n */\nexport function joinPath(base: string, path: string) {\n  return `${base}${path}`.replace(/\\/+/g, '/')\n}\n\n/**\n * Append base to internal (non-relative) urls\n */\nexport function withBase(path: string) {\n  return EXTERNAL_URL_RE.test(path) || !path.startsWith('/')\n    ? path\n    : joinPath(siteDataRef.value.base, path)\n}\n\n/**\n * Converts a url path to the corresponding js chunk filename.\n */\nexport function pathToFile(path: string) {\n  let pagePath = path.replace(/\\.html$/, '')\n  pagePath = decodeURIComponent(pagePath)\n  pagePath = pagePath.replace(/\\/$/, '/index') // /foo/ -> /foo/index\n  if (import.meta.env.DEV) {\n    // always force re-fetch content in dev\n    pagePath += `.md?t=${Date.now()}`\n  } else {\n    // in production, each .md file is built into a .md.js file following\n    // the path conversion scheme.\n    // /foo/bar.html -> ./foo_bar.md\n    if (inBrowser) {\n      const base = import.meta.env.BASE_URL\n      pagePath =\n        sanitizeFileName(\n          pagePath.slice(base.length).replace(/\\//g, '_') || 'index'\n        ) + '.md'\n      // client production build needs to account for page hash, which is\n      // injected directly in the page's html\n      let pageHash = __VP_HASH_MAP__[pagePath.toLowerCase()]\n      if (!pageHash) {\n        pagePath = pagePath.endsWith('_index.md')\n          ? pagePath.slice(0, -9) + '.md'\n          : pagePath.slice(0, -3) + '_index.md'\n        pageHash = __VP_HASH_MAP__[pagePath.toLowerCase()]\n      }\n      if (!pageHash) return null\n      pagePath = `${base}${__ASSETS_DIR__}/${pagePath}.${pageHash}.js`\n    } else {\n      // ssr build uses much simpler name mapping\n      pagePath = `./${sanitizeFileName(\n        pagePath.slice(1).replace(/\\//g, '_')\n      )}.md.js`\n    }\n  }\n\n  return pagePath\n}\n\nexport let contentUpdatedCallbacks: (() => any)[] = []\n\n/**\n * Register callback that is called every time the markdown content is updated\n * in the DOM.\n */\nexport function onContentUpdated(fn: () => any) {\n  contentUpdatedCallbacks.push(fn)\n  tryOnUnmounted(() => {\n    contentUpdatedCallbacks = contentUpdatedCallbacks.filter((f) => f !== fn)\n  })\n}\n\nexport function defineClientComponent(\n  loader: AsyncComponentLoader,\n  args?: any[],\n  cb?: () => Awaitable<void>\n) {\n  return {\n    setup() {\n      const comp = shallowRef()\n      onMounted(async () => {\n        let res = await loader()\n        // interop module default\n        if (res && (res.__esModule || res[Symbol.toStringTag] === 'Module')) {\n          res = res.default\n        }\n        comp.value = res\n        await cb?.()\n      })\n      return () => (comp.value ? h(comp.value, ...(args ?? [])) : null)\n    }\n  }\n}\n\nexport function getScrollOffset() {\n  let scrollOffset = siteDataRef.value.scrollOffset\n  let offset = 0\n  let padding = 24\n  if (typeof scrollOffset === 'object' && 'padding' in scrollOffset) {\n    padding = scrollOffset.padding\n    scrollOffset = scrollOffset.selector\n  }\n  if (typeof scrollOffset === 'number') {\n    offset = scrollOffset\n  } else if (typeof scrollOffset === 'string') {\n    offset = tryOffsetSelector(scrollOffset, padding)\n  } else if (Array.isArray(scrollOffset)) {\n    for (const selector of scrollOffset) {\n      const res = tryOffsetSelector(selector, padding)\n      if (res) {\n        offset = res\n        break\n      }\n    }\n  }\n\n  return offset\n}\n\nfunction tryOffsetSelector(selector: string, padding: number): number {\n  const el = document.querySelector(selector)\n  if (!el) return 0\n  const bot = el.getBoundingClientRect().bottom\n  if (bot < 0) return 0\n  return bot + padding\n}\n"
  },
  {
    "path": "src/client/index.ts",
    "content": "// exports in this file are exposed to themes and md files via 'vitepress'\n// so the user can do `import { useRoute, useData } from 'vitepress'`\n\n// generic types\nexport type { VitePressData } from './app/data'\nexport type { Route, Router } from './app/router'\n\n// theme types\nexport type { EnhanceAppContext, Theme } from './app/theme'\n\n// shared types\nexport type { HeadConfig, Header, PageData, SiteData } from '../../types/shared'\n\n// composables\nexport { dataSymbol, useData } from './app/data'\nexport { useRoute, useRouter } from './app/router'\n\n// utilities\nexport {\n  _escapeHtml,\n  defineClientComponent,\n  getScrollOffset,\n  inBrowser,\n  onContentUpdated,\n  withBase\n} from './app/utils'\n\n// components\nexport { Content } from './app/components/Content'\n"
  },
  {
    "path": "src/client/shims.d.ts",
    "content": "declare const __VP_HASH_MAP__: Record<string, string>\ndeclare const __VP_LOCAL_SEARCH__: boolean\ndeclare const __ALGOLIA__: boolean\ndeclare const __CARBON__: boolean\ndeclare const __VUE_PROD_DEVTOOLS__: boolean\ndeclare const __ASSETS_DIR__: string\n\ndeclare module '*.vue' {\n  import type { DefineComponent } from 'vue'\n  const component: DefineComponent\n  export default component\n}\n\ndeclare module '@siteData' {\n  import type { SiteData } from 'vitepress'\n  const data: SiteData\n  export default data\n}\n\ndeclare module '@theme/index' {\n  import type { Theme } from 'vitepress'\n  const theme: Theme\n  export default theme\n}\n\ndeclare module '@localSearchIndex' {\n  const data: Record<string, () => Promise<{ default: string }>>\n  export default data\n}\n\ndeclare module 'mark.js/src/vanilla.js' {\n  import type Mark from 'mark.js'\n  const mark: typeof Mark\n  export default mark\n}\n"
  },
  {
    "path": "src/client/theme-default/Layout.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\nimport VPBackdrop from './components/VPBackdrop.vue'\nimport VPContent from './components/VPContent.vue'\nimport VPFooter from './components/VPFooter.vue'\nimport VPLocalNav from './components/VPLocalNav.vue'\nimport VPNav from './components/VPNav.vue'\nimport VPSidebar from './components/VPSidebar.vue'\nimport VPSkipLink from './components/VPSkipLink.vue'\nimport { useData } from './composables/data'\nimport { layoutInfoInjectionKey, registerWatchers } from './composables/layout'\nimport { useSidebarControl } from './composables/sidebar'\n\nconst {\n  isOpen: isSidebarOpen,\n  open: openSidebar,\n  close: closeSidebar\n} = useSidebarControl()\n\nregisterWatchers({ closeSidebar })\n\nconst { frontmatter } = useData()\n\nconst slots = useSlots()\nconst heroImageSlotExists = computed(() => !!slots['home-hero-image'])\n\nprovide(layoutInfoInjectionKey, { heroImageSlotExists })\n</script>\n\n<template>\n  <div\n    v-if=\"frontmatter.layout !== false\"\n    class=\"Layout\"\n    :class=\"frontmatter.pageClass\"\n  >\n    <slot name=\"layout-top\" />\n    <VPSkipLink />\n    <VPBackdrop class=\"backdrop\" :show=\"isSidebarOpen\" @click=\"closeSidebar\" />\n    <VPNav>\n      <template #nav-bar-title-before><slot name=\"nav-bar-title-before\" /></template>\n      <template #nav-bar-title-after><slot name=\"nav-bar-title-after\" /></template>\n      <template #nav-bar-content-before><slot name=\"nav-bar-content-before\" /></template>\n      <template #nav-bar-content-after><slot name=\"nav-bar-content-after\" /></template>\n      <template #nav-screen-content-before><slot name=\"nav-screen-content-before\" /></template>\n      <template #nav-screen-content-after><slot name=\"nav-screen-content-after\" /></template>\n    </VPNav>\n    <VPLocalNav :open=\"isSidebarOpen\" @open-menu=\"openSidebar\" />\n\n    <VPSidebar :open=\"isSidebarOpen\">\n      <template #sidebar-nav-before><slot name=\"sidebar-nav-before\" /></template>\n      <template #sidebar-nav-after><slot name=\"sidebar-nav-after\" /></template>\n    </VPSidebar>\n\n    <VPContent>\n      <template #page-top><slot name=\"page-top\" /></template>\n      <template #page-bottom><slot name=\"page-bottom\" /></template>\n\n      <template #not-found><slot name=\"not-found\" /></template>\n      <template #home-hero-before><slot name=\"home-hero-before\" /></template>\n      <template #home-hero-info-before><slot name=\"home-hero-info-before\" /></template>\n      <template #home-hero-info><slot name=\"home-hero-info\" /></template>\n      <template #home-hero-info-after><slot name=\"home-hero-info-after\" /></template>\n      <template #home-hero-actions-after><slot name=\"home-hero-actions-after\" /></template>\n      <template #home-hero-actions-before-actions><slot name=\"home-hero-actions-before-actions\" /></template>\n      <template #home-hero-image><slot name=\"home-hero-image\" /></template>\n      <template #home-hero-after><slot name=\"home-hero-after\" /></template>\n      <template #home-features-before><slot name=\"home-features-before\" /></template>\n      <template #home-features-after><slot name=\"home-features-after\" /></template>\n\n      <template #doc-footer-before><slot name=\"doc-footer-before\" /></template>\n      <template #doc-before><slot name=\"doc-before\" /></template>\n      <template #doc-after><slot name=\"doc-after\" /></template>\n      <template #doc-top><slot name=\"doc-top\" /></template>\n      <template #doc-bottom><slot name=\"doc-bottom\" /></template>\n\n      <template #aside-top><slot name=\"aside-top\" /></template>\n      <template #aside-bottom><slot name=\"aside-bottom\" /></template>\n      <template #aside-outline-before><slot name=\"aside-outline-before\" /></template>\n      <template #aside-outline-after><slot name=\"aside-outline-after\" /></template>\n      <template #aside-ads-before><slot name=\"aside-ads-before\" /></template>\n      <template #aside-ads-after><slot name=\"aside-ads-after\" /></template>\n    </VPContent>\n\n    <VPFooter />\n    <slot name=\"layout-bottom\" />\n  </div>\n  <Content v-else />\n</template>\n\n<style scoped>\n.Layout {\n  display: flex;\n  flex-direction: column;\n  min-height: 100vh;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/NotFound.vue",
    "content": "<script setup lang=\"ts\">\nimport { withBase } from 'vitepress'\nimport { useData } from './composables/data'\nimport { useLangs } from './composables/langs'\n\nconst { theme } = useData()\nconst { currentLang } = useLangs()\n</script>\n\n<template>\n  <div class=\"NotFound\">\n    <p class=\"code\">{{ theme.notFound?.code ?? '404' }}</p>\n    <h1 class=\"title\">{{ theme.notFound?.title ?? 'PAGE NOT FOUND' }}</h1>\n    <div class=\"divider\" />\n    <blockquote class=\"quote\">\n      {{\n        theme.notFound?.quote ??\n        \"But if you don't change your direction, and if you keep looking, you may end up where you are heading.\"\n      }}\n    </blockquote>\n\n    <div class=\"action\">\n      <a\n        class=\"link\"\n        :href=\"withBase(theme.notFound?.link ?? currentLang.link)\"\n        :aria-label=\"theme.notFound?.linkLabel ?? 'go to home'\"\n      >\n        {{ theme.notFound?.linkText ?? 'Take me home' }}\n      </a>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.NotFound {\n  padding: 64px 24px 96px;\n  text-align: center;\n}\n\n@media (min-width: 768px) {\n  .NotFound {\n    padding: 96px 32px 168px;\n  }\n}\n\n.code {\n  line-height: 64px;\n  font-size: 64px;\n  font-weight: 600;\n}\n\n.title {\n  padding-top: 12px;\n  letter-spacing: 2px;\n  line-height: 20px;\n  font-size: 20px;\n  font-weight: 700;\n}\n\n.divider {\n  margin: 24px auto 18px;\n  width: 64px;\n  height: 1px;\n  background-color: var(--vp-c-divider);\n}\n\n.quote {\n  margin: 0 auto;\n  max-width: 256px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.action {\n  padding-top: 20px;\n}\n\n.link {\n  display: inline-block;\n  border: 1px solid var(--vp-c-brand-1);\n  border-radius: 16px;\n  padding: 3px 16px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n  transition:\n    border-color 0.25s,\n    color 0.25s;\n}\n\n.link:hover {\n  border-color: var(--vp-c-brand-2);\n  color: var(--vp-c-brand-2);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPAlgoliaSearchBox.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DocSearchInstance, DocSearchProps } from '@docsearch/js'\nimport type { SidepanelInstance, SidepanelProps } from '@docsearch/sidepanel-js'\nimport { inBrowser, useRouter } from 'vitepress'\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { nextTick, onUnmounted, watch } from 'vue'\nimport type { DocSearchAskAi } from '../../../../types/docsearch'\nimport { useData } from '../composables/data'\nimport { resolveMode, validateCredentials } from '../support/docsearch'\n\nimport '../styles/docsearch.css'\n\nconst props = defineProps<{\n  algoliaOptions: DefaultTheme.AlgoliaSearchOptions\n  openRequest?: {\n    target: 'search' | 'askAi' | 'toggleAskAi'\n    nonce: number\n  } | null\n}>()\n\nconst router = useRouter()\nconst { site } = useData()\n\nlet cleanup = () => {}\nlet docsearchInstance: DocSearchInstance | undefined\nlet sidepanelInstance: SidepanelInstance | undefined\nlet openOnReady: 'search' | 'askAi' | null = null\nlet initializeCount = 0\nlet docsearchLoader: Promise<typeof import('@docsearch/js')> | undefined\nlet sidepanelLoader: Promise<typeof import('@docsearch/sidepanel-js')> | undefined\nlet lastFocusedElement: HTMLElement | null = null\nlet skipEventDocsearch = false\nlet skipEventSidepanel = false\n\nwatch(() => props.algoliaOptions, update, { immediate: true })\nonUnmounted(cleanup)\n\nwatch(\n  () => props.openRequest?.nonce,\n  () => {\n    const req = props.openRequest\n    if (!req) return\n    if (req.target === 'search') {\n      if (docsearchInstance?.isReady) {\n        onBeforeOpen('docsearch', () => docsearchInstance?.open())\n      } else {\n        openOnReady = 'search'\n      }\n    } else if (req.target === 'toggleAskAi') {\n      if (sidepanelInstance?.isOpen) {\n        sidepanelInstance.close()\n      } else {\n        onBeforeOpen('sidepanel', () => sidepanelInstance?.open())\n      }\n    } else {\n      // askAi - open sidepanel or fallback to docsearch modal\n      if (sidepanelInstance?.isReady) {\n        onBeforeOpen('sidepanel', () => sidepanelInstance?.open())\n      } else if (sidepanelInstance) {\n        openOnReady = 'askAi'\n      } else if (docsearchInstance?.isReady) {\n        onBeforeOpen('docsearch', () => docsearchInstance?.openAskAi())\n      } else {\n        openOnReady = 'askAi'\n      }\n    }\n  },\n  { immediate: true }\n)\n\nasync function update(options: DefaultTheme.AlgoliaSearchOptions) {\n  if (!inBrowser) return\n  await nextTick()\n\n  const askAi = options.askAi as DocSearchAskAi | undefined\n\n  const { valid, ...credentials } = validateCredentials({\n    appId: options.appId ?? askAi?.appId,\n    apiKey: options.apiKey ?? askAi?.apiKey,\n    indexName: options.indexName ?? askAi?.indexName\n  })\n\n  if (!valid) {\n    console.warn('[vitepress] Algolia search cannot be initialized: missing appId/apiKey/indexName.')\n    return\n  }\n\n  await initialize({ ...options, ...credentials })\n}\n\nasync function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {\n  const currentInitialize = ++initializeCount\n\n  // Always tear down previous instances first (e.g. on locale changes)\n  cleanup()\n\n  const { useSidePanel } = resolveMode(userOptions)\n  const askAi = userOptions.askAi as DocSearchAskAi | undefined\n\n  const { default: docsearch } = await loadDocsearch()\n  if (currentInitialize !== initializeCount) return\n\n  if (useSidePanel && askAi?.sidePanel) {\n    const { default: sidepanel } = await loadSidepanel()\n    if (currentInitialize !== initializeCount) return\n\n    sidepanelInstance = sidepanel({\n      ...(askAi.sidePanel === true ? {} : askAi.sidePanel),\n      container: '#vp-docsearch-sidepanel',\n      indexName: askAi.indexName ?? userOptions.indexName,\n      appId: askAi.appId ?? userOptions.appId,\n      apiKey: askAi.apiKey ?? userOptions.apiKey,\n      assistantId: askAi.assistantId,\n      onOpen: focusInput,\n      onClose: onClose.bind(null, 'sidepanel'),\n      onReady: () => {\n        if (openOnReady === 'askAi') {\n          openOnReady = null\n          onBeforeOpen('sidepanel', () => sidepanelInstance?.open())\n        }\n      },\n      keyboardShortcuts: {\n        'Ctrl/Cmd+I': false\n      }\n    } as SidepanelProps)\n  }\n\n  const options = {\n    ...userOptions,\n    container: '#vp-docsearch',\n    navigator: {\n      navigate(item) {\n        router.go(item.itemUrl)\n      }\n    },\n    transformItems: (items) => items.map((item) => ({ ...item, url: getRelativePath(item.url) })),\n    // When sidepanel is enabled, intercept Ask AI events to open it instead (hybrid mode)\n    ...(useSidePanel && sidepanelInstance && {\n      interceptAskAiEvent: (initialMessage) => {\n        onBeforeOpen('sidepanel', () => sidepanelInstance?.open(initialMessage))\n        return true\n      }\n    }),\n    onOpen: focusInput,\n    onClose: onClose.bind(null, 'docsearch'),\n    onReady: () => {\n      if (openOnReady === 'search') {\n        openOnReady = null\n        onBeforeOpen('docsearch', () => docsearchInstance?.open())\n      } else if (openOnReady === 'askAi' && !sidepanelInstance) {\n        // No sidepanel configured, use docsearch modal for askAi\n        openOnReady = null\n        onBeforeOpen('docsearch', () => docsearchInstance?.openAskAi())\n      }\n    },\n    keyboardShortcuts: {\n      '/': false,\n      'Ctrl/Cmd+K': false\n    }\n  } as DocSearchProps\n\n  docsearchInstance = docsearch(options)\n\n  cleanup = () => {\n    docsearchInstance?.destroy()\n    sidepanelInstance?.destroy()\n    docsearchInstance = undefined\n    sidepanelInstance = undefined\n    openOnReady = null\n    lastFocusedElement = null\n  }\n}\n\nfunction focusInput() {\n  requestAnimationFrame(() => {\n    const input =\n      document.querySelector<HTMLInputElement>('#docsearch-input') ||\n      document.querySelector<HTMLInputElement>('#docsearch-sidepanel textarea')\n    input?.focus()\n  })\n}\n\nfunction onBeforeOpen(target: 'docsearch' | 'sidepanel', cb: () => void) {\n  if (target === 'docsearch') {\n    if (sidepanelInstance?.isOpen) {\n      skipEventSidepanel = true\n      sidepanelInstance.close()\n    } else if (!docsearchInstance?.isOpen) {\n      if (document.activeElement instanceof HTMLElement) {\n        lastFocusedElement = document.activeElement\n      }\n    }\n  } else if (target === 'sidepanel') {\n    if (docsearchInstance?.isOpen) {\n      skipEventDocsearch = true\n      docsearchInstance.close()\n    } else if (!sidepanelInstance?.isOpen) {\n      if (document.activeElement instanceof HTMLElement) {\n        lastFocusedElement = document.activeElement\n      }\n    }\n  }\n  setTimeout(cb, 0)\n}\n\nfunction onClose(target: 'docsearch' | 'sidepanel') {\n  if (target === 'docsearch') {\n    if (skipEventDocsearch) {\n      skipEventDocsearch = false\n      return\n    }\n  } else if (target === 'sidepanel') {\n    if (skipEventSidepanel) {\n      skipEventSidepanel = false\n      return\n    }\n  }\n  if (lastFocusedElement) {\n    lastFocusedElement.focus()\n    lastFocusedElement = null\n  }\n}\n\nfunction loadDocsearch() {\n  if (!docsearchLoader) {\n    docsearchLoader = import('@docsearch/js')\n  }\n  return docsearchLoader\n}\n\nfunction loadSidepanel() {\n  if (!sidepanelLoader) {\n    sidepanelLoader = import('@docsearch/sidepanel-js')\n  }\n  return sidepanelLoader\n}\n\nfunction getRelativePath(url: string) {\n  const { pathname, hash } = new URL(url, location.origin)\n  return pathname.replace(/\\.html$/, site.value.cleanUrls ? '' : '.html') + hash\n}\n</script>\n\n<template>\n  <div id=\"vp-docsearch\" />\n  <div id=\"vp-docsearch-sidepanel\" />\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPBackdrop.vue",
    "content": "<script lang=\"ts\" setup>\ndefineProps<{\n  show: boolean\n}>()\n</script>\n\n<template>\n  <transition name=\"fade\">\n    <div v-if=\"show\" class=\"VPBackdrop\" />\n  </transition>\n</template>\n\n<style scoped>\n.VPBackdrop {\n  position: fixed;\n  top: 0;\n  /*rtl:ignore*/\n  right: 0;\n  bottom: 0;\n  /*rtl:ignore*/\n  left: 0;\n  z-index: var(--vp-z-index-backdrop);\n  background: var(--vp-backdrop-bg-color);\n  transition: opacity 0.5s;\n}\n\n.VPBackdrop.fade-enter-from,\n.VPBackdrop.fade-leave-to {\n  opacity: 0;\n}\n\n.VPBackdrop.fade-leave-active {\n  transition-duration: .25s;\n}\n\n@media (min-width: 1280px) {\n  .VPBackdrop {\n    display: none;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPBadge.vue",
    "content": "<script setup lang=\"ts\">\ninterface Props {\n  text?: string\n  type?: 'info' | 'tip' | 'warning' | 'danger'\n}\nwithDefaults(defineProps<Props>(), {\n  type: 'tip'\n})\n</script>\n\n<template>\n  <span class=\"VPBadge\" :class=\"type\">\n    <slot>{{ text }}</slot>\n  </span>\n</template>\n\n<style>\n.VPBadge {\n  display: inline-block;\n  margin-left: 2px;\n  border: 1px solid transparent;\n  border-radius: 12px;\n  padding: 0 10px;\n  line-height: 22px;\n  font-size: 12px;\n  font-weight: 500;\n  white-space: nowrap;\n  transform: translateY(-2px);\n}\n\n.VPBadge.small {\n  padding: 0 6px;\n  line-height: 18px;\n  font-size: 10px;\n  transform: translateY(-8px);\n}\n\n.VPDocFooter .VPBadge {\n  display: none;\n}\n\n.vp-doc h1 > .VPBadge,\n.vp-doc h2 > .VPBadge {\n  margin: 0 0 0 2px;\n  vertical-align: middle;\n}\n\n.vp-doc h2 > .VPBadge {\n  padding: 0 8px;\n}\n\n.vp-doc h3 > .VPBadge {\n  vertical-align: middle;\n}\n\n.vp-doc h4 > .VPBadge,\n.vp-doc h5 > .VPBadge,\n.vp-doc h6 > .VPBadge {\n  vertical-align: middle;\n  line-height: 18px;\n}\n\n.VPBadge.info {\n  border-color: var(--vp-badge-info-border);\n  color: var(--vp-badge-info-text);\n  background-color: var(--vp-badge-info-bg);\n}\n\n.VPBadge.tip {\n  border-color: var(--vp-badge-tip-border);\n  color: var(--vp-badge-tip-text);\n  background-color: var(--vp-badge-tip-bg);\n}\n\n.VPBadge.warning {\n  border-color: var(--vp-badge-warning-border);\n  color: var(--vp-badge-warning-text);\n  background-color: var(--vp-badge-warning-bg);\n}\n\n.VPBadge.danger {\n  border-color: var(--vp-badge-danger-border);\n  color: var(--vp-badge-danger-text);\n  background-color: var(--vp-badge-danger-bg);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPButton.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { normalizeLink } from '../support/utils'\nimport { EXTERNAL_URL_RE } from '../../shared'\n\ninterface Props {\n  tag?: string\n  size?: 'medium' | 'big'\n  theme?: 'brand' | 'alt' | 'sponsor'\n  text?: string\n  href?: string\n  target?: string;\n  rel?: string;\n}\nconst props = withDefaults(defineProps<Props>(), {\n  size: 'medium',\n  theme: 'brand'\n})\n\nconst isExternal = computed(\n  () => props.href && EXTERNAL_URL_RE.test(props.href)\n)\n\nconst component = computed(() => {\n  return props.tag || (props.href ? 'a' : 'button')\n})\n</script>\n\n<template>\n  <component\n    :is=\"component\"\n    class=\"VPButton\"\n    :class=\"[size, theme]\"\n    :href=\"href ? normalizeLink(href) : undefined\"\n    :target=\"props.target ?? (isExternal ? '_blank' : undefined)\"\n    :rel=\"props.rel ?? (isExternal ? 'noreferrer' : undefined)\"\n  >\n    <slot>{{ text }}</slot>\n  </component>\n</template>\n\n<style scoped>\n.VPButton {\n  display: inline-block;\n  border: 1px solid transparent;\n  text-align: center;\n  font-weight: 600;\n  white-space: nowrap;\n  transition: color 0.25s, border-color 0.25s, background-color 0.25s;\n}\n\n.VPButton:active {\n  transition: color 0.1s, border-color 0.1s, background-color 0.1s;\n}\n\n.VPButton.medium {\n  border-radius: 20px;\n  padding: 0 20px;\n  line-height: 38px;\n  font-size: 14px;\n}\n\n.VPButton.big {\n  border-radius: 24px;\n  padding: 0 24px;\n  line-height: 46px;\n  font-size: 16px;\n}\n\n.VPButton.brand {\n  border-color: var(--vp-button-brand-border);\n  color: var(--vp-button-brand-text);\n  background-color: var(--vp-button-brand-bg);\n}\n\n.VPButton.brand:hover {\n  border-color: var(--vp-button-brand-hover-border);\n  color: var(--vp-button-brand-hover-text);\n  background-color: var(--vp-button-brand-hover-bg);\n}\n\n.VPButton.brand:active {\n  border-color: var(--vp-button-brand-active-border);\n  color: var(--vp-button-brand-active-text);\n  background-color: var(--vp-button-brand-active-bg);\n}\n\n.VPButton.alt {\n  border-color: var(--vp-button-alt-border);\n  color: var(--vp-button-alt-text);\n  background-color: var(--vp-button-alt-bg);\n}\n\n.VPButton.alt:hover {\n  border-color: var(--vp-button-alt-hover-border);\n  color: var(--vp-button-alt-hover-text);\n  background-color: var(--vp-button-alt-hover-bg);\n}\n\n.VPButton.alt:active {\n  border-color: var(--vp-button-alt-active-border);\n  color: var(--vp-button-alt-active-text);\n  background-color: var(--vp-button-alt-active-bg);\n}\n\n.VPButton.sponsor {\n  border-color: var(--vp-button-sponsor-border);\n  color: var(--vp-button-sponsor-text);\n  background-color: var(--vp-button-sponsor-bg);\n}\n\n.VPButton.sponsor:hover {\n  border-color: var(--vp-button-sponsor-hover-border);\n  color: var(--vp-button-sponsor-hover-text);\n  background-color: var(--vp-button-sponsor-hover-bg);\n}\n\n.VPButton.sponsor:active {\n  border-color: var(--vp-button-sponsor-active-border);\n  color: var(--vp-button-sponsor-active-text);\n  background-color: var(--vp-button-sponsor-active-bg);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPCarbonAds.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { ref, watch, onMounted } from 'vue'\nimport { useAside } from '../composables/aside'\nimport { useData } from '../composables/data'\n\nconst { page } = useData()\nconst props = defineProps<{\n  carbonAds: DefaultTheme.CarbonAdsOptions\n}>()\n\nconst carbonOptions = props.carbonAds\n\nconst { isAsideEnabled } = useAside()\nconst container = ref()\n\nlet isInitialized = false\n\nfunction init() {\n  if (!isInitialized) {\n    isInitialized = true\n    const s = document.createElement('script')\n    s.id = '_carbonads_js'\n    s.src = `//cdn.carbonads.com/carbon.js?serve=${carbonOptions.code}&placement=${carbonOptions.placement}`\n    s.async = true\n    container.value.appendChild(s)\n  }\n}\n\nwatch(() => page.value.relativePath, () => {\n  if (isInitialized && isAsideEnabled.value) {\n    ;(window as any)._carbonads?.refresh()\n  }\n})\n\n// no need to account for option changes during dev, we can just\n// refresh the page\nif (carbonOptions) {\n  onMounted(() => {\n    // if the page is loaded when aside is active, load carbon directly.\n    // otherwise, only load it if the page resizes to wide enough. this avoids\n    // loading carbon at all on mobile where it's never shown\n    if (isAsideEnabled.value) {\n      init()\n    } else {\n      watch(isAsideEnabled, (wide) => wide && init())\n    }\n  })\n}\n</script>\n\n<template>\n  <div class=\"VPCarbonAds\" ref=\"container\" />\n</template>\n\n<style scoped>\n.VPCarbonAds {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  padding: 24px;\n  border-radius: 12px;\n  min-height: 256px;\n  text-align: center;\n  line-height: 18px;\n  font-size: 12px;\n  font-weight: 500;\n  background-color: var(--vp-carbon-ads-bg-color);\n}\n\n.VPCarbonAds :deep(img) {\n  margin: 0 auto;\n  border-radius: 6px;\n}\n\n.VPCarbonAds :deep(.carbon-text) {\n  display: block;\n  margin: 0 auto;\n  padding-top: 12px;\n  color: var(--vp-carbon-ads-text-color);\n  transition: color 0.25s;\n}\n\n.VPCarbonAds :deep(.carbon-text:hover) {\n  color: var(--vp-carbon-ads-hover-text-color);\n}\n\n.VPCarbonAds :deep(.carbon-poweredby) {\n  display: block;\n  padding-top: 6px;\n  font-size: 11px;\n  font-weight: 500;\n  color: var(--vp-carbon-ads-poweredby-color);\n  text-transform: uppercase;\n  transition: color 0.25s;\n}\n\n.VPCarbonAds :deep(.carbon-poweredby:hover) {\n  color: var(--vp-carbon-ads-hover-poweredby-color);\n}\n\n.VPCarbonAds :deep(> div) {\n  display: none;\n}\n\n.VPCarbonAds :deep(> div:first-of-type) {\n  display: block;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPContent.vue",
    "content": "<script setup lang=\"ts\">\nimport NotFound from '../NotFound.vue'\nimport { useData } from '../composables/data'\nimport { useLayout } from '../composables/layout'\nimport VPDoc from './VPDoc.vue'\nimport VPHome from './VPHome.vue'\nimport VPPage from './VPPage.vue'\n\nconst { page, frontmatter } = useData()\nconst { isHome, hasSidebar } = useLayout()\n</script>\n\n<template>\n  <div\n    class=\"VPContent\"\n    id=\"VPContent\"\n    :class=\"{ 'has-sidebar': hasSidebar, 'is-home': isHome }\"\n  >\n    <slot name=\"not-found\" v-if=\"page.isNotFound\"><NotFound /></slot>\n\n    <VPPage v-else-if=\"frontmatter.layout === 'page'\">\n      <template #page-top><slot name=\"page-top\" /></template>\n      <template #page-bottom><slot name=\"page-bottom\" /></template>\n    </VPPage>\n\n    <VPHome v-else-if=\"frontmatter.layout === 'home'\">\n      <template #home-hero-before><slot name=\"home-hero-before\" /></template>\n      <template #home-hero-info-before><slot name=\"home-hero-info-before\" /></template>\n      <template #home-hero-info><slot name=\"home-hero-info\" /></template>\n      <template #home-hero-info-after><slot name=\"home-hero-info-after\" /></template>\n      <template #home-hero-actions-after><slot name=\"home-hero-actions-after\" /></template>\n      <template #home-hero-actions-before-actions><slot name=\"home-hero-actions-before-actions\" /></template>\n      <template #home-hero-image><slot name=\"home-hero-image\" /></template>\n      <template #home-hero-after><slot name=\"home-hero-after\" /></template>\n      <template #home-features-before><slot name=\"home-features-before\" /></template>\n      <template #home-features-after><slot name=\"home-features-after\" /></template>\n    </VPHome>\n\n    <component\n      v-else-if=\"frontmatter.layout && frontmatter.layout !== 'doc'\"\n      :is=\"frontmatter.layout\"\n    />\n\n    <VPDoc v-else>\n      <template #doc-top><slot name=\"doc-top\" /></template>\n      <template #doc-bottom><slot name=\"doc-bottom\" /></template>\n\n      <template #doc-footer-before><slot name=\"doc-footer-before\" /></template>\n      <template #doc-before><slot name=\"doc-before\" /></template>\n      <template #doc-after><slot name=\"doc-after\" /></template>\n\n      <template #aside-top><slot name=\"aside-top\" /></template>\n      <template #aside-outline-before><slot name=\"aside-outline-before\" /></template>\n      <template #aside-outline-after><slot name=\"aside-outline-after\" /></template>\n      <template #aside-ads-before><slot name=\"aside-ads-before\" /></template>\n      <template #aside-ads-after><slot name=\"aside-ads-after\" /></template>\n      <template #aside-bottom><slot name=\"aside-bottom\" /></template>\n    </VPDoc>\n  </div>\n</template>\n\n<style scoped>\n.VPContent {\n  flex-grow: 1;\n  flex-shrink: 0;\n  margin: var(--vp-layout-top-height, 0px) auto 0;\n  width: 100%;\n}\n\n.VPContent.is-home {\n  width: 100%;\n  max-width: 100%;\n}\n\n.VPContent.has-sidebar {\n  margin: 0;\n}\n\n@media (min-width: 960px) {\n  .VPContent {\n    padding-top: var(--vp-nav-height);\n  }\n\n  .VPContent.has-sidebar {\n    margin: var(--vp-layout-top-height, 0px) 0 0;\n    padding-left: var(--vp-sidebar-width);\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPContent.has-sidebar {\n    padding-right: calc((100% - var(--vp-layout-max-width)) / 2);\n    padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDoc.vue",
    "content": "<script setup lang=\"ts\">\nimport { useRoute } from 'vitepress'\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { useLayout } from '../composables/layout'\nimport VPDocAside from './VPDocAside.vue'\nimport VPDocFooter from './VPDocFooter.vue'\n\nconst { theme } = useData()\n\nconst route = useRoute()\nconst { hasSidebar, hasAside, leftAside } = useLayout()\n\nconst pageName = computed(() =>\n  route.path.replace(/[./]+/g, '_').replace(/_html$/, '')\n)\n</script>\n\n<template>\n  <div\n    class=\"VPDoc\"\n    :class=\"{ 'has-sidebar': hasSidebar, 'has-aside': hasAside }\"\n  >\n    <slot name=\"doc-top\" />\n    <div class=\"container\">\n      <div v-if=\"hasAside\" class=\"aside\" :class=\"{'left-aside': leftAside}\">\n        <div class=\"aside-curtain\" />\n        <div class=\"aside-container\">\n          <div class=\"aside-content\">\n            <VPDocAside>\n              <template #aside-top><slot name=\"aside-top\" /></template>\n              <template #aside-bottom><slot name=\"aside-bottom\" /></template>\n              <template #aside-outline-before><slot name=\"aside-outline-before\" /></template>\n              <template #aside-outline-after><slot name=\"aside-outline-after\" /></template>\n              <template #aside-ads-before><slot name=\"aside-ads-before\" /></template>\n              <template #aside-ads-after><slot name=\"aside-ads-after\" /></template>\n            </VPDocAside>\n          </div>\n        </div>\n      </div>\n\n      <div class=\"content\">\n        <div class=\"content-container\">\n          <slot name=\"doc-before\" />\n          <main class=\"main\">\n            <Content\n              class=\"vp-doc\"\n              :class=\"[\n                pageName,\n                theme.externalLinkIcon && 'external-link-icon-enabled'\n              ]\"\n            />\n          </main>\n          <VPDocFooter>\n            <template #doc-footer-before><slot name=\"doc-footer-before\" /></template>\n          </VPDocFooter>\n          <slot name=\"doc-after\" />\n        </div>\n      </div>\n    </div>\n    <slot name=\"doc-bottom\" />\n  </div>\n</template>\n\n<style scoped>\n.VPDoc {\n  padding: 32px 24px 96px;\n  width: 100%;\n}\n\n@media (min-width: 768px) {\n  .VPDoc {\n    padding: 48px 32px 128px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPDoc {\n    padding: 48px 32px 0;\n  }\n\n  .VPDoc:not(.has-sidebar) .container {\n    display: flex;\n    justify-content: center;\n    max-width: 992px;\n  }\n\n  .VPDoc:not(.has-sidebar) .content {\n    max-width: 752px;\n  }\n}\n\n@media (min-width: 1280px) {\n  .VPDoc .container {\n    display: flex;\n    justify-content: center;\n  }\n\n  .VPDoc .aside {\n    display: block;\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPDoc:not(.has-sidebar) .content {\n    max-width: 784px;\n  }\n\n  .VPDoc:not(.has-sidebar) .container {\n    max-width: 1104px;\n  }\n}\n\n.container {\n  margin: 0 auto;\n  width: 100%;\n}\n\n.aside {\n  position: relative;\n  display: none;\n  order: 2;\n  flex-grow: 1;\n  padding-left: 32px;\n  width: 100%;\n  max-width: 256px;\n}\n\n.left-aside {\n  order: 1;\n  padding-left: unset;\n  padding-right: 32px;\n}\n\n.aside-container {\n  position: fixed;\n  top: 0;\n  padding-top: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + var(--vp-doc-top-height, 0px) + 48px);\n  width: 224px;\n  height: 100vh;\n  overflow-x: hidden;\n  overflow-y: auto;\n  scrollbar-width: none;\n}\n\n.aside-container::-webkit-scrollbar {\n  display: none;\n}\n\n.aside-curtain {\n  position: fixed;\n  bottom: 0;\n  z-index: 10;\n  width: 224px;\n  height: 32px;\n  background: linear-gradient(transparent, var(--vp-c-bg) 70%);\n  pointer-events: none;\n}\n\n.aside-content {\n  display: flex;\n  flex-direction: column;\n  min-height: calc(100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px));\n  padding-bottom: 32px;\n}\n\n.content {\n  position: relative;\n  margin: 0 auto;\n  width: 100%;\n}\n\n@media (min-width: 960px) {\n  .content {\n    padding: 0 32px 128px;\n  }\n}\n\n@media (min-width: 1280px) {\n  .content {\n    order: 1;\n    margin: 0;\n    min-width: 640px;\n  }\n}\n\n.content-container {\n  margin: 0 auto;\n}\n\n.VPDoc.has-aside .content-container {\n  max-width: 688px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocAside.vue",
    "content": "<script setup lang=\"ts\">\nimport { useData } from '../composables/data'\nimport VPDocAsideOutline from './VPDocAsideOutline.vue'\nimport VPDocAsideCarbonAds from './VPDocAsideCarbonAds.vue'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <div class=\"VPDocAside\">\n    <slot name=\"aside-top\" />\n\n    <slot name=\"aside-outline-before\" />\n    <VPDocAsideOutline />\n    <slot name=\"aside-outline-after\" />\n\n    <div class=\"spacer\" />\n\n    <slot name=\"aside-ads-before\" />\n    <VPDocAsideCarbonAds v-if=\"theme.carbonAds\" :carbon-ads=\"theme.carbonAds\" />\n    <slot name=\"aside-ads-after\" />\n\n    <slot name=\"aside-bottom\" />\n  </div>\n</template>\n\n<style scoped>\n.VPDocAside {\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n}\n\n.spacer {\n  flex-grow: 1;\n}\n\n.VPDocAside :deep(.spacer + .VPDocAsideSponsors),\n.VPDocAside :deep(.spacer + .VPDocAsideCarbonAds) {\n  margin-top: 24px;\n}\n\n.VPDocAside :deep(.VPDocAsideSponsors + .VPDocAsideCarbonAds) {\n  margin-top: 16px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocAsideCarbonAds.vue",
    "content": "<script setup lang=\"ts\">\nimport { defineAsyncComponent } from 'vue'\nimport type { DefaultTheme } from 'vitepress/theme'\n\ndefineProps<{\n  carbonAds: DefaultTheme.CarbonAdsOptions\n}>()\n\nconst VPCarbonAds = __CARBON__\n  ? defineAsyncComponent(() => import('./VPCarbonAds.vue'))\n  : () => null\n</script>\n\n<template>\n  <div class=\"VPDocAsideCarbonAds\">\n    <VPCarbonAds :carbon-ads=\"carbonAds\" />\n  </div>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocAsideOutline.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useData } from '../composables/data'\nimport { resolveTitle, useActiveAnchor } from '../composables/outline'\nimport VPDocOutlineItem from './VPDocOutlineItem.vue'\nimport { useLayout } from '../composables/layout'\n\nconst { theme } = useData()\n\nconst container = ref()\nconst marker = ref()\n\nconst { headers, hasLocalNav } = useLayout()\n\nuseActiveAnchor(container, marker)\n</script>\n\n<template>\n  <nav\n    aria-labelledby=\"doc-outline-aria-label\"\n    class=\"VPDocAsideOutline\"\n    :class=\"{ 'has-outline': hasLocalNav }\"\n    ref=\"container\"\n  >\n    <div class=\"content\">\n      <div class=\"outline-marker\" ref=\"marker\" />\n\n      <div\n        aria-level=\"2\"\n        class=\"outline-title\"\n        id=\"doc-outline-aria-label\"\n        role=\"heading\"\n      >\n        {{ resolveTitle(theme) }}\n      </div>\n\n      <VPDocOutlineItem :headers :root=\"true\" />\n    </div>\n  </nav>\n</template>\n\n<style scoped>\n.VPDocAsideOutline {\n  display: none;\n}\n\n.VPDocAsideOutline.has-outline {\n  display: block;\n}\n\n.content {\n  position: relative;\n  border-left: 1px solid var(--vp-c-divider);\n  padding-left: 16px;\n  font-size: 13px;\n  font-weight: 500;\n}\n\n.outline-marker {\n  position: absolute;\n  top: 32px;\n  left: -1px;\n  z-index: 0;\n  opacity: 0;\n  width: 2px;\n  border-radius: 2px;\n  height: 18px;\n  background-color: var(--vp-c-brand-1);\n  transition:\n    top 0.25s cubic-bezier(0, 1, 0.5, 1),\n    background-color 0.5s,\n    opacity 0.25s;\n}\n\n.outline-title {\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 600;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocAsideSponsors.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Sponsors } from './VPSponsors.vue'\nimport type { Sponsor } from './VPSponsorsGrid.vue'\nimport VPSponsors from './VPSponsors.vue'\n\ndefineProps<{\n  tier?: string\n  size?: 'xmini' | 'mini' | 'small'\n  data: Sponsors[] | Sponsor[]\n}>()\n</script>\n\n<template>\n  <div class=\"VPDocAsideSponsors\">\n    <VPSponsors mode=\"aside\" :tier :size :data />\n  </div>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocFooter.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { useEditLink } from '../composables/edit-link'\nimport { usePrevNext } from '../composables/prev-next'\nimport VPLink from './VPLink.vue'\nimport VPDocFooterLastUpdated from './VPDocFooterLastUpdated.vue'\n\nconst { theme, page, frontmatter } = useData()\n\nconst editLink = useEditLink()\nconst control = usePrevNext()\n\nconst hasEditLink = computed(\n  () => theme.value.editLink && frontmatter.value.editLink !== false\n)\nconst hasLastUpdated = computed(() => page.value.lastUpdated)\nconst showFooter = computed(\n  () =>\n    hasEditLink.value ||\n    hasLastUpdated.value ||\n    control.value.prev ||\n    control.value.next\n)\n</script>\n\n<template>\n  <footer v-if=\"showFooter\" class=\"VPDocFooter\">\n    <slot name=\"doc-footer-before\" />\n\n    <div v-if=\"hasEditLink || hasLastUpdated\" class=\"edit-info\">\n      <div v-if=\"hasEditLink\" class=\"edit-link\">\n        <VPLink class=\"edit-link-button\" :href=\"editLink.url\" :no-icon=\"true\">\n          <span class=\"vpi-square-pen edit-link-icon\" />\n          {{ editLink.text }}\n        </VPLink>\n      </div>\n\n      <div v-if=\"hasLastUpdated\" class=\"last-updated\">\n        <VPDocFooterLastUpdated />\n      </div>\n    </div>\n\n    <nav\n      v-if=\"control.prev?.link || control.next?.link\"\n      class=\"prev-next\"\n      aria-labelledby=\"doc-footer-aria-label\"\n    >\n      <span class=\"visually-hidden\" id=\"doc-footer-aria-label\">Pager</span>\n\n      <div class=\"pager\">\n        <VPLink\n          v-if=\"control.prev?.link\"\n          class=\"pager-link prev\"\n          :href=\"control.prev.link\"\n        >\n          <span\n            class=\"desc\"\n            v-html=\"theme.docFooter?.prev || 'Previous page'\"\n          ></span>\n          <span class=\"title\" v-html=\"control.prev.text\"></span>\n        </VPLink>\n      </div>\n      <div class=\"pager\">\n        <VPLink\n          v-if=\"control.next?.link\"\n          class=\"pager-link next\"\n          :href=\"control.next.link\"\n        >\n          <span\n            class=\"desc\"\n            v-html=\"theme.docFooter?.next || 'Next page'\"\n          ></span>\n          <span class=\"title\" v-html=\"control.next.text\"></span>\n        </VPLink>\n      </div>\n    </nav>\n  </footer>\n</template>\n\n<style scoped>\n.VPDocFooter {\n  margin-top: 64px;\n}\n\n.edit-info {\n  padding-bottom: 18px;\n}\n\n@media (min-width: 640px) {\n  .edit-info {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding-bottom: 14px;\n  }\n}\n\n.edit-link-button {\n  display: flex;\n  align-items: center;\n  border: 0;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n  transition: color 0.25s;\n}\n\n.edit-link-button:hover {\n  color: var(--vp-c-brand-2);\n}\n\n.edit-link-icon {\n  margin-right: 8px;\n}\n\n.prev-next {\n  border-top: 1px solid var(--vp-c-divider);\n  padding-top: 24px;\n  display: grid;\n  grid-row-gap: 8px;\n}\n\n@media (min-width: 640px) {\n  .prev-next {\n    grid-template-columns: repeat(2, 1fr);\n    grid-column-gap: 16px;\n  }\n}\n\n.pager-link {\n  display: block;\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 8px;\n  padding: 11px 16px 13px;\n  width: 100%;\n  height: 100%;\n  transition: border-color 0.25s;\n}\n\n.pager-link:hover {\n  border-color: var(--vp-c-brand-1);\n}\n\n.pager-link.next {\n  margin-left: auto;\n  text-align: right;\n}\n\n.desc {\n  display: block;\n  line-height: 20px;\n  font-size: 12px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.title {\n  display: block;\n  line-height: 20px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n  transition: color 0.25s;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocFooterLastUpdated.vue",
    "content": "<script setup lang=\"ts\">\nimport { useNavigatorLanguage } from '@vueuse/core'\nimport { computed, onMounted, shallowRef, useTemplateRef, watchEffect } from 'vue'\nimport { useData } from '../composables/data'\n\nconst { theme, page, lang: pageLang } = useData()\nconst { language: browserLang } = useNavigatorLanguage()\n\nconst timeRef = useTemplateRef('timeRef')\n\nconst date = computed(() => new Date(page.value.lastUpdated!))\nconst isoDatetime = computed(() => date.value.toISOString())\nconst datetime = shallowRef('')\n\n// set time on mounted hook to avoid hydration mismatch due to\n// potential differences in timezones of the server and clients\nonMounted(() => {\n  watchEffect(() => {\n    const lang = theme.value.lastUpdated?.formatOptions?.forceLocale\n      ? pageLang.value\n      : browserLang.value\n\n    datetime.value = new Intl.DateTimeFormat(\n      lang,\n      theme.value.lastUpdated?.formatOptions ?? {\n        dateStyle: 'medium',\n        timeStyle: 'medium'\n      }\n    ).format(date.value)\n\n    if (lang && pageLang.value !== lang) {\n      timeRef.value?.setAttribute('lang', lang)\n    } else {\n      timeRef.value?.removeAttribute('lang')\n    }\n  })\n})\n</script>\n\n<template>\n  <p class=\"VPLastUpdated\">\n    {{ theme.lastUpdated?.text || theme.lastUpdatedText || 'Last updated' }}:\n    <time ref=\"timeRef\" :datetime=\"isoDatetime\">{{ datetime }}</time>\n  </p>\n</template>\n\n<style scoped>\n.VPLastUpdated {\n  line-height: 24px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n@media (min-width: 640px) {\n  .VPLastUpdated {\n    line-height: 32px;\n    font-size: 14px;\n    font-weight: 500;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPDocOutlineItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\n\ndefineProps<{\n  headers: DefaultTheme.OutlineItem[]\n  root?: boolean\n}>()\n</script>\n\n<template>\n  <ul class=\"VPDocOutlineItem\" :class=\"root ? 'root' : 'nested'\">\n    <li v-for=\"{ children, link, title } in headers\">\n      <a class=\"outline-link\" :href=\"link\" :title>\n        {{ title }}\n      </a>\n      <template v-if=\"children?.length\">\n        <VPDocOutlineItem :headers=\"children\" />\n      </template>\n    </li>\n  </ul>\n</template>\n\n<style scoped>\n.root {\n  position: relative;\n  z-index: 1;\n}\n\n.nested {\n  padding-right: 16px;\n  padding-left: 16px;\n}\n\n.outline-link {\n  display: block;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 400;\n  color: var(--vp-c-text-2);\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  transition: color 0.5s;\n}\n\n.outline-link:hover,\n.outline-link.active {\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.outline-link.nested {\n  padding-left: 13px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPFeature.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPImage from './VPImage.vue'\nimport VPLink from './VPLink.vue'\n\ndefineProps<{\n  icon?: DefaultTheme.FeatureIcon\n  title: string\n  details?: string\n  link?: string\n  linkText?: string\n  rel?: string\n  target?: string\n}>()\n</script>\n\n<template>\n  <VPLink\n    class=\"VPFeature\"\n    :href=\"link\"\n    :rel\n    :target\n    :no-icon=\"true\"\n    :tag=\"link ? 'a' : 'div'\"\n  >\n    <article class=\"box\">\n      <div v-if=\"typeof icon === 'object' && icon.wrap\" class=\"icon\">\n        <VPImage\n          :image=\"icon\"\n          :alt=\"icon.alt\"\n          :height=\"icon.height || 48\"\n          :width=\"icon.width || 48\"\n        />\n      </div>\n      <VPImage\n        v-else-if=\"typeof icon === 'object'\"\n        :image=\"icon\"\n        :alt=\"icon.alt\"\n        :height=\"icon.height || 48\"\n        :width=\"icon.width || 48\"\n      />\n      <div v-else-if=\"icon\" class=\"icon\" v-html=\"icon\"></div>\n      <h2 class=\"title\" v-html=\"title\"></h2>\n      <ul v-if=\"Array.isArray(details)\" class=\"details\">\n        <li v-for=\"item in details\" :key=\"item\" v-html=\"item\"></li>\n      </ul>\n      <p v-else-if=\"details\" class=\"details\" v-html=\"details\"></p>\n      <div v-if=\"linkText\" class=\"link-text\">\n        <p class=\"link-text-value\">\n          {{ linkText }} <span class=\"vpi-arrow-right link-text-icon\" />\n        </p>\n      </div>\n    </article>\n  </VPLink>\n</template>\n\n<style scoped>\n.VPFeature {\n  display: block;\n  border: 1px solid var(--vp-c-bg-soft);\n  border-radius: 12px;\n  height: 100%;\n  background-color: var(--vp-c-bg-soft);\n  transition: border-color 0.25s, background-color 0.25s;\n}\n\n.VPFeature.link:hover {\n  border-color: var(--vp-c-brand-1);\n}\n\n.box {\n  display: flex;\n  flex-direction: column;\n  padding: 24px;\n  height: 100%;\n}\n\n.box > :deep(.VPImage) {\n  margin-bottom: 20px;\n}\n\n.icon {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  margin-bottom: 20px;\n  border-radius: 6px;\n  background-color: var(--vp-c-default-soft);\n  width: 48px;\n  height: 48px;\n  font-size: 24px;\n  transition: background-color 0.25s;\n}\n\n.title {\n  line-height: 24px;\n  font-size: 16px;\n  font-weight: 600;\n}\n\n.details {\n  flex-grow: 1;\n  padding-top: 8px;\n  line-height: 24px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\nul.details {\n  list-style-type: disc;\n  padding-left: 14px;\n}\n\n.link-text {\n  padding-top: 8px;\n}\n\n.link-text-value {\n  display: flex;\n  align-items: center;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n}\n\n.link-text-icon {\n  margin-left: 6px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPFeatures.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport VPFeature from './VPFeature.vue'\n\nexport interface Feature {\n  icon?: DefaultTheme.FeatureIcon\n  title: string\n  details: string\n  link?: string\n  linkText?: string\n  rel?: string\n  target?: string\n}\n\nconst props = defineProps<{\n  features: Feature[]\n}>()\n\nconst grid = computed(() => {\n  const length = props.features.length\n\n  if (!length) {\n    return\n  } else if (length === 2) {\n    return 'grid-2'\n  } else if (length === 3) {\n    return 'grid-3'\n  } else if (length % 3 === 0) {\n    return 'grid-6'\n  } else if (length > 3) {\n    return 'grid-4'\n  }\n})\n</script>\n\n<template>\n  <div v-if=\"features\" class=\"VPFeatures\">\n    <div class=\"container\">\n      <div class=\"items\">\n        <div\n          v-for=\"feature in features\"\n          :key=\"feature.title\"\n          class=\"item\"\n          :class=\"[grid]\"\n        >\n          <VPFeature\n            :icon=\"feature.icon\"\n            :title=\"feature.title\"\n            :details=\"feature.details\"\n            :link=\"feature.link\"\n            :link-text=\"feature.linkText\"\n            :rel=\"feature.rel\"\n            :target=\"feature.target\"\n          />\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPFeatures {\n  position: relative;\n  padding: 0 24px;\n}\n\n@media (min-width: 640px) {\n  .VPFeatures {\n    padding: 0 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPFeatures {\n    padding: 0 64px;\n  }\n}\n\n.container {\n  margin: 0 auto;\n  max-width: 1152px;\n}\n\n.items {\n  display: flex;\n  flex-wrap: wrap;\n  margin: -8px;\n}\n\n.item {\n  padding: 8px;\n  width: 100%;\n}\n\n@media (min-width: 640px) {\n  .item.grid-2,\n  .item.grid-4,\n  .item.grid-6 {\n    width: calc(100% / 2);\n  }\n}\n\n@media (min-width: 768px) {\n  .item.grid-2,\n  .item.grid-4 {\n    width: calc(100% / 2);\n  }\n\n  .item.grid-3,\n  .item.grid-6 {\n    width: calc(100% / 3);\n  }\n}\n\n@media (min-width: 960px) {\n  .item.grid-4 {\n    width: calc(100% / 4);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPFlyout.vue",
    "content": "<script lang=\"ts\" setup generic=\"T extends DefaultTheme.NavItem\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { ref } from 'vue'\nimport { useFlyout } from '../composables/flyout'\nimport VPMenu from './VPMenu.vue'\n\ndefineProps<{\n  icon?: string\n  button?: string\n  label?: string\n  items?: T[]\n}>()\n\nconst open = ref(false)\nconst el = ref<HTMLElement>()\n\nuseFlyout({ el, onBlur })\n\nfunction onBlur() {\n  open.value = false\n}\n</script>\n\n<template>\n  <div\n    class=\"VPFlyout\"\n    ref=\"el\"\n    @mouseenter=\"open = true\"\n    @mouseleave=\"open = false\"\n  >\n    <button\n      type=\"button\"\n      class=\"button\"\n      aria-haspopup=\"true\"\n      :aria-expanded=\"open\"\n      :aria-label=\"label\"\n      @click=\"open = !open\"\n    >\n      <span v-if=\"button || icon\" class=\"text\">\n        <span v-if=\"icon\" :class=\"[icon, 'option-icon']\" />\n        <span v-if=\"button\" v-html=\"button\"></span>\n        <span class=\"vpi-chevron-down text-icon\" />\n      </span>\n\n      <span v-else class=\"vpi-more-horizontal icon\" />\n    </button>\n\n    <div class=\"menu\">\n      <VPMenu :items>\n        <slot />\n      </VPMenu>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPFlyout {\n  position: relative;\n}\n\n.VPFlyout:hover {\n  color: var(--vp-c-brand-1);\n  transition: color 0.25s;\n}\n\n.VPFlyout:hover .text {\n  color: var(--vp-c-text-2);\n}\n\n.VPFlyout:hover .icon {\n  fill: var(--vp-c-text-2);\n}\n\n.VPFlyout.active .text {\n  color: var(--vp-c-brand-1);\n}\n\n.VPFlyout.active:hover .text {\n  color: var(--vp-c-brand-2);\n}\n\n.button[aria-expanded=\"false\"] + .menu {\n  opacity: 0;\n  visibility: hidden;\n  transform: translateY(0);\n}\n\n.VPFlyout:hover .menu,\n.button[aria-expanded=\"true\"] + .menu {\n  opacity: 1;\n  visibility: visible;\n  transform: translateY(0);\n}\n\n.button {\n  display: flex;\n  align-items: center;\n  padding: 0 12px;\n  height: var(--vp-nav-height);\n  color: var(--vp-c-text-1);\n  transition: color 0.5s;\n}\n\n.text {\n  display: flex;\n  align-items: center;\n  line-height: var(--vp-nav-height);\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.option-icon {\n  margin-right: 0px;\n  font-size: 16px;\n}\n\n.text-icon {\n  margin-left: 4px;\n  font-size: 14px;\n}\n\n.icon {\n  font-size: 20px;\n  transition: fill 0.25s;\n}\n\n.menu {\n  position: absolute;\n  top: calc(var(--vp-nav-height) / 2 + 20px);\n  right: 0;\n  opacity: 0;\n  visibility: hidden;\n  transition: opacity 0.25s, visibility 0.25s, transform 0.25s;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPFooter.vue",
    "content": "<script setup lang=\"ts\">\nimport { useData } from '../composables/data'\nimport { useLayout } from '../composables/layout'\n\nconst { theme, frontmatter } = useData()\nconst { hasSidebar } = useLayout()\n</script>\n\n<template>\n  <footer v-if=\"theme.footer && frontmatter.footer !== false\" class=\"VPFooter\" :class=\"{ 'has-sidebar': hasSidebar }\">\n    <div class=\"container\">\n      <p v-if=\"theme.footer.message\" class=\"message\" v-html=\"theme.footer.message\"></p>\n      <p v-if=\"theme.footer.copyright\" class=\"copyright\" v-html=\"theme.footer.copyright\"></p>\n    </div>\n  </footer>\n</template>\n\n<style scoped>\n.VPFooter {\n  position: relative;\n  z-index: var(--vp-z-index-footer);\n  border-top: 1px solid var(--vp-c-gutter);\n  padding: 32px 24px;\n  background-color: var(--vp-c-bg);\n}\n\n.VPFooter.has-sidebar {\n  display: none;\n}\n\n.VPFooter :deep(a) {\n  text-decoration-line: underline;\n  text-underline-offset: 2px;\n  transition: color 0.25s;\n}\n\n.VPFooter :deep(a:hover) {\n  color: var(--vp-c-text-1);\n}\n\n@media (min-width: 768px) {\n  .VPFooter {\n    padding: 32px;\n  }\n}\n\n.container {\n  margin: 0 auto;\n  max-width: var(--vp-layout-max-width);\n  text-align: center;\n}\n\n.message,\n.copyright {\n  line-height: 24px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHero.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed, inject } from 'vue'\nimport { layoutInfoInjectionKey } from '../composables/layout'\nimport VPButton from './VPButton.vue'\nimport VPImage from './VPImage.vue'\n\nexport interface HeroAction {\n  theme?: 'brand' | 'alt'\n  text: string\n  link: string\n  target?: string\n  rel?: string\n}\n\ndefineProps<{\n  name?: string\n  text?: string\n  tagline?: string\n  image?: DefaultTheme.ThemeableImage\n  actions?: HeroAction[]\n}>()\n\nconst { heroImageSlotExists } = inject(\n  layoutInfoInjectionKey,\n  { heroImageSlotExists: computed(() => false) }\n)\n</script>\n\n<template>\n  <div class=\"VPHero\" :class=\"{ 'has-image': image || heroImageSlotExists }\">\n    <div class=\"container\">\n      <div class=\"main\">\n        <slot name=\"home-hero-info-before\" />\n        <slot name=\"home-hero-info\">\n          <h1 class=\"heading\">\n            <span v-if=\"name\" v-html=\"name\" class=\"name clip\"></span>\n            <span v-if=\"text\" v-html=\"text\" class=\"text\"></span>\n          </h1>\n          <p v-if=\"tagline\" v-html=\"tagline\" class=\"tagline\"></p>\n        </slot>\n        <slot name=\"home-hero-info-after\" />\n\n        <div v-if=\"actions\" class=\"actions\">\n          <slot name=\"home-hero-actions-before-actions\" />\n          <div v-for=\"action in actions\" :key=\"action.link\" class=\"action\">\n            <VPButton\n              tag=\"a\"\n              size=\"medium\"\n              :theme=\"action.theme\"\n              :text=\"action.text\"\n              :href=\"action.link\"\n              :target=\"action.target\"\n              :rel=\"action.rel\"\n            />\n          </div>\n        </div>\n        <slot name=\"home-hero-actions-after\" />\n      </div>\n\n      <div v-if=\"image || heroImageSlotExists\" class=\"image\">\n        <div class=\"image-container\">\n          <div class=\"image-bg\" />\n          <slot name=\"home-hero-image\">\n            <VPImage v-if=\"image\" class=\"image-src\" :image />\n          </slot>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPHero {\n  margin-top: calc((var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1);\n  padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) 24px 48px;\n}\n\n@media (min-width: 640px) {\n  .VPHero {\n    padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 48px 64px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPHero {\n    padding: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 80px) 64px 64px;\n  }\n}\n\n.container {\n  display: flex;\n  flex-direction: column;\n  margin: 0 auto;\n  max-width: 1152px;\n}\n\n@media (min-width: 960px) {\n  .container {\n    flex-direction: row;\n  }\n}\n\n.main {\n  position: relative;\n  z-index: 10;\n  order: 2;\n  flex-grow: 1;\n  flex-shrink: 0;\n}\n\n.VPHero.has-image .container {\n  text-align: center;\n}\n\n@media (min-width: 960px) {\n  .VPHero.has-image .container {\n    text-align: left;\n  }\n}\n\n@media (min-width: 960px) {\n  .main {\n    order: 1;\n    width: calc((100% / 3) * 2);\n  }\n\n  .VPHero.has-image .main {\n    max-width: 592px;\n  }\n}\n\n.heading {\n  display: flex;\n  flex-direction: column;\n}\n\n.name,\n.text {\n  width: fit-content;\n  max-width: 392px;\n  letter-spacing: -0.4px;\n  line-height: 40px;\n  font-size: 32px;\n  font-weight: 700;\n  white-space: pre-wrap;\n\n  &:lang(ja) {\n    font-feature-settings: 'palt';\n    word-break: auto-phrase;\n  }\n}\n\n.VPHero.has-image .name,\n.VPHero.has-image .text {\n  margin: 0 auto;\n}\n\n.name {\n  color: var(--vp-home-hero-name-color);\n}\n\n.clip {\n  background: var(--vp-home-hero-name-background);\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: var(--vp-home-hero-name-color);\n}\n\n@media (min-width: 640px) {\n  .name,\n  .text {\n    max-width: 576px;\n    line-height: 56px;\n    font-size: 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .name,\n  .text {\n    line-height: 64px;\n    font-size: 56px;\n  }\n\n  .VPHero.has-image .name,\n  .VPHero.has-image .text {\n    margin: 0;\n  }\n}\n\n.tagline {\n  padding-top: 8px;\n  max-width: 392px;\n  line-height: 28px;\n  font-size: 18px;\n  font-weight: 500;\n  white-space: pre-wrap;\n  color: var(--vp-c-text-2);\n}\n\n.VPHero.has-image .tagline {\n  margin: 0 auto;\n}\n\n@media (min-width: 640px) {\n  .tagline {\n    padding-top: 12px;\n    max-width: 576px;\n    line-height: 32px;\n    font-size: 20px;\n  }\n}\n\n@media (min-width: 960px) {\n  .tagline {\n    line-height: 36px;\n    font-size: 24px;\n  }\n\n  .VPHero.has-image .tagline {\n    margin: 0;\n  }\n}\n\n.actions {\n  display: flex;\n  flex-wrap: wrap;\n  margin: -6px;\n  padding-top: 24px;\n}\n\n.VPHero.has-image .actions {\n  justify-content: center;\n}\n\n@media (min-width: 640px) {\n  .actions {\n    padding-top: 32px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPHero.has-image .actions {\n    justify-content: flex-start;\n  }\n}\n\n.action {\n  flex-shrink: 0;\n  padding: 6px;\n}\n\n.image {\n  order: 1;\n  margin: -76px -24px -48px;\n}\n\n@media (min-width: 640px) {\n  .image {\n    margin: -108px -24px -48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .image {\n    flex-grow: 1;\n    order: 2;\n    margin: 0;\n    min-height: 100%;\n  }\n}\n\n.image-container {\n  position: relative;\n  margin: 0 auto;\n  width: 320px;\n  height: 320px;\n}\n\n@media (min-width: 640px) {\n  .image-container {\n    width: 392px;\n    height: 392px;\n  }\n}\n\n@media (min-width: 960px) {\n  .image-container {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    width: 100%;\n    height: 100%;\n    /*rtl:ignore*/\n    transform: translate(-32px, -32px);\n  }\n}\n\n.image-bg {\n  position: absolute;\n  top: 50%;\n  /*rtl:ignore*/\n  left: 50%;\n  border-radius: 50%;\n  width: 192px;\n  height: 192px;\n  background-image: var(--vp-home-hero-image-background-image);\n  filter: var(--vp-home-hero-image-filter);\n  /*rtl:ignore*/\n  transform: translate(-50%, -50%);\n}\n\n@media (min-width: 640px) {\n  .image-bg {\n    width: 256px;\n    height: 256px;\n  }\n}\n\n@media (min-width: 960px) {\n  .image-bg {\n    width: 320px;\n    height: 320px;\n  }\n}\n\n:deep(.image-src) {\n  position: absolute;\n  top: 50%;\n  /*rtl:ignore*/\n  left: 50%;\n  max-width: 192px;\n  max-height: 192px;\n  width: 100%;\n  height: 100%;\n  object-fit: contain;\n  /*rtl:ignore*/\n  transform: translate(-50%, -50%);\n}\n\n@media (min-width: 640px) {\n  :deep(.image-src) {\n    max-width: 256px;\n    max-height: 256px;\n  }\n}\n\n@media (min-width: 960px) {\n  :deep(.image-src) {\n    max-width: 320px;\n    max-height: 320px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHome.vue",
    "content": "<script setup lang=\"ts\">\nimport VPHomeHero from './VPHomeHero.vue'\nimport VPHomeFeatures from './VPHomeFeatures.vue'\nimport VPHomeContent from './VPHomeContent.vue'\nimport { useData } from '../composables/data'\n\nconst { frontmatter, theme } = useData()\n</script>\n\n<template>\n  <div \n    class=\"VPHome\" \n    :class=\"{\n      'external-link-icon-enabled': theme.externalLinkIcon\n    }\">\n    <slot name=\"home-hero-before\" />\n    <VPHomeHero>\n      <template #home-hero-info-before><slot name=\"home-hero-info-before\" /></template>\n      <template #home-hero-info><slot name=\"home-hero-info\" /></template>\n      <template #home-hero-info-after><slot name=\"home-hero-info-after\" /></template>\n      <template #home-hero-actions-after><slot name=\"home-hero-actions-after\" /></template>\n      <template #home-hero-actions-before-actions><slot name=\"home-hero-actions-before-actions\" /></template>\n      <template #home-hero-image><slot name=\"home-hero-image\" /></template>\n    </VPHomeHero>\n    <slot name=\"home-hero-after\" />\n\n    <slot name=\"home-features-before\" />\n    <VPHomeFeatures />\n    <slot name=\"home-features-after\" />\n\n    <VPHomeContent v-if=\"frontmatter.markdownStyles !== false\">\n      <Content />\n    </VPHomeContent>\n    <Content v-else />\n  </div>\n</template>\n\n<style scoped>\n.VPHome {\n  margin-bottom: 96px;\n}\n\n@media (min-width: 768px) {\n  .VPHome {\n    margin-bottom: 128px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHomeContent.vue",
    "content": "<script setup lang=\"ts\">\nimport { useWindowSize } from '@vueuse/core'\n\nconst { width: vw } = useWindowSize({\n  initialWidth: 0,\n  includeScrollbar: false\n})\n</script>\n\n<template>\n  <div\n    class=\"vp-doc container\"\n    :style=\"vw ? { '--vp-offset': `calc(50% - ${vw / 2}px)` } : {}\"\n  >\n    <slot />\n  </div>\n</template>\n\n<style scoped>\n.container {\n  margin: auto;\n  width: 100%;\n  max-width: 1280px;\n  padding: 0 24px;\n}\n\n@media (min-width: 640px) {\n  .container {\n    padding: 0 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .container {\n    width: 100%;\n    padding: 0 64px;\n  }\n}\n\n.vp-doc :deep(.VPHomeSponsors),\n.vp-doc :deep(.VPTeamPage) {\n  margin-left: var(--vp-offset, calc(50% - 50vw));\n  margin-right: var(--vp-offset, calc(50% - 50vw));\n}\n\n.vp-doc :deep(.VPHomeSponsors h2) {\n  border-top: none;\n  letter-spacing: normal;\n}\n\n.vp-doc :deep(.VPHomeSponsors a),\n.vp-doc :deep(.VPTeamPage a) {\n  text-decoration: none;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHomeFeatures.vue",
    "content": "<script setup lang=\"ts\">\nimport { useData } from '../composables/data'\nimport VPFeatures from './VPFeatures.vue'\n\nconst { frontmatter: fm } = useData()\n</script>\n\n<template>\n  <VPFeatures\n    v-if=\"fm.features\"\n    class=\"VPHomeFeatures\"\n    :features=\"fm.features\"\n  />\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHomeHero.vue",
    "content": "<script setup lang=\"ts\">\nimport { useData } from '../composables/data'\nimport VPHero from './VPHero.vue'\n\nconst { frontmatter: fm } = useData()\n</script>\n\n<template>\n  <VPHero\n    v-if=\"fm.hero\"\n    class=\"VPHomeHero\"\n    :name=\"fm.hero.name\"\n    :text=\"fm.hero.text\"\n    :tagline=\"fm.hero.tagline\"\n    :image=\"fm.hero.image\"\n    :actions=\"fm.hero.actions\"\n  >\n    <template #home-hero-info-before><slot name=\"home-hero-info-before\" /></template>\n    <template #home-hero-info><slot name=\"home-hero-info\" /></template>\n    <template #home-hero-info-after><slot name=\"home-hero-info-after\" /></template>\n    <template #home-hero-actions-after><slot name=\"home-hero-actions-after\" /></template>\n    <template #home-hero-actions-before-actions><slot name=\"home-hero-actions-before-actions\" /></template>\n    <template #home-hero-image><slot name=\"home-hero-image\" /></template>\n  </VPHero>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPHomeSponsors.vue",
    "content": "<script setup lang=\"ts\">\nimport VPButton from './VPButton.vue'\nimport VPSponsors from './VPSponsors.vue'\n\nexport interface Sponsors {\n  tier: string\n  size?: 'medium' | 'big'\n  items: Sponsor[]\n}\n\nexport interface Sponsor {\n  name: string\n  img: string\n  url: string\n}\ninterface Props {\n  message?: string\n  actionText?: string\n  actionLink?: string\n  data: Sponsors[]\n}\n\nwithDefaults(defineProps<Props>(), {\n  actionText: 'Become a sponsor'\n})\n</script>\n\n<template>\n  <section class=\"VPHomeSponsors\">\n    <div class=\"container\">\n      <div class=\"header\">\n        <div class=\"love\">\n          <span class=\"vpi-heart icon\" />\n        </div>\n        <h2 v-if=\"message\" class=\"message\">{{ message }}</h2>\n      </div>\n\n      <div class=\"sponsors\">\n        <VPSponsors :data />\n      </div>\n\n      <div v-if=\"actionLink\" class=\"action\">\n        <VPButton theme=\"sponsor\" :text=\"actionText\" :href=\"actionLink\" />\n      </div>\n    </div>\n  </section>\n</template>\n\n<style scoped>\n.VPHomeSponsors {\n  border-top: 1px solid var(--vp-c-gutter);\n  padding-top: 88px !important;\n}\n\n.VPHomeSponsors {\n  margin: 96px 0;\n}\n\n@media (min-width: 768px) {\n  .VPHomeSponsors {\n    margin: 128px 0;\n  }\n}\n\n.VPHomeSponsors {\n  padding: 0 24px;\n}\n\n@media (min-width: 768px) {\n  .VPHomeSponsors {\n    padding: 0 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPHomeSponsors {\n    padding: 0 64px;\n  }\n}\n\n.container {\n  margin: 0 auto;\n  max-width: 1152px;\n}\n\n.love {\n  margin: 0 auto;\n  width: fit-content;\n  font-size: 28px;\n  color: var(--vp-c-text-3);\n}\n\n.icon {\n  display: inline-block;\n}\n\n.message {\n  margin: 0 auto;\n  padding-top: 10px;\n  max-width: 320px;\n  text-align: center;\n  line-height: 24px;\n  font-size: 16px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.sponsors {\n  padding-top: 32px;\n}\n\n.action {\n  padding-top: 40px;\n  text-align: center;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPImage.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { withBase } from 'vitepress'\n\ndefineProps<{\n  image: DefaultTheme.ThemeableImage\n  alt?: string\n}>()\n\ndefineOptions({ inheritAttrs: false })\n</script>\n\n<template>\n  <template v-if=\"image\">\n    <img\n      v-if=\"typeof image === 'string' || 'src' in image\"\n      class=\"VPImage\"\n      v-bind=\"typeof image === 'string' ? $attrs : { ...image, ...$attrs }\"\n      :src=\"withBase(typeof image === 'string' ? image : image.src)\"\n      :alt=\"alt ?? (typeof image === 'string' ? '' : image.alt || '')\"\n    />\n    <template v-else>\n      <VPImage\n        class=\"dark\"\n        :image=\"image.dark\"\n        :alt=\"image.alt\"\n        v-bind=\"$attrs\"\n      />\n      <VPImage\n        class=\"light\"\n        :image=\"image.light\"\n        :alt=\"image.alt\"\n        v-bind=\"$attrs\"\n      />\n    </template>\n  </template>\n</template>\n\n<style scoped>\nhtml:not(.dark) .VPImage.dark {\n  display: none;\n}\n.dark .VPImage.light {\n  display: none;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport { normalizeLink } from '../support/utils'\nimport { EXTERNAL_URL_RE } from '../../shared'\n\nconst props = defineProps<{\n  tag?: string\n  href?: string\n  noIcon?: boolean\n  target?: string\n  rel?: string\n}>()\n\nconst tag = computed(() => props.tag ?? (props.href ? 'a' : 'span'))\nconst isExternal = computed(\n  () =>\n    (props.href && EXTERNAL_URL_RE.test(props.href)) ||\n    props.target === '_blank'\n)\n</script>\n\n<template>\n  <component\n    :is=\"tag\"\n    class=\"VPLink\"\n    :class=\"{\n      link: href,\n      'vp-external-link-icon': isExternal,\n      'no-icon': noIcon\n    }\"\n    :href=\"href ? normalizeLink(href) : undefined\"\n    :target=\"target ?? (isExternal ? '_blank' : undefined)\"\n    :rel=\"rel ?? (isExternal ? 'noreferrer' : undefined)\"\n  >\n    <slot />\n  </component>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPLocalNav.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useWindowScroll } from '@vueuse/core'\nimport { computed, onMounted, ref } from 'vue'\nimport { useData } from '../composables/data'\nimport { useLayout } from '../composables/layout'\nimport VPLocalNavOutlineDropdown from './VPLocalNavOutlineDropdown.vue'\n\ndefineProps<{\n  open: boolean\n}>()\n\ndefineEmits<{\n  (e: 'open-menu'): void\n}>()\n\nconst { theme } = useData()\nconst { isHome, hasSidebar, headers, hasLocalNav } = useLayout()\nconst { y } = useWindowScroll()\n\nconst navHeight = ref(0)\n\nonMounted(() => {\n  navHeight.value = parseInt(\n    getComputedStyle(document.documentElement).getPropertyValue(\n      '--vp-nav-height'\n    )\n  )\n})\n\nconst classes = computed(() => {\n  return {\n    VPLocalNav: true,\n    'has-sidebar': hasSidebar.value,\n    empty: !hasLocalNav.value,\n    fixed: !hasLocalNav.value && !hasSidebar.value\n  }\n})\n</script>\n\n<template>\n  <div\n    v-if=\"!isHome && (hasLocalNav || hasSidebar || y >= navHeight)\"\n    :class=\"classes\"\n  >\n    <div class=\"container\">\n      <button\n        v-if=\"hasSidebar\"\n        class=\"menu\"\n        :aria-expanded=\"open\"\n        aria-controls=\"VPSidebarNav\"\n        @click=\"$emit('open-menu')\"\n      >\n        <span class=\"vpi-align-left menu-icon\"></span>\n        <span class=\"menu-text\">\n          {{ theme.sidebarMenuLabel || 'Menu' }}\n        </span>\n      </button>\n\n      <VPLocalNavOutlineDropdown :headers :navHeight />\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPLocalNav {\n  position: sticky;\n  top: 0;\n  /*rtl:ignore*/\n  left: 0;\n  z-index: var(--vp-z-index-local-nav);\n  border-bottom: 1px solid var(--vp-c-gutter);\n  padding-top: var(--vp-layout-top-height, 0px);\n  width: 100%;\n  background-color: var(--vp-local-nav-bg-color);\n}\n\n.VPLocalNav.fixed {\n  position: fixed;\n}\n\n@media (min-width: 960px) {\n  .VPLocalNav {\n    top: var(--vp-nav-height);\n  }\n\n  .VPLocalNav.has-sidebar {\n    padding-left: var(--vp-sidebar-width);\n  }\n\n  .VPLocalNav.empty {\n    display: none;\n  }\n}\n\n@media (min-width: 1280px) {\n  .VPLocalNav {\n    display: none;\n  }\n}\n\n.container {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.menu {\n  display: flex;\n  align-items: center;\n  line-height: 24px;\n  font-size: 12px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n  transition: color 0.5s;\n}\n\n.menu:hover {\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n@media (min-width: 960px) {\n  .menu {\n    display: none;\n  }\n}\n\n.menu-icon {\n  margin-right: 8px;\n  font-size: 14px;\n}\n\n.menu,\n:deep(.VPLocalNavOutlineDropdown > button) {\n  padding: 12px 24px 11px;\n}\n\n@media (min-width: 768px) {\n  .menu,\n  :deep(.VPLocalNavOutlineDropdown > button) {\n    padding: 12px 32px 11px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPLocalNavOutlineDropdown.vue",
    "content": "<script setup lang=\"ts\">\nimport { onKeyStroke } from '@vueuse/core'\nimport { onContentUpdated } from 'vitepress'\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { nextTick, ref, watch } from 'vue'\nimport { useData } from '../composables/data'\nimport { resolveTitle } from '../composables/outline'\nimport VPDocOutlineItem from './VPDocOutlineItem.vue'\n\nconst props = defineProps<{\n  headers: DefaultTheme.OutlineItem[]\n  navHeight: number\n}>()\n\nconst { theme } = useData()\nconst open = ref(false)\nconst vh = ref(0)\nconst main = ref<HTMLDivElement>()\nconst items = ref<HTMLDivElement>()\n\nfunction closeOnClickOutside(e: Event) {\n  if (!main.value?.contains(e.target as Node)) {\n    open.value = false\n  }\n}\n\nwatch(open, (value) => {\n  if (value) {\n    document.addEventListener('click', closeOnClickOutside)\n    return\n  }\n  document.removeEventListener('click', closeOnClickOutside)\n})\n\nonKeyStroke('Escape', () => {\n  open.value = false\n})\n\nonContentUpdated(() => {\n  open.value = false\n})\n\nfunction toggle() {\n  open.value = !open.value\n  vh.value = window.innerHeight + Math.min(window.scrollY - props.navHeight, 0)\n}\n\nfunction onItemClick(e: Event) {\n  if ((e.target as HTMLElement).classList.contains('outline-link')) {\n    // disable animation on hash navigation when page jumps\n    if (items.value) {\n      items.value.style.transition = 'none'\n    }\n    nextTick(() => {\n      open.value = false\n    })\n  }\n}\n\nfunction scrollToTop() {\n  open.value = false\n  window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })\n}\n</script>\n\n<template>\n  <div\n    class=\"VPLocalNavOutlineDropdown\"\n    :style=\"{ '--vp-vh': vh + 'px' }\"\n    ref=\"main\"\n  >\n    <button @click=\"toggle\" :class=\"{ open }\" v-if=\"headers.length > 0\">\n      <span class=\"menu-text\">{{ resolveTitle(theme) }}</span>\n      <span class=\"vpi-chevron-right icon\" />\n    </button>\n    <button @click=\"scrollToTop\" v-else>\n      {{ theme.returnToTopLabel || 'Return to top' }}\n    </button>\n    <Transition name=\"flyout\">\n      <div v-if=\"open\" ref=\"items\" class=\"items\" @click=\"onItemClick\">\n        <div class=\"header\">\n          <a class=\"top-link\" href=\"#\" @click=\"scrollToTop\">\n            {{ theme.returnToTopLabel || 'Return to top' }}\n          </a>\n        </div>\n        <div class=\"outline\">\n          <VPDocOutlineItem :headers />\n        </div>\n      </div>\n    </Transition>\n  </div>\n</template>\n\n<style scoped>\n.VPLocalNavOutlineDropdown button {\n  display: block;\n  font-size: 12px;\n  font-weight: 500;\n  line-height: 24px;\n  color: var(--vp-c-text-2);\n  transition: color 0.5s;\n  position: relative;\n}\n\n.VPLocalNavOutlineDropdown button:hover {\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.VPLocalNavOutlineDropdown button.open {\n  color: var(--vp-c-text-1);\n}\n\n.icon {\n  display: inline-block;\n  vertical-align: middle;\n  margin-left: 2px;\n  font-size: 14px;\n  transform: rotate(0) /*rtl:rotate(180deg)*/;\n  transition: transform 0.25s;\n}\n\n@media (min-width: 960px) {\n  .VPLocalNavOutlineDropdown button {\n    font-size: 14px;\n  }\n\n  .icon {\n    font-size: 16px;\n  }\n}\n\n.open > .icon {\n  /*rtl:ignore*/\n  transform: rotate(90deg);\n}\n\n.items {\n  position: absolute;\n  top: 40px;\n  right: 16px;\n  left: 16px;\n  display: grid;\n  gap: 1px;\n  border: 1px solid var(--vp-c-border);\n  border-radius: 8px;\n  background-color: var(--vp-c-gutter);\n  max-height: calc(var(--vp-vh, 100vh) - 86px);\n  overflow: hidden auto;\n  box-shadow: var(--vp-shadow-3);\n}\n\n@media (min-width: 960px) {\n  .items {\n    right: auto;\n    left: calc(var(--vp-sidebar-width) + 32px);\n    width: 320px;\n  }\n}\n\n.header {\n  background-color: var(--vp-c-bg-soft);\n}\n\n.top-link {\n  display: block;\n  padding: 0 16px;\n  line-height: 48px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n}\n\n.outline {\n  padding: 8px 0;\n  background-color: var(--vp-c-bg-soft);\n}\n\n.flyout-enter-active {\n  transition: all 0.2s ease-out;\n}\n\n.flyout-leave-active {\n  transition: all 0.15s ease-in;\n}\n\n.flyout-enter-from,\n.flyout-leave-to {\n  opacity: 0;\n  transform: translateY(-16px);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPLocalSearchBox.vue",
    "content": "<script lang=\"ts\" setup>\nimport localSearchIndex from '@localSearchIndex'\nimport {\n  computedAsync,\n  watchDebounced,\n  onKeyStroke,\n  useEventListener,\n  useLocalStorage,\n  useScrollLock,\n  useSessionStorage\n} from '@vueuse/core'\nimport { useFocusTrap } from '@vueuse/integrations/useFocusTrap'\nimport Mark from 'mark.js/src/vanilla.js'\nimport MiniSearch, { type SearchResult } from 'minisearch'\nimport { dataSymbol, inBrowser, useRouter } from 'vitepress'\nimport {\n  computed,\n  createApp,\n  markRaw,\n  nextTick,\n  onBeforeUnmount,\n  onMounted,\n  ref,\n  shallowRef,\n  watch,\n  watchEffect,\n  type Ref\n} from 'vue'\nimport type { LocalSearchTranslations } from '../../../../types/local-search'\nimport { pathToFile } from '../../app/utils'\nimport { escapeRegExp } from '../../shared'\nimport { useData } from '../composables/data'\nimport { LRUCache } from '../support/lru'\nimport { createSearchTranslate } from '../support/translation'\n\nconst emit = defineEmits<{\n  (e: 'close'): void\n}>()\n\nconst el = shallowRef<HTMLElement>()\nconst resultsEl = shallowRef<HTMLElement>()\n\n/* Search */\n\nconst searchIndexData = shallowRef(localSearchIndex)\n\n// hmr\nif (import.meta.hot) {\n  import.meta.hot.accept('@localSearchIndex', (m) => {\n    if (m) {\n      searchIndexData.value = m.default\n    }\n  })\n}\n\ninterface Result {\n  title: string\n  titles: string[]\n  text?: string\n}\n\nconst vitePressData = useData()\nconst { activate } = useFocusTrap(el, {\n  immediate: true,\n  allowOutsideClick: true,\n  clickOutsideDeactivates: true,\n  escapeDeactivates: true\n})\nconst { localeIndex, theme } = vitePressData\nconst searchIndex = computedAsync(async () =>\n  markRaw(\n    MiniSearch.loadJSON<Result>(\n      (await searchIndexData.value[localeIndex.value]?.())?.default,\n      {\n        fields: ['title', 'titles', 'text'],\n        storeFields: ['title', 'titles'],\n        searchOptions: {\n          fuzzy: 0.2,\n          prefix: true,\n          boost: { title: 4, text: 2, titles: 1 },\n          ...(theme.value.search?.provider === 'local' &&\n            theme.value.search.options?.miniSearch?.searchOptions)\n        },\n        ...(theme.value.search?.provider === 'local' &&\n          theme.value.search.options?.miniSearch?.options)\n      }\n    )\n  )\n)\n\nconst disableQueryPersistence = computed(() => {\n  return (\n    theme.value.search?.provider === 'local' &&\n    theme.value.search.options?.disableQueryPersistence === true\n  )\n})\n\nconst filterText = disableQueryPersistence.value\n  ? ref('')\n  : useSessionStorage('vitepress:local-search-filter', '')\n\nconst showDetailedList = useLocalStorage(\n  'vitepress:local-search-detailed-list',\n  theme.value.search?.provider === 'local' &&\n    theme.value.search.options?.detailedView === true\n)\n\nconst disableDetailedView = computed(() => {\n  return (\n    theme.value.search?.provider === 'local' &&\n    (theme.value.search.options?.disableDetailedView === true ||\n      theme.value.search.options?.detailedView === false)\n  )\n})\n\nwatchEffect(() => {\n  if (disableDetailedView.value) {\n    showDetailedList.value = false\n  }\n})\n\nconst results: Ref<(SearchResult & Result)[]> = shallowRef([])\n\nconst enableNoResults = ref(false)\n\nwatch(filterText, () => {\n  enableNoResults.value = false\n})\n\nconst mark = computedAsync(async () => {\n  if (!resultsEl.value) return\n  return markRaw(new Mark(resultsEl.value))\n}, null)\n\nconst cache = new LRUCache<string, Map<string, string>>(16) // 16 files\n\nwatchDebounced(\n  () => [searchIndex.value, filterText.value, showDetailedList.value] as const,\n  async ([index, filterTextValue, showDetailedListValue], old, onCleanup) => {\n    if (old?.[0] !== index) {\n      // in case of hmr\n      cache.clear()\n    }\n\n    let canceled = false\n    onCleanup(() => {\n      canceled = true\n    })\n\n    if (!index) return\n\n    // Search\n    results.value = index\n      .search(filterTextValue)\n      .slice(0, 16) as (SearchResult & Result)[]\n    enableNoResults.value = true\n\n    // Highlighting\n    const mods = showDetailedListValue\n      ? await Promise.all(results.value.map((r) => fetchExcerpt(r.id)))\n      : []\n    if (canceled) return\n    for (const { id, mod } of mods) {\n      const mapId = id.slice(0, id.indexOf('#'))\n      let map = cache.get(mapId)\n      if (map) continue\n      map = new Map()\n      cache.set(mapId, map)\n      const comp = mod.default ?? mod\n      if (comp?.render || comp?.setup) {\n        const app = createApp(comp)\n        // Silence warnings about missing components\n        app.config.warnHandler = () => {}\n        app.provide(dataSymbol, vitePressData)\n        Object.defineProperties(app.config.globalProperties, {\n          $frontmatter: {\n            get() {\n              return vitePressData.frontmatter.value\n            }\n          },\n          $params: {\n            get() {\n              return vitePressData.page.value.params\n            }\n          }\n        })\n        const div = document.createElement('div')\n        app.mount(div)\n        const headings = div.querySelectorAll('h1, h2, h3, h4, h5, h6')\n        headings.forEach((el) => {\n          const href = el.querySelector('a')?.getAttribute('href')\n          const anchor = href?.startsWith('#') && href.slice(1)\n          if (!anchor) return\n          let html = ''\n          while ((el = el.nextElementSibling!) && !/^h[1-6]$/i.test(el.tagName))\n            html += el.outerHTML\n          map!.set(anchor, html)\n        })\n        app.unmount()\n      }\n      if (canceled) return\n    }\n\n    const terms = new Set<string>()\n\n    results.value = results.value.map((r) => {\n      const [id, anchor] = r.id.split('#')\n      const map = cache.get(id)\n      const text = map?.get(anchor) ?? ''\n      for (const term in r.match) {\n        terms.add(term)\n      }\n      return { ...r, text }\n    })\n\n    await nextTick()\n    if (canceled) return\n\n    await new Promise((r) => {\n      mark.value?.unmark({\n        done: () => {\n          mark.value?.markRegExp(formMarkRegex(terms), { done: r })\n        }\n      })\n    })\n\n    const excerpts = el.value?.querySelectorAll('.result .excerpt') ?? []\n    for (const excerpt of excerpts) {\n      excerpt\n        .querySelector('mark[data-markjs=\"true\"]')\n        ?.scrollIntoView({ block: 'center' })\n    }\n    // FIXME: without this whole page scrolls to the bottom\n    resultsEl.value?.firstElementChild?.scrollIntoView({ block: 'start' })\n  },\n  { debounce: 200, immediate: true }\n)\n\nasync function fetchExcerpt(id: string) {\n  const file = pathToFile(id.slice(0, id.indexOf('#')))\n  try {\n    if (!file) throw new Error(`Cannot find file for id: ${id}`)\n    return { id, mod: await import(/*@vite-ignore*/ file) }\n  } catch (e) {\n    console.error(e)\n    return { id, mod: {} }\n  }\n}\n\n/* Search input focus */\n\nconst searchInput = ref<HTMLInputElement>()\nconst disableReset = computed(() => {\n  return filterText.value?.length <= 0\n})\nfunction focusSearchInput(select = true) {\n  searchInput.value?.focus()\n  select && searchInput.value?.select()\n}\n\nonMounted(() => {\n  focusSearchInput()\n})\n\nfunction onSearchBarClick(event: PointerEvent) {\n  if (event.pointerType === 'mouse') {\n    focusSearchInput()\n  }\n}\n\n/* Search keyboard selection */\n\nconst selectedIndex = ref(-1)\nconst disableMouseOver = ref(true)\n\nwatch(results, (r) => {\n  selectedIndex.value = r.length ? 0 : -1\n  scrollToSelectedResult()\n})\n\nfunction scrollToSelectedResult() {\n  nextTick(() => {\n    const selectedEl = document.querySelector('.result.selected')\n    selectedEl?.scrollIntoView({ block: 'nearest' })\n  })\n}\n\nonKeyStroke('ArrowUp', (event) => {\n  event.preventDefault()\n  selectedIndex.value--\n  if (selectedIndex.value < 0) {\n    selectedIndex.value = results.value.length - 1\n  }\n  disableMouseOver.value = true\n  scrollToSelectedResult()\n})\n\nonKeyStroke('ArrowDown', (event) => {\n  event.preventDefault()\n  selectedIndex.value++\n  if (selectedIndex.value >= results.value.length) {\n    selectedIndex.value = 0\n  }\n  disableMouseOver.value = true\n  scrollToSelectedResult()\n})\n\nconst router = useRouter()\n\nonKeyStroke('Enter', (e) => {\n  if (e.isComposing) return\n\n  if (e.target instanceof HTMLButtonElement && e.target.type !== 'submit')\n    return\n\n  const selectedPackage = results.value[selectedIndex.value]\n  if (e.target instanceof HTMLInputElement && !selectedPackage) {\n    e.preventDefault()\n    return\n  }\n\n  if (selectedPackage) {\n    router.go(selectedPackage.id)\n    emit('close')\n  }\n})\n\nonKeyStroke('Escape', () => {\n  emit('close')\n})\n\n/* Translations */\n\nconst defaultTranslations: LocalSearchTranslations = {\n  button: {\n    buttonText: 'Search'\n  },\n  modal: {\n    displayDetails: 'Display detailed list',\n    resetButtonTitle: 'Reset search',\n    backButtonTitle: 'Close search',\n    noResultsText: 'No results for',\n    footer: {\n      selectText: 'to select',\n      selectKeyAriaLabel: 'enter',\n      navigateText: 'to navigate',\n      navigateUpKeyAriaLabel: 'up arrow',\n      navigateDownKeyAriaLabel: 'down arrow',\n      closeText: 'to close',\n      closeKeyAriaLabel: 'escape'\n    }\n  }\n}\n\nconst translate = createSearchTranslate(defaultTranslations)\n\n/* Back */\n\nonMounted(() => {\n  // Prevents going to previous site\n  window.history.pushState(null, '', null)\n})\n\nuseEventListener('popstate', (event) => {\n  event.preventDefault()\n  emit('close')\n})\n\n/** Lock body */\n\nconst isLocked = useScrollLock(inBrowser ? document.body : null)\n\nonMounted(() => {\n  nextTick(() => {\n    isLocked.value = true\n    nextTick().then(() => activate())\n  })\n})\n\nonBeforeUnmount(() => {\n  isLocked.value = false\n})\n\nfunction resetSearch() {\n  filterText.value = ''\n  nextTick().then(() => focusSearchInput(false))\n}\n\nfunction formMarkRegex(terms: Set<string>) {\n  return new RegExp(\n    [...terms]\n      .sort((a, b) => b.length - a.length)\n      .map((term) => `(${escapeRegExp(term)})`)\n      .join('|'),\n    'gi'\n  )\n}\n\nfunction onMouseMove(e: MouseEvent) {\n  if (!disableMouseOver.value) return\n  const el = (e.target as HTMLElement)?.closest<HTMLAnchorElement>('.result')\n  const index = Number.parseInt(el?.dataset.index!)\n  if (index >= 0 && index !== selectedIndex.value) {\n    selectedIndex.value = index\n  }\n  disableMouseOver.value = false\n}\n</script>\n\n<template>\n  <Teleport to=\"body\">\n    <div\n      ref=\"el\"\n      role=\"button\"\n      :aria-owns=\"results?.length ? 'localsearch-list' : undefined\"\n      aria-expanded=\"true\"\n      aria-haspopup=\"listbox\"\n      aria-labelledby=\"localsearch-label\"\n      class=\"VPLocalSearchBox\"\n    >\n      <div class=\"backdrop\" @click=\"$emit('close')\" />\n\n      <div class=\"shell\">\n        <form\n          class=\"search-bar\"\n          @pointerup=\"onSearchBarClick($event)\"\n          @submit.prevent=\"\"\n        >\n          <label\n            :title=\"translate('button.buttonText')\"\n            id=\"localsearch-label\"\n            for=\"localsearch-input\"\n          >\n            <span aria-hidden=\"true\" class=\"vpi-search search-icon local-search-icon\" />\n          </label>\n          <div class=\"search-actions before\">\n            <button\n              class=\"back-button\"\n              :title=\"translate('modal.backButtonTitle')\"\n              @click=\"$emit('close')\"\n            >\n              <span class=\"vpi-arrow-left local-search-icon\" />\n            </button>\n          </div>\n          <input\n            ref=\"searchInput\"\n            v-model=\"filterText\"\n            :aria-activedescendant=\"selectedIndex > -1 ? ('localsearch-item-' + selectedIndex) : undefined\"\n            aria-autocomplete=\"both\"\n            :aria-controls=\"results?.length ? 'localsearch-list' : undefined\"\n            aria-labelledby=\"localsearch-label\"\n            autocapitalize=\"off\"\n            autocomplete=\"off\"\n            autocorrect=\"off\"\n            class=\"search-input\"\n            id=\"localsearch-input\"\n            enterkeyhint=\"go\"\n            maxlength=\"64\"\n            :placeholder=\"translate('button.buttonText')\"\n            spellcheck=\"false\"\n            type=\"search\"\n          />\n          <div class=\"search-actions\">\n            <button\n              v-if=\"!disableDetailedView\"\n              class=\"toggle-layout-button\"\n              type=\"button\"\n              :class=\"{ 'detailed-list': showDetailedList }\"\n              :title=\"translate('modal.displayDetails')\"\n              @click=\"\n                selectedIndex > -1 && (showDetailedList = !showDetailedList)\n              \"\n            >\n              <span class=\"vpi-layout-list local-search-icon\" />\n            </button>\n\n            <button\n              class=\"clear-button\"\n              type=\"reset\"\n              :disabled=\"disableReset\"\n              :title=\"translate('modal.resetButtonTitle')\"\n              @click=\"resetSearch\"\n            >\n              <span class=\"vpi-delete local-search-icon\" />\n            </button>\n          </div>\n        </form>\n\n        <ul\n          ref=\"resultsEl\"\n          :id=\"results?.length ? 'localsearch-list' : undefined\"\n          :role=\"results?.length ? 'listbox' : undefined\"\n          :aria-labelledby=\"results?.length ? 'localsearch-label' : undefined\"\n          class=\"results\"\n          @mousemove=\"onMouseMove\"\n        >\n          <li\n            v-for=\"(p, index) in results\"\n            :key=\"p.id\"\n            :id=\"'localsearch-item-' + index\"\n            :aria-selected=\"selectedIndex === index ? 'true' : 'false'\"\n            role=\"option\"\n          >\n            <a\n              :href=\"p.id\"\n              class=\"result\"\n              :class=\"{\n                selected: selectedIndex === index\n              }\"\n              :aria-label=\"[...p.titles, p.title].join(' > ')\"\n              @mouseenter=\"!disableMouseOver && (selectedIndex = index)\"\n              @focusin=\"selectedIndex = index\"\n              @click=\"$emit('close')\"\n              :data-index=\"index\"\n            >\n              <div>\n                <div class=\"titles\">\n                  <span class=\"title-icon\">#</span>\n                  <span\n                    v-for=\"(t, index) in p.titles\"\n                    :key=\"index\"\n                    class=\"title\"\n                  >\n                    <span class=\"text\" v-html=\"t\" />\n                    <span class=\"vpi-chevron-right local-search-icon\" />\n                  </span>\n                  <span class=\"title main\">\n                    <span class=\"text\" v-html=\"p.title\" />\n                  </span>\n                </div>\n\n                <div v-if=\"showDetailedList\" class=\"excerpt-wrapper\">\n                  <div v-if=\"p.text\" class=\"excerpt\" inert>\n                    <div class=\"vp-doc\" v-html=\"p.text\" />\n                  </div>\n                  <div class=\"excerpt-gradient-bottom\" />\n                  <div class=\"excerpt-gradient-top\" />\n                </div>\n              </div>\n            </a>\n          </li>\n          <li\n            v-if=\"filterText && !results.length && enableNoResults\"\n            class=\"no-results\"\n          >\n            {{ translate('modal.noResultsText') }} \"<strong>{{ filterText }}</strong\n            >\"\n          </li>\n        </ul>\n\n        <div class=\"search-keyboard-shortcuts\">\n          <span>\n            <kbd :aria-label=\"translate('modal.footer.navigateUpKeyAriaLabel')\">\n              <span class=\"vpi-arrow-up navigate-icon\" />\n            </kbd>\n            <kbd :aria-label=\"translate('modal.footer.navigateDownKeyAriaLabel')\">\n              <span class=\"vpi-arrow-down navigate-icon\" />\n            </kbd>\n            {{ translate('modal.footer.navigateText') }}\n          </span>\n          <span>\n            <kbd :aria-label=\"translate('modal.footer.selectKeyAriaLabel')\">\n              <span class=\"vpi-corner-down-left navigate-icon\" />\n            </kbd>\n            {{ translate('modal.footer.selectText') }}\n          </span>\n          <span>\n            <kbd :aria-label=\"translate('modal.footer.closeKeyAriaLabel')\">esc</kbd>\n            {{ translate('modal.footer.closeText') }}\n          </span>\n        </div>\n      </div>\n    </div>\n  </Teleport>\n</template>\n\n<style scoped>\n.VPLocalSearchBox {\n  position: fixed;\n  z-index: 100;\n  inset: 0;\n  display: flex;\n}\n\n.backdrop {\n  position: absolute;\n  inset: 0;\n  background: var(--vp-backdrop-bg-color);\n  transition: opacity 0.5s;\n}\n\n.shell {\n  position: relative;\n  padding: 12px;\n  margin: 64px auto;\n  display: flex;\n  flex-direction: column;\n  gap: 16px;\n  background: var(--vp-local-search-bg);\n  width: min(100vw - 60px, 900px);\n  height: min-content;\n  max-height: min(100vh - 128px, 900px);\n  border-radius: 6px;\n}\n\n@media (max-width: 767px) {\n  .shell {\n    margin: 0;\n    width: 100vw;\n    height: 100vh;\n    max-height: none;\n    border-radius: 0;\n  }\n}\n\n.search-bar {\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 4px;\n  display: flex;\n  align-items: center;\n  padding: 0 12px;\n  cursor: text;\n}\n\n@media (max-width: 767px) {\n  .search-bar {\n    padding: 0 8px;\n  }\n}\n\n.search-bar:focus-within {\n  border-color: var(--vp-c-brand-1);\n}\n\n.local-search-icon {\n  display: block;\n  font-size: 18px;\n}\n\n.navigate-icon {\n  display: block;\n  font-size: 14px;\n}\n\n.search-icon {\n  margin: 8px;\n}\n\n@media (max-width: 767px) {\n  .search-icon {\n    display: none;\n  }\n}\n\n.search-input {\n  padding: 6px 12px;\n  font-size: inherit;\n  width: 100%;\n}\n\n.search-input::-webkit-search-cancel-button {\n  display: none;\n}\n\n@media (max-width: 767px) {\n  .search-input {\n    padding: 6px 4px;\n  }\n}\n\n.search-actions {\n  display: flex;\n  gap: 4px;\n}\n\n@media (any-pointer: coarse) {\n  .search-actions {\n    gap: 8px;\n  }\n}\n\n@media (min-width: 769px) {\n  .search-actions.before {\n    display: none;\n  }\n}\n\n.search-actions button {\n  padding: 8px;\n}\n\n.search-actions button:not([disabled]):hover,\n.toggle-layout-button.detailed-list {\n  color: var(--vp-c-brand-1);\n}\n\n.search-actions button.clear-button:disabled {\n  opacity: 0.37;\n}\n\n.search-keyboard-shortcuts {\n  font-size: 0.8rem;\n  opacity: 75%;\n  display: flex;\n  flex-wrap: wrap;\n  gap: 16px;\n  line-height: 14px;\n}\n\n.search-keyboard-shortcuts span {\n  display: flex;\n  align-items: center;\n  gap: 4px;\n}\n\n@media (max-width: 767px) {\n  .search-keyboard-shortcuts {\n    display: none;\n  }\n}\n\n.search-keyboard-shortcuts kbd {\n  background: rgba(128, 128, 128, 0.1);\n  border-radius: 4px;\n  padding: 3px 6px;\n  min-width: 24px;\n  display: inline-block;\n  text-align: center;\n  vertical-align: middle;\n  border: 1px solid rgba(128, 128, 128, 0.15);\n  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);\n}\n\n.results {\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  overflow-x: hidden;\n  overflow-y: auto;\n  overscroll-behavior: contain;\n}\n\n.result {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  border-radius: 4px;\n  transition: none;\n  line-height: 1rem;\n  border: solid 2px var(--vp-local-search-result-border);\n  outline: none;\n}\n\n.result > div {\n  margin: 12px;\n  width: 100%;\n  overflow: hidden;\n}\n\n@media (max-width: 767px) {\n  .result > div {\n    margin: 8px;\n  }\n}\n\n.titles {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px;\n  position: relative;\n  z-index: 1001;\n  padding: 2px 0;\n}\n\n.title {\n  display: flex;\n  align-items: center;\n  gap: 4px;\n}\n\n.title.main {\n  font-weight: 500;\n}\n\n.title-icon {\n  opacity: 0.5;\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n}\n\n.title svg {\n  opacity: 0.5;\n}\n\n.result.selected {\n  --vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);\n  border-color: var(--vp-local-search-result-selected-border);\n}\n\n.excerpt-wrapper {\n  position: relative;\n}\n\n.excerpt {\n  opacity: 50%;\n  pointer-events: none;\n  max-height: 140px;\n  overflow: hidden;\n  position: relative;\n  margin-top: 4px;\n}\n\n.result.selected .excerpt {\n  opacity: 1;\n}\n\n.excerpt :deep(*) {\n  font-size: 0.8rem !important;\n  line-height: 130% !important;\n}\n\n.titles :deep(mark),\n.excerpt :deep(mark) {\n  background-color: var(--vp-local-search-highlight-bg);\n  color: var(--vp-local-search-highlight-text);\n  border-radius: 2px;\n  padding: 0 2px;\n}\n\n.excerpt :deep(.vp-code-group) .tabs {\n  display: none;\n}\n\n.excerpt :deep(.vp-code-group) div[class*='language-'] {\n  border-radius: 8px !important;\n}\n\n.excerpt-gradient-bottom {\n  position: absolute;\n  bottom: -1px;\n  left: 0;\n  width: 100%;\n  height: 8px;\n  background: linear-gradient(transparent, var(--vp-local-search-result-bg));\n  z-index: 1000;\n}\n\n.excerpt-gradient-top {\n  position: absolute;\n  top: -1px;\n  left: 0;\n  width: 100%;\n  height: 8px;\n  background: linear-gradient(var(--vp-local-search-result-bg), transparent);\n  z-index: 1000;\n}\n\n.result.selected .titles,\n.result.selected .title-icon {\n  color: var(--vp-c-brand-1) !important;\n}\n\n.no-results {\n  font-size: 0.9rem;\n  text-align: center;\n  padding: 12px;\n}\n\nsvg {\n  flex: none;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPMenu.vue",
    "content": "<script lang=\"ts\" setup generic=\"T extends DefaultTheme.NavItem\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPMenuLink from './VPMenuLink.vue'\nimport VPMenuGroup from './VPMenuGroup.vue'\n\ndefineProps<{\n  items?: T[]\n}>()\n</script>\n\n<template>\n  <div class=\"VPMenu\">\n    <div v-if=\"items\" class=\"items\">\n      <template v-for=\"item in items\" :key=\"JSON.stringify(item)\">\n        <VPMenuLink v-if=\"'link' in item\" :item />\n        <component\n          v-else-if=\"'component' in item\"\n          :is=\"item.component\"\n          v-bind=\"item.props\"\n        />\n        <VPMenuGroup v-else :text=\"item.text\" :items=\"item.items\" />\n      </template>\n    </div>\n\n    <slot />\n  </div>\n</template>\n\n<style scoped>\n.VPMenu {\n  border-radius: 12px;\n  padding: 12px;\n  min-width: 128px;\n  border: 1px solid var(--vp-c-divider);\n  background-color: var(--vp-c-bg-elv);\n  box-shadow: var(--vp-shadow-3);\n  transition: background-color 0.5s;\n  max-height: calc(100vh - var(--vp-nav-height));\n  overflow-y: auto;\n}\n\n.VPMenu :deep(.group) {\n  margin: 0 -12px;\n  padding: 0 12px 12px;\n}\n\n.VPMenu :deep(.group + .group) {\n  border-top: 1px solid var(--vp-c-divider);\n  padding: 11px 12px 12px;\n}\n\n.VPMenu :deep(.group:last-child) {\n  padding-bottom: 0;\n}\n\n.VPMenu :deep(.group + .item) {\n  border-top: 1px solid var(--vp-c-divider);\n  padding: 11px 16px 0;\n}\n\n.VPMenu :deep(.item) {\n  padding: 0 16px;\n  white-space: nowrap;\n}\n\n.VPMenu :deep(.label) {\n  flex-grow: 1;\n  line-height: 28px;\n  font-size: 12px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n  transition: color 0.5s;\n}\n\n.VPMenu :deep(.action) {\n  padding-left: 24px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPMenuGroup.vue",
    "content": "<script lang=\"ts\" setup generic=\"T extends (DefaultTheme.NavItemComponent | DefaultTheme.NavItemChildren | DefaultTheme.NavItemWithLink)\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPMenuLink from './VPMenuLink.vue'\n\ndefineProps<{\n  text?: string\n  items: T[]\n}>()\n</script>\n\n<template>\n  <div class=\"VPMenuGroup\">\n    <p v-if=\"text\" class=\"title\">{{ text }}</p>\n\n    <template v-for=\"item in items\" :key=\"JSON.stringify(item)\">\n      <VPMenuLink v-if=\"'link' in item\" :item />\n    </template>\n  </div>\n</template>\n\n<style scoped>\n.VPMenuGroup {\n  margin: 12px -12px 0;\n  border-top: 1px solid var(--vp-c-divider);\n  padding: 12px 12px 0;\n}\n\n.VPMenuGroup:first-child {\n  margin-top: 0;\n  border-top: 0;\n  padding-top: 0;\n}\n\n.VPMenuGroup + .VPMenuGroup {\n  margin-top: 12px;\n  border-top: 1px solid var(--vp-c-divider);\n}\n\n.title {\n  padding: 0 12px;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 600;\n  color: var(--vp-c-text-2);\n  white-space: nowrap;\n  transition: color 0.25s;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPMenuLink.vue",
    "content": "<script lang=\"ts\" setup generic=\"T extends DefaultTheme.NavItemWithLink\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { isActive } from '../../shared'\nimport VPLink from './VPLink.vue'\n\nconst props = defineProps<{\n  item: T\n  rel?: string\n}>()\n\nconst { page } = useData()\n\nconst href = computed(() =>\n  typeof props.item.link === 'function'\n    ? props.item.link(page.value)\n    : props.item.link\n)\n\nconst isActiveLink = computed(() =>\n  isActive(\n    page.value.relativePath,\n    props.item.activeMatch || href.value,\n    !!props.item.activeMatch\n  )\n)\n\ndefineOptions({ inheritAttrs: false })\n</script>\n\n<template>\n  <div class=\"VPMenuLink\">\n    <VPLink\n      v-bind=\"$attrs\"\n      :class=\"{ active: isActiveLink }\"\n      :href\n      :target=\"item.target\"\n      :rel=\"props.rel ?? item.rel\"\n      :no-icon=\"item.noIcon\"\n    >\n      <span v-html=\"item.text\"></span>\n    </VPLink>\n  </div>\n</template>\n\n<style scoped>\n.VPMenuGroup + .VPMenuLink {\n  margin: 12px -12px 0;\n  border-top: 1px solid var(--vp-c-divider);\n  padding: 12px 12px 0;\n}\n\n.link {\n  display: block;\n  border-radius: 6px;\n  padding: 0 12px;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n  text-align: left;\n  white-space: nowrap;\n  transition:\n    background-color 0.25s,\n    color 0.25s;\n}\n\n.link:hover {\n  color: var(--vp-c-brand-1);\n  background-color: var(--vp-c-default-soft);\n}\n\n.link.active {\n  color: var(--vp-c-brand-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNav.vue",
    "content": "<script setup lang=\"ts\">\nimport { inBrowser } from 'vitepress'\nimport { computed, provide, watchEffect } from 'vue'\nimport { useData } from '../composables/data'\nimport { navInjectionKey, useNav } from '../composables/nav'\nimport VPNavBar from './VPNavBar.vue'\nimport VPNavScreen from './VPNavScreen.vue'\n\nconst { isScreenOpen, closeScreen, toggleScreen } = useNav()\nconst { frontmatter } = useData()\n\nconst hasNavbar = computed(() => {\n  return frontmatter.value.navbar !== false\n})\n\nprovide(navInjectionKey, { closeScreen })\n\nwatchEffect(() => {\n  if (inBrowser) {\n    document.documentElement.classList.toggle('hide-nav', !hasNavbar.value)\n  }\n})\n</script>\n\n<template>\n  <header v-if=\"hasNavbar\" class=\"VPNav\">\n    <VPNavBar :is-screen-open=\"isScreenOpen\" @toggle-screen=\"toggleScreen\">\n      <template #nav-bar-title-before><slot name=\"nav-bar-title-before\" /></template>\n      <template #nav-bar-title-after><slot name=\"nav-bar-title-after\" /></template>\n      <template #nav-bar-content-before><slot name=\"nav-bar-content-before\" /></template>\n      <template #nav-bar-content-after><slot name=\"nav-bar-content-after\" /></template>\n    </VPNavBar>\n    <VPNavScreen :open=\"isScreenOpen\">\n      <template #nav-screen-content-before><slot name=\"nav-screen-content-before\" /></template>\n      <template #nav-screen-content-after><slot name=\"nav-screen-content-after\" /></template>\n    </VPNavScreen>\n  </header>\n</template>\n\n<style scoped>\n.VPNav {\n  position: relative;\n  top: var(--vp-layout-top-height, 0px);\n  /*rtl:ignore*/\n  left: 0;\n  z-index: var(--vp-z-index-nav);\n  width: 100%;\n  pointer-events: none;\n  transition: background-color 0.5s;\n}\n\n@media (min-width: 960px) {\n  .VPNav {\n    position: fixed;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBar.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useWindowScroll } from '@vueuse/core'\nimport { useLayout } from '../composables/layout'\nimport VPNavBarAppearance from './VPNavBarAppearance.vue'\nimport VPNavBarExtra from './VPNavBarExtra.vue'\nimport VPNavBarHamburger from './VPNavBarHamburger.vue'\nimport VPNavBarMenu from './VPNavBarMenu.vue'\nimport VPNavBarSearch from './VPNavBarSearch.vue'\nimport VPNavBarSocialLinks from './VPNavBarSocialLinks.vue'\nimport VPNavBarTitle from './VPNavBarTitle.vue'\nimport VPNavBarTranslations from './VPNavBarTranslations.vue'\n\nconst props = defineProps<{\n  isScreenOpen: boolean\n}>()\n\ndefineEmits<{\n  (e: 'toggle-screen'): void\n}>()\n\nconst { y } = useWindowScroll()\nconst { isHome, hasSidebar } = useLayout()\n</script>\n\n<template>\n  <div\n    class=\"VPNavBar\"\n    :class=\"{\n      'has-sidebar': hasSidebar,\n      'home': isHome,\n      'top': y === 0,\n      'screen-open': isScreenOpen\n    }\"\n  >\n    <div class=\"wrapper\">\n      <div class=\"container\">\n        <div class=\"title\">\n          <VPNavBarTitle>\n            <template #nav-bar-title-before><slot name=\"nav-bar-title-before\" /></template>\n            <template #nav-bar-title-after><slot name=\"nav-bar-title-after\" /></template>\n          </VPNavBarTitle>\n        </div>\n\n        <div class=\"content\">\n          <div class=\"content-body\">\n            <slot name=\"nav-bar-content-before\" />\n            <VPNavBarSearch class=\"search\" />\n            <VPNavBarMenu class=\"menu\" />\n            <VPNavBarTranslations class=\"translations\" />\n            <VPNavBarAppearance class=\"appearance\" />\n            <VPNavBarSocialLinks class=\"social-links\" />\n            <VPNavBarExtra class=\"extra\" />\n            <slot name=\"nav-bar-content-after\" />\n            <VPNavBarHamburger\n              class=\"hamburger\"\n              :active=\"isScreenOpen\"\n              @click=\"$emit('toggle-screen')\"\n            />\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <div class=\"divider\">\n      <div class=\"divider-line\" />\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPNavBar {\n  position: relative;\n  height: var(--vp-nav-height);\n  pointer-events: none;\n  white-space: nowrap;\n  transition: background-color 0.25s;\n}\n\n.VPNavBar.screen-open {\n  transition: none;\n  background-color: var(--vp-nav-bg-color);\n  border-bottom: 1px solid var(--vp-c-divider);\n}\n\n.VPNavBar:not(.home) {\n  background-color: var(--vp-nav-bg-color);\n}\n\n@media (min-width: 960px) {\n  .VPNavBar:not(.home) {\n    background-color: transparent;\n  }\n\n  .VPNavBar:not(.has-sidebar):not(.home.top) {\n    background-color: var(--vp-nav-bg-color);\n  }\n}\n\n.wrapper {\n  padding: 0 8px 0 24px;\n}\n\n@media (min-width: 768px) {\n  .wrapper {\n    padding: 0 32px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPNavBar.has-sidebar .wrapper {\n    padding: 0;\n  }\n}\n\n.container {\n  display: flex;\n  justify-content: space-between;\n  margin: 0 auto;\n  max-width: calc(var(--vp-layout-max-width) - 64px);\n  height: var(--vp-nav-height);\n  pointer-events: none;\n}\n\n.container > .title,\n.container > .content {\n  pointer-events: none;\n}\n\n.container :deep(*) {\n  pointer-events: auto;\n}\n\n@media (min-width: 960px) {\n  .VPNavBar.has-sidebar .container {\n    max-width: 100%;\n  }\n}\n\n.title {\n  flex-shrink: 0;\n  height: calc(var(--vp-nav-height) - 1px);\n  transition: background-color 0.5s;\n}\n\n@media (min-width: 960px) {\n  .VPNavBar.has-sidebar .title {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 2;\n    padding: 0 32px;\n    width: var(--vp-sidebar-width);\n    height: var(--vp-nav-height);\n    background-color: transparent;\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPNavBar.has-sidebar .title {\n    padding-left: max(32px, calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));\n    width: calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px);\n  }\n}\n\n.content {\n  flex-grow: 1;\n}\n\n@media (min-width: 960px) {\n  .VPNavBar.has-sidebar .content {\n    position: relative;\n    z-index: 1;\n    padding-left: var(--vp-sidebar-width);\n    padding-right: 32px;\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPNavBar.has-sidebar .content {\n    padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));\n    padding-right: calc((100% - var(--vp-layout-max-width)) / 2 + 32px);\n  }\n}\n\n.content-body {\n  display: flex;\n  justify-content: flex-end;\n  align-items: center;\n  height: var(--vp-nav-height);\n  transition: background-color 0.5s;\n}\n\n@media (min-width: 960px) {\n  .VPNavBar:not(.home.top) .content-body {\n    position: relative;\n    background-color: var(--vp-nav-bg-color);\n  }\n\n  .VPNavBar:not(.has-sidebar):not(.home.top) .content-body {\n    background-color: transparent;\n  }\n\n  .content-body {\n    margin-right: -100vw;\n    padding-right: 100vw;\n  }\n}\n\n.menu + .translations::before,\n.menu + .appearance::before,\n.menu + .social-links::before,\n.translations + .appearance::before,\n.appearance + .social-links::before {\n  margin-right: 8px;\n  margin-left: 8px;\n  width: 1px;\n  height: 24px;\n  background-color: var(--vp-c-divider);\n  content: \"\";\n}\n\n.menu + .appearance::before,\n.translations + .appearance::before {\n  margin-right: 16px;\n}\n\n.appearance + .social-links::before {\n  margin-left: 16px;\n}\n\n.social-links {\n  margin-right: -8px;\n}\n\n.divider {\n  width: 100%;\n  height: 1px;\n}\n\n@media (min-width: 960px) {\n  .VPNavBar.has-sidebar .divider {\n    padding-left: var(--vp-sidebar-width);\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPNavBar.has-sidebar .divider {\n    padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));\n  }\n}\n\n.divider-line {\n  width: 100%;\n  height: 1px;\n  transition: background-color 0.5s;\n}\n\n.VPNavBar:not(.home) .divider-line {\n  background-color: var(--vp-c-gutter);\n}\n\n@media (min-width: 960px) {\n  .VPNavBar:not(.home.top) .divider-line {\n    background-color: var(--vp-c-gutter);\n  }\n\n  .VPNavBar:not(.has-sidebar):not(.home.top) .divider {\n    background-color: var(--vp-c-gutter);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarAppearance.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPSwitchAppearance from './VPSwitchAppearance.vue'\n\nconst { site } = useData()\n</script>\n\n<template>\n  <div\n    v-if=\"\n      site.appearance &&\n      site.appearance !== 'force-dark' &&\n      site.appearance !== 'force-auto'\n    \"\n    class=\"VPNavBarAppearance\"\n  >\n    <VPSwitchAppearance />\n  </div>\n</template>\n\n<style scoped>\n.VPNavBarAppearance {\n  display: none;\n}\n\n@media (min-width: 1280px) {\n  .VPNavBarAppearance {\n    display: flex;\n    align-items: center;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarAskAiButton.vue",
    "content": "<template>\n  <button type=\"button\" class=\"VPNavBarAskAiButton\">\n    <span class=\"vpi-sparkles\" aria-hidden=\"true\"></span>\n  </button>\n</template>\n\n<style scoped>\n.VPNavBarAskAiButton {\n  display: flex;\n  align-items: center;\n  height: var(--vp-nav-height);\n  padding: 8px 14px;\n  font-size: 20px;\n}\n\n@media (min-width: 768px) {\n  .VPNavBarAskAiButton {\n    height: auto;\n    padding: 11.5px;\n    transition: color 0.3s ease;\n    background-color: var(--vp-c-bg-alt);\n    border-radius: 8px;\n    font-size: 15px;\n    color: var(--vp-c-text-2);\n  }\n\n  .VPNavBarAskAiButton:hover {\n    color: var(--vp-c-brand-1);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarExtra.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport VPFlyout from './VPFlyout.vue'\nimport VPMenuLink from './VPMenuLink.vue'\nimport VPSwitchAppearance from './VPSwitchAppearance.vue'\nimport VPSocialLinks from './VPSocialLinks.vue'\nimport { useData } from '../composables/data'\nimport { useLangs } from '../composables/langs'\n\nconst { site, theme } = useData()\nconst { localeLinks, currentLang } = useLangs({ correspondingLink: true })\n\nconst hasExtraContent = computed(\n  () =>\n    (localeLinks.value.length && currentLang.value.label) ||\n    site.value.appearance ||\n    theme.value.socialLinks\n)\n</script>\n\n<template>\n  <VPFlyout\n    v-if=\"hasExtraContent\"\n    class=\"VPNavBarExtra\"\n    label=\"extra navigation\"\n  >\n    <div\n      v-if=\"localeLinks.length && currentLang.label\"\n      class=\"group translations\"\n    >\n      <p class=\"trans-title\">{{ currentLang.label }}</p>\n\n      <template v-for=\"locale in localeLinks\" :key=\"locale.link\">\n        <VPMenuLink\n          :item=\"locale\"\n          :lang=\"locale.lang\"\n          :hreflang=\"locale.lang\"\n          rel=\"alternate\"\n          :dir=\"locale.dir\"\n        />\n      </template>\n    </div>\n\n    <div\n      v-if=\"\n        site.appearance &&\n        site.appearance !== 'force-dark' &&\n        site.appearance !== 'force-auto'\n      \"\n      class=\"group\"\n    >\n      <div class=\"item appearance\">\n        <p class=\"label\">\n          {{ theme.darkModeSwitchLabel || 'Appearance' }}\n        </p>\n        <div class=\"appearance-action\">\n          <VPSwitchAppearance />\n        </div>\n      </div>\n    </div>\n\n    <div v-if=\"theme.socialLinks\" class=\"group\">\n      <div class=\"item social-links\">\n        <VPSocialLinks class=\"social-links-list\" :links=\"theme.socialLinks\" />\n      </div>\n    </div>\n  </VPFlyout>\n</template>\n\n<style scoped>\n.VPNavBarExtra {\n  display: none;\n  margin-right: -12px;\n}\n\n@media (min-width: 768px) {\n  .VPNavBarExtra {\n    display: block;\n  }\n}\n\n@media (min-width: 1280px) {\n  .VPNavBarExtra {\n    display: none;\n  }\n}\n\n.trans-title {\n  padding: 0 24px 0 12px;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 700;\n  color: var(--vp-c-text-1);\n}\n\n.item.appearance,\n.item.social-links {\n  display: flex;\n  align-items: center;\n  padding: 0 12px;\n}\n\n.item.appearance {\n  min-width: 176px;\n}\n\n.appearance-action {\n  margin-right: -2px;\n}\n\n.social-links-list {\n  margin: -4px -8px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarHamburger.vue",
    "content": "<script lang=\"ts\" setup>\ndefineProps<{\n  active: boolean\n}>()\n\ndefineEmits<{\n  (e: 'click'): void\n}>()\n</script>\n\n<template>\n  <button\n    type=\"button\"\n    class=\"VPNavBarHamburger\"\n    :class=\"{ active }\"\n    aria-label=\"mobile navigation\"\n    :aria-expanded=\"active\"\n    aria-controls=\"VPNavScreen\"\n    @click=\"$emit('click')\"\n  >\n    <span class=\"container\">\n      <span class=\"top\" />\n      <span class=\"middle\" />\n      <span class=\"bottom\" />\n    </span>\n  </button>\n</template>\n\n<style scoped>\n.VPNavBarHamburger {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  width: 48px;\n  height: var(--vp-nav-height);\n}\n\n@media (min-width: 768px) {\n  .VPNavBarHamburger {\n    display: none;\n  }\n}\n\n.container {\n  position: relative;\n  width: 16px;\n  height: 14px;\n  overflow: hidden;\n}\n\n.VPNavBarHamburger:hover .top    { top: 0; left: 0; transform: translateX(4px); }\n.VPNavBarHamburger:hover .middle { top: 6px; left: 0; transform: translateX(0); }\n.VPNavBarHamburger:hover .bottom { top: 12px; left: 0; transform: translateX(8px); }\n\n.VPNavBarHamburger.active .top    { top: 6px; transform: translateX(0) rotate(225deg); }\n.VPNavBarHamburger.active .middle { top: 6px; transform: translateX(16px); }\n.VPNavBarHamburger.active .bottom { top: 6px; transform: translateX(0) rotate(135deg); }\n\n.VPNavBarHamburger.active:hover .top,\n.VPNavBarHamburger.active:hover .middle,\n.VPNavBarHamburger.active:hover .bottom {\n  background-color: var(--vp-c-text-2);\n  transition: top .25s, background-color .25s, transform .25s;\n}\n\n.top,\n.middle,\n.bottom {\n  position: absolute;\n  width: 16px;\n  height: 2px;\n  background-color: var(--vp-c-text-1);\n  transition: top .25s, background-color .5s, transform .25s;\n}\n\n.top    { top: 0; left: 0; transform: translateX(0); }\n.middle { top: 6px; left: 0; transform: translateX(8px); }\n.bottom { top: 12px; left: 0; transform: translateX(4px); }\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarMenu.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPNavBarMenuLink from './VPNavBarMenuLink.vue'\nimport VPNavBarMenuGroup from './VPNavBarMenuGroup.vue'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <nav\n    v-if=\"theme.nav\"\n    aria-labelledby=\"main-nav-aria-label\"\n    class=\"VPNavBarMenu\"\n  >\n    <span id=\"main-nav-aria-label\" class=\"visually-hidden\">\n      Main Navigation\n    </span>\n    <template v-for=\"item in theme.nav\" :key=\"JSON.stringify(item)\">\n      <VPNavBarMenuLink v-if=\"'link' in item\" :item />\n      <component\n        v-else-if=\"'component' in item\"\n        :is=\"item.component\"\n        v-bind=\"item.props\"\n      />\n      <VPNavBarMenuGroup v-else :item />\n    </template>\n  </nav>\n</template>\n\n<style scoped>\n.VPNavBarMenu {\n  display: none;\n}\n\n@media (min-width: 768px) {\n  .VPNavBarMenu {\n    display: flex;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarMenuGroup.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { isActive } from '../../shared'\nimport VPFlyout from './VPFlyout.vue'\n\nconst props = defineProps<{\n  item: DefaultTheme.NavItemWithChildren\n}>()\n\nconst { page } = useData()\n\nconst isActiveGroup = computed(() => {\n  if (props.item.activeMatch) {\n    return isActive(page.value.relativePath, props.item.activeMatch, true)\n  }\n  return isChildActive(props.item)\n})\n\nfunction isChildActive(navItem: DefaultTheme.NavItem): boolean {\n  if ('component' in navItem) return false\n\n  if ('link' in navItem) {\n    const href =\n      typeof navItem.link === 'function'\n        ? navItem.link(page.value)\n        : navItem.link\n\n    return isActive(\n      page.value.relativePath,\n      navItem.activeMatch || href,\n      !!navItem.activeMatch\n    )\n  }\n\n  return navItem.items.some(isChildActive)\n}\n</script>\n\n<template>\n  <VPFlyout\n    :class=\"{ VPNavBarMenuGroup: true, active: isActiveGroup }\"\n    :button=\"item.text\"\n    :items=\"item.items\"\n  />\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarMenuLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { isActive } from '../../shared'\nimport VPLink from './VPLink.vue'\n\nconst props = defineProps<{\n  item: DefaultTheme.NavItemWithLink\n}>()\n\nconst { page } = useData()\n\nconst href = computed(() =>\n  typeof props.item.link === 'function'\n    ? props.item.link(page.value)\n    : props.item.link\n)\n\nconst isActiveLink = computed(() =>\n  isActive(\n    page.value.relativePath,\n    props.item.activeMatch || href.value,\n    !!props.item.activeMatch\n  )\n)\n</script>\n\n<template>\n  <VPLink\n    :class=\"{ VPNavBarMenuLink: true, active: isActiveLink }\"\n    :href\n    :target=\"item.target\"\n    :rel=\"item.rel\"\n    :no-icon=\"item.noIcon\"\n    tabindex=\"0\"\n  >\n    <span v-html=\"item.text\"></span>\n  </VPLink>\n</template>\n\n<style scoped>\n.VPNavBarMenuLink {\n  display: flex;\n  align-items: center;\n  padding: 0 12px;\n  line-height: var(--vp-nav-height);\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.VPNavBarMenuLink.active {\n  color: var(--vp-c-brand-1);\n}\n\n.VPNavBarMenuLink:hover {\n  color: var(--vp-c-brand-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarSearch.vue",
    "content": "<script lang=\"ts\" setup>\nimport { onKeyStroke } from '@vueuse/core'\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed, defineAsyncComponent, onMounted, ref } from 'vue'\nimport { useData } from '../composables/data'\nimport { resolveMode, resolveOptionsForLanguage } from '../support/docsearch'\nimport { smartComputed } from '../support/reactivity'\nimport VPNavBarAskAiButton from './VPNavBarAskAiButton.vue'\nimport VPNavBarSearchButton from './VPNavBarSearchButton.vue'\n\nconst VPLocalSearchBox = __VP_LOCAL_SEARCH__\n  ? defineAsyncComponent(() => import('./VPLocalSearchBox.vue'))\n  : () => null\n\nconst VPAlgoliaSearchBox = __ALGOLIA__\n  ? defineAsyncComponent(() => import('./VPAlgoliaSearchBox.vue'))\n  : () => null\n\nconst { theme, localeIndex, lang } = useData()\nconst provider = __ALGOLIA__ ? 'algolia' : __VP_LOCAL_SEARCH__ ? 'local' : ''\n\n// #region Algolia Search\n\nconst algoliaOptions = smartComputed<DefaultTheme.AlgoliaSearchOptions>(() => {\n  return resolveOptionsForLanguage(\n    theme.value.search?.options || {},\n    localeIndex.value,\n    lang.value\n  )\n})\n\nconst resolvedMode = computed(() => resolveMode(algoliaOptions.value))\n\nconst askAiSidePanelConfig = computed(() => {\n  if (!resolvedMode.value.useSidePanel) return null\n  const askAi = algoliaOptions.value.askAi\n  if (!askAi || typeof askAi === 'string') return null\n  if (!askAi.sidePanel) return null\n  return askAi.sidePanel === true ? {} : askAi.sidePanel\n})\n\nconst askAiShortcutEnabled = computed(() => {\n  return askAiSidePanelConfig.value?.keyboardShortcuts?.['Ctrl/Cmd+I'] !== false\n})\n\ntype OpenTarget = 'search' | 'askAi' | 'toggleAskAi'\ntype OpenRequest = { target: OpenTarget; nonce: number }\nconst openRequest = ref<OpenRequest | null>(null)\nlet openNonce = 0\n\n// to avoid loading the docsearch js upfront (which is more than 1/3 of the\n// payload), we delay initializing it until the user has actually clicked or\n// hit the hotkey to invoke it.\nconst loaded = ref(false)\nconst actuallyLoaded = ref(false)\n\nonMounted(() => {\n  if (!__ALGOLIA__) return\n\n  const id = 'VPAlgoliaPreconnect'\n  if (document.getElementById(id)) return\n\n  const appId =\n    algoliaOptions.value.appId ||\n    (typeof algoliaOptions.value.askAi === 'object'\n      ? algoliaOptions.value.askAi?.appId\n      : undefined)\n\n  if (!appId) return\n\n  const rIC = window.requestIdleCallback || setTimeout\n  rIC(() => {\n    const preconnect = document.createElement('link')\n    preconnect.id = id\n    preconnect.rel = 'preconnect'\n    preconnect.href = `https://${appId}-dsn.algolia.net`\n    preconnect.crossOrigin = ''\n    document.head.appendChild(preconnect)\n  })\n})\n\nif (__ALGOLIA__) {\n  onKeyStroke('k', (event) => {\n    if (\n      resolvedMode.value.showKeywordSearch &&\n      (event.ctrlKey || event.metaKey)\n    ) {\n      event.preventDefault()\n      loadAndOpen('search')\n    }\n  })\n\n  onKeyStroke('i', (event) => {\n    if (\n      askAiSidePanelConfig.value &&\n      askAiShortcutEnabled.value &&\n      (event.ctrlKey || event.metaKey)\n    ) {\n      event.preventDefault()\n      loadAndOpen('askAi')\n    }\n  })\n\n  onKeyStroke('/', (event) => {\n    if (resolvedMode.value.showKeywordSearch && !isEditingContent(event)) {\n      event.preventDefault()\n      loadAndOpen('search')\n    }\n  })\n}\n\nfunction loadAndOpen(target: OpenTarget) {\n  if (!loaded.value) {\n    loaded.value = true\n  }\n\n  // This will either be handled immediately if DocSearch is ready,\n  // or queued by the AlgoliaSearchBox until its instances become ready.\n  openRequest.value = { target, nonce: ++openNonce }\n}\n\n// #endregion\n\n// #region Local Search\n\nconst showSearch = ref(false)\n\nif (__VP_LOCAL_SEARCH__) {\n  onKeyStroke('k', (event) => {\n    if (event.ctrlKey || event.metaKey) {\n      event.preventDefault()\n      showSearch.value = true\n    }\n  })\n\n  onKeyStroke('/', (event) => {\n    if (!isEditingContent(event)) {\n      event.preventDefault()\n      showSearch.value = true\n    }\n  })\n}\n\n// #endregion\n\nfunction isEditingContent(event: KeyboardEvent): boolean {\n  const element = event.target as HTMLElement\n  const tagName = element.tagName\n\n  return (\n    element.isContentEditable ||\n    tagName === 'INPUT' ||\n    tagName === 'SELECT' ||\n    tagName === 'TEXTAREA'\n  )\n}\n</script>\n\n<template>\n  <div class=\"VPNavBarSearch\">\n    <template v-if=\"provider === 'algolia'\">\n      <VPNavBarSearchButton\n        v-if=\"resolvedMode.showKeywordSearch\"\n        :text=\"algoliaOptions.translations?.button?.buttonText || 'Search'\"\n        :aria-label=\"algoliaOptions.translations?.button?.buttonAriaLabel || 'Search'\"\n        :aria-keyshortcuts=\"'/ control+k meta+k'\"\n        @click=\"loadAndOpen('search')\"\n      />\n      <VPNavBarAskAiButton\n        v-if=\"askAiSidePanelConfig\"\n        :aria-label=\"askAiSidePanelConfig.button?.translations?.buttonAriaLabel || 'Ask AI'\"\n        :aria-keyshortcuts=\"askAiShortcutEnabled ? 'control+i meta+i' : undefined\"\n        @click=\"actuallyLoaded ? loadAndOpen('toggleAskAi') : loadAndOpen('askAi')\"\n      />\n      <VPAlgoliaSearchBox\n        v-if=\"loaded\"\n        :algolia-options\n        :open-request\n        @vue:beforeMount=\"actuallyLoaded = true\"\n      />\n    </template>\n    <template v-else-if=\"provider === 'local'\">\n      <VPNavBarSearchButton\n        :text=\"algoliaOptions.translations?.button?.buttonText || 'Search'\"\n        :aria-label=\"algoliaOptions.translations?.button?.buttonAriaLabel || 'Search'\"\n        :aria-keyshortcuts=\"'/ control+k meta+k'\"\n        @click=\"showSearch = true\"\n      />\n      <VPLocalSearchBox\n        v-if=\"showSearch\"\n        @close=\"showSearch = false\"\n      />\n    </template>\n  </div>\n</template>\n\n<style scoped>\n.VPNavBarSearch {\n  display: flex;\n  align-items: center;\n}\n\n@media (min-width: 768px) {\n  .VPNavBarSearch {\n    gap: 8px;\n    flex-grow: 1;\n    padding-left: 24px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPNavBarSearch {\n    padding-left: 32px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarSearchButton.vue",
    "content": "<script lang=\"ts\" setup>\ndefineProps<{\n  text: string\n}>()\n</script>\n\n<template>\n  <button type=\"button\" class=\"VPNavBarSearchButton\">\n    <span class=\"vpi-search\" aria-hidden=\"true\"></span>\n    <span class=\"text\">{{ text }}</span>\n    <span class=\"keys\" aria-hidden=\"true\">\n      <kbd class=\"key-cmd\">&#x2318;</kbd>\n      <kbd class=\"key-ctrl\">Ctrl</kbd>\n      <kbd>K</kbd>\n    </span>\n  </button>\n</template>\n\n<style scoped>\n.VPNavBarSearchButton {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  height: var(--vp-nav-height);\n  padding: 8px 14px;\n  font-size: 20px;\n}\n\n.text,\n.keys,\n:root.mac .key-ctrl,\n:root:not(.mac) .key-cmd {\n  display: none;\n}\n\nkbd {\n  font-family: inherit;\n  font-weight: 500;\n}\n\n@media (min-width: 768px) {\n  .VPNavBarSearchButton {\n    height: auto;\n    padding: 8px 12px;\n    background-color: var(--vp-c-bg-alt);\n    border-radius: 8px;\n    font-size: 14px;\n    line-height: 1;\n    color: var(--vp-c-text-2);\n  }\n\n  .text {\n    display: inline;\n    font-size: 13px;\n  }\n\n  .keys {\n    display: flex;\n    align-items: center;\n    gap: 4px;\n    padding: 4px 6px;\n    border: 1px solid var(--vp-c-divider);\n    border-radius: 4px;\n    font-size: 12px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarSocialLinks.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPSocialLinks from './VPSocialLinks.vue'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <VPSocialLinks\n    v-if=\"theme.socialLinks\"\n    class=\"VPNavBarSocialLinks\"\n    :links=\"theme.socialLinks\"\n  />\n</template>\n\n<style scoped>\n.VPNavBarSocialLinks {\n  display: none;\n}\n\n@media (min-width: 1280px) {\n  .VPNavBarSocialLinks {\n    display: flex;\n    align-items: center;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useData } from '../composables/data'\nimport { useLangs } from '../composables/langs'\nimport { useLayout } from '../composables/layout'\nimport { normalizeLink } from '../support/utils'\nimport VPImage from './VPImage.vue'\n\nconst { site, theme } = useData()\nconst { hasSidebar } = useLayout()\nconst { currentLang } = useLangs()\n\nconst link = computed(() =>\n  typeof theme.value.logoLink === 'string'\n    ? theme.value.logoLink\n    : theme.value.logoLink?.link\n)\n\nconst rel = computed(() =>\n  typeof theme.value.logoLink === 'string'\n    ? undefined\n    : theme.value.logoLink?.rel\n)\n\nconst target = computed(() =>\n  typeof theme.value.logoLink === 'string'\n    ? undefined\n    : theme.value.logoLink?.target\n)\n</script>\n\n<template>\n  <div class=\"VPNavBarTitle\" :class=\"{ 'has-sidebar': hasSidebar }\">\n    <a\n      class=\"title\"\n      :href=\"link ?? normalizeLink(currentLang.link)\"\n      :rel\n      :target\n    >\n      <slot name=\"nav-bar-title-before\" />\n      <VPImage v-if=\"theme.logo\" class=\"logo\" :image=\"theme.logo\" />\n      <span v-if=\"theme.siteTitle\" v-html=\"theme.siteTitle\"></span>\n      <span v-else-if=\"theme.siteTitle === undefined\">{{ site.title }}</span>\n      <slot name=\"nav-bar-title-after\" />\n    </a>\n  </div>\n</template>\n\n<style scoped>\n.title {\n  display: flex;\n  align-items: center;\n  border-bottom: 1px solid transparent;\n  width: 100%;\n  height: var(--vp-nav-height);\n  font-size: 16px;\n  font-weight: 600;\n  color: var(--vp-c-text-1);\n  transition: opacity 0.25s;\n}\n\n@media (min-width: 960px) {\n  .title {\n    flex-shrink: 0;\n  }\n\n  .VPNavBarTitle.has-sidebar .title {\n    border-bottom-color: var(--vp-c-divider);\n  }\n}\n\n:deep(.logo) {\n  margin-right: 8px;\n  height: var(--vp-nav-logo-height);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavBarTranslations.vue",
    "content": "<script lang=\"ts\" setup>\nimport VPFlyout from './VPFlyout.vue'\nimport VPMenuLink from './VPMenuLink.vue'\nimport { useData } from '../composables/data'\nimport { useLangs } from '../composables/langs'\n\nconst { theme } = useData()\nconst { localeLinks, currentLang } = useLangs({ correspondingLink: true })\n</script>\n\n<template>\n  <VPFlyout\n    v-if=\"localeLinks.length && currentLang.label\"\n    class=\"VPNavBarTranslations\"\n    icon=\"vpi-languages\"\n    :label=\"theme.langMenuLabel || 'Change language'\"\n  >\n    <div class=\"items\">\n      <p class=\"title\">{{ currentLang.label }}</p>\n\n      <template v-for=\"locale in localeLinks\" :key=\"locale.link\">\n        <VPMenuLink\n          :item=\"locale\"\n          :lang=\"locale.lang\"\n          :hreflang=\"locale.lang\"\n          rel=\"alternate\"\n          :dir=\"locale.dir\"\n        />\n      </template>\n    </div>\n  </VPFlyout>\n</template>\n\n<style scoped>\n.VPNavBarTranslations {\n  display: none;\n}\n\n@media (min-width: 1280px) {\n  .VPNavBarTranslations {\n    display: flex;\n    align-items: center;\n  }\n}\n\n.title {\n  padding: 0 24px 0 12px;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 700;\n  color: var(--vp-c-text-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreen.vue",
    "content": "<script setup lang=\"ts\">\nimport { useScrollLock } from '@vueuse/core'\nimport { inBrowser } from 'vitepress'\nimport VPNavScreenAppearance from './VPNavScreenAppearance.vue'\nimport VPNavScreenMenu from './VPNavScreenMenu.vue'\nimport VPNavScreenSocialLinks from './VPNavScreenSocialLinks.vue'\nimport VPNavScreenTranslations from './VPNavScreenTranslations.vue'\n\ndefineProps<{\n  open: boolean\n}>()\n\nconst isLocked = useScrollLock(inBrowser ? document.body : null)\n</script>\n\n<template>\n  <transition\n    name=\"fade\"\n    @enter=\"isLocked = true\"\n    @after-leave=\"isLocked = false\"\n  >\n    <div v-if=\"open\" class=\"VPNavScreen\" id=\"VPNavScreen\">\n      <div class=\"container\">\n        <slot name=\"nav-screen-content-before\" />\n        <VPNavScreenMenu class=\"menu\" />\n        <VPNavScreenTranslations class=\"translations\" />\n        <VPNavScreenAppearance class=\"appearance\" />\n        <VPNavScreenSocialLinks class=\"social-links\" />\n        <slot name=\"nav-screen-content-after\" />\n      </div>\n    </div>\n  </transition>\n</template>\n\n<style scoped>\n.VPNavScreen {\n  position: fixed;\n  top: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px));\n  /*rtl:ignore*/\n  right: 0;\n  bottom: 0;\n  /*rtl:ignore*/\n  left: 0;\n  padding: 0 32px;\n  width: 100%;\n  background-color: var(--vp-nav-screen-bg-color);\n  overflow-y: auto;\n  transition: background-color 0.25s;\n  pointer-events: auto;\n}\n\n.VPNavScreen.fade-enter-active,\n.VPNavScreen.fade-leave-active {\n  transition: opacity 0.25s;\n}\n\n.VPNavScreen.fade-enter-active .container,\n.VPNavScreen.fade-leave-active .container {\n  transition: transform 0.25s ease;\n}\n\n.VPNavScreen.fade-enter-from,\n.VPNavScreen.fade-leave-to {\n  opacity: 0;\n}\n\n.VPNavScreen.fade-enter-from .container,\n.VPNavScreen.fade-leave-to .container {\n  transform: translateY(-8px);\n}\n\n@media (min-width: 768px) {\n  .VPNavScreen {\n    display: none;\n  }\n}\n\n.container {\n  margin: 0 auto;\n  padding: 24px 0 96px;\n  max-width: 288px;\n}\n\n.menu + .translations,\n.menu + .appearance,\n.translations + .appearance {\n  margin-top: 24px;\n}\n\n.menu + .social-links {\n  margin-top: 16px;\n}\n\n.appearance + .social-links {\n  margin-top: 16px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenAppearance.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPSwitchAppearance from './VPSwitchAppearance.vue'\n\nconst { site, theme } = useData()\n</script>\n\n<template>\n  <div\n    v-if=\"\n      site.appearance &&\n      site.appearance !== 'force-dark' &&\n      site.appearance !== 'force-auto'\n    \"\n    class=\"VPNavScreenAppearance\"\n  >\n    <p class=\"text\">\n      {{ theme.darkModeSwitchLabel || 'Appearance' }}\n    </p>\n    <VPSwitchAppearance />\n  </div>\n</template>\n\n<style scoped>\n.VPNavScreenAppearance {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-radius: 8px;\n  padding: 12px 14px 12px 16px;\n  background-color: var(--vp-c-bg-soft);\n}\n\n.text {\n  line-height: 24px;\n  font-size: 12px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenMenu.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPNavScreenMenuLink from './VPNavScreenMenuLink.vue'\nimport VPNavScreenMenuGroup from './VPNavScreenMenuGroup.vue'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <nav v-if=\"theme.nav\" class=\"VPNavScreenMenu\">\n    <template v-for=\"item in theme.nav\" :key=\"JSON.stringify(item)\">\n      <VPNavScreenMenuLink v-if=\"'link' in item\" :item />\n      <component\n        v-else-if=\"'component' in item\"\n        :is=\"item.component\"\n        v-bind=\"item.props\"\n        screen-menu\n      />\n      <VPNavScreenMenuGroup\n        v-else\n        :text=\"item.text || ''\"\n        :items=\"item.items\"\n      />\n    </template>\n  </nav>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenMenuGroup.vue",
    "content": "<script lang=\"ts\" setup>\nimport { computed, ref } from 'vue'\nimport VPNavScreenMenuGroupLink from './VPNavScreenMenuGroupLink.vue'\nimport VPNavScreenMenuGroupSection from './VPNavScreenMenuGroupSection.vue'\n\nconst props = defineProps<{\n  text: string\n  items: any[]\n}>()\n\nconst isOpen = ref(false)\n\nconst groupId = computed(\n  () => `NavScreenGroup-${props.text.replace(' ', '-').toLowerCase()}`\n)\n\nfunction toggle() {\n  isOpen.value = !isOpen.value\n}\n</script>\n\n<template>\n  <div class=\"VPNavScreenMenuGroup\" :class=\"{ open: isOpen }\">\n    <button\n      class=\"button\"\n      :aria-controls=\"groupId\"\n      :aria-expanded=\"isOpen\"\n      @click=\"toggle\"\n    >\n      <span class=\"button-text\" v-html=\"text\"></span>\n      <span class=\"vpi-plus button-icon\" />\n    </button>\n\n    <div :id=\"groupId\" class=\"items\">\n      <template v-for=\"item in items\" :key=\"JSON.stringify(item)\">\n        <div v-if=\"'link' in item\" class=\"item\">\n          <VPNavScreenMenuGroupLink :item />\n        </div>\n\n        <div v-else-if=\"'component' in item\" class=\"item\">\n          <component :is=\"item.component\" v-bind=\"item.props\" screen-menu />\n        </div>\n\n        <div v-else class=\"group\">\n          <VPNavScreenMenuGroupSection :text=\"item.text\" :items=\"item.items\" />\n        </div>\n      </template>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPNavScreenMenuGroup {\n  border-bottom: 1px solid var(--vp-c-divider);\n  height: 48px;\n  overflow: hidden;\n  transition: border-color 0.5s;\n}\n\n.VPNavScreenMenuGroup .items {\n  visibility: hidden;\n}\n\n.VPNavScreenMenuGroup.open .items {\n  visibility: visible;\n}\n\n.VPNavScreenMenuGroup.open {\n  padding-bottom: 10px;\n  height: auto;\n}\n\n.VPNavScreenMenuGroup.open .button {\n  padding-bottom: 6px;\n  color: var(--vp-c-brand-1);\n}\n\n.VPNavScreenMenuGroup.open .button-icon {\n  /*rtl:ignore*/\n  transform: rotate(45deg);\n}\n\n.button {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  padding: 12px 4px 11px 0;\n  width: 100%;\n  line-height: 24px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.button:hover {\n  color: var(--vp-c-brand-1);\n}\n\n.button-icon {\n  transition: transform 0.25s;\n}\n\n.group:first-child {\n  padding-top: 0px;\n}\n\n.group + .group,\n.group + .item {\n  padding-top: 4px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenMenuGroupLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed, inject } from 'vue'\nimport { useData } from '../composables/data'\nimport { isActive } from '../../shared'\nimport { navInjectionKey } from '../composables/nav'\nimport VPLink from './VPLink.vue'\n\nconst props = defineProps<{\n  item: DefaultTheme.NavItemWithLink\n}>()\n\nconst { page } = useData()\n\nconst href = computed(() =>\n  typeof props.item.link === 'function'\n    ? props.item.link(page.value)\n    : props.item.link\n)\n\nconst isActiveLink = computed(() =>\n  isActive(\n    page.value.relativePath,\n    props.item.activeMatch || href.value,\n    !!props.item.activeMatch\n  )\n)\n\nconst { closeScreen } = inject(navInjectionKey)!\n</script>\n\n<template>\n  <VPLink\n    :class=\"{ VPNavScreenMenuGroupLink: true, active: isActiveLink }\"\n    :href\n    :target=\"item.target\"\n    :rel=\"item.rel\"\n    :no-icon=\"item.noIcon\"\n    @click=\"closeScreen\"\n  >\n    <span v-html=\"item.text\"></span>\n  </VPLink>\n</template>\n\n<style scoped>\n.VPNavScreenMenuGroupLink {\n  display: block;\n  margin-left: 12px;\n  line-height: 32px;\n  font-size: 14px;\n  font-weight: 400;\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.VPNavScreenMenuGroupLink:hover {\n  color: var(--vp-c-brand-1);\n}\n\n.VPNavScreenMenuGroupLink.active {\n  color: var(--vp-c-brand-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenMenuGroupSection.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPNavScreenMenuGroupLink from './VPNavScreenMenuGroupLink.vue'\n\ndefineProps<{\n  text?: string\n  items: DefaultTheme.NavItemWithLink[]\n}>()\n</script>\n\n<template>\n  <div class=\"VPNavScreenMenuGroupSection\">\n    <p v-if=\"text\" class=\"title\">{{ text }}</p>\n    <VPNavScreenMenuGroupLink v-for=\"item in items\" :key=\"item.text\" :item />\n  </div>\n</template>\n\n<style scoped>\n.VPNavScreenMenuGroupSection {\n  display: block;\n}\n\n.title {\n  line-height: 32px;\n  font-size: 13px;\n  font-weight: 700;\n  color: var(--vp-c-text-2);\n  transition: color 0.25s;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenMenuLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed, inject } from 'vue'\nimport { useData } from '../composables/data'\nimport { isActive } from '../../shared'\nimport { navInjectionKey } from '../composables/nav'\nimport VPLink from './VPLink.vue'\n\nconst props = defineProps<{\n  item: DefaultTheme.NavItemWithLink\n}>()\n\nconst { page } = useData()\n\nconst href = computed(() =>\n  typeof props.item.link === 'function'\n    ? props.item.link(page.value)\n    : props.item.link\n)\n\nconst isActiveLink = computed(() =>\n  isActive(\n    page.value.relativePath,\n    props.item.activeMatch || href.value,\n    !!props.item.activeMatch\n  )\n)\n\nconst { closeScreen } = inject(navInjectionKey)!\n</script>\n\n<template>\n  <VPLink\n    :class=\"{ VPNavScreenMenuLink: true, active: isActiveLink }\"\n    :href\n    :target=\"item.target\"\n    :rel=\"item.rel\"\n    :no-icon=\"item.noIcon\"\n    @click=\"closeScreen\"\n  >\n    <span v-html=\"item.text\"></span>\n  </VPLink>\n</template>\n\n<style scoped>\n.VPNavScreenMenuLink {\n  display: block;\n  border-bottom: 1px solid var(--vp-c-divider);\n  padding: 12px 0 11px;\n  line-height: 24px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n  transition:\n    border-color 0.25s,\n    color 0.25s;\n}\n\n.VPNavScreenMenuLink:hover {\n  color: var(--vp-c-brand-1);\n}\n\n.VPNavScreenMenuLink.active {\n  color: var(--vp-c-brand-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenSocialLinks.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useData } from '../composables/data'\nimport VPSocialLinks from './VPSocialLinks.vue'\n\nconst { theme } = useData()\n</script>\n\n<template>\n  <VPSocialLinks\n    v-if=\"theme.socialLinks\"\n    class=\"VPNavScreenSocialLinks\"\n    :links=\"theme.socialLinks\"\n  />\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPNavScreenTranslations.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { useLangs } from '../composables/langs'\nimport VPLink from './VPLink.vue'\n\nconst { localeLinks, currentLang } = useLangs({ correspondingLink: true })\nconst isOpen = ref(false)\n\nfunction toggle() {\n  isOpen.value = !isOpen.value\n}\n</script>\n\n<template>\n  <div\n    v-if=\"localeLinks.length && currentLang.label\"\n    class=\"VPNavScreenTranslations\"\n    :class=\"{ open: isOpen }\"\n  >\n    <button class=\"title\" @click=\"toggle\">\n      <span class=\"vpi-languages icon lang\" />\n      {{ currentLang.label }}\n      <span class=\"vpi-chevron-down icon chevron\" />\n    </button>\n\n    <ul class=\"list\">\n      <li v-for=\"locale in localeLinks\" :key=\"locale.link\" class=\"item\">\n        <VPLink\n          class=\"link\"\n          :href=\"locale.link\"\n          :lang=\"locale.lang\"\n          :dir=\"locale.dir\"\n        >\n          {{ locale.text }}\n        </VPLink>\n      </li>\n    </ul>\n  </div>\n</template>\n\n<style scoped>\n.VPNavScreenTranslations {\n  height: 24px;\n  overflow: hidden;\n}\n\n.VPNavScreenTranslations.open {\n  height: auto;\n}\n\n.title {\n  display: flex;\n  align-items: center;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-text-1);\n}\n\n.icon {\n  font-size: 16px;\n}\n\n.icon.lang {\n  margin-right: 8px;\n}\n\n.icon.chevron {\n  margin-left: 4px;\n}\n\n.list {\n  padding: 4px 0 0 24px;\n}\n\n.link {\n  line-height: 32px;\n  font-size: 13px;\n  color: var(--vp-c-text-1);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPPage.vue",
    "content": "<template>\n  <div class=\"VPPage\">\n    <slot name=\"page-top\" />\n    <Content />\n    <slot name=\"page-bottom\" />\n  </div>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSidebar.vue",
    "content": "<script lang=\"ts\" setup>\nimport { useScrollLock } from '@vueuse/core'\nimport { inBrowser } from 'vitepress'\nimport { ref, watch } from 'vue'\nimport { useLayout } from '../composables/layout'\nimport VPSidebarGroup from './VPSidebarGroup.vue'\n\nconst { sidebarGroups, hasSidebar } = useLayout()\n\nconst props = defineProps<{\n  open: boolean\n}>()\n\n// a11y: focus Nav element when menu has opened\nconst navEl = ref<HTMLElement | null>(null)\nconst isLocked = useScrollLock(inBrowser ? document.body : null)\n\nwatch(\n  [props, navEl],\n  () => {\n    if (props.open) {\n      isLocked.value = true\n      navEl.value?.focus()\n    } else isLocked.value = false\n  },\n  { immediate: true, flush: 'post' }\n)\n\nconst key = ref(0)\n\nwatch(\n  sidebarGroups,\n  () => {\n    key.value += 1\n  },\n  { deep: true }\n)\n</script>\n\n<template>\n  <aside\n    v-if=\"hasSidebar\"\n    class=\"VPSidebar\"\n    :class=\"{ open }\"\n    ref=\"navEl\"\n    @click.stop\n  >\n    <div class=\"curtain\" />\n\n    <nav\n      class=\"nav\"\n      id=\"VPSidebarNav\"\n      aria-labelledby=\"sidebar-aria-label\"\n      tabindex=\"-1\"\n    >\n      <span class=\"visually-hidden\" id=\"sidebar-aria-label\">\n        Sidebar Navigation\n      </span>\n\n      <slot name=\"sidebar-nav-before\" />\n      <VPSidebarGroup :items=\"sidebarGroups\" :key />\n      <slot name=\"sidebar-nav-after\" />\n    </nav>\n  </aside>\n</template>\n\n<style scoped>\n.VPSidebar {\n  position: fixed;\n  top: var(--vp-layout-top-height, 0px);\n  bottom: 0;\n  left: 0;\n  z-index: var(--vp-z-index-sidebar);\n  padding: 32px 32px 96px;\n  width: calc(100vw - 64px);\n  max-width: 320px;\n  background-color: var(--vp-sidebar-bg-color);\n  opacity: 0;\n  box-shadow: var(--vp-c-shadow-3);\n  overflow-x: hidden;\n  overflow-y: auto;\n  transform: translateX(-100%);\n  transition: opacity 0.5s, transform 0.25s ease;\n  overscroll-behavior: contain;\n}\n\n.VPSidebar.open {\n  opacity: 1;\n  visibility: visible;\n  transform: translateX(0);\n  transition: opacity 0.25s,\n    transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);\n}\n\n.dark .VPSidebar {\n  box-shadow: var(--vp-shadow-1);\n}\n\n@media (min-width: 960px) {\n  .VPSidebar {\n    padding-top: var(--vp-nav-height);\n    width: var(--vp-sidebar-width);\n    max-width: 100%;\n    background-color: var(--vp-sidebar-bg-color);\n    opacity: 1;\n    visibility: visible;\n    box-shadow: none;\n    transform: translateX(0);\n  }\n}\n\n@media (min-width: 1440px) {\n  .VPSidebar {\n    padding-left: max(32px, calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));\n    width: calc((100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px);\n  }\n}\n\n@media (min-width: 960px) {\n  .curtain {\n    position: sticky;\n    top: calc(var(--vp-nav-height) * -1);\n    left: 0;\n    z-index: 1;\n    margin-top: calc(var(--vp-nav-height) * -1);\n    margin-right: -32px;\n    margin-left: -32px;\n    height: var(--vp-nav-height);\n    background-color: var(--vp-sidebar-bg-color);\n  }\n}\n\n.nav {\n  outline: 0;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSidebarGroup.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\nimport VPSidebarItem from './VPSidebarItem.vue'\n\ndefineProps<{\n  items: DefaultTheme.SidebarItem[]\n}>()\n\nconst disableTransition = ref(true)\n\nlet timer: ReturnType<typeof setTimeout> | null = null\n\nonMounted(() => {\n  timer = setTimeout(() => {\n    timer = null\n    disableTransition.value = false\n  }, 300)\n})\n\nonBeforeUnmount(() => {\n  if (timer != null) {\n    clearTimeout(timer)\n    timer = null\n  }\n})\n</script>\n\n<template>\n  <div\n    v-for=\"item in items\"\n    :key=\"item.text\"\n    class=\"group\"\n    :class=\"{ 'no-transition': disableTransition }\"\n  >\n    <VPSidebarItem :item :depth=\"0\" />\n  </div>\n</template>\n\n<style scoped>\n.no-transition :deep(.caret-icon) {\n  transition: none;\n}\n\n.group + .group {\n  border-top: 1px solid var(--vp-c-divider);\n  padding-top: 10px;\n}\n\n@media (min-width: 960px) {\n  .group {\n    padding-top: 10px;\n    width: calc(var(--vp-sidebar-width) - 64px);\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSidebarItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport { useSidebarItemControl } from '../composables/sidebar'\nimport VPLink from './VPLink.vue'\n\nconst props = defineProps<{\n  item: DefaultTheme.SidebarItem\n  depth: number\n}>()\n\nconst {\n  collapsed,\n  collapsible,\n  isLink,\n  isActiveLink,\n  hasActiveLink,\n  hasChildren,\n  toggle\n} = useSidebarItemControl(computed(() => props.item))\n\nconst sectionTag = computed(() => (hasChildren.value ? 'section' : `div`))\n\nconst linkTag = computed(() => (isLink.value ? 'a' : 'div'))\n\nconst textTag = computed(() => {\n  return !hasChildren.value\n    ? 'p'\n    : props.depth + 2 === 7\n      ? 'p'\n      : `h${props.depth + 2}`\n})\n\nconst itemRole = computed(() => (isLink.value ? undefined : 'button'))\n\nconst classes = computed(() => [\n  [`level-${props.depth}`],\n  { collapsible: collapsible.value },\n  { collapsed: collapsed.value },\n  { 'is-link': isLink.value },\n  { 'is-active': isActiveLink.value },\n  { 'has-active': hasActiveLink.value }\n])\n\nfunction onItemInteraction(e: MouseEvent | Event) {\n  if ('key' in e && e.key !== 'Enter') {\n    return\n  }\n  !props.item.link && toggle()\n}\n\nfunction onCaretClick() {\n  props.item.link && toggle()\n}\n</script>\n\n<template>\n  <component :is=\"sectionTag\" class=\"VPSidebarItem\" :class=\"classes\">\n    <div\n      v-if=\"item.text\"\n      class=\"item\"\n      :role=\"itemRole\"\n      v-on=\"\n        item.items\n          ? { click: onItemInteraction, keydown: onItemInteraction }\n          : {}\n      \"\n      :tabindex=\"item.items && 0\"\n    >\n      <div class=\"indicator\" />\n\n      <VPLink\n        v-if=\"item.link\"\n        :tag=\"linkTag\"\n        class=\"link\"\n        :href=\"item.link\"\n        :rel=\"item.rel\"\n        :target=\"item.target\"\n      >\n        <component :is=\"textTag\" class=\"text\" v-html=\"item.text\" />\n      </VPLink>\n      <component v-else :is=\"textTag\" class=\"text\" v-html=\"item.text\" />\n\n      <div\n        v-if=\"item.collapsed != null && item.items && item.items.length\"\n        class=\"caret\"\n        role=\"button\"\n        aria-label=\"toggle section\"\n        @click=\"onCaretClick\"\n        @keydown.enter=\"onCaretClick\"\n        tabindex=\"0\"\n      >\n        <span class=\"vpi-chevron-right caret-icon\" />\n      </div>\n    </div>\n\n    <div v-if=\"item.items && item.items.length\" class=\"items\">\n      <template v-if=\"depth < 5\">\n        <VPSidebarItem\n          v-for=\"i in item.items\"\n          :key=\"i.text\"\n          :item=\"i\"\n          :depth=\"depth + 1\"\n        />\n      </template>\n    </div>\n  </component>\n</template>\n\n<style scoped>\n.VPSidebarItem.level-0 {\n  padding-bottom: 24px;\n}\n\n.VPSidebarItem.collapsed.level-0 {\n  padding-bottom: 10px;\n}\n\n.item {\n  position: relative;\n  display: flex;\n  width: 100%;\n}\n\n.VPSidebarItem.collapsible > .item {\n  cursor: pointer;\n}\n\n.indicator {\n  position: absolute;\n  top: 6px;\n  bottom: 6px;\n  left: -17px;\n  width: 2px;\n  border-radius: 2px;\n  transition: background-color 0.25s;\n}\n\n.VPSidebarItem.level-2.is-active > .item > .indicator,\n.VPSidebarItem.level-3.is-active > .item > .indicator,\n.VPSidebarItem.level-4.is-active > .item > .indicator,\n.VPSidebarItem.level-5.is-active > .item > .indicator {\n  background-color: var(--vp-c-brand-1);\n}\n\n.link {\n  display: flex;\n  align-items: center;\n  flex-grow: 1;\n}\n\n.text {\n  flex-grow: 1;\n  padding: 4px 0;\n  line-height: 24px;\n  font-size: 14px;\n  transition: color 0.25s;\n}\n\n.VPSidebarItem.level-0 .text {\n  font-weight: 700;\n  color: var(--vp-c-text-1);\n}\n\n.VPSidebarItem.level-1 .text,\n.VPSidebarItem.level-2 .text,\n.VPSidebarItem.level-3 .text,\n.VPSidebarItem.level-4 .text,\n.VPSidebarItem.level-5 .text {\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.VPSidebarItem.level-0.is-link > .item > .link:hover .text,\n.VPSidebarItem.level-1.is-link > .item > .link:hover .text,\n.VPSidebarItem.level-2.is-link > .item > .link:hover .text,\n.VPSidebarItem.level-3.is-link > .item > .link:hover .text,\n.VPSidebarItem.level-4.is-link > .item > .link:hover .text,\n.VPSidebarItem.level-5.is-link > .item > .link:hover .text {\n  color: var(--vp-c-brand-1);\n}\n\n.VPSidebarItem.level-0.has-active > .item > .text,\n.VPSidebarItem.level-1.has-active > .item > .text,\n.VPSidebarItem.level-2.has-active > .item > .text,\n.VPSidebarItem.level-3.has-active > .item > .text,\n.VPSidebarItem.level-4.has-active > .item > .text,\n.VPSidebarItem.level-5.has-active > .item > .text,\n.VPSidebarItem.level-0.has-active > .item > .link > .text,\n.VPSidebarItem.level-1.has-active > .item > .link > .text,\n.VPSidebarItem.level-2.has-active > .item > .link > .text,\n.VPSidebarItem.level-3.has-active > .item > .link > .text,\n.VPSidebarItem.level-4.has-active > .item > .link > .text,\n.VPSidebarItem.level-5.has-active > .item > .link > .text {\n  color: var(--vp-c-text-1);\n}\n\n.VPSidebarItem.level-0.is-active > .item .link > .text,\n.VPSidebarItem.level-1.is-active > .item .link > .text,\n.VPSidebarItem.level-2.is-active > .item .link > .text,\n.VPSidebarItem.level-3.is-active > .item .link > .text,\n.VPSidebarItem.level-4.is-active > .item .link > .text,\n.VPSidebarItem.level-5.is-active > .item .link > .text {\n  color: var(--vp-c-brand-1);\n}\n\n.caret {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  margin-right: -7px;\n  width: 32px;\n  height: 32px;\n  color: var(--vp-c-text-3);\n  cursor: pointer;\n  transition: color 0.25s;\n  flex-shrink: 0;\n}\n\n.item:hover .caret {\n  color: var(--vp-c-text-2);\n}\n\n.item:hover .caret:hover {\n  color: var(--vp-c-text-1);\n}\n\n.caret-icon {\n  font-size: 18px;\n  /*rtl:ignore*/\n  transform: rotate(90deg);\n  transition: transform 0.25s;\n}\n\n.VPSidebarItem.collapsed .caret-icon {\n  transform: rotate(0)/*rtl:rotate(180deg)*/;\n}\n\n.VPSidebarItem.level-1 .items,\n.VPSidebarItem.level-2 .items,\n.VPSidebarItem.level-3 .items,\n.VPSidebarItem.level-4 .items,\n.VPSidebarItem.level-5 .items {\n  border-left: 1px solid var(--vp-c-divider);\n  padding-left: 16px;\n}\n\n.VPSidebarItem.collapsed .items {\n  display: none;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSkipLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport { ref, watch } from 'vue'\nimport { useRoute } from 'vitepress'\nimport { useData } from '../composables/data'\n\nconst { theme } = useData()\nconst route = useRoute()\nconst backToTop = ref()\n\nwatch(() => route.path, () => backToTop.value.focus())\n</script>\n\n<template>\n  <span ref=\"backToTop\" tabindex=\"-1\" />\n  <a href=\"#VPContent\" class=\"VPSkipLink visually-hidden\">\n    {{ theme.skipToContentLabel || 'Skip to content' }}\n  </a>\n</template>\n\n<style scoped>\n.VPSkipLink {\n  position: fixed;\n  top: 8px;\n  left: 8px;\n  padding: 8px 16px;\n  z-index: 999;\n  border-radius: 8px;\n  font-size: 12px;\n  font-weight: bold;\n  text-decoration: none;\n  color: var(--vp-c-brand-1);\n  box-shadow: var(--vp-shadow-3);\n  background-color: var(--vp-c-bg);\n}\n\n.VPSkipLink:focus {\n  height: auto;\n  width: auto;\n  clip: auto;\n  clip-path: none;\n}\n\n@media (min-width: 1280px) {\n  .VPSkipLink {\n    top: 14px;\n    left: 16px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSocialLink.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed, nextTick, onMounted, ref, useSSRContext } from 'vue'\nimport type { SSGContext } from '../../shared'\n\nconst props = defineProps<{\n  icon: DefaultTheme.SocialLinkIcon\n  link: string\n  ariaLabel?: string\n  me: boolean\n}>()\n\nconst el = ref<HTMLAnchorElement>()\n\nonMounted(async () => {\n  await nextTick()\n  const span = el.value?.children[0]\n  if (\n    span instanceof HTMLElement &&\n    span.className.startsWith('vpi-social-') &&\n    (getComputedStyle(span).maskImage ||\n      getComputedStyle(span).webkitMaskImage) === 'none'\n  ) {\n    span.style.setProperty(\n      '--icon',\n      `url('https://api.iconify.design/simple-icons/${props.icon}.svg')`\n    )\n  }\n})\n\nconst svg = computed(() => {\n  if (typeof props.icon === 'object') return props.icon.svg\n  return `<span class=\"vpi-social-${props.icon}\"></span>`\n})\n\nif (import.meta.env.SSR) {\n  typeof props.icon === 'string' &&\n    useSSRContext<SSGContext>()?.vpSocialIcons.add(props.icon)\n}\n</script>\n\n<template>\n  <a\n    ref=\"el\"\n    class=\"VPSocialLink no-icon\"\n    :href=\"link\"\n    :aria-label=\"ariaLabel ?? (typeof icon === 'string' ? icon : '')\"\n    target=\"_blank\"\n    :rel=\"me ? 'me noopener' : 'noopener'\"\n    v-html=\"svg\"\n  ></a>\n</template>\n\n<style scoped>\n.VPSocialLink {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  width: 36px;\n  height: 36px;\n  color: var(--vp-c-text-2);\n  transition: color 0.5s;\n}\n\n.VPSocialLink:hover {\n  color: var(--vp-c-text-1);\n  transition: color 0.25s;\n}\n\n.VPSocialLink > :deep(svg),\n.VPSocialLink > :deep([class^=\"vpi-social-\"]) {\n  width: 20px;\n  height: 20px;\n  fill: currentColor;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSocialLinks.vue",
    "content": "<script lang=\"ts\" setup>\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPSocialLink from './VPSocialLink.vue'\n\nwithDefaults(defineProps<{\n  links: DefaultTheme.SocialLink[]\n  me?: boolean\n}>(), {\n  me: true\n})\n</script>\n\n<template>\n  <div class=\"VPSocialLinks\">\n    <VPSocialLink\n      v-for=\"{ link, icon, ariaLabel } in links\"\n      :key=\"link\"\n      :icon\n      :link\n      :ariaLabel\n      :me\n    />\n  </div>\n</template>\n\n<style scoped>\n.VPSocialLinks {\n  display: flex;\n  justify-content: center;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSponsors.vue",
    "content": "<script setup lang=\"ts\">\nimport type { GridSize } from '../composables/sponsor-grid'\nimport type { Sponsor } from './VPSponsorsGrid.vue'\nimport { computed } from 'vue'\nimport VPSponsorsGrid from './VPSponsorsGrid.vue'\n\nexport interface Sponsors {\n  tier?: string\n  size?: GridSize\n  items: Sponsor[]\n}\ninterface Props {\n  mode?: 'normal' | 'aside'\n  tier?: string\n  size?: GridSize\n  data: Sponsors[] | Sponsor[]\n}\nconst props = withDefaults(defineProps<Props>(), {\n  mode: 'normal'\n})\n\nconst sponsors = computed(() => {\n  const isSponsors = props.data.some((s) => {\n    return 'items' in s\n  })\n\n  if (isSponsors) {\n    return props.data as Sponsors[]\n  }\n\n  return [\n    { tier: props.tier, size: props.size, items: props.data as Sponsor[] }\n  ]\n})\n</script>\n\n<template>\n  <div class=\"VPSponsors vp-sponsor\" :class=\"[mode]\">\n    <section\n      v-for=\"(sponsor, index) in sponsors\"\n      :key=\"index\"\n      class=\"vp-sponsor-section\"\n    >\n      <h3 v-if=\"sponsor.tier\" class=\"vp-sponsor-tier\">{{ sponsor.tier }}</h3>\n      <VPSponsorsGrid :size=\"sponsor.size\" :data=\"sponsor.items\" />\n    </section>\n  </div>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSponsorsGrid.vue",
    "content": "<script setup lang=\"ts\">\nimport type { GridSize } from '../composables/sponsor-grid'\nimport { ref } from 'vue'\nimport { useSponsorsGrid } from '../composables/sponsor-grid'\n\nexport interface Sponsor {\n  name: string\n  img: string\n  url: string\n}\ninterface Props {\n  size?: GridSize\n  data: Sponsor[]\n}\nconst props = withDefaults(defineProps<Props>(), {\n  size: 'medium'\n})\n\nconst el = ref(null)\n\nuseSponsorsGrid({ el, size: props.size })\n</script>\n\n<template>\n  <div class=\"VPSponsorsGrid vp-sponsor-grid\" :class=\"[size]\" ref=\"el\">\n    <div\n      v-for=\"sponsor in data\"\n      :key=\"sponsor.name\"\n      class=\"vp-sponsor-grid-item\"\n    >\n      <a\n        class=\"vp-sponsor-grid-link\"\n        :href=\"sponsor.url\"\n        target=\"_blank\"\n        rel=\"sponsored noopener\"\n      >\n        <article class=\"vp-sponsor-grid-box\">\n          <img\n            class=\"vp-sponsor-grid-image\"\n            :src=\"sponsor.img\"\n            :alt=\"sponsor.name\"\n          />\n        </article>\n      </a>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSwitch.vue",
    "content": "<template>\n  <button class=\"VPSwitch\" type=\"button\" role=\"switch\">\n    <span class=\"check\">\n      <span class=\"icon\" v-if=\"$slots.default\">\n        <slot />\n      </span>\n    </span>\n  </button>\n</template>\n\n<style scoped>\n.VPSwitch {\n  position: relative;\n  border-radius: 11px;\n  display: block;\n  width: 40px;\n  height: 22px;\n  flex-shrink: 0;\n  border: 1px solid var(--vp-input-border-color);\n  background-color: var(--vp-input-switch-bg-color);\n  transition: border-color 0.25s !important;\n}\n\n.VPSwitch:hover {\n  border-color: var(--vp-c-brand-1);\n}\n\n.check {\n  position: absolute;\n  top: 1px;\n  /*rtl:ignore*/\n  left: 1px;\n  width: 18px;\n  height: 18px;\n  border-radius: 50%;\n  background-color: var(--vp-c-neutral-inverse);\n  box-shadow: var(--vp-shadow-1);\n  transition: transform 0.25s !important;\n}\n\n.icon {\n  position: relative;\n  display: block;\n  width: 18px;\n  height: 18px;\n  border-radius: 50%;\n  overflow: hidden;\n}\n\n.icon :deep([class^='vpi-']) {\n  position: absolute;\n  top: 3px;\n  left: 3px;\n  width: 12px;\n  height: 12px;\n  color: var(--vp-c-text-2);\n}\n\n.dark .icon :deep([class^='vpi-']) {\n  color: var(--vp-c-text-1);\n  transition: opacity 0.25s !important;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPSwitchAppearance.vue",
    "content": "<script lang=\"ts\" setup>\nimport { inject, ref, watchPostEffect } from 'vue'\nimport { useData } from '../composables/data'\nimport VPSwitch from './VPSwitch.vue'\n\nconst { isDark, theme } = useData()\n\nconst toggleAppearance = inject('toggle-appearance', () => {\n  isDark.value = !isDark.value\n})\n\nconst switchTitle = ref('')\n\nwatchPostEffect(() => {\n  switchTitle.value = isDark.value\n    ? theme.value.lightModeSwitchTitle || 'Switch to light theme'\n    : theme.value.darkModeSwitchTitle || 'Switch to dark theme'\n})\n</script>\n\n<template>\n  <VPSwitch\n    :title=\"switchTitle\"\n    class=\"VPSwitchAppearance\"\n    :aria-checked=\"isDark\"\n    @click=\"toggleAppearance\"\n  >\n    <span class=\"vpi-sun sun\" />\n    <span class=\"vpi-moon moon\" />\n  </VPSwitch>\n</template>\n\n<style scoped>\n.sun {\n  opacity: 1;\n}\n\n.moon {\n  opacity: 0;\n}\n\n.dark .sun {\n  opacity: 0;\n}\n\n.dark .moon {\n  opacity: 1;\n}\n\n.dark .VPSwitchAppearance :deep(.check) {\n  /*rtl:ignore*/\n  transform: translateX(18px);\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPTeamMembers.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { computed } from 'vue'\nimport VPTeamMembersItem from './VPTeamMembersItem.vue'\n\ninterface Props {\n  size?: 'small' | 'medium'\n  members: DefaultTheme.TeamMember[]\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  size: 'medium'\n})\n\nconst classes = computed(() => [props.size, `count-${props.members.length}`])\n</script>\n\n<template>\n  <div class=\"VPTeamMembers\" :class=\"classes\">\n    <div class=\"container\">\n      <div v-for=\"member in members\" :key=\"member.name\" class=\"item\">\n        <VPTeamMembersItem :size :member />\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.VPTeamMembers.small .container {\n  grid-template-columns: repeat(auto-fit, minmax(224px, 1fr));\n}\n\n.VPTeamMembers.small.count-1 .container {\n  max-width: 276px;\n}\n.VPTeamMembers.small.count-2 .container {\n  max-width: calc(276px * 2 + 24px);\n}\n.VPTeamMembers.small.count-3 .container {\n  max-width: calc(276px * 3 + 24px * 2);\n}\n\n.VPTeamMembers.medium .container {\n  grid-template-columns: repeat(auto-fit, minmax(256px, 1fr));\n}\n\n@media (min-width: 375px) {\n  .VPTeamMembers.medium .container {\n    grid-template-columns: repeat(auto-fit, minmax(288px, 1fr));\n  }\n}\n\n.VPTeamMembers.medium.count-1 .container {\n  max-width: 368px;\n}\n.VPTeamMembers.medium.count-2 .container {\n  max-width: calc(368px * 2 + 24px);\n}\n\n.container {\n  display: grid;\n  gap: 24px;\n  margin: 0 auto;\n  max-width: 1152px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPTeamMembersItem.vue",
    "content": "<script setup lang=\"ts\">\nimport type { DefaultTheme } from 'vitepress/theme'\nimport VPLink from './VPLink.vue'\nimport VPSocialLinks from './VPSocialLinks.vue'\n\ninterface Props {\n  size?: 'small' | 'medium'\n  member: DefaultTheme.TeamMember\n}\n\nwithDefaults(defineProps<Props>(), {\n  size: 'medium'\n})\n</script>\n\n<template>\n  <article class=\"VPTeamMembersItem\" :class=\"[size]\">\n    <div class=\"profile\">\n      <figure class=\"avatar\">\n        <img class=\"avatar-img\" :src=\"member.avatar\" :alt=\"member.name\" />\n      </figure>\n      <div class=\"data\">\n        <h1 class=\"name\">\n          {{ member.name }}\n        </h1>\n        <p v-if=\"member.title || member.org\" class=\"affiliation\">\n          <span v-if=\"member.title\" class=\"title\">\n            {{ member.title }}\n          </span>\n          <span v-if=\"member.title && member.org\" class=\"at\"> @ </span>\n          <VPLink\n            v-if=\"member.org\"\n            class=\"org\"\n            :class=\"{ link: member.orgLink }\"\n            :href=\"member.orgLink\"\n            no-icon\n          >\n            {{ member.org }}\n          </VPLink>\n        </p>\n        <p v-if=\"member.desc\" class=\"desc\" v-html=\"member.desc\" />\n        <div v-if=\"member.links\" class=\"links\">\n          <VPSocialLinks :links=\"member.links\" :me=\"false\" />\n        </div>\n      </div>\n    </div>\n    <div v-if=\"member.sponsor\" class=\"sp\">\n      <VPLink class=\"sp-link\" :href=\"member.sponsor\" no-icon>\n        <span class=\"vpi-heart sp-icon\" /> {{ member.actionText || 'Sponsor' }}\n      </VPLink>\n    </div>\n  </article>\n</template>\n\n<style scoped>\n.VPTeamMembersItem {\n  display: flex;\n  flex-direction: column;\n  gap: 2px;\n  border-radius: 12px;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n\n.VPTeamMembersItem.small .profile {\n  padding: 32px;\n}\n\n.VPTeamMembersItem.small .data {\n  padding-top: 20px;\n}\n\n.VPTeamMembersItem.small .avatar {\n  width: 64px;\n  height: 64px;\n}\n\n.VPTeamMembersItem.small .name {\n  line-height: 24px;\n  font-size: 16px;\n}\n\n.VPTeamMembersItem.small .affiliation {\n  padding-top: 4px;\n  line-height: 20px;\n  font-size: 14px;\n}\n\n.VPTeamMembersItem.small .desc {\n  padding-top: 12px;\n  line-height: 20px;\n  font-size: 14px;\n}\n\n.VPTeamMembersItem.small .links {\n  margin: 0 -16px -20px;\n  padding: 10px 0 0;\n}\n\n.VPTeamMembersItem.medium .profile {\n  padding: 48px 32px;\n}\n\n.VPTeamMembersItem.medium .data {\n  padding-top: 24px;\n  text-align: center;\n}\n\n.VPTeamMembersItem.medium .avatar {\n  width: 96px;\n  height: 96px;\n}\n\n.VPTeamMembersItem.medium .name {\n  letter-spacing: 0.15px;\n  line-height: 28px;\n  font-size: 20px;\n}\n\n.VPTeamMembersItem.medium .affiliation {\n  padding-top: 4px;\n  font-size: 16px;\n}\n\n.VPTeamMembersItem.medium .desc {\n  padding-top: 16px;\n  max-width: 288px;\n  font-size: 16px;\n}\n\n.VPTeamMembersItem.medium .links {\n  margin: 0 -16px -12px;\n  padding: 16px 12px 0;\n}\n\n.profile {\n  flex-grow: 1;\n  background-color: var(--vp-c-bg-soft);\n}\n\n.data {\n  text-align: center;\n}\n\n.avatar {\n  position: relative;\n  flex-shrink: 0;\n  margin: 0 auto;\n  border-radius: 50%;\n  box-shadow: var(--vp-shadow-3);\n}\n\n.avatar-img {\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  border-radius: 50%;\n  object-fit: cover;\n}\n\n.name {\n  margin: 0;\n  font-weight: 600;\n}\n\n.affiliation {\n  margin: 0;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.org.link {\n  color: var(--vp-c-text-2);\n  transition: color 0.25s;\n}\n\n.org.link:hover {\n  color: var(--vp-c-brand-1);\n}\n\n.desc {\n  margin: 0 auto;\n}\n\n.desc :deep(a) {\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n  text-decoration-style: dotted;\n  transition: color 0.25s;\n}\n\n.links {\n  display: flex;\n  justify-content: center;\n  height: 56px;\n}\n\n.sp-link {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n  padding: 16px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-c-sponsor);\n  background-color: var(--vp-c-bg-soft);\n  transition: color 0.25s, background-color 0.25s;\n}\n\n.sp .sp-link.link:hover,\n.sp .sp-link.link:focus {\n  outline: none;\n  color: var(--vp-c-white);\n  background-color: var(--vp-c-sponsor);\n}\n\n.sp-icon {\n  margin-right: 8px;\n  font-size: 16px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPTeamPage.vue",
    "content": "<template>\n  <div class=\"VPTeamPage\">\n    <slot />\n  </div>\n</template>\n\n<style scoped>\n.VPTeamPage {\n  margin: 96px 0;\n}\n\n@media (min-width: 768px) {\n  .VPTeamPage {\n    margin: 128px 0;\n  }\n}\n\n.VPHome :slotted(.VPTeamPageTitle) {\n  border-top: 1px solid var(--vp-c-gutter);\n  padding-top: 88px !important;\n}\n\n:slotted(.VPTeamPageSection + .VPTeamPageSection),\n:slotted(.VPTeamMembers + .VPTeamPageSection) {\n  margin-top: 64px;\n}\n\n:slotted(.VPTeamMembers + .VPTeamMembers) {\n  margin-top: 24px;\n}\n\n@media (min-width: 768px) {\n  :slotted(.VPTeamPageTitle + .VPTeamPageSection) {\n    margin-top: 16px;\n  }\n\n  :slotted(.VPTeamPageSection + .VPTeamPageSection),\n  :slotted(.VPTeamMembers + .VPTeamPageSection) {\n    margin-top: 96px;\n  }\n}\n\n:slotted(.VPTeamMembers) {\n  padding: 0 24px;\n}\n\n@media (min-width: 768px) {\n  :slotted(.VPTeamMembers) {\n    padding: 0 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  :slotted(.VPTeamMembers) {\n    padding: 0 64px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPTeamPageSection.vue",
    "content": "<template>\n  <section class=\"VPTeamPageSection\">\n    <div class=\"title\">\n      <div class=\"title-line\" />\n      <h2 v-if=\"$slots.title\" class=\"title-text\">\n        <slot name=\"title\" />\n      </h2>\n    </div>\n    <p v-if=\"$slots.lead\" class=\"lead\">\n      <slot name=\"lead\" />\n    </p>\n    <div v-if=\"$slots.members\" class=\"members\">\n      <slot name=\"members\" />\n    </div>\n  </section>\n</template>\n\n<style scoped>\n.VPTeamPageSection {\n  padding: 0 32px;\n}\n\n@media (min-width: 768px) {\n  .VPTeamPageSection {\n    padding: 0 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPTeamPageSection {\n    padding: 0 64px;\n  }\n}\n\n.title {\n  position: relative;\n  margin: 0 auto;\n  max-width: 1152px;\n  text-align: center;\n  color: var(--vp-c-text-2);\n}\n\n.title-line {\n  position: absolute;\n  top: 16px;\n  left: 0;\n  width: 100%;\n  height: 1px;\n  background-color: var(--vp-c-divider);\n}\n\n.title-text {\n  position: relative;\n  display: inline-block;\n  padding: 0 24px;\n  letter-spacing: 0;\n  line-height: 32px;\n  font-size: 20px;\n  font-weight: 500;\n  background-color: var(--vp-c-bg);\n}\n\n.lead {\n  margin: 0 auto;\n  max-width: 480px;\n  padding-top: 12px;\n  text-align: center;\n  line-height: 24px;\n  font-size: 16px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n.members {\n  padding-top: 40px;\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/VPTeamPageTitle.vue",
    "content": "<template>\n  <div class=\"VPTeamPageTitle\">\n    <h1 v-if=\"$slots.title\" class=\"title\">\n      <slot name=\"title\" />\n    </h1>\n    <p v-if=\"$slots.lead\" class=\"lead\">\n      <slot name=\"lead\" />\n    </p>\n  </div>\n</template>\n\n<style scoped>\n.VPTeamPageTitle {\n  padding: 48px 32px;\n  text-align: center;\n}\n\n@media (min-width: 768px) {\n  .VPTeamPageTitle {\n    padding: 64px 48px 48px;\n  }\n}\n\n@media (min-width: 960px) {\n  .VPTeamPageTitle {\n    padding: 80px 64px 48px;\n  }\n}\n\n.title {\n  letter-spacing: 0;\n  line-height: 44px;\n  font-size: 36px;\n  font-weight: 500;\n}\n\n@media (min-width: 768px) {\n  .title {\n    letter-spacing: -0.5px;\n    line-height: 56px;\n    font-size: 48px;\n  }\n}\n\n.lead {\n  margin: 0 auto;\n  max-width: 512px;\n  padding-top: 12px;\n  line-height: 24px;\n  font-size: 16px;\n  font-weight: 500;\n  color: var(--vp-c-text-2);\n}\n\n@media (min-width: 768px) {\n  .lead {\n    max-width: 592px;\n    letter-spacing: 0.15px;\n    line-height: 28px;\n    font-size: 20px;\n  }\n}\n</style>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconAlignJustify.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M21,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,11,21,11z\" />\n    <path d=\"M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z\" />\n    <path d=\"M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z\" />\n    <path d=\"M21,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,19,21,19z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconAlignLeft.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z\" />\n    <path d=\"M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z\" />\n    <path d=\"M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z\" />\n    <path d=\"M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconAlignRight.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M21,11H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,11,21,11z\" />\n    <path d=\"M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z\" />\n    <path d=\"M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z\" />\n    <path d=\"M21,19H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,19,21,19z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconArrowLeft.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path\n      d=\"M19,11H7.4l5.3-5.3c0.4-0.4,0.4-1,0-1.4s-1-0.4-1.4,0l-7,7c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.1,0.5,0,0.8c0.1,0.1,0.1,0.2,0.2,0.3l7,7c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L7.4,13H19c0.6,0,1-0.4,1-1S19.6,11,19,11z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconArrowRight.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path\n      d=\"M19.9,12.4c0.1-0.2,0.1-0.5,0-0.8c-0.1-0.1-0.1-0.2-0.2-0.3l-7-7c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l5.3,5.3H5c-0.6,0-1,0.4-1,1s0.4,1,1,1h11.6l-5.3,5.3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l7-7C19.8,12.6,19.9,12.5,19.9,12.4z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconChevronDown.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconChevronLeft.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M15,19c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4L10.4,12l5.3,5.3c0.4,0.4,0.4,1,0,1.4C15.5,18.9,15.3,19,15,19z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconChevronRight.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconChevronUp.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M18,16c-0.3,0-0.5-0.1-0.7-0.3L12,10.4l-5.3,5.3c-0.4,0.4-1,0.4-1.4,0s-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4C18.5,15.9,18.3,16,18,16z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconEdit.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path d=\"M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z\" />\n    <path d=\"M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconHeart.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path d=\"M12,22.2c-0.3,0-0.5-0.1-0.7-0.3l-8.8-8.8c-2.5-2.5-2.5-6.7,0-9.2c2.5-2.5,6.7-2.5,9.2,0L12,4.3l0.4-0.4c0,0,0,0,0,0C13.6,2.7,15.2,2,16.9,2c0,0,0,0,0,0c1.7,0,3.4,0.7,4.6,1.9l0,0c1.2,1.2,1.9,2.9,1.9,4.6c0,1.7-0.7,3.4-1.9,4.6l-8.8,8.8C12.5,22.1,12.3,22.2,12,22.2zM7,4C5.9,4,4.7,4.4,3.9,5.3c-1.8,1.8-1.8,4.6,0,6.4l8.1,8.1l8.1-8.1c0.9-0.9,1.3-2,1.3-3.2c0-1.2-0.5-2.3-1.3-3.2l0,0C19.3,4.5,18.2,4,17,4c0,0,0,0,0,0c-1.2,0-2.3,0.5-3.2,1.3c0,0,0,0,0,0l-1.1,1.1c-0.4,0.4-1,0.4-1.4,0l-1.1-1.1C9.4,4.4,8.2,4,7,4z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconLanguages.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M0 0h24v24H0z\" fill=\"none\"></path>\n    <path\n      d=\" M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z \"\n      class=\"css-c4d79v\"\n    ></path>\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconMinus.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path d=\"M22,13H2a1,1,0,0,1,0-2H22a1,1,0,0,1,0,2Z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconMinusSquare.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 24 24\">\n    <path d=\"M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2zM20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z\" />\n    <path d=\"M16,11H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h8c0.6,0,1-0.4,1-1S16.6,11,16,11z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconMoon.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconMoreHorizontal.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <circle cx=\"12\" cy=\"12\" r=\"2\" />\n    <circle cx=\"19\" cy=\"12\" r=\"2\" />\n    <circle cx=\"5\" cy=\"12\" r=\"2\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconPlus.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M18.9,10.9h-6v-6c0-0.6-0.4-1-1-1s-1,0.4-1,1v6h-6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6v6c0,0.6,0.4,1,1,1s1-0.4,1-1v-6h6c0.6,0,1-0.4,1-1S19.5,10.9,18.9,10.9z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconPlusSquare.vue",
    "content": "<template>\n  <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n    <path d=\"M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2z M20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z\" />\n    <path d=\"M16,11h-3V8c0-0.6-0.4-1-1-1s-1,0.4-1,1v3H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h3v3c0,0.6,0.4,1,1,1s1-0.4,1-1v-3h3c0.6,0,1-0.4,1-1S16.6,11,16,11z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/components/icons/VPIconSun.vue",
    "content": "<template>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" viewBox=\"0 0 24 24\">\n    <path d=\"M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z\" />\n    <path d=\"M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z\" />\n    <path d=\"M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z\" />\n    <path d=\"M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z\" />\n    <path d=\"M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z\" />\n    <path d=\"M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z\" />\n    <path d=\"M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z\" />\n    <path d=\"M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z\" />\n    <path d=\"M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z\" />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/client/theme-default/composables/aside.ts",
    "content": "import { useMediaQuery } from '@vueuse/core'\nimport { computed } from 'vue'\nimport { useLayout } from './layout'\n\nexport function useAside() {\n  const { hasSidebar } = useLayout()\n  const is960 = useMediaQuery('(min-width: 960px)')\n  const is1280 = useMediaQuery('(min-width: 1280px)')\n\n  const isAsideEnabled = computed(() => {\n    if (!is1280.value && !is960.value) {\n      return false\n    }\n\n    return hasSidebar.value ? is1280.value : is960.value\n  })\n\n  return {\n    isAsideEnabled\n  }\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/data.ts",
    "content": "import { useData as useData$ } from 'vitepress'\nimport type { DefaultTheme } from 'vitepress/theme'\n\nexport const useData: typeof useData$<DefaultTheme.Config> = useData$\n"
  },
  {
    "path": "src/client/theme-default/composables/edit-link.ts",
    "content": "import { computed } from 'vue'\nimport { useData } from './data'\n\nexport function useEditLink() {\n  const { theme, page } = useData()\n\n  return computed(() => {\n    const { text = 'Edit this page', pattern = '' } = theme.value.editLink || {}\n    let url: string\n    if (typeof pattern === 'function') {\n      url = pattern(page.value)\n    } else {\n      url = pattern.replace(/:path/g, page.value.filePath)\n    }\n\n    return { url, text }\n  })\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/flyout.ts",
    "content": "import { onUnmounted, readonly, type Ref, ref, watch } from 'vue'\nimport { inBrowser } from '../../shared'\n\ninterface UseFlyoutOptions {\n  el: Ref<HTMLElement | undefined>\n  onFocus?(): void\n  onBlur?(): void\n}\n\nexport const focusedElement = ref<HTMLElement>()\n\nlet active = false\nlet listeners = 0\n\nexport function useFlyout(options: UseFlyoutOptions) {\n  const focus = ref(false)\n\n  if (inBrowser) {\n    !active && activateFocusTracking()\n\n    listeners++\n\n    const unwatch = watch(focusedElement, (el) => {\n      if (el === options.el.value || options.el.value?.contains(el!)) {\n        focus.value = true\n        options.onFocus?.()\n      } else {\n        focus.value = false\n        options.onBlur?.()\n      }\n    })\n\n    onUnmounted(() => {\n      unwatch()\n\n      listeners--\n\n      if (!listeners) {\n        deactivateFocusTracking()\n      }\n    })\n  }\n\n  return readonly(focus)\n}\n\nfunction activateFocusTracking() {\n  document.addEventListener('focusin', handleFocusIn)\n  active = true\n  focusedElement.value = document.activeElement as HTMLElement\n}\n\nfunction deactivateFocusTracking() {\n  document.removeEventListener('focusin', handleFocusIn)\n}\n\nfunction handleFocusIn() {\n  focusedElement.value = document.activeElement as HTMLElement\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/langs.ts",
    "content": "import { computed } from 'vue'\nimport { ensureStartingSlash } from '../support/utils'\nimport { useData } from './data'\n\nexport function useLangs({ correspondingLink = false } = {}) {\n  const { site, localeIndex, page, theme, hash } = useData()\n  const currentLang = computed(() => ({\n    label: site.value.locales[localeIndex.value]?.label,\n    link:\n      site.value.locales[localeIndex.value]?.link ||\n      (localeIndex.value === 'root' ? '/' : `/${localeIndex.value}/`)\n  }))\n\n  const localeLinks = computed(() =>\n    Object.entries(site.value.locales).flatMap(([key, value]) =>\n      currentLang.value.label === value.label\n        ? []\n        : {\n            text: value.label,\n            link:\n              normalizeLink(\n                value.link || (key === 'root' ? '/' : `/${key}/`),\n                theme.value.i18nRouting !== false && correspondingLink,\n                page.value.relativePath.slice(\n                  currentLang.value.link.length - 1\n                ),\n                !site.value.cleanUrls\n              ) + hash.value,\n            lang: value.lang,\n            dir: value.dir\n          }\n    )\n  )\n\n  return { localeLinks, currentLang }\n}\n\nfunction normalizeLink(\n  link: string,\n  addPath: boolean,\n  path: string,\n  addExt: boolean\n) {\n  return addPath\n    ? link.replace(/\\/$/, '') +\n        ensureStartingSlash(\n          path\n            .replace(/(^|\\/)index\\.md$/, '$1')\n            .replace(/\\.md$/, addExt ? '.html' : '')\n        )\n    : link\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/layout.ts",
    "content": "import { inBrowser, onContentUpdated, useRoute } from 'vitepress'\nimport type { DefaultTheme, useLayout as expected } from 'vitepress/theme'\nimport {\n  computed,\n  shallowReadonly,\n  shallowRef,\n  watch,\n  type ComputedRef,\n  type InjectionKey\n} from 'vue'\nimport { getSidebar, getSidebarGroups } from '../support/sidebar'\nimport { useData } from './data'\nimport { getHeaders } from './outline'\nimport { useCloseSidebarOnEscape } from './sidebar'\n\nconst headers = shallowRef<DefaultTheme.OutlineItem[]>([])\nconst sidebar = shallowRef<DefaultTheme.SidebarItem[]>([])\n\nconst is960 = shallowRef(false)\n\nexport function useLayout(): ReturnType<typeof expected> {\n  const { frontmatter, theme } = useData()\n\n  const isHome = computed(() => {\n    return !!(frontmatter.value.isHome ?? frontmatter.value.layout === 'home')\n  })\n\n  const hasSidebar = computed(() => {\n    return (\n      frontmatter.value.sidebar !== false &&\n      sidebar.value.length > 0 &&\n      !isHome.value\n    )\n  })\n\n  const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)\n\n  const sidebarGroups = computed(() => {\n    return hasSidebar.value ? getSidebarGroups(sidebar.value) : []\n  })\n\n  const hasAside = computed(() => {\n    if (isHome.value) return false\n    if (frontmatter.value.aside != null) return !!frontmatter.value.aside\n    return theme.value.aside !== false\n  })\n\n  const leftAside = computed(() => {\n    if (!hasAside.value) return false\n    return frontmatter.value.aside == null\n      ? theme.value.aside === 'left'\n      : frontmatter.value.aside === 'left'\n  })\n\n  const hasLocalNav = computed(() => {\n    return headers.value.length > 0\n  })\n\n  return {\n    isHome,\n    sidebar: shallowReadonly(sidebar),\n    sidebarGroups,\n    hasSidebar,\n    isSidebarEnabled,\n    hasAside,\n    leftAside,\n    headers: shallowReadonly(headers),\n    hasLocalNav\n  }\n}\n\ninterface RegisterWatchersOptions {\n  closeSidebar: () => void\n}\n\nexport function registerWatchers({ closeSidebar }: RegisterWatchersOptions) {\n  const { frontmatter, page, theme } = useData()\n\n  watch(\n    () => [page.value.relativePath, theme.value.sidebar] as const,\n    ([relativePath, sidebarConfig]) => {\n      const newSidebar = sidebarConfig\n        ? getSidebar(sidebarConfig, relativePath)\n        : []\n      if (JSON.stringify(newSidebar) !== JSON.stringify(sidebar.value)) {\n        sidebar.value = newSidebar\n      }\n    },\n    { immediate: true, deep: true, flush: 'sync' }\n  )\n\n  onContentUpdated(() => {\n    headers.value = getHeaders(frontmatter.value.outline ?? theme.value.outline)\n  })\n\n  if (inBrowser) {\n    is960.value = window.innerWidth >= 960\n    window.addEventListener(\n      'resize',\n      () => {\n        is960.value = window.innerWidth >= 960\n      },\n      { passive: true }\n    )\n  }\n\n  const route = useRoute()\n  watch(() => route.path, closeSidebar)\n\n  watch(is960, closeSidebar)\n  useCloseSidebarOnEscape(closeSidebar)\n}\n\nexport interface LayoutInfo {\n  heroImageSlotExists: ComputedRef<boolean>\n}\n\nexport const layoutInfoInjectionKey: InjectionKey<LayoutInfo> =\n  Symbol('layout-info')\n"
  },
  {
    "path": "src/client/theme-default/composables/nav.ts",
    "content": "import { useRoute } from 'vitepress'\nimport { ref, watch, type InjectionKey } from 'vue'\n\nexport function useNav() {\n  const isScreenOpen = ref(false)\n\n  function openScreen() {\n    isScreenOpen.value = true\n    window.addEventListener('resize', closeScreenOnTabletWindow)\n  }\n\n  function closeScreen() {\n    isScreenOpen.value = false\n    window.removeEventListener('resize', closeScreenOnTabletWindow)\n  }\n\n  function toggleScreen() {\n    isScreenOpen.value ? closeScreen() : openScreen()\n  }\n\n  /**\n   * Close screen when the user resizes the window wider than tablet size.\n   */\n  function closeScreenOnTabletWindow() {\n    window.outerWidth >= 768 && closeScreen()\n  }\n\n  const route = useRoute()\n  watch(() => route.path, closeScreen)\n\n  return {\n    isScreenOpen,\n    openScreen,\n    closeScreen,\n    toggleScreen\n  }\n}\n\nexport interface NavExposedMethods {\n  closeScreen: () => void\n}\n\nexport const navInjectionKey: InjectionKey<NavExposedMethods> = Symbol('nav')\n"
  },
  {
    "path": "src/client/theme-default/composables/outline.ts",
    "content": "import { getScrollOffset } from 'vitepress'\nimport type { DefaultTheme } from 'vitepress/theme'\nimport { onMounted, onUnmounted, onUpdated, type Ref } from 'vue'\nimport { throttleAndDebounce } from '../support/utils'\nimport { useAside } from './aside'\n\nconst ignoreRE = /\\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\\b/\n\n// cached list of anchor elements from resolveHeaders\nconst resolvedHeaders: { element: HTMLHeadElement; link: string }[] = []\n\nexport function resolveTitle(theme: DefaultTheme.Config): string {\n  return (\n    (typeof theme.outline === 'object' &&\n      !Array.isArray(theme.outline) &&\n      theme.outline.label) ||\n    theme.outlineTitle ||\n    'On this page'\n  )\n}\n\nexport function getHeaders(\n  range: DefaultTheme.Config['outline']\n): DefaultTheme.OutlineItem[] {\n  const headers = [\n    ...document.querySelectorAll(\n      '.VPDoc h1, .VPDoc h2, .VPDoc h3, .VPDoc h4, .VPDoc h5, .VPDoc h6'\n    )\n  ]\n    .filter((el) => el.id && el.hasChildNodes())\n    .map((el) => {\n      const level = Number(el.tagName[1])\n      return {\n        element: el as HTMLHeadElement,\n        title: serializeHeader(el),\n        link: '#' + el.id,\n        level\n      }\n    })\n\n  return resolveHeaders(headers, range)\n}\n\nfunction serializeHeader(h: Element): string {\n  let ret = ''\n  for (const node of h.childNodes) {\n    if (node.nodeType === 1) {\n      if (ignoreRE.test((node as Element).className)) continue\n      ret += node.textContent\n    } else if (node.nodeType === 3) {\n      ret += node.textContent\n    }\n  }\n  return ret.trim()\n}\n\nexport function resolveHeaders(\n  headers: DefaultTheme.OutlineItem[],\n  range?: DefaultTheme.Config['outline']\n): DefaultTheme.OutlineItem[] {\n  if (range === false) {\n    return []\n  }\n\n  const levelsRange =\n    (typeof range === 'object' && !Array.isArray(range)\n      ? range.level\n      : range) || 2\n\n  const [high, low]: [number, number] =\n    typeof levelsRange === 'number'\n      ? [levelsRange, levelsRange]\n      : levelsRange === 'deep'\n        ? [2, 6]\n        : levelsRange\n\n  return buildTree(headers, high, low)\n}\n\nexport function useActiveAnchor(\n  container: Ref<HTMLElement>,\n  marker: Ref<HTMLElement>\n): void {\n  const { isAsideEnabled } = useAside()\n\n  const onScroll = throttleAndDebounce(setActiveLink, 100)\n\n  let prevActiveLink: HTMLAnchorElement | null = null\n\n  onMounted(() => {\n    requestAnimationFrame(setActiveLink)\n    window.addEventListener('scroll', onScroll)\n  })\n\n  onUpdated(() => {\n    // sidebar update means a route change\n    activateLink(location.hash)\n  })\n\n  onUnmounted(() => {\n    window.removeEventListener('scroll', onScroll)\n  })\n\n  function setActiveLink() {\n    if (!isAsideEnabled.value) {\n      return\n    }\n\n    const scrollY = window.scrollY\n    const innerHeight = window.innerHeight\n    const offsetHeight = document.body.offsetHeight\n    const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1\n\n    // resolvedHeaders may be repositioned, hidden or fix positioned\n    const headers = resolvedHeaders\n      .map(({ element, link }) => ({\n        link,\n        top: getAbsoluteTop(element)\n      }))\n      .filter(({ top }) => !Number.isNaN(top))\n      .sort((a, b) => a.top - b.top)\n\n    // no headers available for active link\n    if (!headers.length) {\n      activateLink(null)\n      return\n    }\n\n    // page top\n    if (scrollY < 1) {\n      activateLink(null)\n      return\n    }\n\n    // page bottom - highlight last link\n    if (isBottom) {\n      activateLink(headers[headers.length - 1].link)\n      return\n    }\n\n    // find the last header above the top of viewport\n    let activeLink: string | null = null\n    for (const { link, top } of headers) {\n      if (top > scrollY + getScrollOffset() + 4) {\n        break\n      }\n      activeLink = link\n    }\n    activateLink(activeLink)\n  }\n\n  function activateLink(hash: string | null) {\n    if (prevActiveLink) {\n      prevActiveLink.classList.remove('active')\n    }\n\n    if (hash == null) {\n      prevActiveLink = null\n    } else {\n      prevActiveLink = container.value.querySelector(\n        `a[href=\"${decodeURIComponent(hash)}\"]`\n      )\n    }\n\n    const activeLink = prevActiveLink\n\n    if (activeLink) {\n      activeLink.classList.add('active')\n      marker.value.style.top = activeLink.offsetTop + 39 + 'px'\n      marker.value.style.opacity = '1'\n    } else {\n      marker.value.style.top = '33px'\n      marker.value.style.opacity = '0'\n    }\n  }\n}\n\nfunction getAbsoluteTop(element: HTMLElement): number {\n  let offsetTop = 0\n  while (element !== document.body) {\n    if (element === null) {\n      // child element is:\n      // - not attached to the DOM (display: none)\n      // - set to fixed position (not scrollable)\n      // - body or html element (null offsetParent)\n      return NaN\n    }\n    offsetTop += element.offsetTop\n    element = element.offsetParent as HTMLElement\n  }\n  return offsetTop\n}\n\nfunction buildTree(\n  data: DefaultTheme.OutlineItem[],\n  min: number,\n  max: number\n): DefaultTheme.OutlineItem[] {\n  resolvedHeaders.length = 0\n\n  const result: DefaultTheme.OutlineItem[] = []\n  const stack: (\n    | DefaultTheme.OutlineItem\n    | { level: number; shouldIgnore: true }\n  )[] = []\n\n  data.forEach((item) => {\n    const node = { ...item, children: [] }\n    let parent = stack[stack.length - 1]\n\n    while (parent && parent.level >= node.level) {\n      stack.pop()\n      parent = stack[stack.length - 1]\n    }\n\n    if (\n      node.element.classList.contains('ignore-header') ||\n      (parent && 'shouldIgnore' in parent)\n    ) {\n      stack.push({ level: node.level, shouldIgnore: true })\n      return\n    }\n\n    if (node.level > max || node.level < min) return\n    resolvedHeaders.push({ element: node.element, link: node.link })\n\n    if (parent) parent.children!.push(node)\n    else result.push(node)\n\n    stack.push(node)\n  })\n\n  return result\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/prev-next.ts",
    "content": "import { computed } from 'vue'\nimport { isActive } from '../../shared'\nimport { getFlatSideBarLinks, getSidebar } from '../support/sidebar'\nimport { useData } from './data'\n\nexport function usePrevNext() {\n  const { page, theme, frontmatter } = useData()\n\n  return computed(() => {\n    const sidebar = getSidebar(theme.value.sidebar, page.value.relativePath)\n    const links = getFlatSideBarLinks(sidebar)\n\n    // ignore inner-page links with hashes\n    const candidates = uniqBy(links, (link) => link.link.replace(/[?#].*$/, ''))\n\n    const index = candidates.findIndex((link) => {\n      return isActive(page.value.relativePath, link.link)\n    })\n\n    const hidePrev =\n      (theme.value.docFooter?.prev === false && !frontmatter.value.prev) ||\n      frontmatter.value.prev === false\n\n    const hideNext =\n      (theme.value.docFooter?.next === false && !frontmatter.value.next) ||\n      frontmatter.value.next === false\n\n    return {\n      prev: hidePrev\n        ? undefined\n        : {\n            text:\n              (typeof frontmatter.value.prev === 'string'\n                ? frontmatter.value.prev\n                : typeof frontmatter.value.prev === 'object'\n                  ? frontmatter.value.prev.text\n                  : undefined) ??\n              candidates[index - 1]?.docFooterText ??\n              candidates[index - 1]?.text,\n            link:\n              (typeof frontmatter.value.prev === 'object'\n                ? frontmatter.value.prev.link\n                : undefined) ?? candidates[index - 1]?.link\n          },\n      next: hideNext\n        ? undefined\n        : {\n            text:\n              (typeof frontmatter.value.next === 'string'\n                ? frontmatter.value.next\n                : typeof frontmatter.value.next === 'object'\n                  ? frontmatter.value.next.text\n                  : undefined) ??\n              candidates[index + 1]?.docFooterText ??\n              candidates[index + 1]?.text,\n            link:\n              (typeof frontmatter.value.next === 'object'\n                ? frontmatter.value.next.link\n                : undefined) ?? candidates[index + 1]?.link\n          }\n    } as {\n      prev?: { text?: string; link?: string }\n      next?: { text?: string; link?: string }\n    }\n  })\n}\n\nfunction uniqBy<T>(array: T[], keyFn: (item: T) => any): T[] {\n  const seen = new Set()\n  return array.filter((item) => {\n    const k = keyFn(item)\n    return seen.has(k) ? false : seen.add(k)\n  })\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/sidebar.ts",
    "content": "import type { DefaultTheme } from 'vitepress/theme'\nimport {\n  computed,\n  onMounted,\n  onUnmounted,\n  ref,\n  watch,\n  watchEffect,\n  watchPostEffect,\n  type ComputedRef\n} from 'vue'\nimport { isActive } from '../../shared'\nimport { hasActiveLink as containsActiveLink } from '../support/sidebar'\nimport { useData } from './data'\n\nconst isOpen = ref(false)\n\n/**\n * a11y: cache the element that opened the Sidebar (the menu button) then\n * focus that button again when Menu is closed with Escape key.\n */\nexport function useCloseSidebarOnEscape(close: () => void) {\n  let triggerElement: HTMLButtonElement | undefined\n\n  watchEffect(() => {\n    triggerElement = isOpen.value\n      ? (document.activeElement as HTMLButtonElement)\n      : undefined\n  })\n\n  onMounted(() => {\n    window.addEventListener('keyup', onEscape)\n  })\n\n  onUnmounted(() => {\n    window.removeEventListener('keyup', onEscape)\n  })\n\n  function onEscape(e: KeyboardEvent) {\n    if (e.key === 'Escape' && isOpen.value) {\n      close()\n      triggerElement?.focus()\n    }\n  }\n}\n\nexport function useSidebarControl() {\n  function open() {\n    isOpen.value = true\n  }\n\n  function close() {\n    isOpen.value = false\n  }\n\n  function toggle() {\n    isOpen.value ? close() : open()\n  }\n\n  return {\n    isOpen,\n    open,\n    close,\n    toggle\n  }\n}\n\nexport function useSidebarItemControl(\n  item: ComputedRef<DefaultTheme.SidebarItem>\n) {\n  const { page, hash } = useData()\n\n  const collapsed = ref(false)\n\n  const collapsible = computed(() => {\n    return item.value.collapsed != null\n  })\n\n  const isLink = computed(() => {\n    return !!item.value.link\n  })\n\n  const isActiveLink = ref(false)\n  const updateIsActiveLink = () => {\n    isActiveLink.value = isActive(page.value.relativePath, item.value.link)\n  }\n\n  watch([page, item, hash], updateIsActiveLink)\n  onMounted(updateIsActiveLink)\n\n  const hasActiveLink = computed(() => {\n    if (isActiveLink.value) {\n      return true\n    }\n\n    return item.value.items\n      ? containsActiveLink(page.value.relativePath, item.value.items)\n      : false\n  })\n\n  const hasChildren = computed(() => {\n    return !!(item.value.items && item.value.items.length)\n  })\n\n  watchEffect(() => {\n    collapsed.value = !!(collapsible.value && item.value.collapsed)\n  })\n\n  watchPostEffect(() => {\n    ;(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false)\n  })\n\n  function toggle() {\n    if (collapsible.value) {\n      collapsed.value = !collapsed.value\n    }\n  }\n\n  return {\n    collapsed,\n    collapsible,\n    isLink,\n    isActiveLink,\n    hasActiveLink,\n    hasChildren,\n    toggle\n  }\n}\n"
  },
  {
    "path": "src/client/theme-default/composables/sponsor-grid.ts",
    "content": "import { type Ref, onMounted, onUnmounted } from 'vue'\nimport { throttleAndDebounce } from '../support/utils'\n\nexport interface GridSetting {\n  [size: string]: [number, number][]\n}\n\nexport type GridSize = 'xmini' | 'mini' | 'small' | 'medium' | 'big'\n\nexport interface UseSponsorsGridOptions {\n  el: Ref<HTMLElement | null>\n  size?: GridSize\n}\n\n/**\n * Defines grid configuration for each sponsor size in tuple.\n *\n * [Screen width, Column size]\n *\n * It sets grid size on matching screen size. For example, `[768, 5]` will\n * set 5 columns when screen size is bigger or equal to 768px.\n *\n * Column will set only when item size is bigger than the column size. For\n * example, even we define 5 columns, if we only have 1 sponsor yet, we would\n * like to show it in 1 column to make it stand out.\n */\nconst GridSettings: GridSetting = {\n  xmini: [[0, 2]],\n  mini: [],\n  small: [\n    [920, 6],\n    [768, 5],\n    [640, 4],\n    [480, 3],\n    [0, 2]\n  ],\n  medium: [\n    [960, 5],\n    [832, 4],\n    [640, 3],\n    [480, 2]\n  ],\n  big: [\n    [832, 3],\n    [640, 2]\n  ]\n}\n\nexport function useSponsorsGrid({\n  el,\n  size = 'medium'\n}: UseSponsorsGridOptions) {\n  const onResize = throttleAndDebounce(manage, 100)\n\n  onMounted(() => {\n    manage()\n    window.addEventListener('resize', onResize)\n  })\n\n  onUnmounted(() => {\n    window.removeEventListener('resize', onResize)\n  })\n\n  function manage() {\n    adjustSlots(el.value!, size)\n  }\n}\n\nfunction adjustSlots(el: HTMLElement, size: GridSize) {\n  const tsize = el.children.length\n  const asize = el.querySelectorAll('.vp-sponsor-grid-item:not(.empty)').length\n\n  const grid = setGrid(el, size, asize)\n\n  manageSlots(el, grid, tsize, asize)\n}\n\nfunction setGrid(el: HTMLElement, size: GridSize, items: number) {\n  const settings = GridSettings[size]\n  const screen = window.innerWidth\n\n  let grid = 1\n\n  settings.some(([breakpoint, value]) => {\n    if (screen >= breakpoint) {\n      grid = items < value ? items : value\n      return true\n    }\n  })\n\n  setGridData(el, grid)\n\n  return grid\n}\n\nfunction setGridData(el: HTMLElement, value: number) {\n  el.dataset.vpGrid = String(value)\n}\n\nfunction manageSlots(\n  el: HTMLElement,\n  grid: number,\n  tsize: number,\n  asize: number\n) {\n  const diff = tsize - asize\n  const rem = asize % grid\n  const drem = rem === 0 ? rem : grid - rem\n\n  neutralizeSlots(el, drem - diff)\n}\n\nfunction neutralizeSlots(el: HTMLElement, count: number) {\n  if (count === 0) {\n    return\n  }\n\n  count > 0 ? addSlots(el, count) : removeSlots(el, count * -1)\n}\n\nfunction addSlots(el: HTMLElement, count: number) {\n  for (let i = 0; i < count; i++) {\n    const slot = document.createElement('div')\n\n    slot.classList.add('vp-sponsor-grid-item', 'empty')\n\n    el.append(slot)\n  }\n}\n\nfunction removeSlots(el: HTMLElement, count: number) {\n  for (let i = 0; i < count; i++) {\n    el.removeChild(el.lastElementChild!)\n  }\n}\n"
  },
  {
    "path": "src/client/theme-default/index.ts",
    "content": "import './styles/fonts.css'\n\nexport * from './without-fonts'\nexport { default as default } from './without-fonts'\n"
  },
  {
    "path": "src/client/theme-default/styles/base.css",
    "content": "@layer __vitepress_base {\n  @media (prefers-reduced-motion: reduce) {\n    *,\n    ::before,\n    ::after {\n      animation-delay: -1ms !important;\n      animation-duration: 1ms !important;\n      animation-iteration-count: 1 !important;\n      background-attachment: initial !important;\n      scroll-behavior: auto !important;\n      transition-duration: 0s !important;\n      transition-delay: 0s !important;\n    }\n  }\n\n  *,\n  ::before,\n  ::after {\n    box-sizing: border-box;\n  }\n\n  html {\n    line-height: 1.4;\n    font-size: 16px;\n    -webkit-text-size-adjust: 100%;\n  }\n\n  html.dark {\n    color-scheme: dark;\n  }\n\n  body {\n    margin: 0;\n    width: 100%;\n    min-width: 320px;\n    min-height: 100vh;\n    line-height: 24px;\n    font-family: var(--vp-font-family-base);\n    font-size: 16px;\n    font-weight: 400;\n    color: var(--vp-c-text-1);\n    background-color: var(--vp-c-bg);\n    font-synthesis: style;\n    text-rendering: optimizeLegibility;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n    text-autospace: normal;\n    text-spacing-trim: normal;\n  }\n\n  main {\n    display: block;\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    margin: 0;\n    line-height: 24px;\n    font-size: 16px;\n    font-weight: 400;\n  }\n\n  p {\n    margin: 0;\n  }\n\n  strong,\n  b {\n    font-weight: 600;\n  }\n\n  /**\n     * Avoid 300ms click delay on touch devices that support the `touch-action`\n     * CSS property.\n     *\n     * In particular, unlike most other browsers, IE11+Edge on Windows 10 on\n     * touch devices and IE Mobile 10-11 DON'T remove the click delay when\n     * `<meta name=\"viewport\" content=\"width=device-width\">` is present.\n     * However, they DO support removing the click delay via\n     * `touch-action: manipulation`.\n     *\n     * See:\n     * - http://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch\n     * - http://caniuse.com/#feat=css-touch-action\n     * - http://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay\n     */\n  a,\n  area,\n  button,\n  [role='button'],\n  input,\n  label,\n  select,\n  summary,\n  textarea {\n    touch-action: manipulation;\n  }\n\n  a {\n    color: inherit;\n    text-decoration: inherit;\n  }\n\n  ol,\n  ul {\n    list-style: none;\n    margin: 0;\n    padding: 0;\n  }\n\n  blockquote {\n    margin: 0;\n  }\n\n  pre,\n  code,\n  kbd,\n  samp {\n    font-family: var(--vp-font-family-mono);\n    text-autospace: no-autospace;\n  }\n\n  img,\n  svg,\n  video,\n  canvas,\n  audio,\n  iframe,\n  embed,\n  object {\n    display: block;\n  }\n\n  figure {\n    margin: 0;\n  }\n\n  img,\n  video {\n    max-width: 100%;\n    height: auto;\n  }\n\n  button,\n  input,\n  optgroup,\n  select,\n  textarea {\n    border: 0;\n    padding: 0;\n    line-height: inherit;\n    color: inherit;\n  }\n\n  button {\n    padding: 0;\n    font-family: inherit;\n    background-color: transparent;\n    background-image: none;\n  }\n\n  button:enabled,\n  [role='button']:enabled {\n    cursor: pointer;\n  }\n\n  button:focus,\n  button:focus-visible {\n    outline: 1px dotted;\n    outline: 4px auto -webkit-focus-ring-color;\n  }\n\n  button:focus:not(:focus-visible) {\n    outline: none !important;\n  }\n\n  input:focus,\n  textarea:focus,\n  select:focus {\n    outline: none;\n  }\n\n  table {\n    border-collapse: collapse;\n  }\n\n  input {\n    background-color: transparent;\n  }\n\n  input:-ms-input-placeholder,\n  textarea:-ms-input-placeholder {\n    color: var(--vp-c-text-3);\n  }\n\n  input::-ms-input-placeholder,\n  textarea::-ms-input-placeholder {\n    color: var(--vp-c-text-3);\n  }\n\n  input::placeholder,\n  textarea::placeholder {\n    color: var(--vp-c-text-3);\n  }\n\n  input::-webkit-outer-spin-button,\n  input::-webkit-inner-spin-button {\n    -webkit-appearance: none;\n    margin: 0;\n  }\n\n  input[type='number'] {\n    -moz-appearance: textfield;\n  }\n\n  textarea {\n    resize: vertical;\n  }\n\n  select {\n    -webkit-appearance: none;\n  }\n\n  fieldset {\n    margin: 0;\n    padding: 0;\n  }\n\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6,\n  li,\n  p {\n    overflow-wrap: break-word;\n  }\n\n  vite-error-overlay {\n    z-index: 9999;\n  }\n\n  mjx-container {\n    overflow-x: auto;\n  }\n\n  mjx-container > svg {\n    display: inline-block;\n    margin: auto;\n  }\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/components/custom-block.css",
    "content": ".custom-block {\n  border: 1px solid transparent;\n  border-radius: 8px;\n  padding: 16px 16px 8px;\n  line-height: 24px;\n  font-size: var(--vp-custom-block-font-size);\n  color: var(--vp-c-text-2);\n}\n\n.custom-block.info {\n  border-color: var(--vp-custom-block-info-border);\n  color: var(--vp-custom-block-info-text);\n  background-color: var(--vp-custom-block-info-bg);\n}\n\n.custom-block.info a,\n.custom-block.info code {\n  color: var(--vp-c-brand-1);\n}\n\n.custom-block.info a:hover,\n.custom-block.info a:hover > code {\n  color: var(--vp-c-brand-2);\n}\n\n.custom-block.info code {\n  background-color: var(--vp-custom-block-info-code-bg);\n}\n\n.custom-block.note {\n  border-color: var(--vp-custom-block-note-border);\n  color: var(--vp-custom-block-note-text);\n  background-color: var(--vp-custom-block-note-bg);\n}\n\n.custom-block.note a,\n.custom-block.note code {\n  color: var(--vp-c-brand-1);\n}\n\n.custom-block.note a:hover,\n.custom-block.note a:hover > code {\n  color: var(--vp-c-brand-2);\n}\n\n.custom-block.note code {\n  background-color: var(--vp-custom-block-note-code-bg);\n}\n\n.custom-block.tip {\n  border-color: var(--vp-custom-block-tip-border);\n  color: var(--vp-custom-block-tip-text);\n  background-color: var(--vp-custom-block-tip-bg);\n}\n\n.custom-block.tip a,\n.custom-block.tip code {\n  color: var(--vp-c-tip-1);\n}\n\n.custom-block.tip a:hover,\n.custom-block.tip a:hover > code {\n  color: var(--vp-c-tip-2);\n}\n\n.custom-block.tip code {\n  background-color: var(--vp-custom-block-tip-code-bg);\n}\n\n.custom-block.important {\n  border-color: var(--vp-custom-block-important-border);\n  color: var(--vp-custom-block-important-text);\n  background-color: var(--vp-custom-block-important-bg);\n}\n\n.custom-block.important a,\n.custom-block.important code {\n  color: var(--vp-c-important-1);\n}\n\n.custom-block.important a:hover,\n.custom-block.important a:hover > code {\n  color: var(--vp-c-important-2);\n}\n\n.custom-block.important code {\n  background-color: var(--vp-custom-block-important-code-bg);\n}\n\n.custom-block.warning {\n  border-color: var(--vp-custom-block-warning-border);\n  color: var(--vp-custom-block-warning-text);\n  background-color: var(--vp-custom-block-warning-bg);\n}\n\n.custom-block.warning a,\n.custom-block.warning code {\n  color: var(--vp-c-warning-1);\n}\n\n.custom-block.warning a:hover,\n.custom-block.warning a:hover > code {\n  color: var(--vp-c-warning-2);\n}\n\n.custom-block.warning code {\n  background-color: var(--vp-custom-block-warning-code-bg);\n}\n\n.custom-block.danger {\n  border-color: var(--vp-custom-block-danger-border);\n  color: var(--vp-custom-block-danger-text);\n  background-color: var(--vp-custom-block-danger-bg);\n}\n\n.custom-block.danger a,\n.custom-block.danger code {\n  color: var(--vp-c-danger-1);\n}\n\n.custom-block.danger a:hover,\n.custom-block.danger a:hover > code {\n  color: var(--vp-c-danger-2);\n}\n\n.custom-block.danger code {\n  background-color: var(--vp-custom-block-danger-code-bg);\n}\n\n.custom-block.caution {\n  border-color: var(--vp-custom-block-caution-border);\n  color: var(--vp-custom-block-caution-text);\n  background-color: var(--vp-custom-block-caution-bg);\n}\n\n.custom-block.caution a,\n.custom-block.caution code {\n  color: var(--vp-c-caution-1);\n}\n\n.custom-block.caution a:hover,\n.custom-block.caution a:hover > code {\n  color: var(--vp-c-caution-2);\n}\n\n.custom-block.caution code {\n  background-color: var(--vp-custom-block-caution-code-bg);\n}\n\n.custom-block.details {\n  border-color: var(--vp-custom-block-details-border);\n  color: var(--vp-custom-block-details-text);\n  background-color: var(--vp-custom-block-details-bg);\n}\n\n.custom-block.details a {\n  color: var(--vp-c-brand-1);\n}\n\n.custom-block.details a:hover,\n.custom-block.details a:hover > code {\n  color: var(--vp-c-brand-2);\n}\n\n.custom-block.details code {\n  background-color: var(--vp-custom-block-details-code-bg);\n}\n\n.custom-block-title {\n  font-weight: 600;\n}\n\n.custom-block p + p {\n  margin: 8px 0;\n}\n\n.custom-block.details summary {\n  margin: 0 0 8px;\n  font-weight: 700;\n  cursor: pointer;\n  user-select: none;\n}\n\n.custom-block.details summary + p {\n  margin: 8px 0;\n}\n\n.custom-block a {\n  color: inherit;\n  font-weight: 600;\n  text-decoration: underline;\n  text-underline-offset: 2px;\n  transition: opacity 0.25s;\n}\n\n.custom-block a:hover {\n  opacity: 0.75;\n}\n\n.custom-block code {\n  font-size: var(--vp-custom-block-code-font-size);\n}\n\n.custom-block.custom-block th,\n.custom-block.custom-block blockquote > p {\n  font-size: var(--vp-custom-block-font-size);\n  color: inherit;\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/components/vp-code-group.css",
    "content": ".vp-code-group {\n  margin-top: 16px;\n}\n\n.vp-code-group .tabs {\n  position: relative;\n  display: flex;\n  margin-right: -24px;\n  margin-left: -24px;\n  padding: 0 12px;\n  background-color: var(--vp-code-tab-bg);\n  overflow-x: auto;\n  overflow-y: hidden;\n  box-shadow: inset 0 -1px var(--vp-code-tab-divider);\n}\n\n@media (min-width: 640px) {\n  .vp-code-group .tabs {\n    margin-right: 0;\n    margin-left: 0;\n    border-radius: 8px 8px 0 0;\n  }\n}\n\n.vp-code-group .tabs input {\n  position: fixed;\n  opacity: 0;\n  pointer-events: none;\n}\n\n.vp-code-group .tabs label {\n  position: relative;\n  display: inline-block;\n  border-bottom: 1px solid transparent;\n  padding: 0 12px;\n  line-height: 48px;\n  font-size: 14px;\n  font-weight: 500;\n  color: var(--vp-code-tab-text-color);\n  white-space: nowrap;\n  cursor: pointer;\n  transition: color 0.25s;\n}\n\n.vp-code-group .tabs label::after {\n  position: absolute;\n  right: 8px;\n  bottom: -1px;\n  left: 8px;\n  z-index: 1;\n  height: 2px;\n  border-radius: 2px;\n  content: '';\n  background-color: transparent;\n  transition: background-color 0.25s;\n}\n\n.vp-code-group label:hover {\n  color: var(--vp-code-tab-hover-text-color);\n}\n\n.vp-code-group input:checked + label {\n  color: var(--vp-code-tab-active-text-color);\n}\n\n.vp-code-group input:checked + label::after {\n  background-color: var(--vp-code-tab-active-bar-color);\n}\n\n.vp-code-group div[class*='language-'],\n.vp-block {\n  display: none;\n  margin-top: 0 !important;\n  border-top-left-radius: 0 !important;\n  border-top-right-radius: 0 !important;\n}\n\n.vp-code-group div[class*='language-'].active,\n.vp-block.active {\n  display: block;\n}\n\n.vp-block {\n  padding: 20px 24px;\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/components/vp-code.css",
    "content": ".dark .shiki span {\n  color: var(--shiki-dark, inherit);\n  text-decoration: var(--shiki-dark-text-decoration, inherit);\n  font-weight: var(--shiki-dark-font-weight, inherit);\n}\n\nhtml:not(.dark) .shiki span {\n  color: var(--shiki-light, inherit);\n  text-decoration: var(--shiki-light-text-decoration, inherit);\n  font-weight: var(--shiki-light-font-weight, inherit);\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/components/vp-doc.css",
    "content": "/**\n * Headings\n * -------------------------------------------------------------------------- */\n\n.vp-doc h1,\n.vp-doc h2,\n.vp-doc h3,\n.vp-doc h4,\n.vp-doc h5,\n.vp-doc h6 {\n  position: relative;\n  font-weight: 600;\n  outline: none;\n}\n\n.vp-doc h1 {\n  letter-spacing: -0.02em;\n  line-height: 40px;\n  font-size: 28px;\n}\n\n.vp-doc h2 {\n  margin: 48px 0 16px;\n  border-top: 1px solid var(--vp-c-divider);\n  padding-top: 24px;\n  letter-spacing: -0.02em;\n  line-height: 32px;\n  font-size: 24px;\n}\n\n.vp-doc h3 {\n  margin: 32px 0 0;\n  letter-spacing: -0.01em;\n  line-height: 28px;\n  font-size: 20px;\n}\n\n.vp-doc h4 {\n  margin: 24px 0 0;\n  letter-spacing: -0.01em;\n  line-height: 24px;\n  font-size: 18px;\n}\n\n.vp-doc .header-anchor {\n  position: absolute;\n  top: 0;\n  left: 0;\n  margin-left: -0.87em;\n  font-weight: 500;\n  user-select: none;\n  opacity: 0;\n  text-decoration: none;\n  transition:\n    color 0.25s,\n    opacity 0.25s;\n}\n\n.vp-doc .header-anchor:before {\n  content: var(--vp-header-anchor-symbol);\n}\n\n.vp-doc h1:hover .header-anchor,\n.vp-doc h1 .header-anchor:focus,\n.vp-doc h2:hover .header-anchor,\n.vp-doc h2 .header-anchor:focus,\n.vp-doc h3:hover .header-anchor,\n.vp-doc h3 .header-anchor:focus,\n.vp-doc h4:hover .header-anchor,\n.vp-doc h4 .header-anchor:focus,\n.vp-doc h5:hover .header-anchor,\n.vp-doc h5 .header-anchor:focus,\n.vp-doc h6:hover .header-anchor,\n.vp-doc h6 .header-anchor:focus {\n  opacity: 1;\n}\n\n@media (min-width: 768px) {\n  .vp-doc h1 {\n    letter-spacing: -0.02em;\n    line-height: 40px;\n    font-size: 32px;\n  }\n}\n\n.vp-doc h2 .header-anchor {\n  top: 24px;\n}\n\n/**\n * Paragraph and inline elements\n * -------------------------------------------------------------------------- */\n\n.vp-doc p,\n.vp-doc img,\n.vp-doc summary {\n  margin: 16px 0;\n}\n\n.vp-doc p {\n  line-height: 28px;\n}\n\n.vp-doc blockquote {\n  margin: 16px 0;\n  border-left: 2px solid var(--vp-c-divider);\n  padding-left: 16px;\n  transition: border-color 0.5s;\n  color: var(--vp-c-text-2);\n}\n\n.vp-doc blockquote > p {\n  margin: 0;\n  font-size: 16px;\n  transition: color 0.5s;\n}\n\n.vp-doc a {\n  font-weight: 500;\n  color: var(--vp-c-brand-1);\n  text-decoration: underline;\n  text-underline-offset: 2px;\n  transition:\n    color 0.25s,\n    opacity 0.25s;\n}\n\n.vp-doc a:hover {\n  color: var(--vp-c-brand-2);\n}\n\n.vp-doc strong {\n  font-weight: 600;\n}\n\n/**\n * Lists\n * -------------------------------------------------------------------------- */\n\n.vp-doc ul,\n.vp-doc ol {\n  padding-left: 1.25rem;\n  margin: 16px 0;\n}\n\n.vp-doc ul {\n  list-style: disc;\n}\n\n.vp-doc ol {\n  list-style: decimal;\n}\n\n.vp-doc li + li {\n  margin-top: 8px;\n}\n\n.vp-doc li > ol,\n.vp-doc li > ul {\n  margin: 8px 0 0;\n}\n\n/**\n * Table\n * -------------------------------------------------------------------------- */\n\n.vp-doc table {\n  display: block;\n  border-collapse: collapse;\n  margin: 20px 0;\n  overflow-x: auto;\n}\n\n.vp-doc tr {\n  background-color: var(--vp-c-bg);\n  border-top: 1px solid var(--vp-c-divider);\n  transition: background-color 0.5s;\n}\n\n.vp-doc tr:nth-child(2n) {\n  background-color: var(--vp-c-bg-soft);\n}\n\n.vp-doc th,\n.vp-doc td {\n  border: 1px solid var(--vp-c-divider);\n  padding: 8px 16px;\n}\n\n.vp-doc th {\n  text-align: left;\n  font-size: 14px;\n  font-weight: 600;\n  color: var(--vp-c-text-2);\n  background-color: var(--vp-c-bg-soft);\n}\n\n.vp-doc td {\n  font-size: 14px;\n}\n\n/**\n * Decorational elements\n * -------------------------------------------------------------------------- */\n\n.vp-doc hr {\n  margin: 16px 0;\n  border: none;\n  border-top: 1px solid var(--vp-c-divider);\n}\n\n/**\n * Custom Block\n * -------------------------------------------------------------------------- */\n\n.vp-doc .custom-block {\n  margin: 16px 0;\n}\n\n.vp-doc .custom-block p {\n  margin: 8px 0;\n  line-height: 24px;\n}\n\n.vp-doc .custom-block p:first-child {\n  margin: 0;\n}\n\n.vp-doc .custom-block div[class*='language-'] {\n  margin: 8px 0 !important;\n  border-radius: 8px;\n}\n\n.vp-doc .custom-block div[class*='language-'] code {\n  font-weight: 400;\n  background-color: transparent;\n}\n\n.vp-doc .custom-block .vp-code-group,\n.vp-doc .custom-block [class*='vp-code-block'] {\n  margin-top: 8px;\n}\n\n.vp-doc .custom-block .vp-code-group .tabs {\n  margin: 0;\n  border-radius: 8px 8px 0 0;\n}\n\n.vp-doc .custom-block .vp-code-group div[class*='language-'],\n.vp-doc .custom-block [class*='vp-code-block'] div[class*='language-'] {\n  margin-top: 0 !important;\n}\n\n/**\n * Code\n * -------------------------------------------------------------------------- */\n\n/* inline code */\n.vp-doc :not(pre, h1, h2, h3, h4, h5, h6) > code {\n  font-size: var(--vp-code-font-size);\n  color: var(--vp-code-color);\n}\n\n.vp-doc :not(pre) > code {\n  border-radius: 4px;\n  padding: 3px 6px;\n  background-color: var(--vp-code-bg);\n  transition:\n    color 0.25s,\n    background-color 0.5s;\n}\n\n.vp-doc a > code {\n  color: var(--vp-code-link-color);\n}\n\n.vp-doc a:hover > code {\n  color: var(--vp-code-link-hover-color);\n}\n\n.vp-doc h1 > code,\n.vp-doc h2 > code,\n.vp-doc h3 > code,\n.vp-doc h4 > code {\n  font-size: 0.9em;\n}\n\n.vp-doc div[class*='language-'],\n.vp-block {\n  position: relative;\n  margin: 16px -24px;\n  background-color: var(--vp-code-block-bg);\n  overflow-x: auto;\n  transition: background-color 0.5s;\n}\n\n@media (min-width: 640px) {\n  .vp-doc div[class*='language-'],\n  .vp-block {\n    border-radius: 8px;\n    margin: 16px 0;\n  }\n}\n\n@media (max-width: 639px) {\n  .vp-doc li div[class*='language-'] {\n    border-radius: 8px 0 0 8px;\n  }\n}\n\n.vp-doc div[class*='language-'] + div[class*='language-'],\n.vp-doc div[class$='-api'] + div[class*='language-'],\n.vp-doc div[class*='language-'] + div[class$='-api'] > div[class*='language-'] {\n  margin-top: -8px;\n}\n\n.vp-doc [class*='language-'] pre,\n.vp-doc [class*='language-'] code {\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n}\n\n.vp-doc [class*='language-'] pre {\n  position: relative;\n  z-index: 1;\n  margin: 0;\n  padding: 20px 0;\n  background: transparent;\n  overflow-x: auto;\n  /*rtl:ignore*/\n  text-align: left;\n}\n\n.vp-doc [class*='language-'] code {\n  display: block;\n  padding: 0 24px;\n  width: fit-content;\n  min-width: 100%;\n  line-height: var(--vp-code-line-height);\n  font-size: var(--vp-code-font-size);\n  color: var(--vp-code-block-color);\n  transition: color 0.5s;\n}\n\n.vp-doc [class*='language-'] code .highlighted {\n  background-color: var(--vp-code-line-highlight-color);\n  transition: background-color 0.5s;\n  margin: 0 -24px;\n  padding: 0 24px;\n  width: calc(100% + 2 * 24px);\n  display: inline-block;\n}\n\n.vp-doc [class*='language-'] code .highlighted.error {\n  background-color: var(--vp-code-line-error-color);\n}\n\n.vp-doc [class*='language-'] code .highlighted.warning {\n  background-color: var(--vp-code-line-warning-color);\n}\n\n.vp-doc [class*='language-'] code .diff {\n  transition: background-color 0.5s;\n  margin: 0 -24px;\n  padding: 0 24px;\n  width: calc(100% + 2 * 24px);\n  display: inline-block;\n}\n\n.vp-doc [class*='language-'] code .diff::before {\n  position: absolute;\n  left: 10px;\n}\n\n.vp-doc [class*='language-'] .has-focused-lines .line:not(.has-focus) {\n  filter: blur(0.095rem);\n  opacity: 0.4;\n  transition:\n    filter 0.35s,\n    opacity 0.35s;\n}\n\n.vp-doc [class*='language-'] .has-focused-lines .line:not(.has-focus) {\n  opacity: 0.7;\n  transition:\n    filter 0.35s,\n    opacity 0.35s;\n}\n\n.vp-doc [class*='language-']:hover .has-focused-lines .line:not(.has-focus) {\n  filter: blur(0);\n  opacity: 1;\n}\n\n.vp-doc [class*='language-'] code .diff.remove {\n  background-color: var(--vp-code-line-diff-remove-color);\n  opacity: 0.7;\n}\n\n.vp-doc [class*='language-'] code .diff.remove::before {\n  content: '-';\n  color: var(--vp-code-line-diff-remove-symbol-color);\n}\n\n.vp-doc [class*='language-'] code .diff.add {\n  background-color: var(--vp-code-line-diff-add-color);\n}\n\n.vp-doc [class*='language-'] code .diff.add::before {\n  content: '+';\n  color: var(--vp-code-line-diff-add-symbol-color);\n}\n\n.vp-doc div[class*='language-'].line-numbers-mode {\n  /*rtl:ignore*/\n  padding-left: 32px;\n}\n\n.vp-doc .line-numbers-wrapper {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  /*rtl:ignore*/\n  left: 0;\n  z-index: 3;\n  /*rtl:ignore*/\n  border-right: 1px solid var(--vp-code-block-divider-color);\n  padding-top: 20px;\n  width: 32px;\n  text-align: center;\n  font-family: var(--vp-font-family-mono);\n  line-height: var(--vp-code-line-height);\n  font-size: var(--vp-code-font-size);\n  color: var(--vp-code-line-number-color);\n  transition:\n    border-color 0.5s,\n    color 0.5s;\n}\n\n.vp-doc [class*='language-'] > button.copy {\n  /*rtl:ignore*/\n  direction: ltr;\n  position: absolute;\n  top: 12px;\n  /*rtl:ignore*/\n  right: 12px;\n  z-index: 3;\n  border: 1px solid var(--vp-code-copy-code-border-color);\n  border-radius: 4px;\n  width: 40px;\n  height: 40px;\n  background-color: var(--vp-code-copy-code-bg);\n  opacity: 0;\n  cursor: pointer;\n  background-image: var(--vp-icon-copy);\n  background-position: 50%;\n  background-size: 20px;\n  background-repeat: no-repeat;\n  transition:\n    border-color 0.25s,\n    background-color 0.25s,\n    opacity 0.25s;\n}\n\n.vp-doc [class*='language-']:hover > button.copy,\n.vp-doc [class*='language-'] > button.copy:focus {\n  opacity: 1;\n}\n\n.vp-doc [class*='language-'] > button.copy:hover,\n.vp-doc [class*='language-'] > button.copy.copied {\n  border-color: var(--vp-code-copy-code-hover-border-color);\n  background-color: var(--vp-code-copy-code-hover-bg);\n}\n\n.vp-doc [class*='language-'] > button.copy.copied,\n.vp-doc [class*='language-'] > button.copy:hover.copied {\n  /*rtl:ignore*/\n  border-radius: 0 4px 4px 0;\n  background-color: var(--vp-code-copy-code-hover-bg);\n  background-image: var(--vp-icon-copied);\n}\n\n.vp-doc [class*='language-'] > button.copy.copied::before,\n.vp-doc [class*='language-'] > button.copy:hover.copied::before {\n  position: relative;\n  top: -1px;\n  /*rtl:ignore*/\n  transform: translateX(calc(-100% - 1px));\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  border: 1px solid var(--vp-code-copy-code-hover-border-color);\n  /*rtl:ignore*/\n  border-right: 0;\n  /*rtl:ignore*/\n  border-radius: 4px 0 0 4px;\n  padding: 0 10px;\n  width: fit-content;\n  height: 40px;\n  text-align: center;\n  font-size: 12px;\n  font-weight: 500;\n  color: var(--vp-code-copy-code-active-text);\n  background-color: var(--vp-code-copy-code-hover-bg);\n  white-space: nowrap;\n  content: var(--vp-code-copy-copied-text-content);\n}\n\n.vp-doc [class*='language-'] > span.lang {\n  position: absolute;\n  top: 2px;\n  /*rtl:ignore*/\n  right: 8px;\n  z-index: 2;\n  font-size: 12px;\n  font-weight: 500;\n  user-select: none;\n  color: var(--vp-code-lang-color);\n  transition:\n    color 0.4s,\n    opacity 0.4s;\n}\n\n.vp-doc [class*='language-']:hover > button.copy + span.lang,\n.vp-doc [class*='language-'] > button.copy:focus + span.lang {\n  opacity: 0;\n}\n\n/**\n * Component: Team\n * -------------------------------------------------------------------------- */\n\n.vp-doc .VPTeamMembers {\n  margin-top: 24px;\n}\n\n.vp-doc .VPTeamMembers.small.count-1 .container {\n  margin: 0 !important;\n  max-width: calc((100% - 24px) / 2) !important;\n}\n\n.vp-doc .VPTeamMembers.small.count-2 .container,\n.vp-doc .VPTeamMembers.small.count-3 .container {\n  max-width: 100% !important;\n}\n\n.vp-doc .VPTeamMembers.medium.count-1 .container {\n  margin: 0 !important;\n  max-width: calc((100% - 24px) / 2) !important;\n}\n\n/**\n * External links\n * -------------------------------------------------------------------------- */\n\n/* prettier-ignore */\n:is(.vp-external-link-icon, .vp-doc a[href*='://'], .vp-doc a[target='_blank']):not(:is(.no-icon, svg a, :has(img, svg)))::after {\n  display: inline-block;\n  margin-top: -1px;\n  margin-left: 4px;\n  width: 11px;\n  height: 11px;\n  background: currentColor;\n  color: var(--vp-c-text-3);\n  flex-shrink: 0;\n  --icon: url(\"data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' %3E%3Cpath d='M0 0h24v24H0V0z' fill='none' /%3E%3Cpath d='M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z' /%3E%3C/svg%3E\");\n  -webkit-mask-image: var(--icon);\n  mask-image: var(--icon);\n  /*rtl:raw:transform: scaleX(-1);*/\n}\n\n.vp-external-link-icon::after {\n  content: '';\n}\n\n/* prettier-ignore */\n.external-link-icon-enabled :is(.vp-doc a[href*='://'], .vp-doc a[target='_blank']):not(:is(.no-icon, svg a, :has(img, svg)))::after {\n  content: '';\n  color: currentColor;\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/components/vp-sponsor.css",
    "content": "/**\n * VPSponsors styles are defined as global because a new class gets\n * allied in onMounted` hook and we can't use scoped style.\n */\n.vp-sponsor {\n  border-radius: 16px;\n  overflow: hidden;\n}\n\n.vp-sponsor.aside {\n  border-radius: 12px;\n}\n\n.vp-sponsor-section + .vp-sponsor-section {\n  margin-top: 4px;\n}\n\n.vp-sponsor-tier {\n  margin: 0 0 4px !important;\n  text-align: center;\n  letter-spacing: 1px !important;\n  line-height: 24px;\n  width: 100%;\n  font-weight: 600;\n  color: var(--vp-c-text-2);\n  background-color: var(--vp-c-bg-soft);\n}\n\n.vp-sponsor.normal .vp-sponsor-tier {\n  padding: 13px 0 11px;\n  font-size: 14px;\n}\n\n.vp-sponsor.aside .vp-sponsor-tier {\n  padding: 9px 0 7px;\n  font-size: 12px;\n}\n\n.vp-sponsor-grid + .vp-sponsor-tier {\n  margin-top: 4px;\n}\n\n.vp-sponsor-grid {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 4px;\n}\n\n.vp-sponsor-grid.xmini .vp-sponsor-grid-link {\n  height: 64px;\n}\n.vp-sponsor-grid.xmini .vp-sponsor-grid-image {\n  max-width: 64px;\n  max-height: 22px;\n}\n\n.vp-sponsor-grid.mini .vp-sponsor-grid-link {\n  height: 72px;\n}\n.vp-sponsor-grid.mini .vp-sponsor-grid-image {\n  max-width: 96px;\n  max-height: 24px;\n}\n\n.vp-sponsor-grid.small .vp-sponsor-grid-link {\n  height: 96px;\n}\n.vp-sponsor-grid.small .vp-sponsor-grid-image {\n  max-width: 96px;\n  max-height: 24px;\n}\n\n.vp-sponsor-grid.medium .vp-sponsor-grid-link {\n  height: 112px;\n}\n.vp-sponsor-grid.medium .vp-sponsor-grid-image {\n  max-width: 120px;\n  max-height: 36px;\n}\n\n.vp-sponsor-grid.big .vp-sponsor-grid-link {\n  height: 184px;\n}\n.vp-sponsor-grid.big .vp-sponsor-grid-image {\n  max-width: 192px;\n  max-height: 56px;\n}\n\n.vp-sponsor-grid[data-vp-grid='2'] .vp-sponsor-grid-item {\n  width: calc((100% - 4px) / 2);\n}\n\n.vp-sponsor-grid[data-vp-grid='3'] .vp-sponsor-grid-item {\n  width: calc((100% - 4px * 2) / 3);\n}\n\n.vp-sponsor-grid[data-vp-grid='4'] .vp-sponsor-grid-item {\n  width: calc((100% - 4px * 3) / 4);\n}\n\n.vp-sponsor-grid[data-vp-grid='5'] .vp-sponsor-grid-item {\n  width: calc((100% - 4px * 4) / 5);\n}\n\n.vp-sponsor-grid[data-vp-grid='6'] .vp-sponsor-grid-item {\n  width: calc((100% - 4px * 5) / 6);\n}\n\n.vp-sponsor-grid-item {\n  flex-shrink: 0;\n  width: 100%;\n  background-color: var(--vp-c-bg-soft);\n  transition: background-color 0.25s;\n}\n\n.vp-sponsor-grid-item:hover {\n  background-color: var(--vp-c-default-soft);\n}\n\n.vp-sponsor-grid-item:hover .vp-sponsor-grid-image {\n  filter: grayscale(0) invert(0);\n}\n\n.vp-sponsor-grid-item.empty:hover {\n  background-color: var(--vp-c-bg-soft);\n}\n\n.dark .vp-sponsor-grid-item:hover {\n  background-color: var(--vp-c-white);\n}\n\n.dark .vp-sponsor-grid-item.empty:hover {\n  background-color: var(--vp-c-bg-soft);\n}\n\n.vp-sponsor-grid-link {\n  display: flex;\n}\n\n.vp-sponsor-grid-box {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  width: 100%;\n}\n\n.vp-sponsor-grid-image {\n  max-width: 100%;\n  filter: grayscale(1);\n  transition: filter 0.25s;\n}\n\n.dark .vp-sponsor-grid-image {\n  filter: grayscale(1) invert(1);\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/docsearch.css",
    "content": "@import '@docsearch/css/dist/style.css';\n@import '@docsearch/css/dist/sidepanel.css';\n\n#vp-docsearch,\n#vp-docsearch-sidepanel,\n.DocSearch-SidepanelButton {\n  display: none;\n}\n\n:root:root {\n  --docsearch-actions-height: auto;\n  --docsearch-actions-width: auto;\n  --docsearch-background-color: var(--vp-c-bg-soft);\n  --docsearch-container-background: var(--vp-backdrop-bg-color);\n  --docsearch-dropdown-menu-background: var(--vp-c-bg-elv);\n  --docsearch-dropdown-menu-item-hover-background: var(--vp-c-default-soft);\n  --docsearch-focus-color: var(--vp-c-brand-1);\n  --docsearch-footer-background: var(--vp-c-bg-alt);\n  --docsearch-highlight-color: var(--vp-c-brand-1);\n  --docsearch-hit-background: var(--vp-c-bg);\n  --docsearch-hit-color: var(--vp-c-text-1);\n  --docsearch-hit-highlight-color: var(--vp-c-brand-soft);\n  --docsearch-icon-color: var(--vp-c-text-2);\n  --docsearch-key-background: var(--vp-code-bg);\n  --docsearch-modal-background: var(--vp-c-bg-soft);\n  --docsearch-muted-color: var(--vp-c-text-2);\n  --docsearch-primary-color: var(--vp-c-brand-1);\n  --docsearch-searchbox-background: var(--vp-c-bg-alt);\n  --docsearch-searchbox-focus-background: transparent;\n  --docsearch-secondary-text-color: var(--vp-c-text-2);\n  --docsearch-sidepanel-accent-muted: var(--vp-c-text-3);\n  --docsearch-sidepanel-text-base: var(--vp-c-text-1);\n  --docsearch-soft-muted-color: var(--vp-c-default-soft);\n  --docsearch-soft-primary-color: var(--vp-c-brand-soft);\n  --docsearch-subtle-color: var(--vp-c-divider);\n  --docsearch-success-color: var(--vp-c-brand-soft);\n  --docsearch-text-color: var(--vp-c-text-1);\n}\n\n:root.dark {\n  --docsearch-modal-shadow: none;\n}\n\n.DocSearch-AskAiScreen-RelatedSources-Item-Link {\n  padding: 8px 12px 8px 10px;\n}\n\n.DocSearch-AskAiScreen-RelatedSources-Item-Link svg {\n  width: 16px;\n  height: 16px;\n}\n\n.DocSearch-AskAiScreen-RelatedSources-Title {\n  padding-bottom: 0;\n  font-size: 12px;\n}\n\n.DocSearch-Clear {\n  padding-right: 6px;\n}\n\n.DocSearch-Commands-Key {\n  padding: 4px;\n  border: 1px solid var(--docsearch-subtle-color);\n  border-radius: 4px;\n}\n\n.DocSearch-Hit a:focus-visible {\n  outline: 2px solid var(--docsearch-focus-color);\n}\n\n.DocSearch-Logo [class^='cls-'] {\n  fill: currentColor;\n}\n\n.DocSearch-Markdown-Content code {\n  padding: 0.2em 0.4em;\n}\n\n.DocSearch-Menu-content {\n  margin-top: -4px;\n  padding: 6px;\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 6px;\n  box-shadow: var(--vp-shadow-2);\n}\n\n.DocSearch-Menu-item {\n  border-radius: 4px;\n}\n\n.DocSearch-SearchBar + .DocSearch-Footer {\n  border-top-color: transparent;\n}\n\n.DocSearch-Sidepanel-Prompt--form {\n  border-color: var(--docsearch-subtle-color);\n  transition: border-color 0.2s;\n}\n\n.DocSearch-Sidepanel-Prompt--submit {\n  background-color: var(--docsearch-soft-primary-color);\n  color: var(--docsearch-primary-color);\n}\n\n.DocSearch-Sidepanel-Prompt--submit:hover {\n  background-color: var(--vp-button-brand-hover-bg);\n  color: var(--vp-button-brand-text);\n}\n\n.DocSearch-Sidepanel-Prompt--submit:disabled,\n.DocSearch-Sidepanel-Prompt--submit[aria-disabled='true'] {\n  background-color: var(--docsearch-soft-muted-color);\n  color: var(--docsearch-muted-color);\n}\n\n.DocSearch-Title {\n  font-size: revert;\n  line-height: revert;\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/fonts.css",
    "content": "/* webfont-marker-begin */\n@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');\n/* webfont-marker-end */\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-cyrillic-ext.woff2') format('woff2');\n  unicode-range:\n    U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-cyrillic.woff2') format('woff2');\n  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-greek-ext.woff2') format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-greek.woff2') format('woff2');\n  unicode-range:\n    U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-vietnamese.woff2') format('woff2');\n  unicode-range:\n    U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,\n    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,\n    U+1EA0-1EF9, U+20AB;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-latin-ext.woff2') format('woff2');\n  unicode-range:\n    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,\n    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,\n    U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-latin.woff2') format('woff2');\n  unicode-range:\n    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,\n    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,\n    U+2215, U+FEFF, U+FFFD;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-cyrillic-ext.woff2') format('woff2');\n  unicode-range:\n    U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-cyrillic.woff2') format('woff2');\n  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-greek-ext.woff2') format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-greek.woff2') format('woff2');\n  unicode-range:\n    U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-vietnamese.woff2') format('woff2');\n  unicode-range:\n    U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,\n    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,\n    U+1EA0-1EF9, U+20AB;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-latin-ext.woff2') format('woff2');\n  unicode-range:\n    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,\n    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,\n    U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n  font-family: Inter;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-latin.woff2') format('woff2');\n  unicode-range:\n    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,\n    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,\n    U+2215, U+FEFF, U+FFFD;\n}\n\n/*\nSome code points in Inter are not compatible with CJK languages.\n\nhttps://www.unicode.org/L2/L2014/14006-sv-western-vs-cjk.pdf\nhttps://www.unicode.org/L2/L2018/18013-svs-proposal.pdf\nhttps://www.unicode.org/L2/L2018/18073-svs-proposal.pdf\nhttps://www.unicode.org/L2/L2023/23212r-quotes-svs-proposal.pdf\n\nhttps://github.com/w3c/clreq/blob/f837ffe4a5501e72c17bd02961ce1b440916624f/local.css#L4\n& U+2015 (similar to U+2014 in Japanese)\n\nAll CJK languages: U+00B7, U+2013, U+2014, U+2015, U+2018, U+2019, U+201C, U+201D, U+2026, U+2E3A\nzh's request: U+007E (Both are fine in ja because unused there)\nzh's request but decision postponed: U+002F (Both are fine in ja; include it into Inter for the time being)\n*/\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-cyrillic-ext.woff2') format('woff2');\n  unicode-range:\n    U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-cyrillic.woff2') format('woff2');\n  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-greek-ext.woff2') format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-greek.woff2') format('woff2');\n  unicode-range:\n    U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-vietnamese.woff2') format('woff2');\n  unicode-range:\n    U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,\n    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,\n    U+1EA0-1EF9, U+20AB;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-latin-ext.woff2') format('woff2');\n  unicode-range:\n    U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020,\n    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n/* Exclude some ambiguous CJK characters. */\n@font-face {\n  font-family: Inter4CJK;\n  font-style: normal;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-roman-latin.woff2') format('woff2');\n  unicode-range:\n    U+0000-007D, U+007F-00B6, U+00B8-00FF, U+0131, U+0152-0153, U+02BB-02BC,\n    U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2016-2017,\n    U+201A-201B, U+201E-2025, U+2027-206F, U+2074, U+20AC, U+2122, U+2191,\n    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-cyrillic-ext.woff2') format('woff2');\n  unicode-range:\n    U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-cyrillic.woff2') format('woff2');\n  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-greek-ext.woff2') format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-greek.woff2') format('woff2');\n  unicode-range:\n    U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-vietnamese.woff2') format('woff2');\n  unicode-range:\n    U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,\n    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,\n    U+1EA0-1EF9, U+20AB;\n}\n\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-latin-ext.woff2') format('woff2');\n  unicode-range:\n    U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020,\n    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n/* Exclude some ambiguous CJK characters. */\n@font-face {\n  font-family: Inter4CJK;\n  font-style: italic;\n  font-weight: 100 900;\n  font-display: swap;\n  src: url('../fonts/inter-italic-latin.woff2') format('woff2');\n  unicode-range:\n    U+0000-007D, U+007F-00B6, U+00B8-00FF, U+0131, U+0152-0153, U+02BB-02BC,\n    U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-2012, U+2016-2017,\n    U+201A-201B, U+201E-2025, U+2027-206F, U+2074, U+20AC, U+2122, U+2191,\n    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n\n/* Generate the subsetted fonts using: `pyftsubset <file>.woff2 --unicodes=\"<range>\" --layout-features+=pnum,tnum --flavor=woff2 --output-file=\"inter-<style>-<subset>.woff2\"` */\n"
  },
  {
    "path": "src/client/theme-default/styles/icons.css",
    "content": "[class^='vpi-'],\n[class*=' vpi-'],\n.vp-icon {\n  width: 1em;\n  height: 1em;\n}\n[class^='vpi-'].bg,\n[class*=' vpi-'].bg,\n.vp-icon.bg {\n  background-size: 100% 100%;\n  background-color: transparent;\n}\n[class^='vpi-']:not(.bg),\n[class*=' vpi-']:not(.bg),\n.vp-icon:not(.bg) {\n  -webkit-mask: var(--icon) no-repeat;\n  mask: var(--icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  mask-size: 100% 100%;\n  background-color: currentColor;\n  color: inherit;\n}\n\n/* internal icons - used under ISC from https://lucide.dev/ */\n.vpi-align-left {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 12H3m14 6H3M21 6H3'/%3E%3C/svg%3E\");\n}\n.vpi-arrow-right,\n.vpi-arrow-down,\n.vpi-arrow-left,\n.vpi-arrow-up {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 12h14m-7-7l7 7l-7 7'/%3E%3C/svg%3E\");\n}\n.vpi-chevron-right,\n.vpi-chevron-down,\n.vpi-chevron-left,\n.vpi-chevron-up {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m9 18l6-6l-6-6'/%3E%3C/svg%3E\");\n}\n.vpi-chevron-down,\n.vpi-arrow-down {\n  /*rtl:ignore*/\n  transform: rotate(90deg);\n}\n.vpi-chevron-left,\n.vpi-arrow-left {\n  /*rtl:ignore*/\n  transform: rotate(180deg);\n}\n.vpi-chevron-up,\n.vpi-arrow-up {\n  /*rtl:ignore*/\n  transform: rotate(-90deg);\n}\n.vpi-square-pen {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3Cpath d='M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-plus {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 12h14m-7-7v14'/%3E%3C/svg%3E\");\n}\n.vpi-sun {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-moon {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 3a6 6 0 0 0 9 9a9 9 0 1 1-9-9'/%3E%3C/svg%3E\");\n}\n.vpi-more-horizontal {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-languages {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m5 8l6 6m-7 0l6-6l2-3M2 5h12M7 2h1m14 20l-5-10l-5 10m2-4h6'/%3E%3C/svg%3E\");\n}\n.vpi-heart {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2c-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z'/%3E%3C/svg%3E\");\n}\n.vpi-search {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='m21 21l-4.34-4.34'/%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-sparkles {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.8'%3E%3Cpath d='M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594zM20 2v4m2-2h-4'/%3E%3Ccircle cx='4' cy='20' r='2'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-layout-list {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='7' height='7' x='3' y='3' rx='1'/%3E%3Crect width='7' height='7' x='3' y='14' rx='1'/%3E%3Cpath d='M14 4h7m-7 5h7m-7 6h7m-7 5h7'/%3E%3C/g%3E%3C/svg%3E\");\n}\n.vpi-delete {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M10 5a2 2 0 0 0-1.344.519l-6.328 5.74a1 1 0 0 0 0 1.481l6.328 5.741A2 2 0 0 0 10 19h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zm2 4l6 6m0-6l-6 6'/%3E%3C/svg%3E\");\n}\n.vpi-corner-down-left {\n  --icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3Cpath d='m9 10l-5 5l5 5'/%3E%3C/g%3E%3C/svg%3E\");\n}\n:root {\n  /* clipboard */\n  --vp-icon-copy: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/g%3E%3C/svg%3E\");\n  /* clipboard-check */\n  --vp-icon-copied: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='rgba(128,128,128,1)' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3Cpath d='m9 14l2 2l4-4'/%3E%3C/g%3E%3C/svg%3E\");\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/utils.css",
    "content": ".visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  white-space: nowrap;\n  clip: rect(0 0 0 0);\n  clip-path: inset(50%);\n  overflow: hidden;\n}\n"
  },
  {
    "path": "src/client/theme-default/styles/vars.css",
    "content": "/**\n * Colors: Solid\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-white: #ffffff;\n  --vp-c-black: #000000;\n\n  --vp-c-neutral: var(--vp-c-black);\n  --vp-c-neutral-inverse: var(--vp-c-white);\n}\n\n.dark {\n  --vp-c-neutral: var(--vp-c-white);\n  --vp-c-neutral-inverse: var(--vp-c-black);\n}\n\n/**\n * Colors: Palette\n *\n * The primitive colors used for accent colors. These colors are referenced\n * by functional colors such as \"Text\", \"Background\", or \"Brand\".\n *\n * Each colors have exact same color scale system with 3 levels of solid\n * colors with different brightness, and 1 soft color.\n *\n * - `XXX-1`: The most solid color used mainly for colored text. It must\n *   satisfy the contrast ratio against when used on top of `XXX-soft`.\n *\n * - `XXX-2`: The color used mainly for hover state of the button.\n *\n * - `XXX-3`: The color for solid background, such as bg color of the button.\n *    It must satisfy the contrast ratio with pure white (#ffffff) text on\n *    top of it.\n *\n * - `XXX-soft`: The color used for subtle background such as custom container\n *    or badges. It must satisfy the contrast ratio when putting `XXX-1` colors\n *    on top of it.\n *\n *    The soft color must be semi transparent alpha channel. This is crucial\n *    because it allows adding multiple \"soft\" colors on top of each other\n *    to create a accent, such as when having inline code block inside\n *    custom containers.\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-gray-1: #dddde3;\n  --vp-c-gray-2: #e4e4e9;\n  --vp-c-gray-3: #ebebef;\n  --vp-c-gray-soft: rgba(142, 150, 170, 0.14);\n\n  --vp-c-indigo-1: #3451b2;\n  --vp-c-indigo-2: #3a5ccc;\n  --vp-c-indigo-3: #5672cd;\n  --vp-c-indigo-soft: rgba(100, 108, 255, 0.14);\n\n  --vp-c-purple-1: #6f42c1;\n  --vp-c-purple-2: #7e4cc9;\n  --vp-c-purple-3: #8e5cd9;\n  --vp-c-purple-soft: rgba(159, 122, 234, 0.14);\n\n  --vp-c-green-1: #18794e;\n  --vp-c-green-2: #299764;\n  --vp-c-green-3: #30a46c;\n  --vp-c-green-soft: rgba(16, 185, 129, 0.14);\n\n  --vp-c-yellow-1: #915930;\n  --vp-c-yellow-2: #946300;\n  --vp-c-yellow-3: #9f6a00;\n  --vp-c-yellow-soft: rgba(234, 179, 8, 0.14);\n\n  --vp-c-red-1: #b8272c;\n  --vp-c-red-2: #d5393e;\n  --vp-c-red-3: #e0575b;\n  --vp-c-red-soft: rgba(244, 63, 94, 0.14);\n\n  --vp-c-sponsor: #db2777;\n}\n\n.dark {\n  --vp-c-gray-1: #515c67;\n  --vp-c-gray-2: #414853;\n  --vp-c-gray-3: #32363f;\n  --vp-c-gray-soft: rgba(101, 117, 133, 0.16);\n\n  --vp-c-indigo-1: #a8b1ff;\n  --vp-c-indigo-2: #5c73e7;\n  --vp-c-indigo-3: #3e63dd;\n  --vp-c-indigo-soft: rgba(100, 108, 255, 0.16);\n\n  --vp-c-purple-1: #c8abfa;\n  --vp-c-purple-2: #a879e6;\n  --vp-c-purple-3: #8e5cd9;\n  --vp-c-purple-soft: rgba(159, 122, 234, 0.16);\n\n  --vp-c-green-1: #3dd68c;\n  --vp-c-green-2: #30a46c;\n  --vp-c-green-3: #298459;\n  --vp-c-green-soft: rgba(16, 185, 129, 0.16);\n\n  --vp-c-yellow-1: #f9b44e;\n  --vp-c-yellow-2: #da8b17;\n  --vp-c-yellow-3: #a46a0a;\n  --vp-c-yellow-soft: rgba(234, 179, 8, 0.16);\n\n  --vp-c-red-1: #f66f81;\n  --vp-c-red-2: #f14158;\n  --vp-c-red-3: #b62a3c;\n  --vp-c-red-soft: rgba(244, 63, 94, 0.16);\n}\n\n/**\n * Colors: Background\n *\n * - `bg`: The bg color used for main screen.\n *\n * - `bg-alt`: The alternative bg color used in places such as \"sidebar\",\n *   or \"code block\".\n *\n * - `bg-elv`: The elevated bg color. This is used at parts where it \"floats\",\n *   such as \"dialog\".\n *\n * - `bg-soft`: The bg color to slightly distinguish some components from\n *   the page. Used for things like \"carbon ads\" or \"table\".\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-bg: #ffffff;\n  --vp-c-bg-alt: #f6f6f7;\n  --vp-c-bg-elv: #ffffff;\n  --vp-c-bg-soft: #f6f6f7;\n}\n\n.dark {\n  --vp-c-bg: #1b1b1f;\n  --vp-c-bg-alt: #161618;\n  --vp-c-bg-elv: #202127;\n  --vp-c-bg-soft: #202127;\n}\n\n/**\n * Colors: Borders\n *\n * - `divider`: This is used for separators. This is used to divide sections\n *   within the same components, such as having separator on \"h2\" heading.\n *\n * - `border`: This is designed for borders on interactive components.\n *   For example this should be used for a button outline.\n *\n * - `gutter`: This is used to divide components in the page. For example\n *   the header and the lest of the page.\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-border: #c2c2c4;\n  --vp-c-divider: #e2e2e3;\n  --vp-c-gutter: #e2e2e3;\n}\n\n.dark {\n  --vp-c-border: #3c3f44;\n  --vp-c-divider: #2e2e32;\n  --vp-c-gutter: #000000;\n}\n\n/**\n * Colors: Text\n *\n * - `text-1`: Used for primary text.\n *\n * - `text-2`: Used for muted texts, such as \"inactive menu\" or \"info texts\".\n *\n * - `text-3`: Used for subtle texts, such as \"placeholders\" or \"caret icon\".\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-text-1: #3c3c43;\n  --vp-c-text-2: #67676c;\n  --vp-c-text-3: #929295;\n}\n\n.dark {\n  --vp-c-text-1: #dfdfd6;\n  --vp-c-text-2: #98989f;\n  --vp-c-text-3: #6a6a71;\n}\n\n/**\n * Colors: Function\n *\n * - `default`: The color used purely for subtle indication without any\n *   special meanings attached to it such as bg color for menu hover state.\n *\n * - `brand`: Used for primary brand colors, such as link text, button with\n *   brand theme, etc.\n *\n * - `tip`: Used to indicate useful information. The default theme uses the\n *   brand color for this by default.\n *\n * - `warning`: Used to indicate warning to the users. Used in custom\n *   container, badges, etc.\n *\n * - `danger`: Used to show error, or dangerous message to the users. Used\n *   in custom container, badges, etc.\n *\n * To understand the scaling system, refer to \"Colors: Palette\" section.\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-default-1: var(--vp-c-gray-1);\n  --vp-c-default-2: var(--vp-c-gray-2);\n  --vp-c-default-3: var(--vp-c-gray-3);\n  --vp-c-default-soft: var(--vp-c-gray-soft);\n\n  --vp-c-brand-1: var(--vp-c-indigo-1);\n  --vp-c-brand-2: var(--vp-c-indigo-2);\n  --vp-c-brand-3: var(--vp-c-indigo-3);\n  --vp-c-brand-soft: var(--vp-c-indigo-soft);\n\n  /* DEPRECATED: Use `--vp-c-brand-1` instead. */\n  --vp-c-brand: var(--vp-c-brand-1);\n\n  --vp-c-tip-1: var(--vp-c-brand-1);\n  --vp-c-tip-2: var(--vp-c-brand-2);\n  --vp-c-tip-3: var(--vp-c-brand-3);\n  --vp-c-tip-soft: var(--vp-c-brand-soft);\n\n  --vp-c-note-1: var(--vp-c-brand-1);\n  --vp-c-note-2: var(--vp-c-brand-2);\n  --vp-c-note-3: var(--vp-c-brand-3);\n  --vp-c-note-soft: var(--vp-c-brand-soft);\n\n  --vp-c-success-1: var(--vp-c-green-1);\n  --vp-c-success-2: var(--vp-c-green-2);\n  --vp-c-success-3: var(--vp-c-green-3);\n  --vp-c-success-soft: var(--vp-c-green-soft);\n\n  --vp-c-important-1: var(--vp-c-purple-1);\n  --vp-c-important-2: var(--vp-c-purple-2);\n  --vp-c-important-3: var(--vp-c-purple-3);\n  --vp-c-important-soft: var(--vp-c-purple-soft);\n\n  --vp-c-warning-1: var(--vp-c-yellow-1);\n  --vp-c-warning-2: var(--vp-c-yellow-2);\n  --vp-c-warning-3: var(--vp-c-yellow-3);\n  --vp-c-warning-soft: var(--vp-c-yellow-soft);\n\n  --vp-c-danger-1: var(--vp-c-red-1);\n  --vp-c-danger-2: var(--vp-c-red-2);\n  --vp-c-danger-3: var(--vp-c-red-3);\n  --vp-c-danger-soft: var(--vp-c-red-soft);\n\n  --vp-c-caution-1: var(--vp-c-red-1);\n  --vp-c-caution-2: var(--vp-c-red-2);\n  --vp-c-caution-3: var(--vp-c-red-3);\n  --vp-c-caution-soft: var(--vp-c-red-soft);\n}\n\n/**\n * Typography\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-font-family-base:\n    'Inter', -apple-system, BlinkMacSystemFont, sans-serif, 'Apple Color Emoji',\n    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n  --vp-font-family-mono:\n    ui-monospace, 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono',\n    'Courier New', monospace;\n  font-optical-sizing: auto;\n}\n\n/* :root and [lang] have the same specificity.\n   [lang] covers the case of e.g. <div lang=\"zh-CN\"> in a non-Chinese page.\n*/\n/* Korean compatibility is unverified, so application of custom Inter to Korean is pending. */\n[lang]:where(:lang(zh, ja)) {\n  --vp-font-family-base:\n    'Inter4CJK', -apple-system, BlinkMacSystemFont, sans-serif,\n    'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n}\n\n[lang]:where(:lang(zh, ja, ko)) {\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6,\n  li,\n  p {\n    line-break: strict;\n  }\n}\n\n/**\n * Shadows\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n  --vp-shadow-2: 0 3px 12px rgba(0, 0, 0, 0.07), 0 1px 4px rgba(0, 0, 0, 0.07);\n  --vp-shadow-3: 0 12px 32px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.08);\n  --vp-shadow-4: 0 14px 44px rgba(0, 0, 0, 0.12), 0 3px 9px rgba(0, 0, 0, 0.12);\n  --vp-shadow-5:\n    0 18px 56px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.16);\n}\n\n/**\n * Z-indexes\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-z-index-footer: 10;\n  --vp-z-index-local-nav: 20;\n  --vp-z-index-nav: 30;\n  --vp-z-index-layout-top: 40;\n  --vp-z-index-backdrop: 50;\n  --vp-z-index-sidebar: 60;\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-z-index-sidebar: 25;\n  }\n}\n\n/**\n * Layouts\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-layout-max-width: 1440px;\n}\n\n/**\n * Component: Header Anchor\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-header-anchor-symbol: '#';\n}\n\n/**\n * Component: Code\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-code-line-height: 1.7;\n  --vp-code-font-size: 0.875em;\n  --vp-code-color: var(--vp-c-brand-1);\n  --vp-code-link-color: var(--vp-c-brand-1);\n  --vp-code-link-hover-color: var(--vp-c-brand-2);\n  --vp-code-bg: var(--vp-c-default-soft);\n\n  --vp-code-block-color: var(--vp-c-text-2);\n  --vp-code-block-bg: var(--vp-c-bg-alt);\n  --vp-code-block-divider-color: var(--vp-c-gutter);\n\n  --vp-code-lang-color: var(--vp-c-text-2);\n\n  --vp-code-line-highlight-color: var(--vp-c-default-soft);\n  --vp-code-line-number-color: var(--vp-c-text-2);\n\n  --vp-code-line-diff-add-color: var(--vp-c-success-soft);\n  --vp-code-line-diff-add-symbol-color: var(--vp-c-success-1);\n\n  --vp-code-line-diff-remove-color: var(--vp-c-danger-soft);\n  --vp-code-line-diff-remove-symbol-color: var(--vp-c-danger-1);\n\n  --vp-code-line-warning-color: var(--vp-c-warning-soft);\n  --vp-code-line-error-color: var(--vp-c-danger-soft);\n\n  --vp-code-copy-code-border-color: var(--vp-c-divider);\n  --vp-code-copy-code-bg: var(--vp-c-bg-soft);\n  --vp-code-copy-code-hover-border-color: var(--vp-c-divider);\n  --vp-code-copy-code-hover-bg: var(--vp-c-bg);\n  --vp-code-copy-code-active-text: var(--vp-c-text-2);\n  --vp-code-copy-copied-text-content: 'Copied';\n\n  --vp-code-tab-divider: var(--vp-code-block-divider-color);\n  --vp-code-tab-text-color: var(--vp-c-text-2);\n  --vp-code-tab-bg: var(--vp-code-block-bg);\n  --vp-code-tab-hover-text-color: var(--vp-c-text-1);\n  --vp-code-tab-active-text-color: var(--vp-c-text-1);\n  --vp-code-tab-active-bar-color: var(--vp-c-brand-1);\n}\n\n:lang(es),\n:lang(pt) {\n  --vp-code-copy-copied-text-content: 'Copiado';\n}\n:lang(fa) {\n  --vp-code-copy-copied-text-content: 'کپی شد';\n}\n:lang(ko) {\n  --vp-code-copy-copied-text-content: '복사됨';\n}\n:lang(ru) {\n  --vp-code-copy-copied-text-content: 'Скопировано';\n}\n:lang(zh) {\n  --vp-code-copy-copied-text-content: '已复制';\n}\n:lang(ja) {\n  --vp-code-copy-copied-text-content: 'コピー完了';\n}\n\n/**\n * Component: Button\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-button-brand-border: transparent;\n  --vp-button-brand-text: var(--vp-c-white);\n  --vp-button-brand-bg: var(--vp-c-brand-3);\n  --vp-button-brand-hover-border: transparent;\n  --vp-button-brand-hover-text: var(--vp-c-white);\n  --vp-button-brand-hover-bg: var(--vp-c-brand-2);\n  --vp-button-brand-active-border: transparent;\n  --vp-button-brand-active-text: var(--vp-c-white);\n  --vp-button-brand-active-bg: var(--vp-c-brand-1);\n\n  --vp-button-alt-border: transparent;\n  --vp-button-alt-text: var(--vp-c-text-1);\n  --vp-button-alt-bg: var(--vp-c-default-3);\n  --vp-button-alt-hover-border: transparent;\n  --vp-button-alt-hover-text: var(--vp-c-text-1);\n  --vp-button-alt-hover-bg: var(--vp-c-default-2);\n  --vp-button-alt-active-border: transparent;\n  --vp-button-alt-active-text: var(--vp-c-text-1);\n  --vp-button-alt-active-bg: var(--vp-c-default-1);\n\n  --vp-button-sponsor-border: var(--vp-c-text-2);\n  --vp-button-sponsor-text: var(--vp-c-text-2);\n  --vp-button-sponsor-bg: transparent;\n  --vp-button-sponsor-hover-border: var(--vp-c-sponsor);\n  --vp-button-sponsor-hover-text: var(--vp-c-sponsor);\n  --vp-button-sponsor-hover-bg: transparent;\n  --vp-button-sponsor-active-border: var(--vp-c-sponsor);\n  --vp-button-sponsor-active-text: var(--vp-c-sponsor);\n  --vp-button-sponsor-active-bg: transparent;\n}\n\n/**\n * Component: Custom Block\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-custom-block-font-size: 14px;\n  --vp-custom-block-code-font-size: 13px;\n\n  --vp-custom-block-info-border: transparent;\n  --vp-custom-block-info-text: var(--vp-c-text-1);\n  --vp-custom-block-info-bg: var(--vp-c-default-soft);\n  --vp-custom-block-info-code-bg: var(--vp-c-default-soft);\n\n  --vp-custom-block-note-border: transparent;\n  --vp-custom-block-note-text: var(--vp-c-text-1);\n  --vp-custom-block-note-bg: var(--vp-c-default-soft);\n  --vp-custom-block-note-code-bg: var(--vp-c-default-soft);\n\n  --vp-custom-block-tip-border: transparent;\n  --vp-custom-block-tip-text: var(--vp-c-text-1);\n  --vp-custom-block-tip-bg: var(--vp-c-tip-soft);\n  --vp-custom-block-tip-code-bg: var(--vp-c-tip-soft);\n\n  --vp-custom-block-important-border: transparent;\n  --vp-custom-block-important-text: var(--vp-c-text-1);\n  --vp-custom-block-important-bg: var(--vp-c-important-soft);\n  --vp-custom-block-important-code-bg: var(--vp-c-important-soft);\n\n  --vp-custom-block-warning-border: transparent;\n  --vp-custom-block-warning-text: var(--vp-c-text-1);\n  --vp-custom-block-warning-bg: var(--vp-c-warning-soft);\n  --vp-custom-block-warning-code-bg: var(--vp-c-warning-soft);\n\n  --vp-custom-block-danger-border: transparent;\n  --vp-custom-block-danger-text: var(--vp-c-text-1);\n  --vp-custom-block-danger-bg: var(--vp-c-danger-soft);\n  --vp-custom-block-danger-code-bg: var(--vp-c-danger-soft);\n\n  --vp-custom-block-caution-border: transparent;\n  --vp-custom-block-caution-text: var(--vp-c-text-1);\n  --vp-custom-block-caution-bg: var(--vp-c-caution-soft);\n  --vp-custom-block-caution-code-bg: var(--vp-c-caution-soft);\n\n  --vp-custom-block-details-border: var(--vp-custom-block-info-border);\n  --vp-custom-block-details-text: var(--vp-custom-block-info-text);\n  --vp-custom-block-details-bg: var(--vp-custom-block-info-bg);\n  --vp-custom-block-details-code-bg: var(--vp-custom-block-info-code-bg);\n}\n\n/**\n * Component: Input\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-input-border-color: var(--vp-c-border);\n  --vp-input-bg-color: var(--vp-c-bg-alt);\n\n  --vp-input-switch-bg-color: var(--vp-c-default-soft);\n}\n\n/**\n * Component: Nav\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-nav-height: 64px;\n  --vp-nav-bg-color: var(--vp-c-bg);\n  --vp-nav-screen-bg-color: var(--vp-c-bg);\n  --vp-nav-logo-height: 24px;\n}\n\n.hide-nav {\n  --vp-nav-height: 0px;\n}\n\n.hide-nav .VPSidebar {\n  --vp-nav-height: 22px;\n}\n\n/**\n * Component: Local Nav\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-local-nav-bg-color: var(--vp-c-bg);\n}\n\n/**\n * Component: Sidebar\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-sidebar-width: 272px;\n  --vp-sidebar-bg-color: var(--vp-c-bg-alt);\n}\n\n/**\n * Colors Backdrop\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-backdrop-bg-color: rgba(0, 0, 0, 0.6);\n}\n\n/**\n * Component: Home\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-home-hero-name-color: var(--vp-c-brand-1);\n  --vp-home-hero-name-background: transparent;\n\n  --vp-home-hero-image-background-image: none;\n  --vp-home-hero-image-filter: none;\n}\n\n/**\n * Component: Badge\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-badge-info-border: transparent;\n  --vp-badge-info-text: var(--vp-c-text-2);\n  --vp-badge-info-bg: var(--vp-c-default-soft);\n\n  --vp-badge-tip-border: transparent;\n  --vp-badge-tip-text: var(--vp-c-tip-1);\n  --vp-badge-tip-bg: var(--vp-c-tip-soft);\n\n  --vp-badge-warning-border: transparent;\n  --vp-badge-warning-text: var(--vp-c-warning-1);\n  --vp-badge-warning-bg: var(--vp-c-warning-soft);\n\n  --vp-badge-danger-border: transparent;\n  --vp-badge-danger-text: var(--vp-c-danger-1);\n  --vp-badge-danger-bg: var(--vp-c-danger-soft);\n}\n\n/**\n * Component: Carbon Ads\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-carbon-ads-text-color: var(--vp-c-text-1);\n  --vp-carbon-ads-poweredby-color: var(--vp-c-text-2);\n  --vp-carbon-ads-bg-color: var(--vp-c-bg-soft);\n  --vp-carbon-ads-hover-text-color: var(--vp-c-brand-1);\n  --vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1);\n}\n\n/**\n  * Component: Local Search\n  * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-local-search-bg: var(--vp-c-bg);\n  --vp-local-search-result-bg: var(--vp-c-bg);\n  --vp-local-search-result-border: var(--vp-c-divider);\n  --vp-local-search-result-selected-bg: var(--vp-c-bg);\n  --vp-local-search-result-selected-border: var(--vp-c-brand-1);\n  --vp-local-search-highlight-bg: var(--vp-c-brand-1);\n  --vp-local-search-highlight-text: var(--vp-c-neutral-inverse);\n}\n"
  },
  {
    "path": "src/client/theme-default/support/docsearch.ts",
    "content": "import type { DefaultTheme } from 'vitepress/theme'\nimport type { DocSearchAskAi } from '../../../../types/docsearch'\nimport { isObject } from '../../shared'\n\nexport type FacetFilter = string | string[] | FacetFilter[]\n\nexport interface ValidatedCredentials {\n  valid: boolean\n  appId?: string\n  apiKey?: string\n  indexName?: string\n}\n\nexport type DocSearchMode = 'auto' | 'sidePanel' | 'hybrid' | 'modal'\n\nexport interface ResolvedMode {\n  mode: DocSearchMode\n  showKeywordSearch: boolean\n  useSidePanel: boolean\n}\n\n/**\n * Resolves the effective mode based on config and available features.\n *\n * - 'auto': infer hybrid vs sidePanel-only from provided config\n * - 'sidePanel': force sidePanel-only even if keyword search is configured\n * - 'hybrid': force hybrid (error if keyword search is not configured)\n * - 'modal': force modal even if sidePanel is configured\n */\nexport function resolveMode(\n  options: Pick<\n    DefaultTheme.AlgoliaSearchOptions,\n    'appId' | 'apiKey' | 'indexName' | 'askAi' | 'mode'\n  >\n): ResolvedMode {\n  const mode = options.mode ?? 'auto'\n  const hasKeyword = hasKeywordSearch(options)\n  const askAi = options.askAi\n  const hasSidePanelConfig = Boolean(\n    askAi && typeof askAi === 'object' && askAi.sidePanel\n  )\n\n  switch (mode) {\n    case 'sidePanel':\n      // Force sidePanel-only - hide keyword search\n      return {\n        mode,\n        showKeywordSearch: false,\n        useSidePanel: true\n      }\n\n    case 'hybrid':\n      // Force hybrid - keyword search must be configured\n      if (!hasKeyword) {\n        console.error(\n          '[vitepress] mode: \"hybrid\" requires keyword search credentials (appId, apiKey, indexName).'\n        )\n      }\n      return {\n        mode,\n        showKeywordSearch: hasKeyword,\n        useSidePanel: true\n      }\n\n    case 'modal':\n      // Force modal - don't use sidepanel for askai, even if configured\n      return {\n        mode,\n        showKeywordSearch: hasKeyword,\n        useSidePanel: false\n      }\n\n    case 'auto':\n    default:\n      // Auto-detect based on config\n      return {\n        mode: 'auto',\n        showKeywordSearch: hasKeyword,\n        useSidePanel: hasSidePanelConfig\n      }\n  }\n}\n\nexport function hasKeywordSearch(\n  options: Pick<\n    DefaultTheme.AlgoliaSearchOptions,\n    'appId' | 'apiKey' | 'indexName'\n  >\n): boolean {\n  return Boolean(options.appId && options.apiKey && options.indexName)\n}\n\nexport function hasAskAi(\n  askAi: DefaultTheme.AlgoliaSearchOptions['askAi']\n): boolean {\n  if (!askAi) return false\n  if (typeof askAi === 'string') return askAi.length > 0\n  return Boolean(askAi.assistantId)\n}\n\n/**\n * Removes existing `lang:` filters and appends `lang:${lang}`.\n * Handles both flat arrays and nested arrays (for OR conditions).\n */\nexport function mergeLangFacetFilters(\n  rawFacetFilters: FacetFilter | FacetFilter[] | undefined,\n  lang: string\n): FacetFilter[] {\n  const input = Array.isArray(rawFacetFilters)\n    ? rawFacetFilters\n    : rawFacetFilters\n      ? [rawFacetFilters]\n      : []\n\n  const filtered = input\n    .map((filter) => {\n      if (Array.isArray(filter)) {\n        // Handle nested arrays (OR conditions)\n        return filter.filter(\n          (f) => typeof f === 'string' && !f.startsWith('lang:')\n        )\n      }\n      return filter\n    })\n    .filter((filter) => {\n      if (typeof filter === 'string') {\n        return !filter.startsWith('lang:')\n      }\n      // Keep nested arrays with remaining filters\n      return Array.isArray(filter) && filter.length > 0\n    })\n\n  return [...filtered, `lang:${lang}`]\n}\n\n/**\n * Validates that required Algolia credentials are present.\n */\nexport function validateCredentials(\n  options: Pick<\n    DefaultTheme.AlgoliaSearchOptions,\n    'appId' | 'apiKey' | 'indexName'\n  >\n): ValidatedCredentials {\n  const appId = options.appId\n  const apiKey = options.apiKey\n  const indexName = options.indexName\n\n  return {\n    valid: Boolean(appId && apiKey && indexName),\n    appId,\n    apiKey,\n    indexName\n  }\n}\n\n/**\n * Builds Ask AI configuration from various input formats.\n */\nexport function buildAskAiConfig(\n  askAiProp: NonNullable<DefaultTheme.AlgoliaSearchOptions['askAi']>,\n  options: DefaultTheme.AlgoliaSearchOptions,\n  lang: string\n): DocSearchAskAi {\n  const isAskAiString = typeof askAiProp === 'string'\n\n  const askAiSearchParameters =\n    !isAskAiString && askAiProp.searchParameters\n      ? { ...askAiProp.searchParameters }\n      : undefined\n\n  // If Ask AI defines its own facetFilters, merge lang filtering into those.\n  // Otherwise, reuse the keyword search facetFilters so Ask AI follows the\n  // same language filtering behavior by default.\n  const askAiFacetFiltersSource =\n    askAiSearchParameters?.facetFilters ??\n    options.searchParameters?.facetFilters\n  const askAiFacetFilters = mergeLangFacetFilters(\n    askAiFacetFiltersSource as FacetFilter | FacetFilter[] | undefined,\n    lang\n  )\n\n  const mergedAskAiSearchParameters = {\n    ...askAiSearchParameters,\n    facetFilters: askAiFacetFilters.length ? askAiFacetFilters : undefined\n  }\n\n  const result: Record<string, any> = {\n    ...(isAskAiString ? {} : askAiProp),\n    indexName: isAskAiString ? options.indexName : askAiProp.indexName,\n    apiKey: isAskAiString ? options.apiKey : askAiProp.apiKey,\n    appId: isAskAiString ? options.appId : askAiProp.appId,\n    assistantId: isAskAiString ? askAiProp : askAiProp.assistantId\n  }\n\n  // Keep `searchParameters` undefined unless it has at least one key.\n  if (Object.values(mergedAskAiSearchParameters).some((v) => v != null)) {\n    result.searchParameters = mergedAskAiSearchParameters\n  }\n\n  return result\n}\n\n/**\n * Resolves Algolia search options for the given language,\n * merging in locale-specific overrides and language facet filters.\n */\nexport function resolveOptionsForLanguage(\n  options: DefaultTheme.AlgoliaSearchOptions,\n  localeIndex: string,\n  lang: string\n): DefaultTheme.AlgoliaSearchOptions {\n  options = deepMerge(options, options.locales?.[localeIndex] || {})\n\n  const facetFilters = mergeLangFacetFilters(\n    options.searchParameters?.facetFilters,\n    lang\n  )\n  const askAi = options.askAi\n    ? buildAskAiConfig(options.askAi, options, lang)\n    : undefined\n\n  return {\n    ...options,\n    searchParameters: { ...options.searchParameters, facetFilters },\n    askAi\n  }\n}\n\nfunction deepMerge<T>(target: T, source: Partial<T>): T {\n  const result = { ...target } as any\n\n  for (const key in source) {\n    const value = source[key]\n    if (value === undefined) continue\n\n    // special case: replace entirely\n    if (key === 'searchParameters') {\n      result[key] = value\n      continue\n    }\n\n    // deep-merge only plain objects; arrays are replaced entirely\n    if (isObject(value) && isObject(result[key])) {\n      result[key] = deepMerge(result[key], value)\n    } else {\n      result[key] = value\n    }\n  }\n\n  delete result.locales\n  return result\n}\n"
  },
  {
    "path": "src/client/theme-default/support/lru.ts",
    "content": "// adapted from https://stackoverflow.com/a/46432113/11613622\n\nexport class LRUCache<K, V> {\n  private max: number\n  private cache: Map<K, V>\n\n  constructor(max: number = 10) {\n    this.max = max\n    this.cache = new Map<K, V>()\n  }\n\n  get(key: K): V | undefined {\n    let item = this.cache.get(key)\n    if (item !== undefined) {\n      // refresh key\n      this.cache.delete(key)\n      this.cache.set(key, item)\n    }\n    return item\n  }\n\n  set(key: K, val: V): void {\n    // refresh key\n    if (this.cache.has(key)) this.cache.delete(key)\n    // evict oldest\n    else if (this.cache.size === this.max) this.cache.delete(this.first()!)\n    this.cache.set(key, val)\n  }\n\n  first(): K | undefined {\n    return this.cache.keys().next().value\n  }\n\n  clear(): void {\n    this.cache.clear()\n  }\n}\n"
  },
  {
    "path": "src/client/theme-default/support/reactivity.ts",
    "content": "import { type ComputedRef, computed } from 'vue'\n\nexport function smartComputed<T>(\n  getter: () => T,\n  comparator = (oldValue: T, newValue: T) =>\n    JSON.stringify(oldValue) === JSON.stringify(newValue)\n): ComputedRef<T> {\n  return computed((oldValue) => {\n    const newValue = getter()\n    return oldValue === undefined || !comparator(oldValue, newValue)\n      ? newValue\n      : oldValue\n  })\n}\n"
  },
  {
    "path": "src/client/theme-default/support/sidebar.ts",
    "content": "import type { DefaultTheme } from 'vitepress/theme'\nimport { isActive } from '../../shared'\nimport { ensureStartingSlash } from './utils'\n\nexport interface SidebarLink {\n  text: string\n  link: string\n  docFooterText?: string\n}\n\ntype SidebarItem = DefaultTheme.SidebarItem\n\n/**\n * Get the `Sidebar` from sidebar option. This method will ensure to get correct\n * sidebar config from `MultiSideBarConfig` with various path combinations such\n * as matching `guide/` and `/guide/`. If no matching config was found, it will\n * return empty array.\n */\nexport function getSidebar(\n  _sidebar: DefaultTheme.Sidebar | undefined,\n  path: string\n): SidebarItem[] {\n  if (Array.isArray(_sidebar)) return addBase(_sidebar)\n  if (_sidebar == null) return []\n\n  path = ensureStartingSlash(path)\n\n  const dir = Object.keys(_sidebar)\n    .sort((a, b) => {\n      return b.split('/').length - a.split('/').length\n    })\n    .find((dir) => {\n      // make sure the multi sidebar key starts with slash too\n      return path.startsWith(ensureStartingSlash(dir))\n    })\n\n  const sidebar = dir ? _sidebar[dir] : []\n  return Array.isArray(sidebar)\n    ? addBase(sidebar)\n    : addBase(sidebar.items, sidebar.base)\n}\n\n/**\n * Get or generate sidebar group from the given sidebar items.\n */\nexport function getSidebarGroups(sidebar: SidebarItem[]): SidebarItem[] {\n  const groups: SidebarItem[] = []\n\n  let lastGroupIndex: number = 0\n\n  for (const index in sidebar) {\n    const item = sidebar[index]\n\n    if (item.items) {\n      lastGroupIndex = groups.push(item)\n      continue\n    }\n\n    if (!groups[lastGroupIndex]) {\n      groups.push({ items: [] })\n    }\n\n    groups[lastGroupIndex]!.items!.push(item)\n  }\n\n  return groups\n}\n\nexport function getFlatSideBarLinks(sidebar: SidebarItem[]): SidebarLink[] {\n  const links: SidebarLink[] = []\n\n  function recursivelyExtractLinks(items: SidebarItem[]) {\n    for (const item of items) {\n      if (item.text && item.link) {\n        links.push({\n          text: item.text,\n          link: item.link,\n          docFooterText: item.docFooterText\n        })\n      }\n\n      if (item.items) {\n        recursivelyExtractLinks(item.items)\n      }\n    }\n  }\n\n  recursivelyExtractLinks(sidebar)\n\n  return links\n}\n\n/**\n * Check if the given sidebar item contains any active link.\n */\nexport function hasActiveLink(\n  path: string,\n  items: SidebarItem | SidebarItem[]\n): boolean {\n  if (Array.isArray(items)) {\n    return items.some((item) => hasActiveLink(path, item))\n  }\n\n  return isActive(path, items.link)\n    ? true\n    : items.items\n      ? hasActiveLink(path, items.items)\n      : false\n}\n\nfunction addBase(items: SidebarItem[], _base?: string): SidebarItem[] {\n  return [...items].map((_item) => {\n    const item = { ..._item }\n    const base = item.base || _base\n    if (base && item.link)\n      item.link = base + item.link.replace(/^\\//, base.endsWith('/') ? '' : '/')\n    if (item.items) item.items = addBase(item.items, base)\n    return item\n  })\n}\n"
  },
  {
    "path": "src/client/theme-default/support/translation.ts",
    "content": "import { useData } from '../composables/data'\n\n/**\n * @param themeObject Can be an object with `translations` and `locales` properties\n */\nexport function createSearchTranslate(\n  defaultTranslations: Record<string, any>\n): (key: string) => string {\n  const { localeIndex, theme } = useData()\n\n  function translate(key: string): string {\n    const keyPath = key.split('.')\n    const themeObject = theme.value.search?.options\n\n    const isObject = themeObject && typeof themeObject === 'object'\n    const locales =\n      (isObject && themeObject.locales?.[localeIndex.value]?.translations) ||\n      null\n    const translations = (isObject && themeObject.translations) || null\n\n    let localeResult: Record<string, any> | null = locales\n    let translationResult: Record<string, any> | null = translations\n    let defaultResult: Record<string, any> | null = defaultTranslations\n\n    const lastKey = keyPath.pop()!\n    for (const k of keyPath) {\n      let fallbackResult: Record<string, any> | null = null\n      const foundInFallback: any = defaultResult?.[k]\n      if (foundInFallback) {\n        fallbackResult = defaultResult = foundInFallback\n      }\n      const foundInTranslation: any = translationResult?.[k]\n      if (foundInTranslation) {\n        fallbackResult = translationResult = foundInTranslation\n      }\n      const foundInLocale: any = localeResult?.[k]\n      if (foundInLocale) {\n        fallbackResult = localeResult = foundInLocale\n      }\n      // Put fallback into unresolved results\n      if (!foundInFallback) {\n        defaultResult = fallbackResult\n      }\n      if (!foundInTranslation) {\n        translationResult = fallbackResult\n      }\n      if (!foundInLocale) {\n        localeResult = fallbackResult\n      }\n    }\n    return (\n      localeResult?.[lastKey] ??\n      translationResult?.[lastKey] ??\n      defaultResult?.[lastKey] ??\n      ''\n    )\n  }\n\n  return translate\n}\n"
  },
  {
    "path": "src/client/theme-default/support/utils.ts",
    "content": "import { withBase } from 'vitepress'\nimport { isExternal, treatAsHtml } from '../../shared'\nimport { useData } from '../composables/data'\n\nexport function throttleAndDebounce(fn: () => void, delay: number): () => void {\n  let timeoutId: NodeJS.Timeout\n  let called = false\n\n  return () => {\n    if (timeoutId) clearTimeout(timeoutId)\n\n    if (!called) {\n      fn()\n      ;(called = true) && setTimeout(() => (called = false), delay)\n    } else timeoutId = setTimeout(fn, delay)\n  }\n}\n\nexport function ensureStartingSlash(path: string): string {\n  return path.startsWith('/') ? path : `/${path}`\n}\n\nexport function normalizeLink(url: string): string {\n  const { pathname, search, hash, protocol } = new URL(url, 'http://a.com')\n\n  if (\n    isExternal(url) ||\n    url.startsWith('#') ||\n    !protocol.startsWith('http') ||\n    !treatAsHtml(pathname)\n  )\n    return url\n\n  const { site } = useData()\n\n  const normalizedPath =\n    pathname.endsWith('/') || pathname.endsWith('.html')\n      ? url\n      : url.replace(\n          /(?:(^\\.+)\\/)?.*$/,\n          `$1${pathname.replace(\n            /(\\.md)?$/,\n            site.value.cleanUrls ? '' : '.html'\n          )}${search}${hash}`\n        )\n\n  return withBase(normalizedPath)\n}\n"
  },
  {
    "path": "src/client/theme-default/without-fonts.ts",
    "content": "import './styles/vars.css'\nimport './styles/base.css'\nimport './styles/icons.css'\nimport './styles/utils.css'\nimport './styles/components/custom-block.css'\nimport './styles/components/vp-code.css'\nimport './styles/components/vp-code-group.css'\nimport './styles/components/vp-doc.css'\nimport './styles/components/vp-sponsor.css'\n\nimport type { Theme } from 'vitepress'\nimport VPBadge from './components/VPBadge.vue'\nimport Layout from './Layout.vue'\n\nexport { default as VPBadge } from './components/VPBadge.vue'\nexport { default as VPButton } from './components/VPButton.vue'\nexport { default as VPDocAsideSponsors } from './components/VPDocAsideSponsors.vue'\nexport { default as VPFeatures } from './components/VPFeatures.vue'\nexport { default as VPHomeContent } from './components/VPHomeContent.vue'\nexport { default as VPHomeFeatures } from './components/VPHomeFeatures.vue'\nexport { default as VPHomeHero } from './components/VPHomeHero.vue'\nexport { default as VPHomeSponsors } from './components/VPHomeSponsors.vue'\nexport { default as VPImage } from './components/VPImage.vue'\nexport { default as VPLink } from './components/VPLink.vue'\nexport { default as VPNavBarSearch } from './components/VPNavBarSearch.vue'\nexport { default as VPSocialLink } from './components/VPSocialLink.vue'\nexport { default as VPSocialLinks } from './components/VPSocialLinks.vue'\nexport { default as VPSponsors } from './components/VPSponsors.vue'\nexport { default as VPTeamMembers } from './components/VPTeamMembers.vue'\nexport { default as VPTeamPage } from './components/VPTeamPage.vue'\nexport { default as VPTeamPageSection } from './components/VPTeamPageSection.vue'\nexport { default as VPTeamPageTitle } from './components/VPTeamPageTitle.vue'\n\nexport { useLayout } from './composables/layout'\n\nconst theme: Theme = {\n  Layout,\n  enhanceApp: ({ app }) => {\n    app.component('Badge', VPBadge)\n  }\n}\n\nexport default theme\n"
  },
  {
    "path": "src/client/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"../../dist/client\",\n    \"declaration\": true,\n    \"declarationDir\": \"../../dist/client-types\",\n    \"types\": [\"../../client.d.ts\", \"@types/node\"],\n    \"paths\": {\n      \"vitepress\": [\"index.ts\"],\n      \"vitepress/theme\": [\"../../theme.d.ts\"]\n    }\n  },\n  \"include\": [\".\"]\n}\n"
  },
  {
    "path": "src/node/alias.ts",
    "content": "import { createRequire } from 'node:module'\nimport { join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { Alias, AliasOptions } from 'vite'\n\nconst require = createRequire(import.meta.url)\nconst PKG_ROOT = resolve(fileURLToPath(import.meta.url), '../..')\n\nexport const DIST_CLIENT_PATH = resolve(PKG_ROOT, 'client')\nexport const APP_PATH = join(DIST_CLIENT_PATH, 'app')\nexport const SHARED_PATH = join(DIST_CLIENT_PATH, 'shared')\nexport const DEFAULT_THEME_PATH = join(DIST_CLIENT_PATH, 'theme-default')\n\n// special virtual file. we can't directly import '/@siteData' because\n// - it's not an actual file so we can't use tsconfig paths to redirect it\n// - TS doesn't allow shimming a module that starts with '/'\nexport const SITE_DATA_ID = '@siteData'\nexport const SITE_DATA_REQUEST_PATH = '/' + SITE_DATA_ID\n\nconst vueRuntimePath = 'vue/dist/vue.runtime.esm-bundler.js'\n\nexport function resolveAliases(root: string, ssr: boolean): AliasOptions {\n  const aliases: Alias[] = [\n    {\n      find: /^vitepress$/,\n      replacement: join(DIST_CLIENT_PATH, '/index.js')\n    },\n    {\n      find: /^vitepress\\/theme$/,\n      replacement: join(DIST_CLIENT_PATH, '/theme-default/index.js')\n    }\n  ]\n\n  if (!ssr) {\n    // Prioritize vue installed in project root and fallback to\n    // vue that comes with vitepress itself.\n    // Only do this when not running SSR build, since `vue` needs to be\n    // externalized during SSR\n    let vuePath\n    try {\n      vuePath = require.resolve(vueRuntimePath, { paths: [root] })\n    } catch (e) {\n      vuePath = require.resolve(vueRuntimePath)\n    }\n    aliases.push({\n      find: /^vue$/,\n      replacement: vuePath\n    })\n  }\n\n  return aliases\n}\n"
  },
  {
    "path": "src/node/build/build.ts",
    "content": "import { getIconsCSS } from '@iconify/utils'\nimport fs from 'fs-extra'\nimport { createHash } from 'node:crypto'\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport pMap from 'p-map'\nimport { packageDirectorySync } from 'package-directory'\nimport * as vite from 'vite'\nimport type { BuildOptions, Rollup } from 'vite'\nimport { resolveConfig, type SiteConfig } from '../config'\nimport { clearCache } from '../markdownToVue'\nimport { slash, type Awaitable, type HeadConfig } from '../shared'\nimport { deserializeFunctions, serializeFunctions } from '../utils/fnSerialize'\nimport { task } from '../utils/task'\nimport { bundle } from './bundle'\nimport { generateSitemap } from './generateSitemap'\nimport { renderPage } from './render'\n\nconst require = createRequire(import.meta.url)\n\nexport async function build(\n  root?: string,\n  buildOptions: BuildOptions & {\n    base?: string\n    mpa?: string\n    onAfterConfigResolve?: (siteConfig: SiteConfig) => Awaitable<void>\n  } = {}\n) {\n  const start = Date.now()\n\n  // @ts-ignore only exists for rolldown-vite\n  if (vite.rolldownVersion) {\n    try {\n      await import('oxc-minify')\n    } catch {\n      throw new Error(\n        '`oxc-minify` is not installed.' +\n          ' vitepress requires `oxc-minify` to be installed when rolldown-vite is used.' +\n          ' Please run `npm install oxc-minify`.'\n      )\n    }\n  }\n\n  process.env.NODE_ENV = 'production'\n  const siteConfig = await resolveConfig(root, 'build', 'production')\n\n  await buildOptions.onAfterConfigResolve?.(siteConfig)\n  delete buildOptions.onAfterConfigResolve\n\n  const unlinkVue = linkVue()\n\n  if (buildOptions.base) {\n    siteConfig.site.base = buildOptions.base\n    delete buildOptions.base\n  }\n\n  if (buildOptions.mpa) {\n    siteConfig.mpa = true\n    delete buildOptions.mpa\n  }\n\n  if (buildOptions.outDir) {\n    siteConfig.outDir = path.resolve(process.cwd(), buildOptions.outDir)\n    delete buildOptions.outDir\n  }\n\n  try {\n    const { clientResult, serverResult, pageToHashMap } = await bundle(\n      siteConfig,\n      buildOptions\n    )\n\n    if (process.env.BUNDLE_ONLY) {\n      return\n    }\n\n    const entryPath = path.join(siteConfig.tempDir, 'app.js')\n    const { render } = await import(pathToFileURL(entryPath).href)\n\n    await task('rendering pages', async () => {\n      const appChunk =\n        clientResult &&\n        (clientResult.output.find(\n          (chunk) =>\n            chunk.type === 'chunk' &&\n            chunk.isEntry &&\n            chunk.facadeModuleId?.endsWith('.js')\n        ) as Rollup.OutputChunk)\n\n      const cssChunk = (\n        siteConfig.mpa ? serverResult : clientResult!\n      ).output.find(\n        (chunk) => chunk.type === 'asset' && chunk.fileName.endsWith('.css')\n      ) as Rollup.OutputAsset\n\n      const assets = (siteConfig.mpa ? serverResult : clientResult!).output\n        .filter(\n          (chunk) => chunk.type === 'asset' && !chunk.fileName.endsWith('.css')\n        )\n        .map((asset) => siteConfig.site.base + asset.fileName)\n\n      // default theme special handling: inject font preload\n      // custom themes will need to use `transformHead` to inject this\n      const additionalHeadTags: HeadConfig[] = []\n      const isDefaultTheme =\n        clientResult &&\n        clientResult.output.some(\n          (chunk) =>\n            chunk.type === 'chunk' &&\n            // @ts-ignore only exists for rolldown-vite\n            (vite.rolldownVersion || chunk.name === 'theme') && // FIXME: remove when rolldown-vite supports manualChunks\n            chunk.moduleIds.some((id) => id.includes('client/theme-default'))\n        )\n\n      const metadataScript = generateMetadataScript(pageToHashMap, siteConfig)\n\n      if (isDefaultTheme) {\n        const fontURL = assets.find((file) =>\n          /inter-roman-latin\\.[\\w-]+\\.woff2/.test(file)\n        )\n        if (fontURL) {\n          additionalHeadTags.push([\n            'link',\n            {\n              rel: 'preload',\n              href: fontURL,\n              as: 'font',\n              type: 'font/woff2',\n              crossorigin: ''\n            }\n          ])\n        }\n      }\n\n      const usedIcons = new Set<string>()\n\n      await pMap(\n        ['404.md', ...siteConfig.pages],\n        async (page) => {\n          await renderPage(\n            render,\n            siteConfig,\n            siteConfig.rewrites.map[page] || page,\n            clientResult,\n            appChunk,\n            cssChunk,\n            assets,\n            pageToHashMap,\n            metadataScript,\n            additionalHeadTags,\n            usedIcons\n          )\n        },\n        { concurrency: siteConfig.buildConcurrency }\n      )\n\n      const icons = require('@iconify-json/simple-icons/icons.json')\n      const iconsCss = getIconsCSS(icons, Array.from(usedIcons).sort(), {\n        iconSelector: '.vpi-social-{name}',\n        commonSelector: '.vpi-social',\n        varName: 'icon',\n        format: process.env.DEBUG ? 'expanded' : 'compressed',\n        mode: 'mask'\n      }).replace(/[^]*?}\\n*/, '')\n\n      fs.writeFileSync(path.join(siteConfig.outDir, 'vp-icons.css'), iconsCss)\n    })\n\n    // emit page hash map for the case where a user session is open\n    // when the site got redeployed (which invalidates current hash map)\n    fs.writeJSONSync(\n      path.join(siteConfig.outDir, 'hashmap.json'),\n      pageToHashMap\n    )\n  } finally {\n    unlinkVue()\n    if (!process.env.DEBUG) {\n      fs.rmSync(siteConfig.tempDir, {\n        recursive: true,\n        force: true,\n        maxRetries: 10\n      })\n    }\n  }\n\n  await generateSitemap(siteConfig)\n  await siteConfig.buildEnd?.(siteConfig)\n  clearCache()\n\n  siteConfig.logger.info(\n    `build complete in ${((Date.now() - start) / 1000).toFixed(2)}s.`\n  )\n}\n\nfunction linkVue() {\n  const root = packageDirectorySync()\n  if (root) {\n    const dest = path.resolve(root, 'node_modules/vue')\n    // if user did not install vue by themselves, link VitePress' version\n    if (!fs.existsSync(dest)) {\n      const src = path.dirname(createRequire(import.meta.url).resolve('vue'))\n      fs.ensureSymlinkSync(src, dest, 'junction')\n      return () => {\n        fs.unlinkSync(dest)\n      }\n    }\n  }\n  return () => {}\n}\n\nfunction generateMetadataScript(\n  pageToHashMap: Record<string, string>,\n  config: SiteConfig\n) {\n  if (config.mpa) {\n    return { html: '', inHead: false }\n  }\n\n  // We embed the hash map and site config strings into each page directly\n  // so that it doesn't alter the main chunk's hash on every build.\n  // It's also embedded as a string and JSON.parsed from the client because\n  // it's faster than embedding as JS object literal.\n  const hashMapString = JSON.stringify(JSON.stringify(pageToHashMap))\n  const siteDataString = JSON.stringify(\n    JSON.stringify(serializeFunctions({ ...config.site, head: [] }))\n  )\n\n  const metadataContent = `window.__VP_HASH_MAP__=JSON.parse(${hashMapString});${\n    siteDataString.includes('_vp-fn_')\n      ? `${deserializeFunctions};window.__VP_SITE_DATA__=deserializeFunctions(JSON.parse(${siteDataString}));`\n      : `window.__VP_SITE_DATA__=JSON.parse(${siteDataString});`\n  }`\n\n  if (!config.metaChunk) {\n    return { html: `<script>${metadataContent}</script>`, inHead: false }\n  }\n\n  const metadataFile = path.join(\n    config.assetsDir,\n    'chunks',\n    `metadata.${createHash('sha256')\n      .update(metadataContent)\n      .digest('hex')\n      .slice(0, 8)}.js`\n  )\n\n  const resolvedMetadataFile = path.join(config.outDir, metadataFile)\n  const metadataFileURL = slash(`${config.site.base}${metadataFile}`)\n\n  fs.ensureDirSync(path.dirname(resolvedMetadataFile))\n  fs.writeFileSync(resolvedMetadataFile, metadataContent)\n\n  return {\n    html: `<script type=\"module\" src=\"${metadataFileURL}\"></script>`,\n    inHead: true\n  }\n}\n"
  },
  {
    "path": "src/node/build/buildMPAClient.ts",
    "content": "import { build, type Rollup } from 'vite'\nimport type { SiteConfig } from '..'\n\nconst virtualEntry = 'client.js'\n\nexport async function buildMPAClient(\n  js: Record<string, string>,\n  config: SiteConfig\n): Promise<Rollup.RollupOutput> {\n  const files = Object.keys(js)\n  const themeFiles = files.filter((f) => !f.endsWith('.md'))\n  const pages = files.filter((f) => f.endsWith('.md'))\n\n  return build({\n    root: config.srcDir,\n    cacheDir: config.cacheDir,\n    base: config.site.base,\n    logLevel: config.vite?.logLevel ?? 'warn',\n    build: {\n      emptyOutDir: false,\n      outDir: config.outDir,\n      rollupOptions: {\n        input: [virtualEntry, ...pages]\n      }\n    },\n    plugins: [\n      {\n        name: 'vitepress-mpa-client',\n        resolveId(id) {\n          if (id === virtualEntry) {\n            return id\n          }\n        },\n        load(id) {\n          if (id === virtualEntry) {\n            return themeFiles\n              .map((file) => `import ${JSON.stringify(file)}`)\n              .join('\\n')\n          } else if (id in js) {\n            return js[id]\n          }\n        }\n      }\n    ]\n  }) as Promise<Rollup.RollupOutput>\n}\n"
  },
  {
    "path": "src/node/build/bundle.ts",
    "content": "import fs from 'fs-extra'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport * as vite from 'vite'\nimport {\n  build,\n  normalizePath,\n  type BuildOptions,\n  type Rollup,\n  type InlineConfig as ViteInlineConfig\n} from 'vite'\nimport { APP_PATH } from '../alias'\nimport type { SiteConfig } from '../config'\nimport { createVitePressPlugin } from '../plugin'\nimport { escapeRegExp, sanitizeFileName, slash } from '../shared'\nimport { task } from '../utils/task'\nimport { buildMPAClient } from './buildMPAClient'\n\n// https://github.com/vitejs/vite/blob/d2aa0969ee316000d3b957d7e879f001e85e369e/packages/vite/src/node/plugins/splitVendorChunk.ts#L14\nconst CSS_LANGS_RE =\n  /\\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\\?)/\n\nconst clientDir = normalizePath(\n  path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../client')\n)\n\n// these deps are also being used in the client code (outside of the theme)\n// exclude them from the theme chunk so there is no circular dependency\nconst excludedModules = [\n  '/@siteData',\n  'node_modules/@vueuse/core/',\n  'node_modules/@vueuse/shared/',\n  'node_modules/vue/',\n  clientDir\n]\n\n// bundles the VitePress app for both client AND server.\nexport async function bundle(\n  config: SiteConfig,\n  options: BuildOptions\n): Promise<{\n  clientResult: Rollup.RollupOutput | null\n  serverResult: Rollup.RollupOutput\n  pageToHashMap: Record<string, string>\n}> {\n  const pageToHashMap = Object.create(null) as Record<string, string>\n  const clientJSMap = Object.create(null) as Record<string, string>\n\n  // define custom rollup input\n  // this is a multi-entry build - every page is considered an entry chunk\n  // the loading is done via filename conversion rules so that the\n  // metadata doesn't need to be included in the main chunk.\n  const input: Record<string, string> = {}\n  config.pages.forEach((file) => {\n    // page filename conversion\n    // foo/bar.md -> foo_bar.md\n    const alias = config.rewrites.map[file] || file\n    input[slash(alias).replace(/\\//g, '_')] = path.resolve(config.srcDir, file)\n  })\n\n  const themeEntryRE = new RegExp(\n    `^${escapeRegExp(\n      path.resolve(config.themeDir, 'index.js').replace(/\\\\/g, '/')\n    ).slice(0, -2)}m?(j|t)s`\n  )\n\n  // resolve options to pass to vite\n  const { rollupOptions } = options\n\n  const resolveViteConfig = async (\n    ssr: boolean\n  ): Promise<ViteInlineConfig> => ({\n    root: config.srcDir,\n    cacheDir: config.cacheDir,\n    base: config.site.base,\n    logLevel: config.vite?.logLevel ?? 'warn',\n    plugins: await createVitePressPlugin(\n      config,\n      ssr,\n      pageToHashMap,\n      clientJSMap\n    ),\n    ssr: {\n      noExternal: ['vitepress', '@docsearch/css']\n    },\n    build: {\n      ...options,\n      emptyOutDir: true,\n      ssr,\n      ssrEmitAssets: config.mpa,\n      minify: ssr ? !!config.mpa : (options.minify ?? !process.env.DEBUG),\n      outDir: ssr ? config.tempDir : config.outDir,\n      cssCodeSplit: false,\n      rollupOptions: {\n        ...rollupOptions,\n        input: {\n          // use different entry based on ssr or not\n          app: path.resolve(APP_PATH, ssr ? 'ssr.js' : 'index.js'),\n          ...input\n        },\n        // important so that each page chunk and the index export things for each\n        // other\n        preserveEntrySignatures: 'allow-extension',\n        output: {\n          sanitizeFileName,\n          ...rollupOptions?.output,\n          assetFileNames: `${config.assetsDir}/[name].[hash].[ext]`,\n          ...(ssr\n            ? {\n                entryFileNames: '[name].js',\n                chunkFileNames: '[name].[hash].js'\n              }\n            : {\n                entryFileNames: `${config.assetsDir}/[name].[hash].js`,\n                chunkFileNames(chunk) {\n                  // avoid ads chunk being intercepted by adblock\n                  return /(?:Carbon|BuySell)Ads/.test(chunk.name)\n                    ? `${config.assetsDir}/chunks/ui-custom.[hash].js`\n                    : `${config.assetsDir}/chunks/[name].[hash].js`\n                },\n                // @ts-ignore skip setting it for rolldown-vite since it doesn't support `manualChunks`\n                ...(vite.rolldownVersion\n                  ? undefined\n                  : {\n                      manualChunks(\n                        id: string,\n                        ctx: Pick<Rollup.PluginContext, 'getModuleInfo'>\n                      ) {\n                        // move known framework code into a stable chunk so that\n                        // custom theme changes do not invalidate hash for all pages\n                        if (\n                          id.startsWith('\\0vite') ||\n                          ctx.getModuleInfo(id)?.meta['vite:asset']\n                        ) {\n                          return 'framework'\n                        }\n                        if (id.includes('plugin-vue:export-helper')) {\n                          return 'framework'\n                        }\n                        if (\n                          id.includes(`${clientDir}/app`) &&\n                          id !== `${clientDir}/app/index.js`\n                        ) {\n                          return 'framework'\n                        }\n                        if (\n                          isEagerChunk(id, ctx.getModuleInfo) &&\n                          /@vue\\/(runtime|shared|reactivity)/.test(id)\n                        ) {\n                          return 'framework'\n                        }\n\n                        if (\n                          (id.startsWith(`${clientDir}/theme-default`) ||\n                            !excludedModules.some((i) => id.includes(i))) &&\n                          staticImportedByEntry(\n                            id,\n                            ctx.getModuleInfo,\n                            cacheTheme,\n                            themeEntryRE\n                          )\n                        ) {\n                          return 'theme'\n                        }\n                      }\n                    })\n              })\n        }\n      }\n    },\n    configFile: config.vite?.configFile\n  })\n\n  let clientResult!: Rollup.RollupOutput | null\n  let serverResult!: Rollup.RollupOutput\n\n  await task('building client + server bundles', async () => {\n    clientResult = config.mpa\n      ? null\n      : ((await build(await resolveViteConfig(false))) as Rollup.RollupOutput)\n    serverResult = (await build(\n      await resolveViteConfig(true)\n    )) as Rollup.RollupOutput\n  })\n\n  if (config.mpa) {\n    // in MPA mode, we need to copy over the non-js asset files from the\n    // server build since there is no client-side build.\n    await Promise.all(\n      serverResult.output.map(async (chunk) => {\n        if (!chunk.fileName.endsWith('.js')) {\n          const tempPath = path.resolve(config.tempDir, chunk.fileName)\n          const outPath = path.resolve(config.outDir, chunk.fileName)\n          await fs.copy(tempPath, outPath)\n        }\n      })\n    )\n    // also copy over public dir\n    const publicDir = path.resolve(config.srcDir, 'public')\n    if (fs.existsSync(publicDir)) {\n      await fs.copy(publicDir, config.outDir)\n    }\n    // build <script client> bundle\n    if (Object.keys(clientJSMap).length) {\n      clientResult = await buildMPAClient(clientJSMap, config)\n    }\n  }\n\n  // sort pageToHashMap to ensure stable output\n  const sortedPageToHashMap = Object.create(null) as Record<string, string>\n  Object.keys(pageToHashMap)\n    .sort()\n    .forEach((key) => {\n      sortedPageToHashMap[key] = pageToHashMap[key]\n    })\n\n  return { clientResult, serverResult, pageToHashMap: sortedPageToHashMap }\n}\n\nconst cache = new Map<string, boolean>()\nconst cacheTheme = new Map<string, boolean>()\n\n/**\n * Check if a module is statically imported by at least one entry.\n */\nfunction isEagerChunk(id: string, getModuleInfo: Rollup.GetModuleInfo) {\n  if (\n    id.includes('node_modules') &&\n    !CSS_LANGS_RE.test(id) &&\n    staticImportedByEntry(id, getModuleInfo, cache)\n  ) {\n    return true\n  }\n}\n\nfunction staticImportedByEntry(\n  id: string,\n  getModuleInfo: Rollup.GetModuleInfo,\n  cache: Map<string, boolean>,\n  entryRE: RegExp | null = null,\n  importStack: string[] = []\n): boolean {\n  if (cache.has(id)) {\n    return !!cache.get(id)\n  }\n  if (importStack.includes(id)) {\n    // circular deps!\n    cache.set(id, false)\n    return false\n  }\n  const mod = getModuleInfo(id)\n  if (!mod) {\n    cache.set(id, false)\n    return false\n  }\n\n  if (entryRE ? entryRE.test(id) : mod.isEntry) {\n    cache.set(id, true)\n    return true\n  }\n  const someImporterIs = mod.importers.some((importer: string) =>\n    staticImportedByEntry(\n      importer,\n      getModuleInfo,\n      cache,\n      entryRE,\n      importStack.concat(id)\n    )\n  )\n  cache.set(id, someImporterIs)\n  return someImporterIs\n}\n"
  },
  {
    "path": "src/node/build/generateSitemap.ts",
    "content": "import fs from 'fs-extra'\nimport matter from 'gray-matter'\nimport path from 'node:path'\nimport {\n  SitemapStream,\n  type EnumChangefreq,\n  type Img,\n  type LinkItem,\n  type NewsItem\n} from 'sitemap'\nimport type { SiteConfig } from '../config'\nimport { slash } from '../shared'\nimport { getGitTimestamp } from '../utils/getGitTimestamp'\nimport { task } from '../utils/task'\n\nexport async function generateSitemap(siteConfig: SiteConfig) {\n  if (!siteConfig.sitemap?.hostname) return\n\n  const getLastmod = async (url: string) => {\n    if (!siteConfig.lastUpdated) return undefined\n\n    let file = url.replace(/(^|\\/)$/, '$1index')\n    file = file.replace(/(\\.html)?$/, '.md')\n    file = siteConfig.rewrites.inv[file] || file\n    file = path.join(siteConfig.srcDir, file)\n\n    if (!fs.existsSync(file)) return undefined\n\n    const { data } = matter.read(file)\n    if (data.lastUpdated === false) return undefined\n    if (data.lastUpdated instanceof Date) return +data.lastUpdated\n\n    return (await getGitTimestamp(slash(file))) || undefined\n  }\n\n  await task('generating sitemap', async () => {\n    const locales = siteConfig.userConfig.locales || {}\n    const filteredLocales = Object.keys(locales).filter(\n      (locale) => locales[locale].lang && locale !== 'root'\n    )\n    const defaultLang =\n      locales?.root?.lang || siteConfig.userConfig.lang || 'en-US'\n\n    const pages = siteConfig.pages.map(\n      (page) => siteConfig.rewrites.map[page] || page\n    )\n\n    const groupedPages: Record<string, { lang: string; url: string }[]> = {}\n    pages.forEach((page) => {\n      const locale = page.split('/')[0]\n      const lang = locales[locale]?.lang || defaultLang\n\n      let url = page.replace(/(^|\\/)index\\.md$/, '$1')\n      url = url.replace(/\\.md$/, siteConfig.cleanUrls ? '' : '.html')\n      if (filteredLocales.includes(locale)) page = page.slice(locale.length + 1)\n\n      if (!groupedPages[page]) groupedPages[page] = []\n      groupedPages[page].push({ url, lang })\n    })\n\n    const _items = await Promise.all(\n      Object.values(groupedPages).map(async (pages) => {\n        if (pages.length < 2)\n          return { url: pages[0].url, lastmod: await getLastmod(pages[0].url) }\n\n        return await Promise.all(\n          pages.map(async ({ url }) => {\n            return { url, lastmod: await getLastmod(url), links: pages }\n          })\n        )\n      })\n    )\n\n    let items: SitemapItem[] = _items.flat()\n    items = (await siteConfig.sitemap?.transformItems?.(items)) || items\n\n    const sitemapStream = new SitemapStream(siteConfig.sitemap)\n    const sitemapPath = path.join(siteConfig.outDir, 'sitemap.xml')\n    const writeStream = fs.createWriteStream(sitemapPath)\n\n    sitemapStream.pipe(writeStream)\n    items.forEach((item) => sitemapStream.write(item))\n    sitemapStream.end()\n  })\n}\n\n// ============================== Patched Types ===============================\n\nexport interface SitemapItem {\n  lastmod?: string | number | Date\n  changefreq?: `${EnumChangefreq}`\n  fullPrecisionPriority?: boolean\n  priority?: number\n  news?: NewsItem\n  expires?: string\n  androidLink?: string\n  ampLink?: string\n  url: string\n  video?: any\n  img?: string | Img | (string | Img)[]\n  links?: LinkItem[]\n  lastmodfile?: string | Buffer | URL\n  lastmodISO?: string\n  lastmodrealtime?: boolean\n}\n"
  },
  {
    "path": "src/node/build/render.ts",
    "content": "import { isBooleanAttr } from '@vue/shared'\nimport fs from 'fs-extra'\nimport path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport * as vite from 'vite'\nimport { normalizePath, transformWithEsbuild, type Rollup } from 'vite'\nimport { version } from '../../../package.json'\nimport type { SiteConfig } from '../config'\nimport {\n  EXTERNAL_URL_RE,\n  createTitle,\n  escapeHtml,\n  mergeHead,\n  notFoundPageData,\n  resolveSiteDataByRoute,\n  sanitizeFileName,\n  slash,\n  type HeadConfig,\n  type PageData,\n  type SSGContext\n} from '../shared'\n\nexport async function renderPage(\n  render: (path: string) => Promise<SSGContext>,\n  config: SiteConfig,\n  page: string, // foo.md\n  result: Rollup.RollupOutput | null,\n  appChunk: Rollup.OutputChunk | null,\n  cssChunk: Rollup.OutputAsset | null,\n  assets: string[],\n  pageToHashMap: Record<string, string>,\n  metadataScript: { html: string; inHead: boolean },\n  additionalHeadTags: HeadConfig[],\n  usedIcons: Set<string>\n) {\n  const routePath = `/${page.replace(/\\.md$/, '')}`\n  const siteData = resolveSiteDataByRoute(config.site, page)\n\n  // render page\n  const context = await render(routePath)\n  const { content, teleports, vpSocialIcons } =\n    (await config.postRender?.(context)) ?? context\n\n  // add used social icons to the set\n  vpSocialIcons.forEach((icon) => usedIcons.add(icon))\n\n  const pageName = sanitizeFileName(page.replace(/\\//g, '_'))\n  // server build doesn't need hash\n  const pageServerJsFileName = pageName + '.js'\n  // for any initial page load, we only need the lean version of the page js\n  // since the static content is already on the page!\n  const pageHash = pageToHashMap[pageName.toLowerCase()]\n  const pageClientJsFileName = `${config.assetsDir}/${pageName}.${pageHash}.lean.js`\n\n  let pageData: PageData\n  let hasCustom404 = true\n\n  try {\n    // resolve page data so we can render head tags\n    const { __pageData } = await import(\n      pathToFileURL(path.join(config.tempDir, pageServerJsFileName)).href\n    )\n    pageData = __pageData\n  } catch (e) {\n    if (page === '404.md') {\n      hasCustom404 = false\n      pageData = notFoundPageData\n    } else {\n      throw e\n    }\n  }\n\n  const title: string = createTitle(siteData, pageData)\n  const description: string = pageData.description || siteData.description\n  const stylesheetLink = cssChunk\n    ? `<link rel=\"preload stylesheet\" href=\"${siteData.base}${cssChunk.fileName}\" as=\"style\">`\n    : ''\n\n  let preloadLinks =\n    config.mpa || (!hasCustom404 && page === '404.md')\n      ? []\n      : result && appChunk\n        ? [\n            ...new Set([\n              // resolve imports for index.js + page.md.js and inject script tags\n              // for them as well so we fetch everything as early as possible\n              // without having to wait for entry chunks to parse\n              ...resolvePageImports(config, page, result, appChunk),\n              pageClientJsFileName\n            ])\n          ]\n        : []\n\n  let prefetchLinks: string[] = []\n\n  const { shouldPreload } = config\n  if (shouldPreload) {\n    prefetchLinks = preloadLinks.filter((link) => !shouldPreload(link, page))\n    preloadLinks = preloadLinks.filter((link) => shouldPreload(link, page))\n  }\n\n  const toHeadTags = (files: string[], rel: string): HeadConfig[] =>\n    files.map((file) => [\n      'link',\n      {\n        rel,\n        // don't add base to external urls\n        href: (EXTERNAL_URL_RE.test(file) ? '' : siteData.base) + file\n      }\n    ])\n\n  const preloadHeadTags = toHeadTags(preloadLinks, 'modulepreload')\n  const prefetchHeadTags = toHeadTags(prefetchLinks, 'prefetch')\n\n  const headBeforeTransform = [\n    ...additionalHeadTags,\n    ...preloadHeadTags,\n    ...prefetchHeadTags,\n    ...mergeHead(\n      siteData.head,\n      filterOutHeadDescription(pageData.frontmatter.head)\n    )\n  ]\n\n  const head = mergeHead(\n    headBeforeTransform,\n    (await config.transformHead?.({\n      page,\n      siteConfig: config,\n      siteData,\n      pageData,\n      title,\n      description,\n      head: headBeforeTransform,\n      content,\n      assets\n    })) || []\n  )\n\n  let inlinedScript = ''\n  if (config.mpa && result) {\n    const matchingChunk = result.output.find(\n      (chunk) =>\n        chunk.type === 'chunk' &&\n        chunk.facadeModuleId === slash(path.join(config.srcDir, page))\n    ) as Rollup.OutputChunk\n    if (matchingChunk) {\n      if (!matchingChunk.code.includes('import')) {\n        inlinedScript = `<script type=\"module\">${matchingChunk.code}</script>`\n        fs.removeSync(path.resolve(config.outDir, matchingChunk.fileName))\n      } else {\n        inlinedScript = `<script type=\"module\" src=\"${siteData.base}${matchingChunk.fileName}\"></script>`\n      }\n    }\n  }\n\n  const dir = pageData.frontmatter.dir || siteData.dir || 'ltr'\n\n  const html = `<!DOCTYPE html>\n<html lang=\"${siteData.lang}\" dir=\"${dir}\">\n  <head>\n    <meta charset=\"utf-8\">\n    ${\n      isMetaViewportOverridden(head)\n        ? ''\n        : '<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">'\n    }\n    <title>${escapeHtml(title)}</title>\n    ${\n      isDescriptionOverridden(head)\n        ? ''\n        : `<meta name=\"description\" content=\"${description}\">`\n    }\n    <meta name=\"generator\" content=\"VitePress v${version}\">\n    ${stylesheetLink}\n    <link rel=\"preload stylesheet\" href=\"${siteData.base}vp-icons.css\" as=\"style\">\n    ${metadataScript.inHead ? metadataScript.html : ''}\n    ${\n      appChunk\n        ? `<script type=\"module\" src=\"${siteData.base}${appChunk.fileName}\"></script>`\n        : ''\n    }\n    ${await renderHead(head)}\n  </head>\n  <body>${teleports?.body || ''}\n    <div id=\"app\">${page === '404.md' ? '' : content}</div>\n    ${metadataScript.inHead ? '' : metadataScript.html}\n    ${inlinedScript}\n  </body>\n</html>`\n\n  const htmlFileName = path.join(config.outDir, page.replace(/\\.md$/, '.html'))\n  await fs.ensureDir(path.dirname(htmlFileName))\n  const transformedHtml = await config.transformHtml?.(html, htmlFileName, {\n    page,\n    siteConfig: config,\n    siteData,\n    pageData,\n    title,\n    description,\n    head,\n    content,\n    assets\n  })\n  await fs.writeFile(htmlFileName, transformedHtml || html)\n}\n\nfunction resolvePageImports(\n  config: SiteConfig,\n  page: string,\n  result: Rollup.RollupOutput,\n  appChunk: Rollup.OutputChunk\n) {\n  page = config.rewrites.inv[page] || page\n  // find the page's js chunk and inject script tags for its imports so that\n  // they start fetching as early as possible\n  let srcPath = path.resolve(config.srcDir, page)\n  try {\n    if (!config.vite?.resolve?.preserveSymlinks) {\n      srcPath = fs.realpathSync(srcPath)\n    }\n  } catch (e) {\n    // if the page is a virtual page generated by a dynamic route this would\n    // fail, which is expected\n  }\n  srcPath = normalizePath(srcPath)\n  const pageChunk = result.output.find(\n    (chunk) => chunk.type === 'chunk' && chunk.facadeModuleId === srcPath\n  ) as Rollup.OutputChunk\n  return [\n    ...appChunk.imports,\n    // ...appChunk.dynamicImports,\n    ...pageChunk.imports\n    // ...pageChunk.dynamicImports\n  ]\n}\n\nasync function renderHead(head: HeadConfig[]): Promise<string> {\n  const tags = await Promise.all(\n    head.map(async ([tag, attrs = {}, innerHTML = '']) => {\n      const openTag = `<${tag}${renderAttrs(attrs)}>`\n      if (tag !== 'link' && tag !== 'meta') {\n        if (\n          tag === 'script' &&\n          (attrs.type === undefined || attrs.type.includes('javascript'))\n        ) {\n          innerHTML = await minifyScript(innerHTML, 'inline-script.js')\n        }\n        return `${openTag}${innerHTML}</${tag}>`\n      } else {\n        return openTag\n      }\n    })\n  )\n  return tags.join('\\n    ')\n}\n\nfunction renderAttrs(attrs: Record<string, string>): string {\n  return Object.keys(attrs)\n    .map((key) => {\n      if (isBooleanAttr(key)) return ` ${key}`\n      return ` ${key}=\"${escapeHtml(attrs[key] as string)}\"`\n    })\n    .join('')\n}\n\nasync function minifyScript(code: string, filename: string): Promise<string> {\n  // @ts-ignore use oxc-minify when rolldown-vite is used\n  if (vite.rolldownVersion) {\n    const oxcMinify = await import('oxc-minify')\n    return (await oxcMinify.minify(filename, code)).code.trim()\n  }\n  return (\n    await transformWithEsbuild(code, filename, { minify: true })\n  ).code.trim()\n}\n\nfunction filterOutHeadDescription(head: HeadConfig[] = []) {\n  return head.filter(([type, attrs]) => {\n    return !(type === 'meta' && attrs?.name === 'description')\n  })\n}\n\nfunction isDescriptionOverridden(head: HeadConfig[] = []) {\n  return head.some(([type, attrs]) => {\n    return type === 'meta' && attrs?.name === 'description'\n  })\n}\n\nfunction isMetaViewportOverridden(head: HeadConfig[] = []) {\n  return head.some(([type, attrs]) => {\n    return type === 'meta' && attrs?.name === 'viewport'\n  })\n}\n"
  },
  {
    "path": "src/node/cli.ts",
    "content": "import minimist from 'minimist'\nimport c from 'picocolors'\nimport { createLogger, type Logger } from 'vite'\nimport {\n  build,\n  createServer,\n  disposeMdItInstance,\n  resolveConfig,\n  serve\n} from '.'\nimport { version } from '../../package.json'\nimport { init } from './init/init'\nimport { clearCache } from './markdownToVue'\nimport { bindShortcuts } from './shortcuts'\n\nif (process.env.DEBUG) {\n  Error.stackTraceLimit = Infinity\n}\n\nconst argv: any = minimist(process.argv.slice(2))\n\nObject.keys(argv).forEach((key) => {\n  if (argv[key] === 'true') {\n    argv[key] = true\n  } else if (argv[key] === 'false') {\n    argv[key] = false\n  }\n})\n\nconst logVersion = (logger: Logger) => {\n  logger.info(`\\n  ${c.green(`${c.bold('vitepress')} v${version}`)}\\n`, {\n    clear: !logger.hasWarned\n  })\n}\n\nconst command = argv._[0]\nconst root = argv._[command ? 1 : 0]\nif (root) {\n  argv.root = root\n}\n\nlet restartPromise: Promise<void> | undefined\n\nif (!command || command === 'dev') {\n  if (argv.force) {\n    delete argv.force\n    argv.optimizeDeps = { force: true }\n  }\n\n  let config = await resolveConfig(root, argv).catch(\n    logErrorAndExit.bind(null, `failed to resolve config. error:`)\n  )\n  const createDevServer = async (isRestart = true) => {\n    const server = await createServer(root, argv, restartServer, config)\n    function restartServer() {\n      if (!restartPromise) {\n        restartPromise = (async () => {\n          try {\n            config = await resolveConfig(root, argv)\n          } catch (err: any) {\n            logError(`failed to resolve config. error:`, err)\n            return\n          }\n          disposeMdItInstance()\n          clearCache()\n          await server.close()\n          await createDevServer()\n        })().finally(() => {\n          restartPromise = undefined\n        })\n      }\n      return restartPromise\n    }\n    await server.listen(undefined, isRestart)\n    logVersion(server.config.logger)\n    server.printUrls()\n    bindShortcuts(server, restartServer)\n  }\n  createDevServer(false).catch(\n    logErrorAndExit.bind(null, `failed to start server. error:`)\n  )\n} else if (command === 'init') {\n  createLogger().info('', { clear: true })\n  init(argv.root)\n} else {\n  if (command === 'build') {\n    build(root, {\n      ...argv,\n      onAfterConfigResolve(siteConfig) {\n        logVersion(siteConfig.logger)\n      }\n    }).catch(logErrorAndExit.bind(null, `build error:`))\n  } else if (command === 'serve' || command === 'preview') {\n    serve(argv).catch(\n      logErrorAndExit.bind(null, `failed to start server. error:`)\n    )\n  } else {\n    logErrorAndExit(`unknown command \"${command}\".`)\n  }\n}\n\nfunction logErrorAndExit(message: string, err?: any): never {\n  logError(message, err)\n  process.exit(1)\n}\n\nfunction logError(message: string, err?: any) {\n  const logger = createLogger()\n  logger.error(\n    [\n      c.red(message),\n      err && 'message' in err && err.message,\n      err && 'stack' in err && err.stack\n    ]\n      .filter(Boolean)\n      .join('\\n')\n  )\n}\n"
  },
  {
    "path": "src/node/config.ts",
    "content": "import { createDebug } from 'obug'\nimport fs from 'fs-extra'\nimport path from 'node:path'\nimport c from 'picocolors'\nimport {\n  createLogger,\n  loadConfigFromFile,\n  mergeConfig as mergeViteConfig,\n  normalizePath,\n  type ConfigEnv\n} from 'vite'\nimport { DEFAULT_THEME_PATH } from './alias'\nimport type { DefaultTheme } from './defaultTheme'\nimport { resolvePages } from './plugins/dynamicRoutesPlugin'\nimport {\n  APPEARANCE_KEY,\n  VP_SOURCE_KEY,\n  isObject,\n  slash,\n  type AdditionalConfig,\n  type Awaitable,\n  type HeadConfig,\n  type SiteData\n} from './shared'\nimport type { RawConfigExports, SiteConfig, UserConfig } from './siteConfig'\nimport { glob } from './utils/glob'\n\nexport { resolvePages } from './plugins/dynamicRoutesPlugin'\nexport { resolveSiteDataByRoute } from './shared'\nexport * from './siteConfig'\n\nconst debug = createDebug('vitepress:config')\n\nconst resolve = (root: string, file: string) =>\n  normalizePath(path.resolve(root, `.vitepress`, file))\n\nexport type { ConfigEnv }\nexport type UserConfigFn<ThemeConfig> = (\n  env: ConfigEnv\n) => Awaitable<UserConfig<ThemeConfig>>\nexport type UserConfigExport<ThemeConfig> =\n  | Awaitable<UserConfig<ThemeConfig>>\n  | UserConfigFn<ThemeConfig>\n\n/**\n * Type config helper\n */\nexport function defineConfig<ThemeConfig = DefaultTheme.Config>(\n  config: UserConfig<NoInfer<ThemeConfig>>\n) {\n  return config\n}\n\nexport type AdditionalConfigFn<ThemeConfig> = (\n  env: ConfigEnv\n) => Awaitable<AdditionalConfig<ThemeConfig>>\nexport type AdditionalConfigExport<ThemeConfig> =\n  | Awaitable<AdditionalConfig<ThemeConfig>>\n  | AdditionalConfigFn<ThemeConfig>\n\n/**\n *  Type config helper for additional/locale-specific config\n */\nexport function defineAdditionalConfig<ThemeConfig = DefaultTheme.Config>(\n  config: AdditionalConfig<NoInfer<ThemeConfig>>\n) {\n  return config\n}\n\n/**\n * Type config helper for custom theme config\n *\n * @deprecated use `defineConfig` instead\n */\nexport function defineConfigWithTheme<ThemeConfig>(\n  config: UserConfig<ThemeConfig>\n) {\n  return config\n}\n\nexport async function resolveConfig(\n  root: string = process.cwd(),\n  command: 'serve' | 'build' = 'serve',\n  mode = 'development'\n): Promise<SiteConfig> {\n  // normalize root into absolute path\n  root = normalizePath(path.resolve(root))\n\n  const [userConfig, configPath, configDeps] = await resolveUserConfig(\n    root,\n    command,\n    mode\n  )\n\n  const logger =\n    userConfig.vite?.customLogger ??\n    createLogger(userConfig.vite?.logLevel, {\n      prefix: '[vitepress]',\n      allowClearScreen: userConfig.vite?.clearScreen\n    })\n  const site = await resolveSiteData(root, userConfig)\n  const srcDir = normalizePath(path.resolve(root, userConfig.srcDir || '.'))\n  const assetsDir = userConfig.assetsDir\n    ? slash(userConfig.assetsDir).replace(/^\\.?\\/|\\/$/g, '')\n    : 'assets'\n  const outDir = userConfig.outDir\n    ? normalizePath(path.resolve(root, userConfig.outDir))\n    : resolve(root, 'dist')\n  const cacheDir = userConfig.cacheDir\n    ? normalizePath(path.resolve(root, userConfig.cacheDir))\n    : resolve(root, 'cache')\n\n  const resolvedAssetsDir = normalizePath(path.resolve(outDir, assetsDir))\n  if (!resolvedAssetsDir.startsWith(outDir)) {\n    throw new Error(\n      [\n        `assetsDir cannot be set to a location outside of the outDir.`,\n        `outDir: ${outDir}`,\n        `assetsDir: ${assetsDir}`,\n        `resolved: ${resolvedAssetsDir}`\n      ].join('\\n  ')\n    )\n  }\n\n  // resolve theme path\n  const userThemeDir = resolve(root, 'theme')\n  const themeDir = (await fs.pathExists(userThemeDir))\n    ? userThemeDir\n    : DEFAULT_THEME_PATH\n\n  const config: Omit<SiteConfig, 'pages' | 'dynamicRoutes' | 'rewrites'> = {\n    root,\n    srcDir,\n    assetsDir,\n    site,\n    themeDir,\n    configPath,\n    configDeps,\n    outDir,\n    cacheDir,\n    logger,\n    tempDir: resolve(root, '.temp'),\n    markdown: userConfig.markdown,\n    lastUpdated:\n      userConfig.lastUpdated ?? !!userConfig.themeConfig?.lastUpdated,\n    vue: userConfig.vue,\n    vite: userConfig.vite,\n    shouldPreload: userConfig.shouldPreload,\n    mpa: !!userConfig.mpa,\n    metaChunk: !!userConfig.metaChunk,\n    ignoreDeadLinks: userConfig.ignoreDeadLinks,\n    cleanUrls: !!userConfig.cleanUrls,\n    useWebFonts:\n      userConfig.useWebFonts ??\n      typeof process.versions.webcontainer === 'string',\n    postRender: userConfig.postRender,\n    buildEnd: userConfig.buildEnd,\n    transformHead: userConfig.transformHead,\n    transformHtml: userConfig.transformHtml,\n    transformPageData: userConfig.transformPageData,\n    userConfig,\n    sitemap: userConfig.sitemap,\n    buildConcurrency: userConfig.buildConcurrency ?? 64\n  }\n\n  // to be shared with content loaders\n  // @ts-ignore\n  global.VITEPRESS_CONFIG = config\n\n  // resolve pages after setting global, so that path loaders can access it\n  await resolvePages(config, true)\n\n  return config as SiteConfig\n}\n\nconst supportedConfigExtensions = ['js', 'ts', 'mjs', 'mts']\nconst additionalConfigRE = /(?:^|\\/|\\\\)config\\.m?[jt]s$/\nconst additionalConfigGlob = `**/config.{js,mjs,ts,mts}`\n\nexport function isAdditionalConfigFile(path: string) {\n  return additionalConfigRE.test(path)\n}\n\nasync function gatherAdditionalConfig(\n  root: string,\n  command: 'serve' | 'build',\n  mode: string,\n  srcDir: string = '.',\n  srcExclude: string[] = []\n) {\n  //\n\n  const candidates = await glob([additionalConfigGlob], {\n    cwd: path.resolve(root, srcDir),\n    ignore: srcExclude\n  })\n\n  const deps: string[][] = []\n\n  const exports = await Promise.all(\n    candidates.map(async (file) => {\n      const id = normalizePath(`/${path.dirname(file)}/`)\n\n      const configExports = await loadConfigFromFile(\n        { command, mode },\n        normalizePath(path.resolve(root, srcDir, file)),\n        root\n      ).catch(console.error) // Skip additionalConfig file if it fails to load\n\n      if (!configExports) {\n        debug(`Failed to load additional config from ${file}`)\n        return\n      }\n\n      deps.push(\n        configExports.dependencies.map((file) =>\n          normalizePath(path.resolve(file))\n        )\n      )\n\n      if (mode === 'development') {\n        ;(configExports.config as any)[VP_SOURCE_KEY] = '/' + slash(file)\n      }\n\n      return [id, configExports.config as AdditionalConfig] as const\n    })\n  )\n\n  return [Object.fromEntries(exports.filter((e) => e != null)), deps] as const\n}\n\nexport async function resolveUserConfig(\n  root: string,\n  command: 'serve' | 'build',\n  mode: string\n): Promise<[UserConfig, configPath: string | undefined, configDeps: string[]]> {\n  // load user config\n  const configPath = supportedConfigExtensions\n    .flatMap((ext) => [\n      resolve(root, `config/index.${ext}`),\n      resolve(root, `config.${ext}`)\n    ])\n    .find(fs.pathExistsSync)\n\n  let userConfig: RawConfigExports = {}\n  let configDeps: string[] = []\n  if (!configPath) {\n    debug(`no config file found.`)\n  } else {\n    const configExports = await loadConfigFromFile(\n      { command, mode },\n      configPath,\n      root\n    )\n    if (configExports) {\n      userConfig = configExports.config\n      configDeps = configExports.dependencies.map((file) =>\n        normalizePath(path.resolve(file))\n      )\n    }\n    debug(`loaded config at ${c.yellow(configPath)}`)\n  }\n\n  // Auto-generate additional config if user leaves it unspecified\n  if (userConfig.additionalConfig === undefined) {\n    const [additionalConfig, additionalDeps] = await gatherAdditionalConfig(\n      root,\n      command,\n      mode,\n      userConfig.srcDir,\n      userConfig.srcExclude\n    )\n    userConfig.additionalConfig = additionalConfig\n    configDeps = configDeps.concat(...additionalDeps)\n  }\n\n  return [await resolveConfigExtends(userConfig), configPath, configDeps]\n}\n\nasync function resolveConfigExtends(\n  config: RawConfigExports\n): Promise<UserConfig> {\n  const resolved = await (typeof config === 'function' ? config() : config)\n  if (resolved.extends) {\n    const base = await resolveConfigExtends(resolved.extends)\n    return mergeConfig(base, resolved)\n  }\n  return resolved\n}\n\nexport function mergeConfig(a: UserConfig, b: UserConfig, isRoot = true) {\n  const merged: Record<string, any> = { ...a }\n  for (const key in b) {\n    const value = b[key as keyof UserConfig]\n    if (value == null) {\n      continue\n    }\n    const existing = merged[key]\n    if (Array.isArray(existing) && Array.isArray(value)) {\n      merged[key] = [...existing, ...value]\n      continue\n    }\n    if (isObject(existing) && isObject(value)) {\n      if (isRoot && key === 'vite') {\n        merged[key] = mergeViteConfig(existing, value)\n      } else {\n        merged[key] = mergeConfig(existing, value, false)\n      }\n      continue\n    }\n    merged[key] = value\n  }\n  return merged\n}\n\nexport async function resolveSiteData(\n  root: string,\n  userConfig?: UserConfig,\n  command: 'serve' | 'build' = 'serve',\n  mode = 'development'\n): Promise<SiteData> {\n  userConfig = userConfig || (await resolveUserConfig(root, command, mode))[0]\n\n  return {\n    lang: userConfig.lang || 'en-US',\n    dir: userConfig.dir || 'ltr',\n    title: userConfig.title || 'VitePress',\n    titleTemplate: userConfig.titleTemplate,\n    description: userConfig.description || 'A VitePress site',\n    base: userConfig.base ? userConfig.base.replace(/([^/])$/, '$1/') : '/',\n    head: resolveSiteDataHead(userConfig),\n    router: {\n      prefetchLinks: userConfig.router?.prefetchLinks ?? true\n    },\n    appearance: userConfig.appearance ?? true,\n    themeConfig: userConfig.themeConfig || {},\n    locales: userConfig.locales || {},\n    scrollOffset: userConfig.scrollOffset ?? 134,\n    cleanUrls: !!userConfig.cleanUrls,\n    contentProps: userConfig.contentProps,\n    additionalConfig: userConfig.additionalConfig\n  }\n}\n\nfunction resolveSiteDataHead(userConfig?: UserConfig): HeadConfig[] {\n  const head = userConfig?.head ?? []\n  if (userConfig?.mpa) return head\n\n  // add inline script to apply dark mode, if user enables the feature.\n  // this is required to prevent \"flash\" on initial page load.\n  if (userConfig?.appearance ?? true) {\n    // if appearance mode set to light or dark, default to the defined mode\n    // in case the user didn't specify a preference - otherwise, default to auto\n    const fallbackPreference =\n      typeof userConfig?.appearance === 'string'\n        ? userConfig?.appearance\n        : typeof userConfig?.appearance === 'object'\n          ? (userConfig.appearance.initialValue ?? 'auto')\n          : 'auto'\n\n    head.push([\n      'script',\n      { id: 'check-dark-mode' },\n      fallbackPreference === 'force-dark'\n        ? `document.documentElement.classList.add('dark')`\n        : fallbackPreference === 'force-auto'\n          ? `;(() => {\n               if (window.matchMedia('(prefers-color-scheme: dark)').matches)\n                 document.documentElement.classList.add('dark')\n             })()`\n          : `;(() => {\n               const preference = localStorage.getItem('${APPEARANCE_KEY}') || '${fallbackPreference}'\n               const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches\n               if (!preference || preference === 'auto' ? prefersDark : preference === 'dark')\n                 document.documentElement.classList.add('dark')\n             })()`\n    ])\n  }\n\n  head.push([\n    'script',\n    { id: 'check-mac-os' },\n    `document.documentElement.classList.toggle('mac', /Mac|iPhone|iPod|iPad/i.test(navigator.platform))`\n  ])\n\n  return head\n}\n"
  },
  {
    "path": "src/node/contentLoader.ts",
    "content": "import fs from 'fs-extra'\nimport matter from 'gray-matter'\nimport path from 'node:path'\nimport pMap from 'p-map'\nimport { normalizePath } from 'vite'\nimport type { SiteConfig } from './config'\nimport { createMarkdownRenderer } from './markdown/markdown'\nimport type { Awaitable } from './shared'\nimport { glob, normalizeGlob, type GlobOptions } from './utils/glob'\n\nexport interface ContentOptions<T = ContentData[]> {\n  /**\n   * Include src?\n   * @default false\n   */\n  includeSrc?: boolean\n\n  /**\n   * Render src to HTML and include in data?\n   * @default false\n   */\n  render?: boolean\n\n  /**\n   * If `boolean`, whether to parse and include excerpt? (rendered as HTML)\n   *\n   * If `function`, control how the excerpt is extracted from the content.\n   *\n   * If `string`, define a custom separator to be used for extracting the\n   * excerpt. Default separator is `---` if `excerpt` is `true`.\n   *\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt\n   * @see https://github.com/jonschlinkert/gray-matter#optionsexcerpt_separator\n   *\n   * @default false\n   */\n  excerpt?:\n    | boolean\n    | ((\n        file: {\n          data: { [key: string]: any }\n          content: string\n          excerpt?: string\n        },\n        options?: any\n      ) => void)\n    | string\n\n  /**\n   * Transform the data. Note the data will be inlined as JSON in the client\n   * bundle if imported from components or markdown files.\n   */\n  transform?: (data: ContentData[]) => Awaitable<T>\n\n  /**\n   * Options to pass to `tinyglobby` and `picomatch` for globbing.\n   */\n  globOptions?: GlobOptions\n}\n\nexport interface ContentData {\n  url: string\n  src: string | undefined\n  html: string | undefined\n  frontmatter: Record<string, any>\n  excerpt: string | undefined\n}\n\n/**\n * Create a loader object that can be directly used as the default export\n * of a data loader file.\n */\nexport function createContentLoader<T = ContentData[]>(\n  /**\n   * files to glob / watch - relative to srcDir\n   */\n  watch: string | string[],\n  options: ContentOptions<T> = {}\n) {\n  const config: SiteConfig = (global as any).VITEPRESS_CONFIG\n  if (!config) {\n    throw new Error(\n      'content loader invoked without an active vitepress process, ' +\n        'or before vitepress config is resolved.'\n    )\n  }\n\n  const cache = new Map<string, { data: any; timestamp: number }>()\n\n  watch = normalizeGlob(watch, config.srcDir)\n\n  return {\n    watch,\n    options: { globOptions: options.globOptions },\n\n    async load(files?: string[]) {\n      // the loader is being called directly, do a fresh glob\n      files ??= await glob(watch, {\n        absolute: true,\n        ...options.globOptions\n      })\n\n      const md = await createMarkdownRenderer(\n        config.srcDir,\n        config.markdown,\n        config.site.base,\n        config.logger\n      )\n\n      const raw = await pMap(\n        files,\n        async (file) => {\n          if (!file.endsWith('.md')) return null\n\n          const timestamp = fs.statSync(file).mtimeMs\n          const cached = cache.get(file)\n\n          if (cached && timestamp === cached.timestamp) return cached.data\n\n          const src = fs.readFileSync(file, 'utf-8')\n\n          const renderExcerpt = options.excerpt\n          const { data: frontmatter, excerpt } = matter(\n            src,\n            typeof renderExcerpt === 'string'\n              ? { excerpt_separator: renderExcerpt }\n              : { excerpt: renderExcerpt as any } // gray-matter types are wrong\n          )\n\n          const url =\n            '/' +\n            normalizePath(path.relative(config.srcDir, file))\n              .replace(/(^|\\/)index\\.md$/, '$1')\n              .replace(/\\.md$/, config.cleanUrls ? '' : '.html')\n\n          const html = options.render ? await md.renderAsync(src) : undefined\n          const renderedExcerpt = renderExcerpt\n            ? excerpt && (await md.renderAsync(excerpt))\n            : undefined\n\n          const data: ContentData = {\n            src: options.includeSrc ? src : undefined,\n            html,\n            frontmatter,\n            excerpt: renderedExcerpt,\n            url\n          }\n\n          cache.set(file, { data, timestamp })\n          return data\n        },\n        { concurrency: config.buildConcurrency }\n      )\n\n      const filtered = raw.filter((i) => i !== null)\n      return options.transform?.(filtered) ?? (filtered as T)\n    }\n  }\n}\n"
  },
  {
    "path": "src/node/defaultTheme.ts",
    "content": "// this file contains node-only types of default theme\n// (functions starting with _ are node-only)\n// in most of the cases these will leak to client too\n// but these can import types from dev deps\n\nimport type { MarkdownItAsync } from 'markdown-it-async'\nimport type { DefaultTheme } from '../../types/default-theme'\nimport type { PageSplitSection } from '../../types/local-search'\nimport type { Awaitable, MarkdownEnv } from './shared'\n\ndeclare module '../../types/default-theme.js' {\n  namespace DefaultTheme {\n    interface LocalSearchOptions {\n      /**\n       * Allows transformation of content before indexing (node only)\n       * Return empty string to skip indexing\n       */\n      _render?: (\n        src: string,\n        env: MarkdownEnv,\n        md: MarkdownItAsync\n      ) => Awaitable<string>\n    }\n\n    interface MiniSearchOptions {\n      /**\n       * Overrides the default regex based page splitter.\n       * Supports async generator, making it possible to run in true parallel\n       * (when used along with `node:child_process` or `worker_threads`)\n       * ---\n       * This should be especially useful for scalability reasons.\n       * ---\n       * @param {string} path - absolute path to the markdown source file\n       * @param {string} html - document page rendered as html\n       */\n      _splitIntoSections?: (\n        path: string,\n        html: string\n      ) =>\n        | AsyncGenerator<PageSplitSection>\n        | Generator<PageSplitSection>\n        | Awaitable<PageSplitSection[]>\n    }\n  }\n}\n\nexport type { DefaultTheme }\n"
  },
  {
    "path": "src/node/index.ts",
    "content": "export { loadEnv, type Plugin } from 'vite'\nexport * from './build/build'\nexport * from './config'\nexport * from './contentLoader'\nexport type { DefaultTheme } from './defaultTheme'\nexport * from './init/init'\nexport * from './markdown/markdown'\nexport {\n  defineRoutes,\n  type ResolvedRouteConfig,\n  type RouteModule\n} from './plugins/dynamicRoutesPlugin'\nexport { defineLoader, type LoaderModule } from './plugins/staticDataPlugin'\nexport * from './postcss/isolateStyles'\nexport * from './serve/serve'\nexport * from './server'\nexport * from './utils/getGitTimestamp'\n\n// shared types\nexport type { HeadConfig, Header, SiteData } from '../../types/shared'\n"
  },
  {
    "path": "src/node/init/init.ts",
    "content": "import {\n  cancel,\n  confirm,\n  group,\n  intro,\n  outro,\n  select,\n  text\n} from '@clack/prompts'\nimport fs from 'fs-extra'\nimport template from 'lodash.template'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport c from 'picocolors'\nimport { slash } from '../shared'\n\nexport enum ScaffoldThemeType {\n  Default = 'default theme',\n  DefaultCustom = 'default theme + customization',\n  Custom = 'custom theme'\n}\n\nexport interface ScaffoldOptions {\n  root?: string\n  srcDir?: string\n  title?: string\n  description?: string\n  theme?: ScaffoldThemeType\n  useTs?: boolean\n  injectNpmScripts?: boolean\n  addNpmScriptsPrefix?: boolean\n  npmScriptsPrefix?: string\n}\n\nconst getPackageManger = () => {\n  const name = process.env?.npm_config_user_agent || 'npm'\n  return name.split('/')[0]\n}\n\nexport async function init(root?: string) {\n  intro(c.bold(c.cyan('Welcome to VitePress!')))\n\n  const options = await group(\n    {\n      root: async () => {\n        if (root) return root\n\n        return text({\n          message: 'Where should VitePress initialize the config?',\n          initialValue: './',\n          defaultValue: './',\n          validate() {\n            // TODO make sure directory is inside\n            return undefined\n          }\n        })\n      },\n\n      srcDir: async ({ results }: any) => {\n        return text({\n          message: 'Where should VitePress look for your markdown files?',\n          initialValue: results.root,\n          defaultValue: results.root\n        })\n      },\n\n      title: async () => {\n        return text({\n          message: 'Site title:',\n          placeholder: 'My Awesome Project',\n          defaultValue: 'My Awesome Project'\n        })\n      },\n\n      description: async () => {\n        return text({\n          message: 'Site description:',\n          placeholder: 'A VitePress Site',\n          defaultValue: 'A VitePress Site'\n        })\n      },\n\n      theme: async () => {\n        return select({\n          message: 'Theme:',\n          options: [\n            {\n              value: ScaffoldThemeType.Default,\n              label: 'Default Theme',\n              hint: 'Out of the box, good-looking docs'\n            },\n            {\n              value: ScaffoldThemeType.DefaultCustom,\n              label: 'Default Theme + Customization',\n              hint: 'Add custom CSS and layout slots'\n            },\n            {\n              value: ScaffoldThemeType.Custom,\n              label: 'Custom Theme',\n              hint: 'Build your own or use external'\n            }\n          ]\n        })\n      },\n\n      useTs: async () => {\n        return confirm({\n          message: 'Use TypeScript for config and theme files?'\n        })\n      },\n\n      injectNpmScripts: async () => {\n        return confirm({\n          message: 'Add VitePress npm scripts to package.json?'\n        })\n      },\n\n      addNpmScriptsPrefix: async ({ results }: any) => {\n        if (!results.injectNpmScripts) return false\n\n        return confirm({\n          message: 'Add a prefix for VitePress npm scripts?'\n        })\n      },\n\n      npmScriptsPrefix: async ({ results }: any) => {\n        if (!results.addNpmScriptsPrefix) return 'docs'\n\n        return text({\n          message: 'Prefix for VitePress npm scripts:',\n          placeholder: 'docs',\n          defaultValue: 'docs'\n        })\n      }\n    },\n    {\n      onCancel: () => {\n        cancel('Cancelled.')\n        process.exit(0)\n      }\n    }\n  )\n\n  outro(scaffold(options))\n}\n\nexport function scaffold({\n  root: root_ = './',\n  srcDir: srcDir_ = root_,\n  title = 'My Awesome Project',\n  description = 'A VitePress Site',\n  theme = ScaffoldThemeType.Default,\n  useTs = true,\n  injectNpmScripts = true,\n  addNpmScriptsPrefix = true,\n  npmScriptsPrefix = 'docs'\n}: ScaffoldOptions) {\n  const resolvedRoot = path.resolve(root_)\n  const root = path.relative(process.cwd(), resolvedRoot)\n\n  const resolvedSrcDir = path.resolve(srcDir_)\n  const srcDir = path.relative(resolvedRoot, resolvedSrcDir)\n\n  const templateDir = path.resolve(\n    path.dirname(fileURLToPath(import.meta.url)),\n    '../../template'\n  )\n\n  const data = {\n    srcDir: srcDir ? JSON.stringify(srcDir) : undefined, // omit if default\n    title: JSON.stringify(title),\n    description: JSON.stringify(description),\n    useTs,\n    defaultTheme:\n      theme === ScaffoldThemeType.Default ||\n      theme === ScaffoldThemeType.DefaultCustom\n  }\n\n  const pkgPath = path.resolve('package.json')\n  const userPkg = fs.existsSync(pkgPath)\n    ? JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n    : {}\n\n  const useMjs = userPkg.type !== 'module'\n\n  const renderFile = (file: string) => {\n    const filePath = path.resolve(templateDir, file)\n    let targetPath = path.resolve(resolvedRoot, file)\n\n    if (useMjs && file === '.vitepress/config.js') {\n      targetPath = targetPath.replace(/\\.js$/, '.mjs')\n    }\n    if (useTs) {\n      targetPath = targetPath.replace(/\\.(m?)js$/, '.$1ts')\n    }\n    if (file.endsWith('.md')) {\n      targetPath = path.resolve(resolvedSrcDir, file)\n    }\n\n    const content = fs.readFileSync(filePath, 'utf-8')\n    const compiled = template(content)(data)\n\n    fs.outputFileSync(targetPath, compiled)\n  }\n\n  const filesToScaffold = [\n    'index.md',\n    'api-examples.md',\n    'markdown-examples.md',\n    '.vitepress/config.js'\n  ]\n\n  if (theme === ScaffoldThemeType.DefaultCustom) {\n    filesToScaffold.push(\n      '.vitepress/theme/index.js',\n      '.vitepress/theme/style.css'\n    )\n  } else if (theme === ScaffoldThemeType.Custom) {\n    filesToScaffold.push(\n      '.vitepress/theme/index.js',\n      '.vitepress/theme/style.css',\n      '.vitepress/theme/Layout.vue'\n    )\n  }\n\n  for (const file of filesToScaffold) {\n    renderFile(file)\n  }\n\n  const tips = []\n\n  const gitignorePrefix = root ? `${slash(root)}/.vitepress` : '.vitepress'\n  if (fs.existsSync('.git')) {\n    tips.push(\n      `Make sure to add ${c.cyan(`${gitignorePrefix}/dist`)} and ${c.cyan(`${gitignorePrefix}/cache`)} to your ${c.cyan(`.gitignore`)} file.`\n    )\n  }\n\n  if (\n    theme !== ScaffoldThemeType.Default &&\n    !userPkg.dependencies?.['vue'] &&\n    !userPkg.devDependencies?.['vue']\n  ) {\n    tips.push(\n      `Since you've chosen to customize the theme, you should also explicitly install ${c.cyan(`vue`)} as a dev dependency.`\n    )\n  }\n\n  const tip = tips.length ? c.yellow([`\\n\\nTips:`, ...tips].join('\\n- ')) : ``\n  const dir = root ? ' ' + root : ''\n  const pm = getPackageManger()\n\n  if (injectNpmScripts) {\n    const scripts: Record<string, string> = {}\n    const prefix = addNpmScriptsPrefix ? `${npmScriptsPrefix}:` : ''\n\n    scripts[`${prefix}dev`] = `vitepress dev${dir}`\n    scripts[`${prefix}build`] = `vitepress build${dir}`\n    scripts[`${prefix}preview`] = `vitepress preview${dir}`\n\n    Object.assign(userPkg.scripts || (userPkg.scripts = {}), scripts)\n    fs.writeFileSync(pkgPath, JSON.stringify(userPkg, null, 2))\n\n    return `Done! Now run ${c.cyan(`${pm} run ${prefix}dev`)} and start writing.${tip}`\n  } else {\n    return `You're all set! Now run ${c.cyan(`${pm === 'npm' ? 'npx' : pm} vitepress dev${dir}`)} and start writing.${tip}`\n  }\n}\n"
  },
  {
    "path": "src/node/markdown/markdown.ts",
    "content": "import {\n  componentPlugin,\n  type ComponentPluginOptions\n} from '@mdit-vue/plugin-component'\nimport {\n  frontmatterPlugin,\n  type FrontmatterPluginOptions\n} from '@mdit-vue/plugin-frontmatter'\nimport {\n  headersPlugin,\n  type HeadersPluginOptions\n} from '@mdit-vue/plugin-headers'\nimport { sfcPlugin, type SfcPluginOptions } from '@mdit-vue/plugin-sfc'\nimport { titlePlugin } from '@mdit-vue/plugin-title'\nimport { tocPlugin, type TocPluginOptions } from '@mdit-vue/plugin-toc'\nimport { slugify as defaultSlugify } from '@mdit-vue/shared'\nimport type {\n  CodeToHastOptions,\n  LanguageInput,\n  ShikiTransformer,\n  ThemeRegistrationAny\n} from '@shikijs/types'\nimport anchorPlugin from 'markdown-it-anchor'\nimport { MarkdownItAsync, type MarkdownItAsyncOptions } from 'markdown-it-async'\nimport attrsPlugin, { type MarkdownItAttrsOptions } from 'markdown-it-attrs'\nimport mditCjkFriendly from 'markdown-it-cjk-friendly'\nimport { full as emojiPlugin } from 'markdown-it-emoji'\nimport type { BuiltinLanguage, BuiltinTheme, Highlighter } from 'shiki'\nimport type { Logger } from 'vite'\nimport type { Awaitable } from '../shared'\nimport { containerPlugin, type ContainerOptions } from './plugins/containers'\nimport { gitHubAlertsPlugin } from './plugins/githubAlerts'\nimport { highlight as createHighlighter } from './plugins/highlight'\nimport { imagePlugin, type Options as ImageOptions } from './plugins/image'\nimport { lineNumberPlugin } from './plugins/lineNumbers'\nimport { linkPlugin } from './plugins/link'\nimport { preWrapperPlugin } from './plugins/preWrapper'\nimport { restoreEntities } from './plugins/restoreEntities'\nimport { snippetPlugin } from './plugins/snippet'\n\nexport type { Header } from '../shared'\n\nexport type ThemeOptions =\n  | ThemeRegistrationAny\n  | BuiltinTheme\n  | {\n      light: ThemeRegistrationAny | BuiltinTheme\n      dark: ThemeRegistrationAny | BuiltinTheme\n    }\n\nexport interface MarkdownOptions extends MarkdownItAsyncOptions {\n  /* ==================== General Options ==================== */\n\n  /**\n   * Setup markdown-it instance before applying plugins\n   */\n  preConfig?: (md: MarkdownItAsync) => Awaitable<void>\n  /**\n   * Setup markdown-it instance\n   */\n  config?: (md: MarkdownItAsync) => Awaitable<void>\n  /**\n   * Disable cache (experimental)\n   */\n  cache?: boolean\n  externalLinks?: Record<string, string>\n\n  /* ==================== Syntax Highlighting ==================== */\n\n  /**\n   * Custom theme for syntax highlighting.\n   *\n   * You can also pass an object with `light` and `dark` themes to support dual themes.\n   *\n   * @example { theme: 'github-dark' }\n   * @example { theme: { light: 'github-light', dark: 'github-dark' } }\n   *\n   * You can use an existing theme.\n   * @see https://shiki.style/themes\n   * Or add your own theme.\n   * @see https://shiki.style/guide/load-theme\n   */\n  theme?: ThemeOptions\n  /**\n   * Custom languages for syntax highlighting or pre-load built-in languages.\n   * @see https://shiki.style/languages\n   */\n  languages?: (LanguageInput | BuiltinLanguage)[]\n  /**\n   * Custom language aliases for syntax highlighting.\n   * Maps custom language names to existing languages.\n   * Alias lookup is case-insensitive and underscores in language names are displayed as spaces.\n   *\n   * @example\n   *\n   * Maps `my_lang` to use Python syntax highlighting.\n   * ```js\n   * { 'my_lang': 'python' }\n   * ```\n   *\n   * Usage in markdown:\n   * ````md\n   * ```My_Lang\n   * # This will be highlighted as Python code\n   * # and will show \"My Lang\" as the language label\n   * print(\"Hello, World!\")\n   * ```\n   * ````\n   *\n   * @see https://shiki.style/guide/load-lang#custom-language-aliases\n   */\n  languageAlias?: Record<string, string>\n  /**\n   * Custom language labels for display.\n   * Overrides the default language label shown in code blocks.\n   * Keys are case-insensitive.\n   *\n   * @example { 'vue': 'Vue SFC' }\n   */\n  languageLabel?: Record<string, string>\n  /**\n   * Show line numbers in code blocks\n   * @default false\n   */\n  lineNumbers?: boolean\n  /**\n   * Fallback language when the specified language is not available.\n   */\n  defaultHighlightLang?: string\n  /**\n   * Transformers applied to code blocks\n   * @see https://shiki.style/guide/transformers\n   */\n  codeTransformers?: ShikiTransformer[]\n  /**\n   * Color replacements applied during syntax highlighting.\n   * Accepts either a flat color map or per-theme replacements.\n   * @see https://shiki.style/guide/theme-colors#color-replacements\n   */\n  colorReplacements?: CodeToHastOptions['colorReplacements']\n  /**\n   * Setup Shiki instance\n   */\n  shikiSetup?: (shiki: Highlighter) => void | Promise<void>\n  /**\n   * The tooltip text for the copy button in code blocks\n   * @default 'Copy Code'\n   */\n  codeCopyButtonTitle?: string\n\n  /* ==================== Markdown It Plugins ==================== */\n\n  /**\n   * Options for `markdown-it-anchor`\n   * @see https://github.com/valeriangalliat/markdown-it-anchor\n   */\n  anchor?: anchorPlugin.AnchorOptions\n  /**\n   * Options for `markdown-it-attrs`\n   * @see https://github.com/arve0/markdown-it-attrs\n   */\n  attrs?: MarkdownItAttrsOptions & { disable?: boolean }\n  /**\n   * Options for `markdown-it-emoji`\n   * @see https://github.com/markdown-it/markdown-it-emoji\n   */\n  emoji?: {\n    defs?: Record<string, string>\n    enabled?: string[]\n    shortcuts?: Record<string, string | string[]>\n  }\n  /**\n   * Options for `@mdit-vue/plugin-frontmatter`\n   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-frontmatter\n   */\n  frontmatter?: FrontmatterPluginOptions\n  /**\n   * Options for `@mdit-vue/plugin-headers`\n   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers\n   */\n  headers?: HeadersPluginOptions | boolean\n  /**\n   * Options for `@mdit-vue/plugin-sfc`\n   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-sfc\n   */\n  sfc?: SfcPluginOptions\n  /**\n   * Options for `@mdit-vue/plugin-toc`\n   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc\n   */\n  toc?: TocPluginOptions\n  /**\n   * Options for `@mdit-vue/plugin-component`\n   * @see https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-component\n   */\n  component?: ComponentPluginOptions\n  /**\n   * Options for `markdown-it-container`\n   * @see https://github.com/markdown-it/markdown-it-container\n   */\n  container?: ContainerOptions\n  /**\n   * Math support\n   *\n   * You need to install `markdown-it-mathjax3` and set `math` to `true` to enable it.\n   * You can also pass options to `markdown-it-mathjax3` here.\n   * @default false\n   * @see https://vitepress.dev/guide/markdown#math-equations\n   */\n  math?: boolean | any\n  image?: ImageOptions\n  /**\n   * Allows disabling the github alerts plugin\n   * @default true\n   * @see https://vitepress.dev/guide/markdown#github-flavored-alerts\n   */\n  gfmAlerts?: boolean\n  /**\n   * Allows disabling the CJK-friendly plugin.\n   * This plugin adds support for emphasis marks (**bold**) in Japanese, Chinese, and Korean text.\n   * @default true\n   * @see https://github.com/tats-u/markdown-cjk-friendly\n   */\n  cjkFriendlyEmphasis?: boolean\n  /**\n   * @see cjkFriendlyEmphasis\n   * @deprecated use `cjkFriendly` instead\n   */\n  cjkFriendly?: boolean\n}\n\nexport type MarkdownRenderer = MarkdownItAsync\n\n// highlight is marked as any to avoid type conflicts with plugins expecting\n// regular markdown-it which has sync highlight function. Such plugins will fail\n// if they access highlight directly but currently none of the ones we use do that.\nlet md: (MarkdownRenderer & { options: { highlight?: any } }) | undefined\nlet _disposeHighlighter: (() => void) | undefined\n\nexport function disposeMdItInstance() {\n  if (md) {\n    md = undefined\n    _disposeHighlighter?.()\n  }\n}\n\n/**\n * @experimental\n */\nexport async function createMarkdownRenderer(\n  srcDir: string,\n  options: MarkdownOptions = {},\n  base = '/',\n  logger: Pick<Logger, 'warn'> = console\n): Promise<MarkdownRenderer> {\n  if (md) return md\n\n  const theme = options.theme ?? { light: 'github-light', dark: 'github-dark' }\n  const codeCopyButtonTitle = options.codeCopyButtonTitle || 'Copy Code'\n\n  let [highlight, dispose] = options.highlight\n    ? [options.highlight, () => {}]\n    : await createHighlighter(theme, options, logger)\n\n  _disposeHighlighter = dispose\n\n  md = new MarkdownItAsync({ html: true, linkify: true, highlight, ...options })\n\n  md.linkify.set({ fuzzyLink: false })\n  restoreEntities(md)\n\n  if (options.preConfig) {\n    await options.preConfig(md)\n  }\n\n  const slugify = options.anchor?.slugify ?? defaultSlugify\n\n  // custom plugins\n  componentPlugin(md, options.component)\n  preWrapperPlugin(md, {\n    codeCopyButtonTitle,\n    languageLabel: options.languageLabel\n  })\n  snippetPlugin(md, srcDir)\n  containerPlugin(md, options.container)\n  imagePlugin(md, options.image)\n  linkPlugin(\n    md,\n    { target: '_blank', rel: 'noreferrer', ...options.externalLinks },\n    base,\n    slugify\n  )\n  lineNumberPlugin(md, options.lineNumbers)\n\n  const tableOpen = md.renderer.rules.table_open\n  md.renderer.rules.table_open = function (tokens, idx, options, env, self) {\n    const token = tokens[idx]\n    if (token.attrIndex('tabindex') < 0) token.attrPush(['tabindex', '0'])\n    return tableOpen\n      ? tableOpen(tokens, idx, options, env, self)\n      : self.renderToken(tokens, idx, options)\n  }\n\n  if (options.gfmAlerts !== false) {\n    gitHubAlertsPlugin(md, options.container)\n  }\n\n  // third party plugins\n  if (!options.attrs?.disable) {\n    attrsPlugin(md, options.attrs)\n  }\n  emojiPlugin(md, options.emoji)\n\n  // mdit-vue plugins\n  anchorPlugin(md, {\n    slugify,\n    getTokensText: (tokens) => {\n      return tokens\n        .filter((t) => !['html_inline', 'emoji'].includes(t.type))\n        .map((t) => t.content)\n        .join('')\n    },\n    permalink: (slug, _, state, idx) => {\n      const title =\n        state.tokens[idx + 1]?.children\n          ?.filter((token) => ['text', 'code_inline'].includes(token.type))\n          .reduce((acc, t) => acc + t.content, '')\n          .trim() || ''\n\n      const linkTokens = [\n        Object.assign(new state.Token('text', '', 0), { content: ' ' }),\n        Object.assign(new state.Token('link_open', 'a', 1), {\n          attrs: [\n            ['class', 'header-anchor'],\n            ['href', `#${slug}`],\n            ['aria-label', `Permalink to “${title}”`]\n          ]\n        }),\n        Object.assign(new state.Token('html_inline', '', 0), {\n          content: '&#8203;',\n          meta: { isPermalinkSymbol: true }\n        }),\n        new state.Token('link_close', 'a', -1)\n      ]\n\n      state.tokens[idx + 1].children?.push(...linkTokens)\n    },\n    ...options.anchor\n  })\n\n  frontmatterPlugin(md, options.frontmatter)\n\n  if (options.headers) {\n    headersPlugin(md, {\n      level: [2, 3, 4, 5, 6],\n      slugify,\n      ...(typeof options.headers === 'boolean' ? undefined : options.headers)\n    })\n  }\n\n  sfcPlugin(md, options.sfc)\n  titlePlugin(md)\n  tocPlugin(md, {\n    slugify,\n    ...options.toc,\n    format: (s) => {\n      const title = s.replaceAll('&amp;', '&') // encoded twice because of restoreEntities\n      return options.toc?.format?.(title) ?? title\n    }\n  })\n\n  if (options.math) {\n    try {\n      const mathPlugin = await import('markdown-it-mathjax3')\n      ;(mathPlugin.default ?? mathPlugin)(md, {\n        ...(typeof options.math === 'boolean' ? {} : options.math)\n      })\n      const origMathInline = md.renderer.rules.math_inline!\n      md.renderer.rules.math_inline = function (...args) {\n        return origMathInline\n          .apply(this, args)\n          .replace(/^<mjx-container /, '<mjx-container v-pre ')\n      }\n      const origMathBlock = md.renderer.rules.math_block!\n      md.renderer.rules.math_block = function (...args) {\n        return origMathBlock\n          .apply(this, args)\n          .replace(/^<mjx-container /, '<mjx-container v-pre tabindex=\"0\" ')\n      }\n    } catch (error) {\n      throw new Error(\n        'You need to install `markdown-it-mathjax3@^4` to use math support.'\n      )\n    }\n  }\n\n  if (options.cjkFriendlyEmphasis !== false && options.cjkFriendly !== false) {\n    mditCjkFriendly(md)\n  }\n\n  // apply user config\n  if (options.config) {\n    await options.config(md)\n  }\n\n  return md\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/containers.ts",
    "content": "import type { MarkdownItAsync } from 'markdown-it-async'\nimport container from 'markdown-it-container'\nimport type { RenderRule } from 'markdown-it/lib/renderer.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport type { MarkdownEnv } from '../../shared'\nimport { extractTitle } from './preWrapper'\n\nexport const containerPlugin = (\n  md: MarkdownItAsync,\n  options?: ContainerOptions\n) => {\n  md.use(...createContainer('tip', options?.tipLabel || 'TIP', md))\n    .use(...createContainer('info', options?.infoLabel || 'INFO', md))\n    .use(...createContainer('warning', options?.warningLabel || 'WARNING', md))\n    .use(...createContainer('danger', options?.dangerLabel || 'DANGER', md))\n    .use(...createContainer('details', options?.detailsLabel || 'Details', md))\n    // explicitly escape Vue syntax\n    .use(container, 'v-pre', {\n      render: (tokens: Token[], idx: number) =>\n        tokens[idx].nesting === 1 ? `<div v-pre>\\n` : `</div>\\n`\n    })\n    .use(container, 'raw', {\n      render: (tokens: Token[], idx: number) =>\n        tokens[idx].nesting === 1 ? `<div class=\"vp-raw\">\\n` : `</div>\\n`\n    })\n    .use(...createCodeGroup(md))\n}\n\ntype ContainerArgs = [typeof container, string, { render: RenderRule }]\n\nfunction createContainer(\n  klass: string,\n  defaultTitle: string,\n  md: MarkdownItAsync\n): ContainerArgs {\n  return [\n    container,\n    klass,\n    {\n      render(tokens, idx, _options, env: MarkdownEnv & { references?: any }) {\n        const token = tokens[idx]\n        if (token.nesting === 1) {\n          token.attrJoin('class', `${klass} custom-block`)\n          const attrs = md.renderer.renderAttrs(token)\n          const info = token.info.trim().slice(klass.length).trim()\n          const title = md.renderInline(info || defaultTitle, {\n            references: env.references\n          })\n          const titleClass =\n            'custom-block-title' + (info ? '' : ' custom-block-title-default')\n          if (klass === 'details')\n            return `<details ${attrs}><summary>${title}</summary>\\n`\n          return `<div ${attrs}><p class=\"${titleClass}\">${title}</p>\\n`\n        } else return klass === 'details' ? `</details>\\n` : `</div>\\n`\n      }\n    }\n  ]\n}\n\nfunction createCodeGroup(md: MarkdownItAsync): ContainerArgs {\n  return [\n    container,\n    'code-group',\n    {\n      render(tokens, idx) {\n        if (tokens[idx].nesting === 1) {\n          let tabs = ''\n          let checked = 'checked'\n\n          for (\n            let i = idx + 1;\n            !(\n              tokens[i].nesting === -1 &&\n              tokens[i].type === 'container_code-group_close'\n            );\n            ++i\n          ) {\n            const isHtml = tokens[i].type === 'html_block'\n\n            if (\n              (tokens[i].type === 'fence' && tokens[i].tag === 'code') ||\n              isHtml\n            ) {\n              const title = extractTitle(\n                isHtml ? tokens[i].content : tokens[i].info,\n                isHtml\n              )\n\n              if (title) {\n                tabs += `<input type=\"radio\" name=\"group-${idx}\" id=\"tab-${i}\" ${checked}><label data-title=\"${md.utils.escapeHtml(title)}\" for=\"tab-${i}\">${title}</label>`\n\n                if (checked && !isHtml) tokens[i].info += ' active'\n                checked = ''\n              }\n            }\n          }\n\n          return `<div class=\"vp-code-group\"><div class=\"tabs\">${tabs}</div><div class=\"blocks\">\\n`\n        }\n        return `</div></div>\\n`\n      }\n    }\n  ]\n}\n\nexport interface ContainerOptions {\n  infoLabel?: string\n  noteLabel?: string\n  tipLabel?: string\n  warningLabel?: string\n  dangerLabel?: string\n  detailsLabel?: string\n  importantLabel?: string\n  cautionLabel?: string\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/githubAlerts.ts",
    "content": "import type { MarkdownItAsync } from 'markdown-it-async'\nimport type { ContainerOptions } from './containers'\n\nconst markerRE =\n  /^\\[!(TIP|NOTE|INFO|IMPORTANT|WARNING|CAUTION|DANGER)\\]([^\\n\\r]*)/i\n\nexport const gitHubAlertsPlugin = (\n  md: MarkdownItAsync,\n  options?: ContainerOptions\n) => {\n  const titleMark = {\n    tip: options?.tipLabel || 'TIP',\n    note: options?.noteLabel || 'NOTE',\n    info: options?.infoLabel || 'INFO',\n    important: options?.importantLabel || 'IMPORTANT',\n    warning: options?.warningLabel || 'WARNING',\n    caution: options?.cautionLabel || 'CAUTION',\n    danger: options?.dangerLabel || 'DANGER'\n  } as Record<string, string>\n\n  md.core.ruler.after('block', 'github-alerts', (state) => {\n    const tokens = state.tokens\n    for (let i = 0; i < tokens.length; i++) {\n      if (tokens[i].type === 'blockquote_open') {\n        const startIndex = i\n        const open = tokens[startIndex]\n        let endIndex = i + 1\n        while (\n          endIndex < tokens.length &&\n          (tokens[endIndex].type !== 'blockquote_close' ||\n            tokens[endIndex].level !== open.level)\n        )\n          endIndex++\n        if (endIndex === tokens.length) continue\n        const close = tokens[endIndex]\n        const firstContent = tokens\n          .slice(startIndex, endIndex + 1)\n          .find((token) => token.type === 'inline')\n        if (!firstContent) continue\n        const match = firstContent.content.match(markerRE)\n        if (!match) continue\n        const type = match[1].toLowerCase()\n        const title = match[2].trim() || titleMark[type] || capitalize(type)\n        firstContent.content = firstContent.content\n          .slice(match[0].length)\n          .trimStart()\n        open.type = 'github_alert_open'\n        open.tag = 'div'\n        open.meta = {\n          title,\n          type\n        }\n        close.type = 'github_alert_close'\n        close.tag = 'div'\n      }\n    }\n  })\n  md.renderer.rules.github_alert_open = function (tokens, idx) {\n    const { title, type } = tokens[idx].meta\n    const attrs = ''\n    return `<div class=\"${type} custom-block github-alert\"${attrs}><p class=\"custom-block-title\">${title}</p>\\n`\n  }\n}\n\nfunction capitalize(str: string) {\n  return str.charAt(0).toUpperCase() + str.slice(1)\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/highlight.ts",
    "content": "import {\n  transformerMetaHighlight,\n  transformerNotationDiff,\n  transformerNotationErrorLevel,\n  transformerNotationFocus,\n  transformerNotationHighlight\n} from '@shikijs/transformers'\nimport { customAlphabet } from 'nanoid'\nimport c from 'picocolors'\nimport type { BundledLanguage, ShikiTransformer } from 'shiki'\nimport { createHighlighter, guessEmbeddedLanguages, isSpecialLang } from 'shiki'\nimport type { Logger } from 'vite'\nimport { isShell } from '../../shared'\nimport type { MarkdownOptions, ThemeOptions } from '../markdown'\n\nconst nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10)\n\n/**\n * Prevents the leading '$' symbol etc from being selectable/copyable. Also\n * normalizes its syntax so there's no leading spaces, and only a single\n * trailing space.\n *\n * NOTE: Any changes to this function may also need to update\n * `src/client/app/composables/copyCode.ts`\n */\nfunction transformerDisableShellSymbolSelect(): ShikiTransformer {\n  return {\n    name: 'vitepress:disable-shell-symbol-select',\n    tokens(tokensByLine) {\n      if (!isShell(this.options.lang)) return\n\n      for (const tokens of tokensByLine) {\n        if (tokens.length < 2) continue\n\n        // The first token should only be a symbol token\n        const firstTokenText = tokens[0].content.trim()\n        if (firstTokenText !== '$' && firstTokenText !== '>') continue\n\n        // The second token must have a leading space (separates the symbol)\n        if (tokens[1].content[0] !== ' ') continue\n\n        tokens[0].content = firstTokenText + ' '\n        tokens[0].htmlStyle ??= {}\n        tokens[0].htmlStyle['user-select'] = 'none'\n        tokens[0].htmlStyle['-webkit-user-select'] = 'none'\n        tokens[1].content = tokens[1].content.slice(1)\n      }\n    }\n  }\n}\n\nexport async function highlight(\n  theme: ThemeOptions,\n  options: MarkdownOptions,\n  logger: Pick<Logger, 'warn'> = console\n): Promise<\n  [(str: string, lang: string, attrs: string) => Promise<string>, () => void]\n> {\n  const {\n    defaultHighlightLang: defaultLang = 'txt',\n    codeTransformers: userTransformers = []\n  } = options\n\n  const langAlias = Object.fromEntries(\n    Object.entries(options.languageAlias || {}) //\n      .map(([k, v]) => [k.toLowerCase(), v])\n  )\n\n  const highlighter = await createHighlighter({\n    themes:\n      typeof theme === 'object' && 'light' in theme && 'dark' in theme\n        ? [theme.light, theme.dark]\n        : [theme],\n    langs: [...(options.languages || []), ...Object.values(langAlias)],\n    langAlias\n  })\n\n  await options?.shikiSetup?.(highlighter)\n\n  const transformers: ShikiTransformer[] = [\n    transformerMetaHighlight(),\n    transformerNotationDiff(),\n    transformerNotationFocus({\n      classActiveLine: 'has-focus',\n      classActivePre: 'has-focused-lines'\n    }),\n    transformerNotationHighlight(),\n    transformerNotationErrorLevel(),\n    transformerDisableShellSymbolSelect(),\n    {\n      name: 'vitepress:add-dir',\n      pre(node) {\n        node.properties.dir = 'ltr'\n      }\n    }\n  ]\n\n  // keep in sync with ./preWrapper.ts#extractLang\n  const langRE = /^[a-zA-Z0-9-_]+/\n  const vueRE = /-vue$/\n\n  return [\n    async (str, lang, attrs) => {\n      const match = langRE.exec(lang)\n      if (match) {\n        const orig = lang\n        lang = match[0].toLowerCase()\n        attrs = orig.slice(lang.length).replace(/(?<!=)\\{/g, ' {') + ' ' + attrs\n        attrs = attrs.trim().replace(/\\s+/g, ' ')\n      }\n\n      lang ||= defaultLang\n\n      const vPre = !vueRE.test(lang)\n      if (!vPre) lang = lang.slice(0, -4)\n\n      try {\n        // https://github.com/shikijs/shiki/issues/952\n        if (\n          !isSpecialLang(lang) &&\n          !highlighter.getLoadedLanguages().includes(lang)\n        ) {\n          await highlighter.loadLanguage(lang as any)\n        }\n      } catch {\n        logger.warn(\n          c.yellow(\n            `\\nThe language '${lang}' is not loaded, falling back to '${defaultLang}' for syntax highlighting.`\n          )\n        )\n        lang = defaultLang\n      }\n\n      const mustaches = new Map<string, string>()\n\n      const removeMustache = (s: string) => {\n        if (vPre) return s\n        return s.replace(/\\{\\{.*?\\}\\}/g, (match) => {\n          let marker = mustaches.get(match)\n          if (!marker) {\n            marker = nanoid()\n            mustaches.set(match, marker)\n          }\n          return marker\n        })\n      }\n\n      const restoreMustache = (s: string) => {\n        mustaches.forEach((marker, match) => {\n          s = s.replaceAll(marker, match)\n        })\n        return s\n      }\n\n      str = removeMustache(str).trimEnd()\n\n      const embeddedLang = guessEmbeddedLanguages(str, lang, highlighter)\n      await highlighter.loadLanguage(...(embeddedLang as BundledLanguage[]))\n\n      const highlighted = highlighter.codeToHtml(str, {\n        lang,\n        transformers: [\n          ...transformers,\n          {\n            name: 'vitepress:v-pre',\n            pre(node) {\n              if (vPre) node.properties['v-pre'] = ''\n            }\n          },\n          {\n            name: 'vitepress:empty-line',\n            code(hast) {\n              hast.children.forEach((span) => {\n                if (\n                  span.type === 'element' &&\n                  span.tagName === 'span' &&\n                  Array.isArray(span.properties.class) &&\n                  span.properties.class.includes('line') &&\n                  span.children.length === 0\n                ) {\n                  span.children.push({\n                    type: 'element',\n                    tagName: 'wbr',\n                    properties: {},\n                    children: []\n                  })\n                }\n              })\n            }\n          },\n          ...userTransformers\n        ],\n        meta: { __raw: attrs },\n        ...(typeof theme === 'object' && 'light' in theme && 'dark' in theme\n          ? { themes: theme, defaultColor: false }\n          : { theme }),\n        colorReplacements: {\n          'github-light': {\n            '#959da5': '#6c676f',\n            '#28a745': '#0e790b',\n            '#b08800': '#846312',\n            '#e36209': '#c13617',\n            '#3192aa': '#05728b',\n            '#d73a49': '#c62739',\n            '#22863a': '#11782a',\n            '#6a737d': '#62687b',\n            '#1b7c83': '#06747a',\n            '#0366d6': '#0663d0',\n            '#cb2431': '#c82430'\n          },\n          'github-dark': {\n            '#586069': '#5b93a3',\n            '#6a737d': '#818e99',\n            '#ea4a5a': '#ef5564',\n            '#2188ff': '#268bf9'\n          },\n          ...options.colorReplacements\n        }\n      })\n\n      return restoreMustache(highlighted)\n    },\n    highlighter.dispose\n  ]\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/image.ts",
    "content": "// markdown-it plugin for normalizing image source\n\nimport type { MarkdownItAsync } from 'markdown-it-async'\nimport { EXTERNAL_URL_RE } from '../../shared'\n\nexport interface Options {\n  /**\n   * Support native lazy loading for the `<img>` tag.\n   * @default false\n   */\n  lazyLoading?: boolean\n}\n\nexport const imagePlugin = (\n  md: MarkdownItAsync,\n  { lazyLoading }: Options = {}\n) => {\n  const imageRule = md.renderer.rules.image!\n  md.renderer.rules.image = (tokens, idx, options, env, self) => {\n    const token = tokens[idx]\n    let url = token.attrGet('src')\n    if (url && !EXTERNAL_URL_RE.test(url)) {\n      if (!/^\\.?\\//.test(url)) url = './' + url\n      token.attrSet('src', decodeURIComponent(url))\n    }\n    if (lazyLoading) {\n      token.attrSet('loading', 'lazy')\n    }\n    return imageRule(tokens, idx, options, env, self)\n  }\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/lineNumbers.ts",
    "content": "// markdown-it plugin for generating line numbers.\n// It depends on preWrapper plugin.\n\nimport type { MarkdownItAsync } from 'markdown-it-async'\n\nexport const lineNumberPlugin = (md: MarkdownItAsync, enable = false) => {\n  const fence = md.renderer.rules.fence!\n  md.renderer.rules.fence = (...args) => {\n    const rawCode = fence(...args)\n\n    const [tokens, idx] = args\n    const info = tokens[idx].info\n\n    if (\n      (!enable && !/:line-numbers\\b/.test(info)) ||\n      (enable && /:no-line-numbers\\b/.test(info))\n    ) {\n      return rawCode\n    }\n\n    let startLineNumber = 1\n    const matchStartLineNumber = info.match(/=(\\d+)/)\n    if (matchStartLineNumber && matchStartLineNumber[1]) {\n      startLineNumber = parseInt(matchStartLineNumber[1])\n    }\n\n    const code = rawCode.slice(\n      rawCode.indexOf('<code>'),\n      rawCode.indexOf('</code>')\n    )\n\n    const lines = code.split('\\n')\n\n    const lineNumbersCode = [...Array(lines.length)]\n      .map(\n        (_, index) =>\n          `<span class=\"line-number\">${index + startLineNumber}</span><br>`\n      )\n      .join('')\n\n    const lineNumbersWrapperCode = `<div class=\"line-numbers-wrapper\" aria-hidden=\"true\">${lineNumbersCode}</div>`\n\n    const finalCode = rawCode\n      .replace(/<\\/div>$/, `${lineNumbersWrapperCode}</div>`)\n      .replace(/\"(language-[^\"]*?)\"/, '\"$1 line-numbers-mode\"')\n\n    return finalCode\n  }\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/link.ts",
    "content": "// markdown-it plugin for:\n// 1. adding target=\"_blank\" to external links\n// 2. normalize internal links to end with `.html`\n\nimport type { MarkdownItAsync } from 'markdown-it-async'\nimport { URL } from 'node:url'\nimport {\n  EXTERNAL_URL_RE,\n  isExternal,\n  treatAsHtml,\n  type MarkdownEnv\n} from '../../shared'\n\nconst indexRE = /(^|.*\\/)index.md(#?.*)$/i\n\nexport const linkPlugin = (\n  md: MarkdownItAsync,\n  externalAttrs: Record<string, string>,\n  base: string,\n  slugify: (str: string) => string\n) => {\n  md.renderer.rules.link_open = (\n    tokens,\n    idx,\n    options,\n    env: MarkdownEnv,\n    self\n  ) => {\n    const token = tokens[idx]\n    const hrefIndex = token.attrIndex('href')\n    if (\n      hrefIndex >= 0 &&\n      token.attrIndex('target') < 0 &&\n      token.attrIndex('download') < 0 &&\n      token.attrGet('class') !== 'header-anchor' // header anchors are already normalized\n    ) {\n      const hrefAttr = token.attrs![hrefIndex]\n      let [url, frag] = hrefAttr[1].split(':~:', 2)\n      hrefAttr[1] = url\n      if (isExternal(url)) {\n        Object.entries(externalAttrs).forEach(([key, val]) => {\n          token.attrSet(key, val)\n        })\n        // catch localhost links as dead link\n        if (url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost:')) {\n          pushLink(url, env)\n        }\n        hrefAttr[1] = url\n      } else {\n        const { pathname, protocol } = new URL(url, 'http://a.com')\n\n        if (\n          // skip internal anchor links\n          !url.startsWith('#') &&\n          // skip mail/custom protocol links\n          protocol.startsWith('http') &&\n          // skip links to files (other than html/md)\n          treatAsHtml(pathname)\n        ) {\n          normalizeHref(hrefAttr, env)\n        } else if (url.startsWith('#')) {\n          hrefAttr[1] = decodeURI(normalizeHash(hrefAttr[1]))\n        }\n\n        // append base to internal (non-relative) urls\n        if (hrefAttr[1].startsWith('/')) {\n          hrefAttr[1] = `${base}${hrefAttr[1]}`.replace(/\\/+/g, '/')\n        }\n      }\n      if (frag) {\n        hrefAttr[1] += (hrefAttr[1].includes('#') ? '' : '#') + ':~:' + frag\n      }\n    }\n    return self.renderToken(tokens, idx, options)\n  }\n\n  function normalizeHref(hrefAttr: [string, string], env: MarkdownEnv) {\n    let url = hrefAttr[1]\n\n    const indexMatch = url.match(indexRE)\n    if (indexMatch) {\n      const [, path, hash] = indexMatch\n      url = path + normalizeHash(hash)\n    } else {\n      let cleanUrl = url.replace(/[?#].*$/, '')\n      // transform foo.md -> foo[.html]\n      if (cleanUrl.endsWith('.md')) {\n        cleanUrl = cleanUrl.replace(/\\.md$/, env.cleanUrls ? '' : '.html')\n      }\n      // transform ./foo -> ./foo[.html]\n      if (\n        !env.cleanUrls &&\n        !cleanUrl.endsWith('.html') &&\n        !cleanUrl.endsWith('/')\n      ) {\n        cleanUrl += '.html'\n      }\n      const parsed = new URL(url, 'http://a.com')\n      url = cleanUrl + parsed.search + normalizeHash(parsed.hash)\n    }\n\n    // ensure leading . for relative paths\n    if (!url.startsWith('/') && !url.startsWith('./')) {\n      url = './' + url\n    }\n\n    // export it for existence check\n    pushLink(url.replace(/\\.html$/, ''), env)\n\n    // markdown-it encodes the uri\n    hrefAttr[1] = decodeURI(url)\n  }\n\n  function normalizeHash(str: string) {\n    return str ? encodeURI('#' + slugify(decodeURI(str).slice(1))) : ''\n  }\n\n  function pushLink(link: string, env: MarkdownEnv) {\n    const links = env.links || (env.links = [])\n    links.push(link)\n  }\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/preWrapper.ts",
    "content": "import type { MarkdownItAsync } from 'markdown-it-async'\n\nexport interface Options {\n  codeCopyButtonTitle: string\n  languageLabel?: Record<string, string>\n}\n\nexport function preWrapperPlugin(md: MarkdownItAsync, options: Options) {\n  const langLabel = Object.fromEntries(\n    Object.entries(options.languageLabel || {}) //\n      .map(([k, v]) => [k.toLowerCase(), v])\n  )\n\n  const fence = md.renderer.rules.fence!\n  md.renderer.rules.fence = (...args) => {\n    const [tokens, idx] = args\n    const token = tokens[idx]\n\n    // remove title from info\n    token.info = token.info.replace(/\\[.*\\]/, '')\n\n    const active = / active( |$)/.test(token.info) ? ' active' : ''\n    token.info = token.info.replace(/ active$/, '').replace(/ active /, ' ')\n\n    const lang = extractLang(token.info)\n    const label = langLabel[lang.toLowerCase()] || lang.replace(/_/g, ' ')\n\n    return (\n      `<div class=\"language-${lang}${active}\">` +\n      `<button title=\"${options.codeCopyButtonTitle}\" class=\"copy\"></button>` +\n      `<span class=\"lang\">${label}</span>` +\n      fence(...args) +\n      '</div>'\n    )\n  }\n}\n\nexport function extractTitle(info: string, html = false) {\n  if (html) {\n    return (\n      info.replace(/<!--[^]*?-->/g, '').match(/data-title=\"(.*?)\"/)?.[1] || ''\n    )\n  }\n  return info.match(/\\[(.*)\\]/)?.[1] || extractLang(info) || 'txt'\n}\n\nfunction extractLang(info: string): string {\n  return (\n    /^[a-zA-Z0-9-_]+/\n      .exec(info)?.[0]\n      .replace(/-vue$/, '') // remove -vue suffix\n      .replace(/^vue-html$/, 'template')\n      .replace(/^ansi$/, '') || ''\n  )\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/restoreEntities.ts",
    "content": "import type { MarkdownItAsync } from 'markdown-it-async'\nimport type StateCore from 'markdown-it/lib/rules_core/state_core.mjs'\nimport type Token from 'markdown-it/lib/token.mjs'\nimport { escapeHtml } from '../../shared'\n\nexport function restoreEntities(md: MarkdownItAsync): void {\n  md.core.ruler.at('text_join', text_join)\n  md.renderer.rules.text = (tokens, idx) => escapeHtml(tokens[idx].content)\n}\n\nfunction text_join(state: StateCore): void {\n  let curr, last\n  const blockTokens = state.tokens\n  const l = blockTokens.length\n\n  for (let j = 0; j < l; ++j) {\n    if (blockTokens[j].type !== 'inline') continue\n\n    const tokens = blockTokens[j].children || []\n    const max = tokens.length\n\n    for (curr = 0; curr < max; ++curr)\n      if (tokens[curr].type === 'text_special') tokens[curr].type = 'text'\n\n    for (curr = last = 0; curr < max; ++curr)\n      if (\n        tokens[curr].type === 'text' &&\n        curr + 1 < max &&\n        tokens[curr + 1].type === 'text'\n      ) {\n        tokens[curr + 1].content =\n          getContent(tokens[curr]) + getContent(tokens[curr + 1])\n        tokens[curr + 1].info = ''\n        tokens[curr + 1].markup = ''\n      } else {\n        if (curr !== last) tokens[last] = tokens[curr]\n        ++last\n      }\n\n    if (curr !== last) tokens.length = last\n  }\n}\n\nfunction getContent(token: Token): string {\n  return token.info === 'entity'\n    ? token.markup\n    : token.info === 'escape' && token.content === '&'\n      ? '&amp;'\n      : token.content\n}\n"
  },
  {
    "path": "src/node/markdown/plugins/snippet.ts",
    "content": "import fs from 'fs-extra'\nimport type { MarkdownItAsync } from 'markdown-it-async'\nimport type { RuleBlock } from 'markdown-it/lib/parser_block.mjs'\nimport path from 'node:path'\nimport type { MarkdownEnv } from '../../shared'\n\n/**\n * raw path format: \"/path/to/file.extension#region {meta} [title]\"\n *    where #region, {meta} and [title] are optional\n *    meta can be like '1,2,4-6 lang', 'lang' or '1,2,4-6'\n *    lang can contain special characters like C++, C#, F#, etc.\n *    path can be relative to the current file or absolute\n *    file extension is optional\n *    path can contain spaces and dots\n *\n * captures: ['/path/to/file.extension', 'extension', '#region', '{meta}', '[title]']\n */\nexport const rawPathRegexp =\n  /^(.+?(?:(?:\\.([a-z0-9]+))?))(?:(#[\\w-]+))?(?: ?(?:{(\\d+(?:[,-]\\d+)*)? ?(\\S+)? ?(\\S+)?}))? ?(?:\\[(.+)\\])?$/\n\nexport function rawPathToToken(rawPath: string) {\n  const [\n    filepath = '',\n    extension = '',\n    region = '',\n    lines = '',\n    lang = '',\n    attrs = '',\n    rawTitle = ''\n  ] = (rawPathRegexp.exec(rawPath) || []).slice(1)\n\n  const title = rawTitle || filepath.split('/').pop() || ''\n\n  return { filepath, extension, region, lines, lang, attrs, title }\n}\n\nexport function dedent(text: string): string {\n  const lines = text.split('\\n')\n\n  const minIndentLength = lines.reduce((acc, line) => {\n    for (let i = 0; i < line.length; i++) {\n      if (line[i] !== ' ' && line[i] !== '\\t') return Math.min(i, acc)\n    }\n    return acc\n  }, Infinity)\n\n  if (minIndentLength < Infinity) {\n    return lines.map((x) => x.slice(minIndentLength)).join('\\n')\n  }\n\n  return text\n}\n\nconst markers = [\n  {\n    start: /^\\s*\\/\\/\\s*#?region\\b\\s*(.*?)\\s*$/,\n    end: /^\\s*\\/\\/\\s*#?endregion\\b\\s*(.*?)\\s*$/\n  },\n  {\n    start: /^\\s*<!--\\s*#?region\\b\\s*(.*?)\\s*-->/,\n    end: /^\\s*<!--\\s*#?endregion\\b\\s*(.*?)\\s*-->/\n  },\n  {\n    start: /^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\//,\n    end: /^\\s*\\/\\*\\s*#endregion\\b\\s*(.*?)\\s*\\*\\//\n  },\n  {\n    start: /^\\s*#[rR]egion\\b\\s*(.*?)\\s*$/,\n    end: /^\\s*#[eE]nd ?[rR]egion\\b\\s*(.*?)\\s*$/\n  },\n  {\n    start: /^\\s*#\\s*#?region\\b\\s*(.*?)\\s*$/,\n    end: /^\\s*#\\s*#?endregion\\b\\s*(.*?)\\s*$/\n  },\n  {\n    start: /^\\s*(?:--|::|@?REM)\\s*#region\\b\\s*(.*?)\\s*$/,\n    end: /^\\s*(?:--|::|@?REM)\\s*#endregion\\b\\s*(.*?)\\s*$/\n  },\n  {\n    start: /^\\s*#pragma\\s+region\\b\\s*(.*?)\\s*$/,\n    end: /^\\s*#pragma\\s+endregion\\b\\s*(.*?)\\s*$/\n  },\n  {\n    start: /^\\s*\\(\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\)/,\n    end: /^\\s*\\(\\*\\s*#endregion\\b\\s*(.*?)\\s*\\*\\)/\n  }\n]\n\nexport function findRegion(lines: Array<string>, regionName: string) {\n  let chosen: { re: (typeof markers)[number]; start: number } | null = null\n  // find the regex pair for a start marker that matches the given region name\n  for (let i = 0; i < lines.length; i++) {\n    for (const re of markers) {\n      if (re.start.exec(lines[i])?.[1] === regionName) {\n        chosen = { re, start: i + 1 }\n        break\n      }\n    }\n    if (chosen) break\n  }\n  if (!chosen) return null\n\n  let counter = 1\n  // scan the rest of the lines to find the matching end marker, handling nested markers\n  for (let i = chosen.start; i < lines.length; i++) {\n    // check for an inner start marker for the same region\n    if (chosen.re.start.exec(lines[i])?.[1] === regionName) {\n      counter++\n      continue\n    }\n    // check for an end marker for the same region\n    const endRegion = chosen.re.end.exec(lines[i])?.[1]\n    // allow empty region name on the end marker as a fallback\n    if (endRegion === regionName || endRegion === '') {\n      if (--counter === 0) return { ...chosen, end: i }\n    }\n  }\n\n  return null\n}\n\nexport const snippetPlugin = (md: MarkdownItAsync, srcDir: string) => {\n  const parser: RuleBlock = (state, startLine, endLine, silent) => {\n    const CH = '<'.charCodeAt(0)\n    const pos = state.bMarks[startLine] + state.tShift[startLine]\n    const max = state.eMarks[startLine]\n\n    // if it's indented more than 3 spaces, it should be a code block\n    if (state.sCount[startLine] - state.blkIndent >= 4) {\n      return false\n    }\n\n    for (let i = 0; i < 3; ++i) {\n      const ch = state.src.charCodeAt(pos + i)\n      if (ch !== CH || pos + i >= max) return false\n    }\n\n    if (silent) {\n      return true\n    }\n\n    const start = pos + 3\n    const end = state.skipSpacesBack(max, pos)\n\n    const rawPath = state.src\n      .slice(start, end)\n      .trim()\n      .replace(/^@/, srcDir)\n      .trim()\n\n    const { filepath, extension, region, lines, lang, attrs, title } =\n      rawPathToToken(rawPath)\n\n    state.line = startLine + 1\n\n    const token = state.push('fence', 'code', 0)\n    token.info = `${lang || extension}${lines ? `{${lines}}` : ''}${\n      title ? `[${title}]` : ''\n    }  ${attrs ?? ''}`\n\n    const { realPath, path: _path } = state.env as MarkdownEnv\n    const resolvedPath = path.resolve(path.dirname(realPath ?? _path), filepath)\n\n    // @ts-ignore\n    token.src = [resolvedPath, region.slice(1)]\n    token.markup = '```'\n    token.map = [startLine, startLine + 1]\n\n    return true\n  }\n\n  const fence = md.renderer.rules.fence!\n\n  md.renderer.rules.fence = (...args) => {\n    const [tokens, idx, , { includes }] = args\n    const token = tokens[idx]\n    // @ts-ignore\n    const [src, regionName] = token.src ?? []\n\n    if (!src) return fence(...args)\n\n    if (includes) {\n      includes.push(src)\n    }\n\n    const isAFile = fs.statSync(src).isFile()\n    if (!fs.existsSync(src) || !isAFile) {\n      token.content = isAFile\n        ? `Code snippet path not found: ${src}`\n        : `Invalid code snippet option`\n      token.info = ''\n      return fence(...args)\n    }\n\n    let content = fs.readFileSync(src, 'utf8').replace(/\\r\\n/g, '\\n')\n\n    if (regionName) {\n      const lines = content.split('\\n')\n      const region = findRegion(lines, regionName)\n\n      if (region) {\n        content = dedent(\n          lines\n            .slice(region.start, region.end)\n            .filter((l) => !(region.re.start.test(l) || region.re.end.test(l)))\n            .join('\\n')\n        )\n      }\n    }\n\n    token.content = content\n    return fence(...args)\n  }\n\n  md.block.ruler.before('fence', 'snippet', parser)\n}\n"
  },
  {
    "path": "src/node/markdownToVue.ts",
    "content": "import { resolveTitleFromToken } from '@mdit-vue/shared'\nimport { createDebug } from 'obug'\nimport fs from 'fs-extra'\nimport { LRUCache } from 'lru-cache'\nimport path from 'node:path'\nimport type { SiteConfig } from './config'\nimport {\n  createMarkdownRenderer,\n  type MarkdownOptions,\n  type MarkdownRenderer\n} from './markdown/markdown'\nimport { getPageDataTransformer } from './plugins/dynamicRoutesPlugin'\nimport {\n  EXTERNAL_URL_RE,\n  getLocaleForPath,\n  slash,\n  treatAsHtml,\n  type HeadConfig,\n  type MarkdownEnv,\n  type PageData\n} from './shared'\nimport { getGitTimestamp } from './utils/getGitTimestamp'\nimport { processIncludes } from './utils/processIncludes'\n\nconst debug = createDebug('vitepress:md')\nconst cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })\n\nexport interface MarkdownCompileResult {\n  vueSrc: string\n  pageData: PageData\n  deadLinks: { url: string; file: string }[]\n  includes: string[]\n}\n\nexport function clearCache(relativePath?: string) {\n  if (!relativePath) {\n    cache.clear()\n    return\n  }\n\n  relativePath = JSON.stringify({ relativePath }).slice(1)\n  cache.find((_, key) => key.endsWith(relativePath!) && cache.delete(key))\n}\n\nlet __pages: string[] = []\nlet __dynamicRoutes = new Map<string, [string, string]>()\nlet __rewrites = new Map<string, string>()\nlet __ts: number\n\nfunction getResolutionCache(siteConfig: SiteConfig) {\n  // @ts-expect-error internal\n  if (siteConfig.__dirty) {\n    __pages = siteConfig.pages.map((p) => slash(p.replace(/\\.md$/, '')))\n\n    __dynamicRoutes = new Map(\n      siteConfig.dynamicRoutes.map((r) => [\n        r.fullPath,\n        [slash(path.join(siteConfig.srcDir, r.route)), r.loaderPath]\n      ])\n    )\n\n    __rewrites = new Map(\n      Object.entries(siteConfig.rewrites.map).map(([key, value]) => [\n        slash(path.join(siteConfig.srcDir, key)),\n        slash(path.join(siteConfig.srcDir, value!))\n      ])\n    )\n\n    __ts = Date.now()\n\n    // @ts-expect-error internal\n    siteConfig.__dirty = false\n  }\n\n  return {\n    pages: __pages,\n    dynamicRoutes: __dynamicRoutes,\n    rewrites: __rewrites,\n    ts: __ts\n  }\n}\n\nexport async function createMarkdownToVueRenderFn(\n  srcDir: string,\n  options: MarkdownOptions = {},\n  base = '/',\n  includeLastUpdatedData = false,\n  cleanUrls = false,\n  siteConfig: SiteConfig\n) {\n  const md = await createMarkdownRenderer(\n    srcDir,\n    options,\n    base,\n    siteConfig?.logger\n  )\n\n  return async (\n    src: string,\n    file: string,\n    publicDir: string\n  ): Promise<MarkdownCompileResult> => {\n    const { pages, dynamicRoutes, rewrites, ts } =\n      getResolutionCache(siteConfig)\n\n    const dynamicRoute = dynamicRoutes.get(file)\n    const fileOrig = dynamicRoute?.[0] || file\n    const transformPageData = [\n      siteConfig?.transformPageData,\n      getPageDataTransformer(dynamicRoute?.[1]!)\n    ].filter((fn) => fn != null)\n\n    file = rewrites.get(file) || file\n    const relativePath = slash(path.relative(srcDir, file))\n\n    const cacheKey = JSON.stringify({ src, ts, relativePath })\n    if (options.cache !== false) {\n      const cached = cache.get(cacheKey)\n      if (cached) {\n        debug(`[cache hit] ${relativePath}`)\n        return cached\n      }\n    }\n\n    const start = Date.now()\n\n    // resolve params for dynamic routes\n    let params\n    src = src.replace(\n      /^__VP_PARAMS_START([^]+?)__VP_PARAMS_END__/,\n      (_, paramsString) => {\n        params = JSON.parse(paramsString)\n        return ''\n      }\n    )\n\n    // resolve includes\n    let includes: string[] = []\n    src = processIncludes(md, srcDir, src, fileOrig, includes, cleanUrls)\n\n    const localeIndex = getLocaleForPath(siteConfig?.site, relativePath)\n\n    // reset env before render\n    const env: MarkdownEnv = {\n      path: file,\n      relativePath,\n      cleanUrls,\n      includes,\n      realPath: fileOrig,\n      localeIndex\n    }\n    const html = await md.renderAsync(src, env)\n    const {\n      frontmatter = {},\n      headers = [],\n      links = [],\n      sfcBlocks,\n      title = ''\n    } = env\n\n    // validate data.links\n    const deadLinks: MarkdownCompileResult['deadLinks'] = []\n    const recordDeadLink = (url: string) => {\n      deadLinks.push({ url, file: fileOrig })\n    }\n\n    function shouldIgnoreDeadLink(url: string) {\n      if (!siteConfig?.ignoreDeadLinks) {\n        return false\n      }\n      if (siteConfig.ignoreDeadLinks === true) {\n        return true\n      }\n      if (siteConfig.ignoreDeadLinks === 'localhostLinks') {\n        return url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost')\n      }\n\n      return siteConfig.ignoreDeadLinks.some((ignore) => {\n        if (typeof ignore === 'string') return url === ignore\n        if (ignore instanceof RegExp) return ignore.test(url)\n        if (typeof ignore === 'function') return ignore(url, fileOrig)\n        return false\n      })\n    }\n\n    if (links && siteConfig?.ignoreDeadLinks !== true) {\n      const dir = path.dirname(file)\n      for (let url of links) {\n        const { pathname } = new URL(url, 'http://a.com')\n        if (!treatAsHtml(pathname)) continue\n\n        url = url.replace(/[?#].*$/, '').replace(/\\.(html|md)$/, '')\n        if (url.endsWith('/')) url += `index`\n\n        let resolved = decodeURIComponent(\n          slash(\n            url.startsWith('/')\n              ? url.slice(1)\n              : path.relative(srcDir, path.resolve(dir, url))\n          )\n        )\n        resolved =\n          siteConfig?.rewrites.inv[resolved + '.md']?.slice(0, -3) || resolved\n\n        if (\n          !pages.includes(resolved) &&\n          !fs.existsSync(path.resolve(dir, publicDir, `${resolved}.html`)) &&\n          !shouldIgnoreDeadLink(url)\n        ) {\n          recordDeadLink(url)\n        }\n      }\n    }\n\n    let pageData: PageData = {\n      title: inferTitle(md, frontmatter, title),\n      titleTemplate: frontmatter.titleTemplate as any,\n      description: inferDescription(frontmatter),\n      frontmatter,\n      headers,\n      params,\n      relativePath,\n      filePath: slash(path.relative(srcDir, fileOrig))\n    }\n\n    if (includeLastUpdatedData && frontmatter.lastUpdated !== false) {\n      if (frontmatter.lastUpdated instanceof Date) {\n        pageData.lastUpdated = +frontmatter.lastUpdated\n      } else {\n        pageData.lastUpdated = await getGitTimestamp(fileOrig)\n      }\n    }\n\n    for (const fn of transformPageData) {\n      if (fn) {\n        const dataToMerge = await fn(pageData, { siteConfig })\n        if (dataToMerge) pageData = { ...pageData, ...dataToMerge }\n      }\n    }\n\n    const vueSrc = [\n      ...injectPageDataCode(\n        sfcBlocks?.scripts.map((item) => item.content) ?? [],\n        pageData\n      ),\n      `<template><div>${html}</div></template>`,\n      ...(sfcBlocks?.styles.map((item) => item.content) ?? []),\n      ...(sfcBlocks?.customBlocks.map((item) => item.content) ?? [])\n    ].join('\\n')\n\n    debug(`[render] ${file} in ${Date.now() - start}ms.`)\n\n    const result = { vueSrc, pageData, deadLinks, includes }\n    if (options.cache !== false) cache.set(cacheKey, result)\n    return result\n  }\n}\n\nconst scriptRE = /<\\/script>/\nconst scriptLangTsRE = /<\\s*script[^>]*\\blang=['\"]ts['\"][^>]*/\nconst scriptSetupRE = /<\\s*script[^>]*\\bsetup\\b[^>]*/\nconst scriptClientRE = /<\\s*script[^>]*\\bclient\\b[^>]*/\nconst defaultExportRE = /((?:^|\\n|;)\\s*)export(\\s*)default/\nconst namedDefaultExportRE = /((?:^|\\n|;)\\s*)export(.+)as(\\s*)default/\n\nfunction injectPageDataCode(tags: string[], data: PageData) {\n  const code = `\\nexport const __pageData = JSON.parse(${JSON.stringify(\n    JSON.stringify(data)\n  )})`\n\n  const existingScriptIndex = tags.findIndex((tag) => {\n    return (\n      scriptRE.test(tag) &&\n      !scriptSetupRE.test(tag) &&\n      !scriptClientRE.test(tag)\n    )\n  })\n\n  const isUsingTS = tags.findIndex((tag) => scriptLangTsRE.test(tag)) > -1\n\n  if (existingScriptIndex > -1) {\n    const tagSrc = tags[existingScriptIndex]\n    // user has <script> tag inside markdown\n    // if it doesn't have export default it will error out on build\n    const hasDefaultExport =\n      defaultExportRE.test(tagSrc) || namedDefaultExportRE.test(tagSrc)\n    tags[existingScriptIndex] = tagSrc.replace(\n      scriptRE,\n      code +\n        (hasDefaultExport\n          ? ``\n          : `\\nexport default {name:${JSON.stringify(data.relativePath)}}`) +\n        `</script>`\n    )\n  } else {\n    tags.unshift(\n      `<script ${\n        isUsingTS ? 'lang=\"ts\"' : ''\n      }>${code}\\nexport default {name:${JSON.stringify(\n        data.relativePath\n      )}}</script>`\n    )\n  }\n\n  return tags\n}\n\nconst inferTitle = (\n  md: MarkdownRenderer,\n  frontmatter: Record<string, any>,\n  title: string\n) => {\n  if (typeof frontmatter.title === 'string') {\n    const titleToken = md.parseInline(frontmatter.title, {})[0]\n    if (titleToken) {\n      return resolveTitleFromToken(titleToken, {\n        shouldAllowHtml: false,\n        shouldEscapeText: false\n      })\n    }\n  }\n  return title\n}\n\nconst inferDescription = (frontmatter: Record<string, any>) => {\n  const { description, head } = frontmatter\n\n  if (description !== undefined) {\n    return description\n  }\n\n  return (head && getHeadMetaContent(head, 'description')) || ''\n}\n\nconst getHeadMetaContent = (head: HeadConfig[], name: string) => {\n  if (!head || !head.length) {\n    return undefined\n  }\n\n  const meta = head.find(([tag, attrs = {}]) => {\n    return tag === 'meta' && attrs.name === name && attrs.content\n  })\n\n  return meta && meta[1].content\n}\n"
  },
  {
    "path": "src/node/plugin.ts",
    "content": "import path from 'node:path'\nimport c from 'picocolors'\nimport {\n  mergeConfig,\n  normalizePath,\n  searchForWorkspaceRoot,\n  type EnvironmentModuleNode,\n  type Plugin,\n  type ResolvedConfig,\n  type Rollup,\n  type UserConfig\n} from 'vite'\nimport {\n  APP_PATH,\n  DEFAULT_THEME_PATH,\n  DIST_CLIENT_PATH,\n  SITE_DATA_ID,\n  SITE_DATA_REQUEST_PATH,\n  resolveAliases\n} from './alias'\nimport { isAdditionalConfigFile, resolvePages, type SiteConfig } from './config'\nimport {\n  clearCache,\n  createMarkdownToVueRenderFn,\n  type MarkdownCompileResult\n} from './markdownToVue'\nimport { dynamicRoutesPlugin } from './plugins/dynamicRoutesPlugin'\nimport { localSearchPlugin } from './plugins/localSearchPlugin'\nimport { rewritesPlugin } from './plugins/rewritesPlugin'\nimport { staticDataPlugin } from './plugins/staticDataPlugin'\nimport { webFontsPlugin } from './plugins/webFontsPlugin'\nimport { slash, type PageDataPayload } from './shared'\nimport { deserializeFunctions, serializeFunctions } from './utils/fnSerialize'\nimport { cacheAllGitTimestamps } from './utils/getGitTimestamp'\n\ndeclare module 'vite' {\n  interface UserConfig {\n    vitepress?: SiteConfig\n  }\n}\n\nconst themeRE = /(?:^|\\/)\\.vitepress\\/theme\\/index\\.(m|c)?(j|t)s$/\nconst startsWithThemeRE = /^@theme(?:\\/|$)/\nconst docsearchRE = /\\/docsearch\\.css(?:$|\\?)/\n\nconst hashRE = /\\.([-\\w]+)\\.js$/\nconst staticInjectMarkerRE = /\\bcreateStaticVNode\\((?:(\".*\")|('.*')), (\\d+)\\)/g\nconst staticStripRE = /['\"`]__VP_STATIC_START__[^]*?__VP_STATIC_END__['\"`]/g\nconst staticRestoreRE = /__VP_STATIC_(START|END)__/g\n\n// matches client-side js blocks in MPA mode.\n// in the future we may add different execution strategies like visible or\n// media queries.\nconst scriptClientRE = /<script\\b[^>]*client\\b[^>]*>([^]*?)<\\/script>/\n\nconst isPageChunk = (\n  chunk: Rollup.OutputAsset | Rollup.OutputChunk\n): chunk is Rollup.OutputChunk & { facadeModuleId: string } =>\n  !!(\n    chunk.type === 'chunk' &&\n    chunk.isEntry &&\n    chunk.facadeModuleId &&\n    chunk.facadeModuleId.endsWith('.md')\n  )\n\nconst cleanUrl = (url: string): string => url.replace(/[?#].*$/s, '')\n\nexport async function createVitePressPlugin(\n  siteConfig: SiteConfig,\n  ssr = false,\n  pageToHashMap?: Record<string, string>,\n  clientJSMap?: Record<string, string>,\n  restartServer?: () => Promise<void>\n) {\n  const {\n    srcDir,\n    configPath,\n    configDeps,\n    markdown,\n    site,\n    vue: userVuePluginOptions,\n    vite: userViteConfig,\n    lastUpdated,\n    cleanUrls\n  } = siteConfig\n\n  let markdownToVue: Awaited<ReturnType<typeof createMarkdownToVueRenderFn>>\n\n  // lazy require plugin-vue to respect NODE_ENV in @vue/compiler-x\n  const vuePlugin = await import('@vitejs/plugin-vue').then((r) =>\n    r.default({\n      include: /\\.(?:vue|md)$/,\n      ...userVuePluginOptions\n    })\n  )\n\n  const processClientJS = (code: string, id: string) => {\n    return scriptClientRE.test(code)\n      ? code.replace(scriptClientRE, (_, content) => {\n          if (ssr && clientJSMap) clientJSMap[id] = content\n          return `\\n`.repeat(_.split('\\n').length - 1)\n        })\n      : code\n  }\n\n  let siteData = site\n  let allDeadLinks: MarkdownCompileResult['deadLinks'] = []\n  let config: ResolvedConfig\n  let importerMap: Record<string, Set<string> | undefined> = {}\n\n  const vitePressPlugin: Plugin = {\n    name: 'vitepress',\n\n    async configResolved(resolvedConfig) {\n      config = resolvedConfig\n      // pre-resolve git timestamps\n      if (lastUpdated) await cacheAllGitTimestamps(srcDir)\n      markdownToVue = await createMarkdownToVueRenderFn(\n        srcDir,\n        markdown,\n        config.base,\n        lastUpdated,\n        cleanUrls,\n        siteConfig\n      )\n    },\n\n    config() {\n      const baseConfig: UserConfig = {\n        resolve: {\n          alias: resolveAliases(siteConfig.root, ssr)\n        },\n        define: {\n          __VP_LOCAL_SEARCH__: site.themeConfig?.search?.provider === 'local',\n          __ALGOLIA__:\n            site.themeConfig?.search?.provider === 'algolia' ||\n            !!site.themeConfig?.algolia, // legacy\n          __CARBON__: !!site.themeConfig?.carbonAds,\n          __ASSETS_DIR__: JSON.stringify(siteConfig.assetsDir),\n          __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: !!process.env.DEBUG\n        },\n        optimizeDeps: {\n          // force include vue to avoid duplicated copies when linked + optimized\n          include: [\n            'vue',\n            'vitepress > @vue/devtools-api',\n            'vitepress > @vueuse/core'\n          ].filter((d) => d != null),\n          exclude: ['@docsearch/js', '@docsearch/sidepanel-js', 'vitepress']\n        },\n        server: {\n          fs: {\n            allow: [\n              DIST_CLIENT_PATH,\n              srcDir,\n              searchForWorkspaceRoot(process.cwd())\n            ]\n          }\n        },\n        vitepress: siteConfig\n      }\n      return userViteConfig\n        ? mergeConfig(baseConfig, userViteConfig)\n        : baseConfig\n    },\n\n    resolveId(id, importer, resolveOptions) {\n      if (id === SITE_DATA_ID) {\n        return SITE_DATA_REQUEST_PATH\n      }\n      if (startsWithThemeRE.test(id)) {\n        return this.resolve(\n          siteConfig.themeDir + id.slice(6),\n          importer,\n          Object.assign({ skipSelf: true }, resolveOptions)\n        )\n      }\n    },\n\n    load(id) {\n      if (id === SITE_DATA_REQUEST_PATH) {\n        let data = siteData\n        // head info is not needed by the client in production build\n        if (config.command === 'build') {\n          data = { ...siteData, head: [] }\n          // in production client build, the data is inlined on each page\n          // to avoid config changes invalidating every chunk.\n          if (!ssr) {\n            return `export default window.__VP_SITE_DATA__`\n          }\n        }\n        data = serializeFunctions(data)\n        return `${deserializeFunctions};export default deserializeFunctions(JSON.parse(${JSON.stringify(JSON.stringify(data))}))`\n      }\n    },\n\n    async transform(code, id) {\n      if (docsearchRE.test(normalizePath(id))) {\n        return code.replaceAll('[data-theme=dark]', '.dark')\n      }\n      if (id.endsWith('.vue')) {\n        return processClientJS(code, id)\n      }\n      if (id.endsWith('.md')) {\n        const relativePath = path.posix.relative(srcDir, id)\n        // transform .md files into vueSrc so plugin-vue can handle it\n        const { vueSrc, deadLinks, includes, pageData } = await markdownToVue(\n          code,\n          id,\n          config.publicDir\n        )\n        allDeadLinks.push(...deadLinks)\n        if (includes.length) {\n          includes.forEach((i) => {\n            ;(importerMap[slash(i)] ??= new Set()).add(relativePath)\n            this.addWatchFile(i)\n          })\n        }\n        if (\n          this.environment.mode === 'dev' &&\n          this.environment.name === 'client'\n        ) {\n          logDeadLinks(deadLinks, siteConfig.logger, true)\n          const payload: PageDataPayload = {\n            path: `/${siteConfig.rewrites.map[relativePath] || relativePath}`,\n            pageData\n          }\n          // notify the client to update page data\n          this.environment.hot.send({\n            type: 'custom',\n            event: 'vitepress:pageData',\n            data: payload\n          })\n        }\n        return processClientJS(vueSrc, id)\n      }\n    },\n\n    renderStart() {\n      if (allDeadLinks.length > 0) {\n        logDeadLinks(allDeadLinks, siteConfig.logger)\n        siteConfig.logger.info(\n          c.cyan(\n            '\\nIf this is expected, you can disable this check via config. Refer: https://vitepress.dev/reference/site-config#ignoredeadlinks\\n'\n          )\n        )\n        throw new Error(`${allDeadLinks.length} dead link(s) found.`)\n      }\n    },\n\n    configureServer(server) {\n      if (configPath) {\n        server.watcher.add(configPath)\n        configDeps.forEach((file) => server.watcher.add(file))\n      }\n\n      // serve our index.html after vite history fallback\n      return () => {\n        server.middlewares.use(async (req, res, next) => {\n          const url = req.url && cleanUrl(req.url)\n          if (url?.endsWith('.html')) {\n            res.statusCode = 200\n            res.setHeader('Content-Type', 'text/html')\n            let html = `\\\n<!DOCTYPE html>\n<html>\n  <head>\n    <title></title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/@fs/${APP_PATH}/index.js\"></script>\n  </body>\n</html>`\n            html = await server.transformIndexHtml(url, html, req.originalUrl)\n            res.end(html)\n            return\n          }\n          next()\n        })\n      }\n    },\n\n    renderChunk(code, chunk) {\n      if (!ssr && isPageChunk(chunk as Rollup.OutputChunk)) {\n        // For each page chunk, inject marker for start/end of static strings.\n        // we do this here because in generateBundle the chunks would have been\n        // minified and we won't be able to safely locate the strings.\n        // Using a regexp relies on specific output from Vue compiler core,\n        // which is a reasonable trade-off considering the massive perf win over\n        // a full AST parse.\n        code = code.replace(staticInjectMarkerRE, (_, str1, str2, flag) => {\n          const str = str1 || str2\n          const quote = str[0]\n          return `createStaticVNode(${quote}__VP_STATIC_START__${str.slice(1, -1)}__VP_STATIC_END__${quote}, ${flag})`\n        })\n        return code\n      }\n      return null\n    },\n\n    generateBundle: {\n      order: ssr ? null : 'post',\n      handler(_options, bundle) {\n        if (ssr) {\n          this.emitFile({\n            type: 'asset',\n            fileName: 'package.json',\n            source: '{ \"private\": true, \"type\": \"module\" }'\n          })\n          return\n        }\n\n        // client build:\n        // for each .md entry chunk, adjust its name to its correct path.\n        for (const name in bundle) {\n          const chunk = bundle[name]\n          if (isPageChunk(chunk)) {\n            // record page -> hash relations\n            const hash = chunk.fileName.match(hashRE)![1]\n            pageToHashMap![chunk.name.toLowerCase()] = hash\n\n            // inject another chunk with the content stripped\n            this.emitFile({\n              type: 'asset',\n              name: name + '-lean',\n              fileName: chunk.fileName.replace(/\\.js$/, '.lean.js'),\n              source: chunk.code.replace(staticStripRE, `\"\"`)\n            })\n\n            // remove static markers from original code\n            chunk.code = chunk.code.replace(staticRestoreRE, '')\n          }\n        }\n      }\n    },\n\n    async hotUpdate({ file, type }) {\n      if (this.environment.name !== 'client') return\n      const relativePath = path.posix.relative(srcDir, file)\n\n      // update pages, dynamicRoutes and rewrites on md file creation / deletion\n      if (file.endsWith('.md') && type !== 'update') {\n        await resolvePages(siteConfig)\n      }\n\n      if (type === 'delete') {\n        delete importerMap[relativePath]\n      }\n\n      if (\n        file === configPath ||\n        configDeps.includes(file) ||\n        isAdditionalConfigFile(file)\n      ) {\n        siteConfig.logger.info(\n          c.green(\n            `${path.relative(process.cwd(), file)} changed, restarting server...\\n`\n          ),\n          { clear: true, timestamp: true }\n        )\n\n        return restartServer?.()\n      }\n\n      if (themeRE.test(relativePath) && type !== 'update') {\n        siteConfig.themeDir =\n          type === 'create' ? path.posix.dirname(file) : DEFAULT_THEME_PATH\n        siteConfig.logger.info(c.green('page reload ') + c.dim(relativePath), {\n          clear: true,\n          timestamp: true\n        })\n        this.environment.moduleGraph.invalidateAll()\n        this.environment.hot.send({ type: 'full-reload' })\n        return []\n      }\n    }\n  }\n\n  const hmrFix: Plugin = {\n    name: 'vitepress:hmr-fix',\n    async hotUpdate({ file, modules: existingMods }) {\n      if (this.environment.name !== 'client') return\n      const modules: EnvironmentModuleNode[] = []\n\n      if (file.endsWith('.md')) {\n        const mod = this.environment.moduleGraph.getModuleById(file)\n        mod && modules.push(mod)\n      }\n\n      importerMap[slash(file)]?.forEach((relativePath) => {\n        clearCache(relativePath)\n        const mod = this.environment.moduleGraph.getModuleById(\n          path.posix.join(srcDir, relativePath)\n        )\n        mod && modules.push(mod)\n      })\n\n      return modules.length ? [...existingMods, ...modules] : undefined\n    }\n  }\n\n  return [\n    vitePressPlugin,\n    rewritesPlugin(siteConfig),\n    vuePlugin,\n    hmrFix,\n    webFontsPlugin(siteConfig.useWebFonts),\n    ...(userViteConfig?.plugins || []),\n    await localSearchPlugin(siteConfig),\n    staticDataPlugin,\n    await dynamicRoutesPlugin(siteConfig)\n  ]\n}\n\nfunction logDeadLinks(\n  deadLinks: MarkdownCompileResult['deadLinks'],\n  logger: SiteConfig['logger'],\n  devMode = false\n) {\n  const logged = new Set<string>()\n  deadLinks.forEach(({ url, file }, i) => {\n    const key = `${file}:::${url}`\n    if (logged.has(key)) return\n    logged.add(key)\n    const prefix = '\\n'.repeat(i === 0 ? (devMode ? 1 : 2) : 0)\n    logger.warn(\n      c.yellow(\n        `${prefix}(!) Found dead link ${c.cyan(url)} in file ${c.white(c.dim(file))}`\n      )\n    )\n  })\n}\n"
  },
  {
    "path": "src/node/plugins/dynamicRoutesPlugin.ts",
    "content": "import fs from 'fs-extra'\nimport path from 'node:path'\nimport c from 'picocolors'\nimport pm from 'picomatch'\nimport {\n  loadConfigFromFile,\n  normalizePath,\n  type EnvironmentModuleGraph,\n  type EnvironmentModuleNode,\n  type Logger,\n  type Plugin\n} from 'vite'\nimport type { Awaitable } from '../shared'\nimport { type SiteConfig, type UserConfig } from '../siteConfig'\nimport { glob, normalizeGlob, type GlobOptions } from '../utils/glob'\nimport { ModuleGraph } from '../utils/moduleGraph'\nimport { resolveRewrites } from './rewritesPlugin'\n\ninterface UserRouteConfig {\n  params: Record<string, string>\n  content?: string\n}\n\nexport type ResolvedRouteConfig = UserRouteConfig & {\n  /**\n   * the raw route (relative to src root), e.g. foo/[bar].md\n   */\n  route: string\n  /**\n   * the actual path with params resolved (relative to src root), e.g. foo/1.md\n   */\n  path: string\n  /**\n   * absolute fs path\n   */\n  fullPath: string\n  /**\n   * the path to the paths loader module\n   */\n  loaderPath: string\n}\n\nexport interface RouteModule {\n  watch?: string[] | string\n  paths:\n    | UserRouteConfig[]\n    | ((watchedFiles: string[]) => Awaitable<UserRouteConfig[]>)\n  transformPageData?: UserConfig['transformPageData']\n  options?: { globOptions?: GlobOptions }\n}\n\ninterface ResolvedRouteModule {\n  watch: string[]\n  routes?: ResolvedRouteConfig[]\n  loader: RouteModule['paths']\n  transformPageData?: RouteModule['transformPageData']\n  options: NonNullable<RouteModule['options']>\n}\n\nconst dynamicRouteRE = /\\[(\\w+?)\\]/g\nconst pathLoaderRE = /\\.paths\\.m?[jt]s$/\n\nconst routeModuleCache = new Map<string, ResolvedRouteModule>()\nlet moduleGraph = new ModuleGraph()\nlet discoveredPages = new Set<string>()\n\n/**\n * Helper for defining routes with type inference\n */\nexport function defineRoutes(loader: RouteModule): RouteModule {\n  return loader\n}\n\ntype Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport async function resolvePages(\n  siteConfig: Optional<SiteConfig, 'pages' | 'dynamicRoutes' | 'rewrites'>,\n  rebuildCache = false\n): Promise<void> {\n  if (rebuildCache) {\n    moduleGraph = new ModuleGraph()\n    routeModuleCache.clear()\n    discoveredPages.clear()\n  }\n\n  const allMarkdownFiles = await glob(['**/*.md'], {\n    cwd: siteConfig.srcDir,\n    ignore: siteConfig.userConfig.srcExclude\n  })\n\n  const pages: string[] = []\n  const dynamicRouteFiles: string[] = []\n\n  allMarkdownFiles.forEach((file) => {\n    dynamicRouteRE.lastIndex = 0\n    ;(dynamicRouteRE.test(file) ? dynamicRouteFiles : pages).push(file)\n  })\n\n  const dynamicRoutes = await resolveDynamicRoutes(\n    siteConfig.srcDir,\n    dynamicRouteFiles,\n    siteConfig.logger\n  )\n  pages.push(...dynamicRoutes.map((r) => r.path))\n\n  const externalDynamicRoutes =\n    siteConfig.dynamicRoutes?.filter((r) => !discoveredPages.has(r.path)) || []\n  const externalPages =\n    siteConfig.pages?.filter((p) => !discoveredPages.has(p)) || []\n\n  const finalDynamicRoutes = [...dynamicRoutes, ...externalDynamicRoutes].sort(\n    (a, b) => a.path.localeCompare(b.path)\n  )\n  const finalPages = [...pages, ...externalPages].sort()\n\n  const rewrites = resolveRewrites(pages, siteConfig.userConfig.rewrites)\n\n  Object.assign(siteConfig, {\n    pages: finalPages,\n    dynamicRoutes: finalDynamicRoutes,\n    rewrites,\n    // @ts-expect-error internal flag to reload resolution cache in ../markdownToVue.ts\n    __dirty: true\n  } satisfies Partial<SiteConfig>)\n\n  discoveredPages = new Set(pages)\n}\n\nexport const dynamicRoutesPlugin = async (\n  config: SiteConfig\n): Promise<Plugin> => {\n  return {\n    name: 'vitepress:dynamic-routes',\n    enforce: 'pre',\n\n    resolveId(id) {\n      if (!id.endsWith('.md')) return\n      const normalizedId = id.startsWith(config.srcDir)\n        ? id\n        : normalizePath(path.resolve(config.srcDir, id.replace(/^\\//, '')))\n      const matched = config.dynamicRoutes.find(\n        (r) => r.fullPath === normalizedId\n      )\n      if (matched) return normalizedId\n    },\n\n    load(id) {\n      const matched = config.dynamicRoutes.find((r) => r.fullPath === id)\n      if (matched) {\n        const { route, params, content } = matched\n        const routeFile = normalizePath(path.resolve(config.srcDir, route))\n\n        moduleGraph.add(id, [routeFile])\n        moduleGraph.add(routeFile, [matched.loaderPath])\n\n        let baseContent = fs.readFileSync(routeFile, 'utf-8')\n\n        // inject raw content\n        // this is intended for integration with CMS\n        // we use a special injection syntax so the content is rendered as\n        // static local content instead of included as runtime data.\n        if (content) {\n          baseContent = baseContent.replace(\n            /<!--\\s*@content\\s*-->/,\n            content.replace(/\\$/g, '$$$')\n          )\n        }\n\n        // params are injected with special markers and extracted as part of\n        // __pageData in ../markdownToVue.ts\n        return `__VP_PARAMS_START${JSON.stringify(params)}__VP_PARAMS_END__${baseContent}`\n      }\n    },\n\n    async hotUpdate({ file, modules: existingMods }) {\n      if (this.environment.name !== 'client') return\n\n      const modules: EnvironmentModuleNode[] = []\n      const normalizedFile = normalizePath(file)\n\n      // Trigger update if a module or its dependencies changed.\n      modules.push(...getModules(normalizedFile, this.environment.moduleGraph))\n\n      // Also check if the file matches any custom watch patterns.\n      let watchedFileChanged = false\n      for (const [file, route] of routeModuleCache) {\n        if (\n          route.watch?.length &&\n          pm(route.watch, route.options.globOptions)(normalizedFile)\n        ) {\n          route.routes = undefined\n          watchedFileChanged = true\n          modules.push(...getModules(file, this.environment.moduleGraph, false))\n        }\n      }\n\n      if (\n        (modules.length && !normalizedFile.endsWith('.md')) ||\n        watchedFileChanged ||\n        pathLoaderRE.test(normalizedFile)\n      ) {\n        // path loader module or deps updated, reset loaded routes\n        await resolvePages(config)\n      }\n\n      return modules.length ? [...existingMods, ...modules] : undefined\n    }\n  }\n}\n\nexport function getPageDataTransformer(\n  loaderPath: string\n): UserConfig['transformPageData'] | undefined {\n  return routeModuleCache.get(loaderPath)?.transformPageData\n}\n\nasync function resolveDynamicRoutes(\n  srcDir: string,\n  routes: string[],\n  logger: Logger\n): Promise<ResolvedRouteConfig[]> {\n  const pendingResolveRoutes: Promise<ResolvedRouteConfig[]>[] = []\n  const newModuleGraph = moduleGraph.clone()\n\n  for (const route of routes) {\n    // locate corresponding route paths file\n    const fullPath = normalizePath(path.resolve(srcDir, route))\n\n    const paths = ['js', 'ts', 'mjs', 'mts'].map((ext) =>\n      fullPath.replace(/\\.md$/, `.paths.${ext}`)\n    )\n\n    const pathsFile = paths.find((p) => fs.existsSync(p))\n\n    if (pathsFile == null) {\n      logger.warn(\n        c.yellow(\n          `Missing paths file for dynamic route ${route}: ` +\n            `a corresponding ${paths[0]} (or .ts/.mjs/.mts) file is needed.`\n        )\n      )\n      continue\n    }\n\n    // load the paths loader module\n    let watch: ResolvedRouteModule['watch']\n    let loader: ResolvedRouteModule['loader']\n    let transformPageData: ResolvedRouteModule['transformPageData']\n    let options: ResolvedRouteModule['options']\n\n    const loaderPath = normalizePath(pathsFile)\n    const existing = routeModuleCache.get(loaderPath)\n\n    if (existing) {\n      // use cached routes if not invalidated by hmr\n      if (existing.routes) {\n        pendingResolveRoutes.push(Promise.resolve(existing.routes))\n        continue\n      }\n\n      ;({ watch, loader, transformPageData, options } = existing)\n    } else {\n      let mod\n      try {\n        mod = await loadConfigFromFile(\n          {} as any,\n          pathsFile,\n          undefined,\n          'silent'\n        )\n      } catch (err: any) {\n        logger.warn(\n          `${c.yellow(`Failed to load ${pathsFile}:`)}\\n${err.message}\\n${err.stack}`\n        )\n        continue\n      }\n\n      if (!mod) {\n        logger.warn(\n          c.yellow(\n            `Invalid paths file export in ${pathsFile}. ` +\n              `Missing \"default\" export.`\n          )\n        )\n        continue\n      }\n\n      const loaderModule = mod.config as RouteModule\n      watch = normalizeGlob(loaderModule.watch, path.dirname(pathsFile))\n      loader = loaderModule.paths\n      transformPageData = loaderModule.transformPageData\n      options = loaderModule.options || {}\n\n      if (!loader) {\n        logger.warn(\n          c.yellow(\n            `Invalid paths file export in ${pathsFile}. ` +\n              `Missing \"paths\" property from default export.`\n          )\n        )\n        continue\n      }\n\n      // record deps for hmr\n      newModuleGraph.add(\n        loaderPath,\n        mod.dependencies.map((p) => normalizePath(path.resolve(p)))\n      )\n    }\n\n    const resolveRoute = async (): Promise<ResolvedRouteConfig[]> => {\n      let pathsData: UserRouteConfig[]\n\n      if (typeof loader === 'function') {\n        const watchedFiles = await glob(watch, {\n          absolute: true,\n          ...options.globOptions\n        })\n        pathsData = await loader(watchedFiles)\n      } else {\n        pathsData = loader\n      }\n\n      const routes = pathsData.map((userConfig) => {\n        const resolvedPath = route.replace(\n          dynamicRouteRE,\n          (_, key) => userConfig.params[key]\n        )\n        return {\n          path: resolvedPath,\n          fullPath: normalizePath(path.resolve(srcDir, resolvedPath)),\n          route,\n          loaderPath,\n          ...userConfig\n        }\n      })\n\n      const mod = { watch, routes, loader, transformPageData, options }\n      routeModuleCache.set(loaderPath, mod)\n\n      return routes\n    }\n\n    pendingResolveRoutes.push(resolveRoute())\n  }\n\n  const resolvedRoutes = (await Promise.all(pendingResolveRoutes)).flat()\n  moduleGraph = newModuleGraph\n\n  return resolvedRoutes\n}\n\nfunction getModules(\n  id: string,\n  envModuleGraph: EnvironmentModuleGraph,\n  deleteFromRouteModuleCache = true\n) {\n  const modules: EnvironmentModuleNode[] = []\n  for (const file of moduleGraph.delete(id)) {\n    deleteFromRouteModuleCache && routeModuleCache.delete(file)\n    modules.push(...(envModuleGraph.getModulesByFile(file)?.values() ?? []))\n  }\n  return modules\n}\n"
  },
  {
    "path": "src/node/plugins/localSearchPlugin.ts",
    "content": "import { createDebug } from 'obug'\nimport fs from 'fs-extra'\nimport MiniSearch from 'minisearch'\nimport path from 'node:path'\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { SiteConfig } from '../config'\nimport type { DefaultTheme } from '../defaultTheme'\nimport { createMarkdownRenderer } from '../markdown/markdown'\nimport { getLocaleForPath, slash, type MarkdownEnv } from '../shared'\nimport { processIncludes } from '../utils/processIncludes'\n\nconst debug = createDebug('vitepress:local-search')\n\nconst LOCAL_SEARCH_INDEX_ID = '@localSearchIndex'\nconst LOCAL_SEARCH_INDEX_REQUEST_PATH = '/' + LOCAL_SEARCH_INDEX_ID\n\ninterface IndexObject {\n  id: string\n  text: string\n  title: string\n  titles: string[]\n}\n\nexport async function localSearchPlugin(\n  siteConfig: SiteConfig<DefaultTheme.Config>\n): Promise<Plugin> {\n  if (siteConfig.site.themeConfig?.search?.provider !== 'local') {\n    return {\n      name: 'vitepress:local-search',\n      resolveId(id) {\n        if (id.startsWith(LOCAL_SEARCH_INDEX_ID)) {\n          return LOCAL_SEARCH_INDEX_REQUEST_PATH\n        }\n      },\n      load(id) {\n        if (id.startsWith(LOCAL_SEARCH_INDEX_REQUEST_PATH)) {\n          return `export default '{}'`\n        }\n      }\n    }\n  }\n\n  const md = await createMarkdownRenderer(\n    siteConfig.srcDir,\n    siteConfig.markdown,\n    siteConfig.site.base,\n    siteConfig.logger\n  )\n\n  const options = siteConfig.site.themeConfig.search.options || {}\n\n  async function render(file: string) {\n    if (!fs.existsSync(file)) return ''\n    const { srcDir, cleanUrls = false } = siteConfig\n    const relativePath = slash(path.relative(srcDir, file))\n    const env: MarkdownEnv = { path: file, relativePath, cleanUrls }\n    const md_raw = await fs.promises.readFile(file, 'utf-8')\n    const md_src = processIncludes(md, srcDir, md_raw, file, [], cleanUrls)\n    if (options._render) {\n      return await options._render(md_src, env, md)\n    } else {\n      const html = await md.renderAsync(md_src, env)\n      return env.frontmatter?.search === false ? '' : html\n    }\n  }\n\n  const indexByLocales = new Map<string, MiniSearch<IndexObject>>()\n\n  function getIndexByLocale(locale: string) {\n    let index = indexByLocales.get(locale)\n    if (!index) {\n      index = new MiniSearch<IndexObject>({\n        fields: ['title', 'titles', 'text'],\n        storeFields: ['title', 'titles'],\n        ...options.miniSearch?.options\n      })\n      indexByLocales.set(locale, index)\n    }\n    return index\n  }\n\n  let server: ViteDevServer | undefined\n  let pending: Promise<void>\n\n  function onIndexUpdated() {\n    if (!server) return\n    server.moduleGraph.onFileChange(LOCAL_SEARCH_INDEX_REQUEST_PATH)\n    // HMR\n    const mod = server.moduleGraph.getModuleById(\n      LOCAL_SEARCH_INDEX_REQUEST_PATH\n    )\n    if (!mod) return\n    server.ws.send({\n      type: 'update',\n      updates: [\n        {\n          acceptedPath: mod.url,\n          path: mod.url,\n          timestamp: Date.now(),\n          type: 'js-update'\n        }\n      ]\n    })\n  }\n\n  function getDocId(file: string) {\n    let relFile = slash(path.relative(siteConfig.srcDir, file))\n    relFile = siteConfig.rewrites.map[relFile] || relFile\n    let id = slash(path.join(siteConfig.site.base, relFile))\n    id = id.replace(/(^|\\/)index\\.md$/, '$1')\n    id = id.replace(/\\.md$/, siteConfig.cleanUrls ? '' : '.html')\n    return id\n  }\n\n  async function indexFile(page: string) {\n    const file = path.join(siteConfig.srcDir, page)\n    // get file metadata\n    const fileId = getDocId(file)\n    const locale = getLocaleForPath(siteConfig.site, page)\n    const index = getIndexByLocale(locale)\n    // retrieve file and split into \"sections\"\n    const html = await render(file)\n    const sections =\n      // user provided generator\n      (await options.miniSearch?._splitIntoSections?.(file, html)) ??\n      // default implementation\n      splitPageIntoSections(html)\n    // add sections to the locale index\n    for await (const section of sections) {\n      if (!section || !(section.text || section.titles)) break\n      const { anchor, text, titles } = section\n      const id = anchor ? [fileId, anchor].join('#') : fileId\n      index.add({\n        id,\n        text,\n        title: titles.at(-1)!,\n        titles: titles.slice(0, -1)\n      })\n    }\n  }\n\n  async function scanForBuild() {\n    debug('🔍️ Indexing files for search...')\n    for (const page of siteConfig.pages) {\n      await indexFile(page)\n    }\n    debug('✅ Indexing finished...')\n  }\n\n  return {\n    name: 'vitepress:local-search',\n\n    config: () => ({\n      optimizeDeps: {\n        include: [\n          'vitepress > @vueuse/integrations/useFocusTrap',\n          'vitepress > mark.js/src/vanilla.js',\n          'vitepress > minisearch'\n        ]\n      }\n    }),\n\n    configureServer(_server) {\n      server = _server\n      pending = scanForBuild().then(onIndexUpdated)\n    },\n\n    resolveId(id) {\n      if (id.startsWith(LOCAL_SEARCH_INDEX_ID)) {\n        return `/${id}`\n      }\n    },\n\n    async load(id) {\n      if (id === LOCAL_SEARCH_INDEX_REQUEST_PATH) {\n        await pending\n        if (process.env.NODE_ENV === 'production') {\n          await scanForBuild()\n        }\n        let records: string[] = []\n        for (const [locale] of indexByLocales) {\n          records.push(\n            `${JSON.stringify(\n              locale\n            )}: () => import('${LOCAL_SEARCH_INDEX_ID}${locale}')`\n          )\n        }\n        return `export default {${records.join(',')}}`\n      } else if (id.startsWith(LOCAL_SEARCH_INDEX_REQUEST_PATH)) {\n        await pending\n        return `export default ${JSON.stringify(\n          JSON.stringify(\n            indexByLocales.get(\n              id.replace(LOCAL_SEARCH_INDEX_REQUEST_PATH, '')\n            ) ?? {}\n          )\n        )}`\n      }\n    },\n\n    async hotUpdate({ file }) {\n      if (this.environment.name !== 'client') return\n\n      if (file.endsWith('.md')) {\n        await indexFile(file)\n        debug('🔍️ Updated', file)\n        onIndexUpdated()\n      }\n    }\n  }\n}\n\nconst headingRegex = /<h(\\d*).*?>(.*?<a.*? href=\"#.*?\".*?>.*?<\\/a>)<\\/h\\1>/gi\nconst headingContentRegex = /(.*)<a.*? href=\"#(.*?)\".*?>.*?<\\/a>/i\n\n/**\n * Splits HTML into sections based on headings\n */\nfunction* splitPageIntoSections(html: string) {\n  const result = html.split(headingRegex)\n  result.shift()\n  let parentTitles: string[] = []\n  for (let i = 0; i < result.length; i += 3) {\n    const level = parseInt(result[i]) - 1\n    const heading = result[i + 1]\n    const headingResult = headingContentRegex.exec(heading)\n    const title = clearHtmlTags(headingResult?.[1] ?? '').trim()\n    const anchor = headingResult?.[2] ?? ''\n    const content = result[i + 2]\n    if (!title || !content) continue\n    let titles = parentTitles.slice(0, level)\n    titles[level] = title\n    titles = titles.filter(Boolean)\n    yield { anchor, titles, text: getSearchableText(content) }\n    if (level === 0) {\n      parentTitles = [title]\n    } else {\n      parentTitles[level] = title\n    }\n  }\n}\n\nfunction getSearchableText(content: string) {\n  content = clearHtmlTags(content)\n  return content\n}\n\nfunction clearHtmlTags(str: string) {\n  return str.replace(/<[^>]*>/g, '')\n}\n"
  },
  {
    "path": "src/node/plugins/rewritesPlugin.ts",
    "content": "import { compile, match } from 'path-to-regexp'\nimport type { Plugin } from 'vite'\nimport type { SiteConfig, UserConfig } from '../siteConfig'\n\nexport function resolveRewrites(\n  pages: string[],\n  userRewrites: UserConfig['rewrites']\n) {\n  const pageToRewrite: Record<string, string> = {}\n  const rewriteToPage: Record<string, string> = {}\n\n  if (typeof userRewrites === 'function') {\n    for (const page of pages) {\n      const dest = userRewrites(page)\n      if (dest && dest !== page) {\n        pageToRewrite[page] = dest\n        rewriteToPage[dest] = page\n      }\n    }\n  } else if (typeof userRewrites === 'object') {\n    const rewriteRules = Object.entries(userRewrites || {}).map(\n      ([from, to]) => ({\n        toPath: compile(`/${to}`, { validate: false }),\n        matchUrl: match(from.startsWith('^') ? new RegExp(from) : from)\n      })\n    )\n\n    if (rewriteRules.length) {\n      for (const page of pages) {\n        for (const { matchUrl, toPath } of rewriteRules) {\n          const res = matchUrl(page)\n          if (res) {\n            const dest = toPath(res.params).slice(1)\n            pageToRewrite[page] = dest\n            rewriteToPage[dest] = page\n            break\n          }\n        }\n      }\n    }\n  }\n\n  return {\n    map: pageToRewrite,\n    inv: rewriteToPage\n  }\n}\n\nexport const rewritesPlugin = (config: SiteConfig): Plugin => {\n  return {\n    name: 'vitepress:rewrites',\n    configureServer(server) {\n      // dev rewrite\n      server.middlewares.use((req, _res, next) => {\n        if (req.url) {\n          const page = decodeURI(req.url)\n            .replace(/[?#].*$/, '')\n            .slice(config.site.base.length)\n\n          if (config.rewrites.inv[page]) {\n            req.url = req.url.replace(\n              encodeURI(page),\n              encodeURI(config.rewrites.inv[page]!)\n            )\n          }\n        }\n        next()\n      })\n    }\n  }\n}\n"
  },
  {
    "path": "src/node/plugins/staticDataPlugin.ts",
    "content": "import path from 'node:path'\nimport pm from 'picomatch'\nimport {\n  loadConfigFromFile,\n  normalizePath,\n  type EnvironmentModuleNode,\n  type Plugin,\n  type ViteDevServer\n} from 'vite'\nimport type { Awaitable } from '../shared'\nimport { glob, normalizeGlob, type GlobOptions } from '../utils/glob'\n\nconst loaderMatch = /\\.data\\.m?(j|t)s($|\\?)/\n\nlet server: ViteDevServer\n\nexport interface LoaderModule<T = any> {\n  watch?: string[] | string\n  load: (watchedFiles: string[]) => Awaitable<T>\n  options?: { globOptions?: GlobOptions }\n}\n\n/**\n * Helper for defining loaders with type inference\n */\nexport function defineLoader<T>(loader: LoaderModule<T>): LoaderModule<T> {\n  return loader\n}\n\n// Map from loader module id to its module info\nconst idToLoaderModulesMap: Record<\n  string,\n  (Required<Omit<LoaderModule, 'watch'>> & { watch: string[] }) | undefined\n> = Object.create(null)\n\n// Map from dependency file to a set of loader module ids\nconst depToLoaderModuleIdsMap: Record<string, Set<string>> = Object.create(null)\n\n// During build, the load hook will be called on the same file twice\n// once for client and once for server build. Not only is this wasteful, it\n// also leads to a race condition in loadConfigFromFile() that results in an\n// fs unlink error. So we reuse the same Promise during build to avoid double\n// loading.\nlet idToPendingPromiseMap: Record<string, Promise<string> | undefined> =\n  Object.create(null)\nlet isBuild = false\n\nexport const staticDataPlugin: Plugin = {\n  name: 'vitepress:data',\n\n  configResolved(config) {\n    isBuild = config.command === 'build'\n  },\n\n  configureServer(_server) {\n    server = _server\n  },\n\n  async load(id) {\n    if (loaderMatch.test(id)) {\n      let _resolve: ((res: any) => void) | undefined\n      if (isBuild) {\n        if (idToPendingPromiseMap[id]) return idToPendingPromiseMap[id]\n        idToPendingPromiseMap[id] = new Promise((r) => {\n          _resolve = r\n        })\n      }\n\n      const base = path.dirname(id)\n      let watch: LoaderModule['watch']\n      let load: LoaderModule['load']\n      let options: LoaderModule['options']\n\n      const existing = idToLoaderModulesMap[id]\n      if (existing) {\n        ;({ watch, load, options } = existing)\n      } else {\n        // use vite's load config util as a way to load Node.js file with\n        // TS & native ESM support\n        const res = await loadConfigFromFile({} as any, id.replace(/\\?.*$/, ''))\n\n        // record deps for hmr\n        if (server && res) {\n          for (const dep of res.dependencies) {\n            const depPath = normalizePath(path.resolve(dep))\n            if (!depToLoaderModuleIdsMap[depPath]) {\n              depToLoaderModuleIdsMap[depPath] = new Set()\n            }\n            depToLoaderModuleIdsMap[depPath].add(id)\n          }\n        }\n\n        const loaderModule = res?.config as LoaderModule\n        watch = normalizeGlob(loaderModule.watch, base)\n        load = loaderModule.load\n        options = loaderModule.options || {}\n      }\n\n      // load the data\n      const watchedFiles = await glob(watch, {\n        absolute: true,\n        ...options.globOptions\n      })\n      const data = await load(watchedFiles)\n\n      // record loader module for HMR\n      if (server) idToLoaderModulesMap[id] = { watch, load, options }\n\n      const result = `export const data = JSON.parse(${JSON.stringify(JSON.stringify(data))})`\n\n      if (_resolve) _resolve(result)\n      return result\n    }\n  },\n\n  hotUpdate({ file, modules: existingMods }) {\n    if (this.environment.name !== 'client') return\n\n    const modules: EnvironmentModuleNode[] = []\n    const normalizedFile = normalizePath(file)\n\n    // Trigger update if a dependency (including transitive ones) changed.\n    if (normalizedFile in depToLoaderModuleIdsMap) {\n      for (const id of Array.from(\n        depToLoaderModuleIdsMap[normalizedFile] || []\n      )) {\n        delete idToLoaderModulesMap[id]\n        const mod = this.environment.moduleGraph.getModuleById(id)\n        if (mod) modules.push(mod)\n      }\n    }\n\n    // Also check if the file matches any custom watch patterns.\n    for (const id in idToLoaderModulesMap) {\n      const loader = idToLoaderModulesMap[id]\n      if (\n        loader?.watch?.length &&\n        pm(loader.watch, loader.options.globOptions)(normalizedFile)\n      ) {\n        const mod = this.environment.moduleGraph.getModuleById(id)\n        if (mod) modules.push(mod)\n      }\n    }\n\n    return modules.length ? [...existingMods, ...modules] : undefined\n  }\n}\n"
  },
  {
    "path": "src/node/plugins/webFontsPlugin.ts",
    "content": "import type { Plugin } from 'vite'\n\nconst webfontMarkerRE =\n  /\\/(?:\\*|\\/) *webfont-marker-begin *(?:\\*\\/|\\n|\\r|\\n\\r|\\r\\n)([^]*?)\\/(?:\\*|\\/) *webfont-marker-end *(?:\\*\\/|\\n|\\r|\\n\\r|\\r\\n|$)/\n\nexport const webFontsPlugin = (enabled = false): Plugin => ({\n  name: 'vitepress:webfonts',\n  enforce: 'pre',\n\n  transform(code, id) {\n    if (/[\\\\/]fonts\\.s?css/.test(id)) {\n      if (enabled) {\n        return code.match(webfontMarkerRE)?.[1]\n      } else {\n        return code.replace(webfontMarkerRE, '')\n      }\n    }\n  }\n})\n"
  },
  {
    "path": "src/node/postcss/isolateStyles.ts",
    "content": "import type { Plugin } from 'postcss'\nimport selectorParser from 'postcss-selector-parser'\n\ntype Options = {\n  includeFiles?: RegExp[]\n  ignoreFiles?: RegExp[]\n  prefix?: string\n}\n\nexport function postcssIsolateStyles({\n  includeFiles = [/vp-doc\\.css/, /base\\.css/],\n  ignoreFiles,\n  prefix = ':not(:where(.vp-raw, .vp-raw *))'\n}: Options = {}): Plugin {\n  const prefixNodes = selectorParser().astSync(prefix).first.nodes\n\n  return /* prettier-ignore */ {\n    postcssPlugin: 'postcss-isolate-styles',\n    Once(root) {\n      const file = root.source?.input.file\n      if (file && includeFiles?.length && !includeFiles.some((re) => re.test(file))) return\n      if (file && ignoreFiles?.length && ignoreFiles.some((re) => re.test(file))) return\n\n      root.walkRules((rule) => {\n        if (!rule.selector || rule.selector.includes(prefix)) return\n        if (rule.parent?.type === 'atrule' && /\\bkeyframes$/i.test(rule.parent.name)) return\n\n        rule.selector = selectorParser((selectors) => {\n          selectors.each((sel) => {\n            if (!sel.nodes.length) return\n            const insertionIndex = sel.nodes.findLastIndex((n) => n.type !== 'pseudo') + 1\n            sel.nodes.splice(insertionIndex, 0, ...prefixNodes.map((n) => n.clone() as any))\n          })\n        }).processSync(rule.selector)\n      })\n    }\n  }\n}\n"
  },
  {
    "path": "src/node/serve/serve.ts",
    "content": "import compression from '@polka/compression'\nimport fs from 'fs-extra'\nimport path from 'node:path'\nimport polka, { type IOptions } from 'polka'\nimport sirv from 'sirv'\nimport { resolveConfig } from '../config'\n\nfunction trimChar(str: string, char: string) {\n  while (str.charAt(0) === char) {\n    str = str.substring(1)\n  }\n\n  while (str.charAt(str.length - 1) === char) {\n    str = str.substring(0, str.length - 1)\n  }\n\n  return str\n}\n\nexport interface ServeOptions {\n  base?: string\n  root?: string\n  port?: number\n}\n\nexport async function serve(options: ServeOptions = {}) {\n  const port = options.port ?? 4173\n  const config = await resolveConfig(options.root, 'serve', 'production')\n  const base = trimChar(options?.base ?? config?.site?.base ?? '', '/')\n\n  const notAnAsset = (pathname: string) =>\n    !pathname.includes(`/${config.assetsDir}/`)\n  const notFound = fs.readFileSync(path.resolve(config.outDir, './404.html'))\n  const onNoMatch: IOptions['onNoMatch'] = (req, res) => {\n    res.statusCode = 404\n    if (notAnAsset(req.path)) res.write(notFound.toString())\n    res.end()\n  }\n\n  const compress = compression()\n  const serve = sirv(config.outDir, {\n    etag: true,\n    maxAge: 31536000,\n    immutable: true,\n    setHeaders(res, pathname) {\n      if (notAnAsset(pathname)) {\n        // force server validation for non-asset files since they\n        // are not fingerprinted\n        res.setHeader('cache-control', 'no-cache')\n      }\n    }\n  })\n\n  if (base) {\n    return polka({ onNoMatch })\n      .use(base, compress, serve)\n      .listen(port, () => {\n        config.logger.info(\n          `Built site served at http://localhost:${port}/${base}/`\n        )\n      })\n  } else {\n    return polka({ onNoMatch })\n      .use(compress, serve)\n      .listen(port, () => {\n        config.logger.info(`Built site served at http://localhost:${port}/`)\n      })\n  }\n}\n"
  },
  {
    "path": "src/node/server.ts",
    "content": "import { createServer as createViteServer, type ServerOptions } from 'vite'\nimport { resolveConfig, type SiteConfig } from './config'\nimport { createVitePressPlugin } from './plugin'\n\nexport async function createServer(\n  root: string = process.cwd(), // for backwards compatibility\n  serverOptions: ServerOptions & { base?: string } = {},\n  restartServer?: () => Promise<void>,\n  config?: SiteConfig // new code should pass config directly\n) {\n  config ??= await resolveConfig(root)\n\n  const { base, ...server } = serverOptions\n  config.site.base = base ?? config.site.base\n\n  return createViteServer({\n    root: config.srcDir,\n    base: config.site.base,\n    cacheDir: config.cacheDir,\n    plugins: await createVitePressPlugin(config, false, {}, {}, restartServer),\n    server,\n    customLogger: config.logger,\n    configFile: config.vite?.configFile\n  })\n}\n"
  },
  {
    "path": "src/node/shortcuts.ts",
    "content": "import c from 'picocolors'\nimport type { ViteDevServer } from 'vite'\nimport type { Awaitable } from './shared'\n\nexport type CLIShortcut = {\n  key: string\n  description: string\n  action(\n    server: ViteDevServer,\n    restartServer: () => Promise<void>\n  ): Awaitable<void>\n}\n\nexport function bindShortcuts(\n  server: ViteDevServer,\n  restartServer: () => Promise<void>\n): void {\n  if (!server.httpServer || !process.stdin.isTTY || process.env.CI) {\n    return\n  }\n\n  server.config.logger.info(\n    c.dim(c.green('  ➜')) +\n      c.dim('  press ') +\n      c.bold('h') +\n      c.dim(' to show help')\n  )\n\n  let actionRunning = false\n\n  const onInput = async (input: string) => {\n    // ctrl+c or ctrl+d\n    if (input === '\\x03' || input === '\\x04') {\n      await server.close().finally(() => process.exit(1))\n      return\n    }\n\n    if (actionRunning) return\n\n    if (input === 'h') {\n      server.config.logger.info(\n        [\n          '',\n          c.bold('  Shortcuts'),\n          ...SHORTCUTS.map(\n            (shortcut) =>\n              c.dim('  press ') +\n              c.bold(shortcut.key) +\n              c.dim(` to ${shortcut.description}`)\n          )\n        ].join('\\n')\n      )\n    }\n\n    const shortcut = SHORTCUTS.find((shortcut) => shortcut.key === input)\n    if (!shortcut) return\n\n    actionRunning = true\n    await shortcut.action(server, restartServer)\n    actionRunning = false\n  }\n\n  process.stdin.setRawMode(true)\n\n  process.stdin.on('data', onInput).setEncoding('utf8').resume()\n\n  server.httpServer.on('close', () => {\n    process.stdin.off('data', onInput).pause()\n    process.stdin.setRawMode(false)\n  })\n}\n\nconst SHORTCUTS: CLIShortcut[] = [\n  {\n    key: 'r',\n    description: 'restart the server',\n    async action(server, restartServer) {\n      server.config.logger.info(c.green(`restarting server...\\n`), {\n        clear: true,\n        timestamp: true\n      })\n      await restartServer()\n    }\n  },\n  {\n    key: 'u',\n    description: 'show server url',\n    action(server) {\n      server.config.logger.info('')\n      server.printUrls()\n    }\n  },\n  {\n    key: 'o',\n    description: 'open in browser',\n    action(server) {\n      server.openBrowser()\n    }\n  },\n  {\n    key: 'c',\n    description: 'clear console',\n    action(server) {\n      server.config.logger.clearScreen('error')\n    }\n  },\n  {\n    key: 'q',\n    description: 'quit',\n    async action(server) {\n      await server.close().finally(() => process.exit())\n    }\n  }\n]\n"
  },
  {
    "path": "src/node/siteConfig.ts",
    "content": "import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'\nimport type { UseDarkOptions } from '@vueuse/core'\nimport type { SitemapStreamOptions } from 'sitemap'\nimport type { Logger, UserConfig as ViteConfig } from 'vite'\nimport type { SitemapItem } from './build/generateSitemap'\nimport type { MarkdownOptions } from './markdown/markdown'\nimport type { ResolvedRouteConfig } from './plugins/dynamicRoutesPlugin'\nimport type {\n  Awaitable,\n  HeadConfig,\n  LocaleConfig,\n  LocaleSpecificConfig,\n  PageData,\n  SSGContext,\n  SiteData\n} from './shared'\nimport type {\n  AdditionalConfigDict,\n  AdditionalConfigLoader\n} from '../../types/shared'\n\nexport type RawConfigExports<ThemeConfig = any> =\n  | Awaitable<UserConfig<ThemeConfig>>\n  | (() => Awaitable<UserConfig<ThemeConfig>>)\n\nexport interface TransformContext<ThemeConfig = any> {\n  page: string\n  siteConfig: SiteConfig<ThemeConfig>\n  siteData: SiteData\n  pageData: PageData\n  title: string\n  description: string\n  head: HeadConfig[]\n  content: string\n  assets: string[]\n}\n\nexport interface TransformPageContext<ThemeConfig = any> {\n  siteConfig: SiteConfig<ThemeConfig>\n}\n\nexport interface UserConfig<\n  ThemeConfig = any\n> extends LocaleSpecificConfig<ThemeConfig> {\n  extends?: RawConfigExports<ThemeConfig>\n\n  base?: string\n  srcDir?: string\n  srcExclude?: string[]\n  outDir?: string\n  assetsDir?: string\n  cacheDir?: string\n\n  shouldPreload?: (link: string, page: string) => boolean\n\n  locales?: LocaleConfig<ThemeConfig>\n\n  router?: {\n    prefetchLinks?: boolean\n  }\n\n  appearance?:\n    | boolean\n    | 'dark'\n    | 'force-dark'\n    | 'force-auto'\n    | (Omit<UseDarkOptions, 'initialValue'> & { initialValue?: 'dark' })\n  lastUpdated?: boolean\n  contentProps?: Record<string, any>\n\n  /**\n   * MarkdownIt options\n   */\n  markdown?: MarkdownOptions\n  /**\n   * Options to pass on to `@vitejs/plugin-vue`\n   */\n  vue?: VuePluginOptions\n  /**\n   * Vite config\n   */\n  vite?: ViteConfig & { configFile?: string | false }\n\n  /**\n   * Configure the scroll offset when the theme has a sticky header.\n   * Can be a number or a selector element to get the offset from.\n   * Can also be an array of selectors in case some elements will be\n   * invisible due to responsive layout. VitePress will fallback to the next\n   * selector if a selector fails to match, or the matched element is not\n   * currently visible in viewport.\n   */\n  scrollOffset?:\n    | number\n    | string\n    | string[]\n    | { selector: string | string[]; padding: number }\n\n  /**\n   * Enable MPA / zero-JS mode.\n   * @experimental\n   */\n  mpa?: boolean\n\n  /**\n   * Extracts metadata to a separate chunk.\n   * @experimental\n   */\n  metaChunk?: boolean\n\n  /**\n   * Don't fail builds due to dead links.\n   *\n   * @default false\n   */\n  ignoreDeadLinks?:\n    | boolean\n    | 'localhostLinks'\n    | (string | RegExp | ((link: string, source: string) => boolean))[]\n\n  /**\n   * Don't force `.html` on URLs.\n   *\n   * @default false\n   */\n  cleanUrls?: boolean\n\n  /**\n   * Use web fonts instead of emitting font files to dist.\n   * The used theme should import a file named `fonts.(s)css` for this to work.\n   * If you are a theme author, to support this, place your web font import\n   * between `webfont-marker-begin` and `webfont-marker-end` comments.\n   *\n   * @default true in webcontainers, else false\n   */\n  useWebFonts?: boolean\n\n  /**\n   * This option allows you to configure the concurrency of the build.\n   * A lower number will reduce the memory usage but will increase the build time.\n   *\n   * @experimental\n   * @default 64\n   */\n  buildConcurrency?: number\n\n  /**\n   * @experimental\n   *\n   * source -> destination\n   */\n  rewrites?: Record<string, string> | ((id: string) => string)\n\n  /**\n   * @experimental\n   */\n  sitemap?: SitemapStreamOptions & {\n    hostname: string\n    transformItems?: (items: SitemapItem[]) => Awaitable<SitemapItem[]>\n  }\n\n  /**\n   * Build end hook: called when SSG finish.\n   * @param siteConfig The resolved configuration.\n   */\n  buildEnd?: (siteConfig: SiteConfig<ThemeConfig>) => Awaitable<void>\n\n  /**\n   * Render end hook: called when SSR rendering is done.\n   */\n  postRender?: (context: SSGContext) => Awaitable<SSGContext | void>\n\n  /**\n   * Head transform hook: runs before writing HTML to dist.\n   *\n   * This build hook will allow you to modify the head adding new entries that cannot be statically added.\n   */\n  transformHead?: (\n    ctx: TransformContext<ThemeConfig>\n  ) => Awaitable<HeadConfig[] | void>\n\n  /**\n   * HTML transform hook: runs before writing HTML to dist.\n   */\n  transformHtml?: (\n    code: string,\n    id: string,\n    ctx: TransformContext<ThemeConfig>\n  ) => Awaitable<string | void>\n\n  /**\n   * PageData transform hook: runs when rendering markdown to vue\n   */\n  transformPageData?: (\n    pageData: PageData,\n    ctx: TransformPageContext<ThemeConfig>\n  ) => Awaitable<Partial<PageData> | { [key: string]: any } | void>\n\n  /**\n   * Multi-layer configuration overloading.\n   * Auto-resolves to `docs/.../config.{js,mjs,ts,mts}` when unspecified.\n   *\n   * Set to `{}` to opt-out.\n   *\n   * @experimental\n   */\n  additionalConfig?:\n    | AdditionalConfigDict<ThemeConfig>\n    | AdditionalConfigLoader<ThemeConfig>\n}\n\nexport interface SiteConfig<ThemeConfig = any> extends Pick<\n  UserConfig<ThemeConfig>,\n  | 'markdown'\n  | 'vue'\n  | 'vite'\n  | 'shouldPreload'\n  | 'router'\n  | 'mpa'\n  | 'metaChunk'\n  | 'lastUpdated'\n  | 'ignoreDeadLinks'\n  | 'cleanUrls'\n  | 'useWebFonts'\n  | 'postRender'\n  | 'buildEnd'\n  | 'transformHead'\n  | 'transformHtml'\n  | 'transformPageData'\n  | 'sitemap'\n> {\n  root: string\n  srcDir: string\n  site: SiteData<ThemeConfig>\n  configPath: string | undefined\n  configDeps: string[]\n  themeDir: string\n  outDir: string\n  assetsDir: string\n  cacheDir: string\n  tempDir: string\n  pages: string[]\n  dynamicRoutes: ResolvedRouteConfig[]\n  rewrites: {\n    map: Record<string, string | undefined>\n    inv: Record<string, string | undefined>\n  }\n  logger: Logger\n  userConfig: UserConfig<ThemeConfig>\n  buildConcurrency: number\n}\n"
  },
  {
    "path": "src/node/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"../../dist/node\",\n    \"types\": [\"node\"],\n    \"sourceMap\": true\n  },\n  \"include\": [\".\"]\n}\n"
  },
  {
    "path": "src/node/utils/fnSerialize.ts",
    "content": "export function serializeFunctions(value: any, key?: string): any {\n  if (Array.isArray(value)) {\n    return value.map((v) => serializeFunctions(v))\n  } else if (typeof value === 'object' && value !== null) {\n    return Object.keys(value).reduce((acc, key) => {\n      if (key[0] === '_') return acc\n      acc[key] = serializeFunctions(value[key], key)\n      return acc\n    }, {} as any)\n  } else if (typeof value === 'function') {\n    let serialized = value.toString()\n    if (\n      key &&\n      (serialized.startsWith(key) || serialized.startsWith('async ' + key))\n    ) {\n      serialized = serialized.replace(key, 'function')\n    }\n    return `_vp-fn_${serialized}`\n  } else {\n    return value\n  }\n}\n\n/*\nexport function deserializeFunctions(value: any): any {\n  if (Array.isArray(value)) {\n    return value.map(deserializeFunctions)\n  } else if (typeof value === 'object' && value !== null) {\n    return Object.keys(value).reduce((acc, key) => {\n      acc[key] = deserializeFunctions(value[key])\n      return acc\n    }, {} as any)\n  } else if (typeof value === 'string' && value.startsWith('_vp-fn_')) {\n    return new Function(`return ${value.slice(7)}`)()\n  } else {\n    return value\n  }\n}\n*/\n\nexport const deserializeFunctions =\n  'function deserializeFunctions(r){return Array.isArray(r)?r.map(deserializeFunctions):typeof r==\"object\"&&r!==null?Object.keys(r).reduce((t,n)=>(t[n]=deserializeFunctions(r[n]),t),{}):typeof r==\"string\"&&r.startsWith(\"_vp-fn_\")?new Function(`return ${r.slice(7)}`)():r}'\n"
  },
  {
    "path": "src/node/utils/getGitTimestamp.ts",
    "content": "import { spawn, sync } from 'cross-spawn'\nimport { createDebug } from 'obug'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { Transform, type TransformCallback } from 'node:stream'\nimport { slash } from '../shared'\n\nconst debug = createDebug('vitepress:git')\nconst cache = new Map<string, number>()\n\nconst RS = 0x1e\nconst NUL = 0x00\nconst LF = 0x0a\n\ninterface GitLogRecord {\n  ts: number\n  files: string[]\n}\n\ntype State = 'READ_TS' | 'READ_FILE'\n\nclass GitLogParser extends Transform {\n  #state: State = 'READ_TS'\n  #tsBytes: number[] = []\n  #fileBytes: number[] = []\n  #files: string[] = []\n\n  constructor() {\n    super({ readableObjectMode: true })\n  }\n\n  override _transform(\n    chunk: Buffer,\n    _enc: BufferEncoding,\n    cb: TransformCallback\n  ): void {\n    try {\n      for (let i = 0; i < chunk.length; i++) {\n        const b = chunk[i] === LF ? NUL : chunk[i] // treat LF as NUL\n\n        switch (this.#state) {\n          case 'READ_TS': {\n            if (b === RS) {\n              // ignore\n            } else if (b === NUL) {\n              this.#state = 'READ_FILE'\n            } else {\n              this.#tsBytes.push(b)\n            }\n            break\n          }\n\n          case 'READ_FILE': {\n            if (b === RS) {\n              this.#emitRecord()\n            } else if (b === NUL) {\n              if (this.#fileBytes.length > 0) {\n                this.#files.push(Buffer.from(this.#fileBytes).toString('utf8'))\n                this.#fileBytes.length = 0\n              }\n            } else {\n              this.#fileBytes.push(b)\n            }\n            break\n          }\n        }\n      }\n\n      cb()\n    } catch (err) {\n      cb(err as Error)\n    }\n  }\n\n  override _flush(cb: TransformCallback): void {\n    try {\n      if (this.#state === 'READ_FILE') {\n        if (this.#fileBytes.length > 0) {\n          throw new Error('GitLogParser: unexpected EOF while reading filename')\n        } else {\n          this.#emitRecord()\n        }\n      }\n\n      cb()\n    } catch (err) {\n      cb(err as Error)\n    }\n  }\n\n  #emitRecord(): void {\n    const ts = Buffer.from(this.#tsBytes).toString('utf8')\n    const rec: GitLogRecord = {\n      ts: Number.parseInt(ts, 10) * 1000,\n      files: this.#files.slice()\n    }\n    if (rec.ts > 0 && rec.files.length > 0) this.push(rec)\n\n    this.#tsBytes.length = 0\n    this.#fileBytes.length = 0\n    this.#files.length = 0\n    this.#state = 'READ_TS'\n  }\n}\n\nexport async function cacheAllGitTimestamps(\n  root: string,\n  pathspec: string[] = ['*.md']\n): Promise<void> {\n  const cp = sync('git', ['rev-parse', '--show-toplevel'], { cwd: root })\n  if (cp.error) throw cp.error\n  const gitRoot = cp.stdout.toString('utf8').trim()\n\n  const args = [\n    'log',\n    '--pretty=format:%x1e%at%x00', // RS + epoch + NUL\n    '--name-only',\n    '-z',\n    '--',\n    ...pathspec\n  ]\n\n  return new Promise((resolve, reject) => {\n    cache.clear()\n    const child = spawn('git', args, { cwd: root })\n\n    child.stdout\n      .pipe(new GitLogParser())\n      .on('data', (rec: GitLogRecord) => {\n        for (const file of rec.files) {\n          const slashed = slash(path.resolve(gitRoot, file))\n          if (!cache.has(slashed)) cache.set(slashed, rec.ts)\n        }\n      })\n      .on('error', reject)\n      .on('end', resolve)\n\n    child.on('error', reject)\n  })\n}\n\nexport async function getGitTimestamp(file: string): Promise<number> {\n  const cached = cache.get(file)\n  if (cached) return cached\n\n  // most likely will never happen except for recently added files in dev\n  debug(`[cache miss] ${file}`)\n\n  if (!fs.existsSync(file)) return 0\n\n  return new Promise((resolve, reject) => {\n    const child = spawn(\n      'git',\n      ['log', '-1', '--pretty=%at', '--', path.basename(file)],\n      { cwd: path.dirname(file) }\n    )\n\n    let output = ''\n    child.stdout.on('data', (d) => (output += String(d)))\n\n    child.on('close', () => {\n      const ts = Number.parseInt(output.trim(), 10) * 1000\n      if (!(ts > 0)) return resolve(0)\n\n      cache.set(file, ts)\n      resolve(ts)\n    })\n\n    child.on('error', reject)\n  })\n}\n"
  },
  {
    "path": "src/node/utils/glob.ts",
    "content": "import path from 'node:path'\nimport { glob as _glob } from 'tinyglobby'\nimport { normalizePath } from 'vite'\n\nexport interface GlobOptions {\n  absolute?: boolean\n  cwd?: string\n  ignore?: string | string[]\n  dot?: boolean\n  debug?: boolean\n}\n\nexport function normalizeGlob(\n  patterns: string[] | string | undefined,\n  base: string\n): string[] {\n  if (!patterns) return []\n  if (typeof patterns === 'string') patterns = [patterns]\n  return patterns.map((p) =>\n    p[0] === '!'\n      ? '!' + normalizePath(path.resolve(base, p.slice(1)))\n      : normalizePath(path.resolve(base, p))\n  )\n}\n\nexport async function glob(\n  patterns: string[] | undefined,\n  options?: GlobOptions\n): Promise<string[]> {\n  if (!patterns?.length) return []\n  return (\n    await _glob(patterns, {\n      expandDirectories: false,\n      ...options,\n      ignore: ['**/node_modules/**', '**/dist/**', ...(options?.ignore || [])]\n    })\n  ).sort()\n}\n"
  },
  {
    "path": "src/node/utils/moduleGraph.ts",
    "content": "export class ModuleGraph {\n  // Each module is tracked with its dependencies and dependents.\n  private nodes: Map<\n    string,\n    { dependencies: Set<string>; dependents: Set<string> }\n  > = new Map()\n\n  /**\n   * Adds or updates a module by merging the provided dependencies\n   * with any existing ones.\n   *\n   * For every new dependency, the module is added to that dependency's\n   * 'dependents' set.\n   *\n   * @param module - The module to add or update.\n   * @param dependencies - Array of module names that the module depends on.\n   */\n  add(module: string, dependencies: string[]): void {\n    // Ensure the module exists in the graph.\n    if (!this.nodes.has(module)) {\n      this.nodes.set(module, {\n        dependencies: new Set(),\n        dependents: new Set()\n      })\n    }\n    const moduleNode = this.nodes.get(module)!\n\n    // Merge the new dependencies with any that already exist.\n    for (const dep of dependencies) {\n      if (!moduleNode.dependencies.has(dep) && dep !== module) {\n        moduleNode.dependencies.add(dep)\n        // Ensure the dependency exists in the graph.\n        if (!this.nodes.has(dep)) {\n          this.nodes.set(dep, {\n            dependencies: new Set(),\n            dependents: new Set()\n          })\n        }\n        // Add the module as a dependent of the dependency.\n        this.nodes.get(dep)!.dependents.add(module)\n      }\n    }\n  }\n\n  /**\n   * Deletes a module and all modules that (transitively) depend on it.\n   *\n   * This method performs a depth-first search from the target module,\n   * collects all affected modules, and then removes them from the graph,\n   * cleaning up their references from other nodes.\n   *\n   * @param module - The module to delete.\n   * @returns A Set containing the deleted module and all modules that depend on it.\n   */\n  delete(module: string): Set<string> {\n    const deleted = new Set<string>()\n    if (!this.nodes.has(module)) return deleted\n\n    const stack: string[] = [module]\n\n    // Traverse the reverse dependency graph (using dependents).\n    while (stack.length) {\n      const current = stack.pop()!\n      if (!deleted.has(current)) {\n        deleted.add(current)\n        const node = this.nodes.get(current)\n        if (node) {\n          for (const dependent of node.dependents) {\n            stack.push(dependent)\n          }\n        }\n      }\n    }\n\n    // Remove deleted nodes from the graph.\n    // For each deleted node, also remove it from its dependencies' dependents.\n    for (const mod of deleted) {\n      const node = this.nodes.get(mod)\n      if (node) {\n        for (const dep of node.dependencies) {\n          const depNode = this.nodes.get(dep)\n          if (depNode) {\n            depNode.dependents.delete(mod)\n          }\n        }\n      }\n      this.nodes.delete(mod)\n    }\n\n    return deleted\n  }\n\n  /**\n   * Clears all modules from the graph.\n   */\n  clear(): void {\n    this.nodes.clear()\n  }\n\n  /**\n   * Creates a deep clone of the ModuleGraph instance.\n   * This is useful for preserving the state of the graph\n   * before making modifications.\n   *\n   * @returns A new ModuleGraph instance with the same state as the original.\n   */\n  clone(): ModuleGraph {\n    const clone = new ModuleGraph()\n    for (const [module, { dependencies, dependents }] of this.nodes) {\n      clone.nodes.set(module, {\n        dependencies: new Set(dependencies),\n        dependents: new Set(dependents)\n      })\n    }\n    return clone\n  }\n}\n"
  },
  {
    "path": "src/node/utils/processIncludes.ts",
    "content": "import matter from 'gray-matter'\nimport type { MarkdownItAsync } from 'markdown-it-async'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { findRegion } from '../markdown/plugins/snippet'\nimport { slash, type MarkdownEnv } from '../shared'\n\nexport function processIncludes(\n  md: MarkdownItAsync,\n  srcDir: string,\n  src: string,\n  file: string,\n  includes: string[],\n  cleanUrls: boolean\n): string {\n  const includesRE = /<!--\\s*@include:\\s*(.*?)\\s*-->/g\n  const regionRE = /(#[^\\s\\{]+)/\n  const rangeRE = /\\{(\\d*),(\\d*)\\}$/\n\n  return src.replace(includesRE, (m: string, m1: string) => {\n    if (!m1.length) return m\n\n    const range = m1.match(rangeRE)\n    const region = m1.match(regionRE)\n\n    const hasMeta = !!(region || range)\n\n    if (hasMeta) {\n      const len = (region?.[0].length || 0) + (range?.[0].length || 0)\n      m1 = m1.slice(0, -len) // remove meta info from the include path\n    }\n\n    const atPresent = m1[0] === '@'\n\n    const includePath = atPresent\n      ? path.join(srcDir, m1.slice(m1[1] === '/' ? 2 : 1))\n      : path.join(path.dirname(file), m1)\n\n    let content = fs.readFileSync(includePath, 'utf-8')\n\n    if (region) {\n      const [regionName] = region\n      const lines = content.split(/\\r?\\n/)\n      let { start, end } = findRegion(lines, regionName.slice(1)) ?? {}\n\n      if (start === undefined) {\n        // region not found, it might be a header\n        const tokens = md\n          .parse(content, {\n            path: includePath,\n            relativePath: slash(path.relative(srcDir, includePath)),\n            cleanUrls\n          } satisfies MarkdownEnv)\n          .filter((t) => t.type === 'heading_open' && t.map)\n        const idx = tokens.findIndex(\n          (t) => t.attrGet('id') === regionName.slice(1)\n        )\n        const token = tokens[idx]\n        if (token) {\n          start = token.map![1]\n          const level = parseInt(token.tag.slice(1))\n          for (let i = idx + 1; i < tokens.length; i++) {\n            if (parseInt(tokens[i].tag.slice(1)) <= level) {\n              end = tokens[i].map![0]\n              break\n            }\n          }\n        }\n      }\n\n      content = lines.slice(start, end).join('\\n')\n    }\n\n    if (range) {\n      const [, startLine, endLine] = range\n      const lines = content.split(/\\r?\\n/)\n      content = lines\n        .slice(\n          startLine ? parseInt(startLine) - 1 : undefined,\n          endLine ? parseInt(endLine) : undefined\n        )\n        .join('\\n')\n    }\n\n    if (!hasMeta && path.extname(includePath) === '.md') {\n      content = matter(content).content\n    }\n\n    includes.push(slash(includePath))\n\n    // recursively process includes in the content\n    return processIncludes(\n      md,\n      srcDir,\n      content,\n      includePath,\n      includes,\n      cleanUrls\n    )\n  })\n}\n"
  },
  {
    "path": "src/node/utils/task.ts",
    "content": "import ora from 'ora'\n\nexport const okMark = '\\x1b[32m✓\\x1b[0m'\nexport const failMark = '\\x1b[31m✗\\x1b[0m'\n\nexport async function task(taskName: string, task: () => Promise<void>) {\n  const spinner = ora({ discardStdin: false })\n  spinner.start(taskName + '...')\n\n  try {\n    await task()\n  } catch (e) {\n    spinner.stopAndPersist({ symbol: failMark })\n    throw e\n  }\n\n  spinner.stopAndPersist({ symbol: okMark })\n}\n"
  },
  {
    "path": "src/shared/shared.ts",
    "content": "import type {\n  AdditionalConfig,\n  HeadConfig,\n  PageData,\n  SiteData\n} from '../../types/shared'\n\nexport type {\n  Awaitable,\n  DefaultTheme,\n  HeadConfig,\n  Header,\n  LocaleConfig,\n  LocaleSpecificConfig,\n  MarkdownEnv,\n  PageData,\n  PageDataPayload,\n  SiteData,\n  SSGContext,\n  AdditionalConfig,\n  AdditionalConfigDict,\n  AdditionalConfigLoader\n} from '../../types/shared'\n\nexport const EXTERNAL_URL_RE = /^(?:[a-z]+:|\\/\\/)/i\nexport const APPEARANCE_KEY = 'vitepress-theme-appearance'\n\nexport const VP_SOURCE_KEY = '[VP_SOURCE]'\nconst UnpackStackView = Symbol('stack-view:unpack')\n\nconst HASH_WITHOUT_FRAGMENT_RE = /#.*?(?=:~:|$)/\nconst HASH_OR_QUERY_RE = /[?#].*$/\nconst INDEX_OR_EXT_RE = /(?:(^|\\/)index)?\\.(?:md|html)$/\n\nexport const inBrowser = typeof document !== 'undefined'\n\nexport const notFoundPageData: PageData = {\n  relativePath: '404.md',\n  filePath: '',\n  title: '404',\n  description: 'Not Found',\n  headers: [],\n  frontmatter: { sidebar: false, layout: 'page' },\n  lastUpdated: 0,\n  isNotFound: true\n}\n\nexport function isActive(\n  currentPath: string,\n  matchPath?: string,\n  asRegex: boolean = false\n): boolean {\n  if (matchPath === undefined) {\n    return false\n  }\n\n  currentPath = normalize(`/${currentPath}`)\n\n  if (asRegex) {\n    return new RegExp(matchPath).test(currentPath)\n  }\n\n  if (normalize(matchPath) !== currentPath) {\n    return false\n  }\n\n  const hashMatch = matchPath.match(HASH_WITHOUT_FRAGMENT_RE)\n\n  if (hashMatch) {\n    return (inBrowser ? location.hash : '') === hashMatch[0]\n  }\n\n  return true\n}\n\nexport function normalize(path: string): string {\n  return decodeURI(path)\n    .replace(HASH_OR_QUERY_RE, '')\n    .replace(INDEX_OR_EXT_RE, '$1')\n}\n\nexport function isExternal(path: string): boolean {\n  return EXTERNAL_URL_RE.test(path)\n}\n\nexport function getLocaleForPath(\n  siteData: SiteData | undefined,\n  relativePath: string\n): string {\n  return (\n    Object.keys(siteData?.locales || {}).find(\n      (key) =>\n        key !== 'root' &&\n        !isExternal(key) &&\n        isActive(relativePath, `^/${key}/`, true)\n    ) || 'root'\n  )\n}\n\n/**\n * this merges the locales data to the main data by the route\n */\nexport function resolveSiteDataByRoute(\n  siteData: SiteData,\n  relativePath: string\n): SiteData {\n  const localeIndex = getLocaleForPath(siteData, relativePath)\n  const { label, link, ...localeConfig } = siteData.locales[localeIndex] ?? {}\n  Object.assign(localeConfig, { localeIndex })\n\n  const additionalConfigs = resolveAdditionalConfig(siteData, relativePath)\n\n  if (inBrowser && (import.meta as any).env?.DEV) {\n    ;(localeConfig as any)[VP_SOURCE_KEY] = `locale config (${localeIndex})`\n    reportConfigLayers(relativePath, [\n      ...additionalConfigs,\n      localeConfig,\n      siteData\n    ])\n  }\n\n  const topLayer = {\n    head: mergeHead(\n      siteData.head ?? [],\n      localeConfig.head ?? [],\n      ...additionalConfigs.map((data) => data.head ?? []).reverse()\n    )\n  } as SiteData\n\n  return stackView<SiteData>(\n    topLayer,\n    ...additionalConfigs,\n    localeConfig,\n    siteData\n  )\n}\n\n/**\n * Create the page title string based on config.\n */\nexport function createTitle(siteData: SiteData, pageData: PageData): string {\n  const title = pageData.title || siteData.title\n  const template = pageData.titleTemplate ?? siteData.titleTemplate\n\n  if (typeof template === 'string' && template.includes(':title')) {\n    return template.replace(/:title/g, title)\n  }\n\n  const templateString = createTitleTemplate(siteData.title, template)\n\n  if (title === templateString.slice(3)) {\n    return title\n  }\n\n  return `${title}${templateString}`\n}\n\nfunction createTitleTemplate(\n  siteTitle: string,\n  template?: string | boolean\n): string {\n  if (template === false) {\n    return ''\n  }\n\n  if (template === true || template === undefined) {\n    return ` | ${siteTitle}`\n  }\n\n  if (siteTitle === template) {\n    return ''\n  }\n\n  return ` | ${template}`\n}\n\nexport function mergeHead(...headArrays: HeadConfig[][]): HeadConfig[] {\n  const merged: HeadConfig[] = []\n  const metaKeyMap = new Map<string, number>()\n\n  for (const current of headArrays) {\n    for (const tag of current) {\n      const [type, attrs] = tag\n      const keyAttr = Object.entries(attrs)[0]\n\n      if (type !== 'meta' || !keyAttr) {\n        merged.push(tag)\n        continue\n      }\n\n      const key = `${keyAttr[0]}=${keyAttr[1]}`\n      const existingIndex = metaKeyMap.get(key)\n\n      if (existingIndex != null) {\n        merged[existingIndex] = tag // replace existing tag\n      } else {\n        metaKeyMap.set(key, merged.length)\n        merged.push(tag)\n      }\n    }\n  }\n\n  return merged\n}\n\n// https://github.com/rollup/rollup/blob/fec513270c6ac350072425cc045db367656c623b/src/utils/sanitizeFileName.ts\n\nconst INVALID_CHAR_REGEX = /[\\u0000-\\u001F\"#$&*+,:;<=>?[\\]^`{|}\\u007F]/g\nconst DRIVE_LETTER_REGEX = /^[a-z]:/i\n\nexport function sanitizeFileName(name: string): string {\n  const match = DRIVE_LETTER_REGEX.exec(name)\n  const driveLetter = match ? match[0] : ''\n\n  return (\n    driveLetter +\n    name\n      .slice(driveLetter.length)\n      .replace(INVALID_CHAR_REGEX, '_')\n      .replace(/(^|\\/)_+(?=[^/]*$)/, '$1')\n  )\n}\n\nexport function slash(p: string): string {\n  return p.replace(/\\\\/g, '/')\n}\n\nconst KNOWN_EXTENSIONS = new Set()\n\nexport function treatAsHtml(filename: string): boolean {\n  if (KNOWN_EXTENSIONS.size === 0) {\n    const extraExts =\n      (typeof process === 'object' && process.env?.VITE_EXTRA_EXTENSIONS) ||\n      (import.meta as any).env?.VITE_EXTRA_EXTENSIONS ||\n      ''\n\n    // md, html? are intentionally omitted\n    ;(\n      '3g2,3gp,aac,ai,apng,au,avif,bin,bmp,cer,class,conf,crl,css,csv,dll,' +\n      'doc,eps,epub,exe,gif,gz,ics,ief,jar,jpe,jpeg,jpg,js,json,jsonld,m4a,' +\n      'man,mid,midi,mjs,mov,mp2,mp3,mp4,mpe,mpeg,mpg,mpp,oga,ogg,ogv,ogx,' +\n      'opus,otf,p10,p7c,p7m,p7s,pdf,png,ps,qt,roff,rtf,rtx,ser,svg,t,tif,' +\n      'tiff,tr,ts,tsv,ttf,txt,vtt,wav,weba,webm,webp,woff,woff2,xhtml,xml,' +\n      'yaml,yml,zip' +\n      (extraExts && typeof extraExts === 'string' ? ',' + extraExts : '')\n    )\n      .split(',')\n      .forEach((ext) => KNOWN_EXTENSIONS.add(ext))\n  }\n\n  const ext = filename.split('.').pop()\n\n  return ext == null || !KNOWN_EXTENSIONS.has(ext.toLowerCase())\n}\n\n// https://github.com/sindresorhus/escape-string-regexp/blob/ba9a4473850cb367936417e97f1f2191b7cc67dd/index.js\nexport function escapeRegExp(str: string) {\n  return str.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d')\n}\n\n/**\n * @internal\n */\nexport function escapeHtml(str: string): string {\n  return str\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/&(?![\\w#]+;)/g, '&amp;')\n}\n\nfunction resolveAdditionalConfig(\n  { additionalConfig }: SiteData,\n  path: string\n): AdditionalConfig[] {\n  if (additionalConfig === undefined) return []\n  if (typeof additionalConfig === 'function')\n    return additionalConfig(path) ?? []\n\n  const configs: AdditionalConfig[] = []\n  const segments = path.split('/').slice(0, -1) // remove file name\n\n  while (segments.length) {\n    const key = `/${segments.join('/')}/`\n    configs.push(additionalConfig[key])\n    segments.pop()\n  }\n\n  configs.push(additionalConfig['/'])\n  return configs.filter((config) => config !== undefined)\n}\n\n// This helps users to understand which configuration files are active\nfunction reportConfigLayers(path: string, layers: Partial<SiteData>[]) {\n  const summaryTitle = `Config Layers for ${path}:`\n\n  const summary = layers.map((c, i, arr) => {\n    const n = i + 1\n    if (n === arr.length) return `${n}. .vitepress/config (root)`\n    return `${n}. ${(c as any)?.[VP_SOURCE_KEY] ?? '(Unknown Source)'}`\n  })\n\n  console.debug(\n    [summaryTitle, ''.padEnd(summaryTitle.length, '='), ...summary].join('\\n')\n  )\n}\n\n/**\n * Creates a deep, merged view of multiple objects without mutating originals.\n * Returns a readonly proxy behaving like a merged object of the input objects.\n * Layers are merged in descending precedence, i.e. earlier layer is on top.\n */\nexport function stackView<T extends ObjectType>(..._layers: Partial<T>[]): T {\n  const layers = _layers.filter((layer) => isObject(layer))\n  if (layers.length <= 1) return _layers[0] as T\n\n  const allKeys = new Set(layers.flatMap((layer) => Reflect.ownKeys(layer)))\n  const allKeysArray = [...allKeys]\n\n  return new Proxy({} as T, {\n    // TODO: optimize for performance, this is a hot path\n    get(_, prop) {\n      if (prop === UnpackStackView) return layers\n      return stackView(\n        ...layers\n          .map((layer) => layer[prop])\n          .filter((v): v is NonNullable<T[string | symbol]> => v !== undefined)\n      )\n    },\n    set() {\n      throw new Error('StackView is read-only and cannot be mutated.')\n    },\n    has(_, prop) {\n      return allKeys.has(prop)\n    },\n    ownKeys() {\n      return allKeysArray\n    },\n    getOwnPropertyDescriptor(_, prop) {\n      for (const layer of layers) {\n        const descriptor = Object.getOwnPropertyDescriptor(layer, prop)\n        if (descriptor) return descriptor\n      }\n    }\n  })\n}\n\nstackView.unpack = function <T>(obj: T): T[] | undefined {\n  return (obj as any)?.[UnpackStackView]\n}\n\ntype ObjectType = Record<PropertyKey, any>\nexport function isObject(value: unknown): value is ObjectType {\n  return Object.prototype.toString.call(value) === '[object Object]'\n}\n\nconst shellLangs = ['shellscript', 'shell', 'bash', 'sh', 'zsh']\nexport function isShell(lang: string): boolean {\n  return shellLangs.includes(lang)\n}\n"
  },
  {
    "path": "src/shared/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"lib\": [\"esnext\", \"dom\", \"dom.iterable\"]\n  },\n  \"include\": [\".\"]\n}\n"
  },
  {
    "path": "template/.vitepress/config.js",
    "content": "import { defineConfig } from 'vitepress'\n\n// https://vitepress.dev/reference/site-config\nexport default defineConfig({<% if (srcDir) { %>\n  srcDir: <%= srcDir %>,\n  <% } %>\n  title: <%= title %>,\n  description: <%= description %><% if (defaultTheme) { %>,\n  themeConfig: {\n    // https://vitepress.dev/reference/default-theme-config\n    nav: [\n      { text: 'Home', link: '/' },\n      { text: 'Examples', link: '/markdown-examples' }\n    ],\n\n    sidebar: [\n      {\n        text: 'Examples',\n        items: [\n          { text: 'Markdown Examples', link: '/markdown-examples' },\n          { text: 'Runtime API Examples', link: '/api-examples' }\n        ]\n      }\n    ],\n\n    socialLinks: [\n      { icon: 'github', link: 'https://github.com/vuejs/vitepress' }\n    ]\n  }<% } %>\n})\n"
  },
  {
    "path": "template/.vitepress/theme/Layout.vue",
    "content": "<script setup<%= useTs ? ' lang=\"ts\"' : '' %>>\nimport { useData } from 'vitepress'\n\n// https://vitepress.dev/reference/runtime-api#usedata\nconst { site, frontmatter } = useData()\n</script>\n\n<template>\n  <div v-if=\"frontmatter.home\">\n    <h1>{{ site.title }}</h1>\n    <p>{{ site.description }}</p>\n    <ul>\n      <li><a href=\"/markdown-examples.html\">Markdown Examples</a></li>\n      <li><a href=\"/api-examples.html\">API Examples</a></li>\n    </ul>\n  </div>\n  <div v-else>\n    <a href=\"/\">Home</a>\n    <Content />\n  </div>\n</template>\n"
  },
  {
    "path": "template/.vitepress/theme/index.js",
    "content": "// https://vitepress.dev/guide/custom-theme\n<% if (!defaultTheme) { %>import Layout from './Layout.vue'<% if (useTs) { %>\nimport type { Theme } from 'vitepress'<% } %>\nimport './style.css'\n\n<% if (!useTs) { %>/** @type {import('vitepress').Theme} */\n<% } %>export default {\n  Layout,\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}<% if (useTs) { %> satisfies Theme<% } %>\n<% } else { %>import { h } from 'vue'<% if (useTs) { %>\nimport type { Theme } from 'vitepress'<% } %>\nimport DefaultTheme from 'vitepress/theme'\nimport './style.css'\n\n<% if (!useTs) { %>/** @type {import('vitepress').Theme} */\n<% } %>export default {\n  extends: DefaultTheme,\n  Layout: () => {\n    return h(DefaultTheme.Layout, null, {\n      // https://vitepress.dev/guide/extending-default-theme#layout-slots\n    })\n  },\n  enhanceApp({ app, router, siteData }) {\n    // ...\n  }\n}<% if (useTs) { %> satisfies Theme<% } %><% } %>\n"
  },
  {
    "path": "template/.vitepress/theme/style.css",
    "content": "<% if (defaultTheme) { %>/**\n * Customize default theme styling by overriding CSS variables:\n * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css\n */\n\n/**\n * Colors\n *\n * Each colors have exact same color scale system with 3 levels of solid\n * colors with different brightness, and 1 soft color.\n *\n * - `XXX-1`: The most solid color used mainly for colored text. It must\n *   satisfy the contrast ratio against when used on top of `XXX-soft`.\n *\n * - `XXX-2`: The color used mainly for hover state of the button.\n *\n * - `XXX-3`: The color for solid background, such as bg color of the button.\n *   It must satisfy the contrast ratio with pure white (#ffffff) text on\n *   top of it.\n *\n * - `XXX-soft`: The color used for subtle background such as custom container\n *   or badges. It must satisfy the contrast ratio when putting `XXX-1` colors\n *   on top of it.\n *\n *   The soft color must be semi transparent alpha channel. This is crucial\n *   because it allows adding multiple \"soft\" colors on top of each other\n *   to create an accent, such as when having inline code block inside\n *   custom containers.\n *\n * - `default`: The color used purely for subtle indication without any\n *   special meanings attached to it such as bg color for menu hover state.\n *\n * - `brand`: Used for primary brand colors, such as link text, button with\n *   brand theme, etc.\n *\n * - `tip`: Used to indicate useful information. The default theme uses the\n *   brand color for this by default.\n *\n * - `warning`: Used to indicate warning to the users. Used in custom\n *   container, badges, etc.\n *\n * - `danger`: Used to show error, or dangerous message to the users. Used\n *   in custom container, badges, etc.\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-default-1: var(--vp-c-gray-1);\n  --vp-c-default-2: var(--vp-c-gray-2);\n  --vp-c-default-3: var(--vp-c-gray-3);\n  --vp-c-default-soft: var(--vp-c-gray-soft);\n\n  --vp-c-brand-1: var(--vp-c-indigo-1);\n  --vp-c-brand-2: var(--vp-c-indigo-2);\n  --vp-c-brand-3: var(--vp-c-indigo-3);\n  --vp-c-brand-soft: var(--vp-c-indigo-soft);\n\n  --vp-c-tip-1: var(--vp-c-brand-1);\n  --vp-c-tip-2: var(--vp-c-brand-2);\n  --vp-c-tip-3: var(--vp-c-brand-3);\n  --vp-c-tip-soft: var(--vp-c-brand-soft);\n\n  --vp-c-warning-1: var(--vp-c-yellow-1);\n  --vp-c-warning-2: var(--vp-c-yellow-2);\n  --vp-c-warning-3: var(--vp-c-yellow-3);\n  --vp-c-warning-soft: var(--vp-c-yellow-soft);\n\n  --vp-c-danger-1: var(--vp-c-red-1);\n  --vp-c-danger-2: var(--vp-c-red-2);\n  --vp-c-danger-3: var(--vp-c-red-3);\n  --vp-c-danger-soft: var(--vp-c-red-soft);\n}\n\n/**\n * Component: Button\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-button-brand-border: transparent;\n  --vp-button-brand-text: var(--vp-c-white);\n  --vp-button-brand-bg: var(--vp-c-brand-3);\n  --vp-button-brand-hover-border: transparent;\n  --vp-button-brand-hover-text: var(--vp-c-white);\n  --vp-button-brand-hover-bg: var(--vp-c-brand-2);\n  --vp-button-brand-active-border: transparent;\n  --vp-button-brand-active-text: var(--vp-c-white);\n  --vp-button-brand-active-bg: var(--vp-c-brand-1);\n}\n\n/**\n * Component: Home\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(\n    120deg,\n    #bd34fe 30%,\n    #41d1ff\n  );\n\n  --vp-home-hero-image-background-image: linear-gradient(\n    -45deg,\n    #bd34fe 50%,\n    #47caff 50%\n  );\n  --vp-home-hero-image-filter: blur(44px);\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(68px);\n  }\n}\n\n/**\n * Component: Custom Block\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-custom-block-tip-border: transparent;\n  --vp-custom-block-tip-text: var(--vp-c-text-1);\n  --vp-custom-block-tip-bg: var(--vp-c-brand-soft);\n  --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);\n}\n<% } else { %>\nhtml {\n  font-family: Arial, Helvetica;\n}\n<% } %>\n"
  },
  {
    "path": "template/api-examples.md",
    "content": "---\noutline: deep\n---\n\n# Runtime API Examples\n\nThis page demonstrates usage of some of the runtime APIs provided by VitePress.\n\nThe main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:\n\n```md\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { theme, page, frontmatter } = useData()\n</script>\n\n## Results\n\n### Theme Data\n<pre>{{ theme }}</pre>\n\n### Page Data\n<pre>{{ page }}</pre>\n\n### Page Frontmatter\n<pre>{{ frontmatter }}</pre>\n```\n\n<script setup>\nimport { useData } from 'vitepress'\n\nconst { site, theme, page, frontmatter } = useData()\n</script>\n\n## Results\n\n### Theme Data\n<pre>{{ theme }}</pre>\n\n### Page Data\n<pre>{{ page }}</pre>\n\n### Page Frontmatter\n<pre>{{ frontmatter }}</pre>\n\n## More\n\nCheck out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).\n"
  },
  {
    "path": "template/index.md",
    "content": "<% if (defaultTheme) { %>---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\n\nhero:\n  name: <%= title %>\n  text: <%= description %>\n  tagline: My great project tagline\n  actions:\n    - theme: brand\n      text: Markdown Examples\n      link: /markdown-examples\n    - theme: alt\n      text: API Examples\n      link: /api-examples\n\nfeatures:\n  - title: Feature A\n    details: Lorem ipsum dolor sit amet, consectetur adipiscing elit\n  - title: Feature B\n    details: Lorem ipsum dolor sit amet, consectetur adipiscing elit\n  - title: Feature C\n    details: Lorem ipsum dolor sit amet, consectetur adipiscing elit\n---\n<% } else { %>---\nhome: true\n---\n<% } %>\n"
  },
  {
    "path": "template/markdown-examples.md",
    "content": "# Markdown Extension Examples\n\nThis page demonstrates some of the built-in markdown extensions provided by VitePress.\n\n## Syntax Highlighting\n\nVitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:\n\n**Input**\n\n````md\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n````\n\n**Output**\n\n```js{4}\nexport default {\n  data () {\n    return {\n      msg: 'Highlighted!'\n    }\n  }\n}\n```\n\n## Custom Containers\n\n**Input**\n\n```md\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n```\n\n**Output**\n\n::: info\nThis is an info box.\n:::\n\n::: tip\nThis is a tip.\n:::\n\n::: warning\nThis is a warning.\n:::\n\n::: danger\nThis is a dangerous warning.\n:::\n\n::: details\nThis is a details block.\n:::\n\n## More\n\nCheck out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).\n"
  },
  {
    "path": "theme-without-fonts.d.ts",
    "content": "export * from './theme.js'\nexport { default } from './theme.js'\n"
  },
  {
    "path": "theme.d.ts",
    "content": "// so that users can do `import DefaultTheme from 'vitepress/theme'`\n\nimport type { ComputedRef, DefineComponent, ShallowRef } from 'vue'\nimport type { EnhanceAppContext } from './dist/client/index.js'\nimport type { DefaultTheme } from './types/default-theme.js'\n\nexport type { DefaultTheme } from './types/default-theme.js'\n\ndeclare const theme: {\n  Layout: DefineComponent\n  enhanceApp: (ctx: EnhanceAppContext) => void\n}\n\nexport default theme\n\nexport declare const useLayout: () => {\n  isHome: ComputedRef<boolean>\n\n  sidebar: Readonly<ShallowRef<DefaultTheme.SidebarItem[]>>\n  sidebarGroups: ComputedRef<DefaultTheme.SidebarItem[]>\n  hasSidebar: ComputedRef<boolean>\n  isSidebarEnabled: ComputedRef<boolean>\n\n  hasAside: ComputedRef<boolean>\n  leftAside: ComputedRef<boolean>\n\n  /**\n   * The outline headers of the current page.\n   */\n  headers: Readonly<ShallowRef<DefaultTheme.OutlineItem[]>>\n  /**\n   * Whether the current page has a local nav. Local nav is shown when the\n   * \"outline\" is present in the page. However, note that the actual\n   * local nav visibility depends on the screen width as well.\n   */\n  hasLocalNav: ComputedRef<boolean>\n}\n\n// TODO: add props for these\nexport declare const VPBadge: DefineComponent\nexport declare const VPButton: DefineComponent\nexport declare const VPDocAsideSponsors: DefineComponent\nexport declare const VPFeatures: DefineComponent\nexport declare const VPHomeContent: DefineComponent\nexport declare const VPHomeFeatures: DefineComponent\nexport declare const VPHomeHero: DefineComponent\nexport declare const VPHomeSponsors: DefineComponent\nexport declare const VPImage: DefineComponent\nexport declare const VPLink: DefineComponent\nexport declare const VPNavBarSearch: DefineComponent\nexport declare const VPSocialLink: DefineComponent\nexport declare const VPSocialLinks: DefineComponent\nexport declare const VPSponsors: DefineComponent\nexport declare const VPTeamMembers: DefineComponent\nexport declare const VPTeamPage: DefineComponent\nexport declare const VPTeamPageSection: DefineComponent\nexport declare const VPTeamPageTitle: DefineComponent\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"esnext\",\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"noUnusedLocals\": true,\n    \"resolveJsonModule\": true,\n    \"verbatimModuleSyntax\": true,\n    \"jsx\": \"preserve\",\n    \"lib\": [\"esnext\", \"dom\", \"dom.iterable\"]\n  },\n  \"exclude\": [\n    \"**/node_modules/**\",\n    \"**/dist/**\",\n    \"template\",\n    \"bin\",\n    \"docs/snippets\",\n    \"scripts\"\n  ]\n}\n"
  },
  {
    "path": "types/default-theme.d.ts",
    "content": "import type { Options as _MiniSearchOptions } from 'minisearch'\nimport type { DocSearchProps } from './docsearch.js'\nimport type { LocalSearchTranslations } from './local-search.js'\nimport type { Header, PageData } from './shared.js'\n\nexport namespace DefaultTheme {\n  export interface Config {\n    /**\n     * The logo file of the site.\n     *\n     * @example '/logo.svg'\n     */\n    logo?: ThemeableImage\n\n    /**\n     * Overrides the link of the site logo.\n     */\n    logoLink?: string | { link?: string; rel?: string; target?: string }\n\n    /**\n     * Custom site title in navbar. If the value is undefined,\n     * `config.title` will be used.\n     */\n    siteTitle?: string | false\n\n    /**\n     * Custom header levels of outline in the aside component.\n     *\n     * @default 2\n     */\n    outline?: Outline | Outline['level'] | false\n\n    /**\n     * @deprecated Use `outline.label` instead.\n     *\n     * @default 'On this page'\n     */\n    outlineTitle?: string\n\n    /**\n     * The nav items.\n     */\n    nav?: NavItem[]\n\n    /**\n     * The sidebar items.\n     */\n    sidebar?: Sidebar\n\n    /**\n     * Set to `false` to prevent rendering of aside container.\n     * Set to `true` to render the aside to the right.\n     * Set to `left` to render the aside to the left.\n     *\n     * @default true\n     */\n    aside?: boolean | 'left'\n\n    /**\n     * Info for the edit link. If it's undefined, the edit link feature will\n     * be disabled.\n     */\n    editLink?: EditLink\n\n    /**\n     * @deprecated Use `lastUpdated.text` instead.\n     *\n     * Set custom last updated text.\n     *\n     * @default 'Last updated'\n     */\n    lastUpdatedText?: string\n\n    lastUpdated?: LastUpdatedOptions\n\n    /**\n     * Set custom prev/next labels.\n     */\n    docFooter?: DocFooter\n\n    /**\n     * The social links to be displayed at the end of the nav bar. Perfect for\n     * placing links to social services such as GitHub, Twitter, Facebook, etc.\n     */\n    socialLinks?: SocialLink[]\n\n    /**\n     * The footer configuration.\n     */\n    footer?: Footer\n\n    /**\n     * @default 'Appearance'\n     */\n    darkModeSwitchLabel?: string\n\n    /**\n     * @default 'Switch to light theme'\n     */\n    lightModeSwitchTitle?: string\n\n    /**\n     * @default 'Switch to dark theme'\n     */\n    darkModeSwitchTitle?: string\n\n    /**\n     * @default 'Menu'\n     */\n    sidebarMenuLabel?: string\n\n    /**\n     * @default 'Return to top'\n     */\n    returnToTopLabel?: string\n\n    /**\n     * Set custom `aria-label` for language menu button.\n     *\n     * @default 'Change language'\n     */\n    langMenuLabel?: string\n\n    /**\n     * @default 'Skip to content'\n     */\n    skipToContentLabel?: string\n\n    search?:\n      | { provider: 'local'; options?: LocalSearchOptions }\n      | { provider: 'algolia'; options: AlgoliaSearchOptions }\n\n    /**\n     * The carbon ads options. Leave it undefined to disable the ads feature.\n     */\n    carbonAds?: CarbonAdsOptions\n\n    /**\n     * Changing locale when current url is `/foo` will redirect to `/locale/foo`.\n     *\n     * @default true\n     */\n    i18nRouting?: boolean\n\n    /**\n     * Show external link icon in Markdown links.\n     *\n     * @default false\n     */\n    externalLinkIcon?: boolean\n\n    /**\n     * Customize text of 404 page.\n     */\n    notFound?: NotFoundOptions\n  }\n\n  // nav -----------------------------------------------------------------------\n\n  export type NavItem = NavItemComponent | NavItemWithLink | NavItemWithChildren\n\n  export interface NavItemComponent {\n    component: string\n    props?: Record<string, any>\n  }\n\n  export interface NavItemWithLink {\n    text: string\n    link: string | ((payload: PageData) => string)\n    items?: never\n\n    /**\n     * `activeMatch` is expected to be a regex string. We can't use actual\n     * RegExp object here because it isn't serializable\n     */\n    activeMatch?: string\n    rel?: string\n    target?: string\n    noIcon?: boolean\n  }\n\n  export interface NavItemChildren {\n    text?: string\n    items: NavItemWithLink[]\n  }\n\n  export interface NavItemWithChildren {\n    text?: string\n    items: (NavItemComponent | NavItemChildren | NavItemWithLink)[]\n\n    /**\n     * `activeMatch` is expected to be a regex string. We can't use actual\n     * RegExp object here because it isn't serializable\n     */\n    activeMatch?: string\n  }\n\n  // image ---------------------------------------------------------------------\n\n  export type ThemeableImage =\n    | string\n    | { src: string; alt?: string; [prop: string]: any }\n    | { light: string; dark: string; alt?: string; [prop: string]: any }\n\n  export type FeatureIcon =\n    | string\n    | {\n        src: string\n        alt?: string\n        width?: string\n        height?: string\n        wrap?: boolean\n      }\n    | {\n        light: string\n        dark: string\n        alt?: string\n        width?: string\n        height?: string\n        wrap?: boolean\n      }\n\n  // sidebar -------------------------------------------------------------------\n\n  export type Sidebar = SidebarItem[] | SidebarMulti\n\n  export interface SidebarMulti {\n    [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string }\n  }\n\n  export type SidebarItem = {\n    /**\n     * The text label of the item.\n     */\n    text?: string\n\n    /**\n     * The link of the item.\n     */\n    link?: string\n\n    /**\n     * The children of the item.\n     */\n    items?: SidebarItem[]\n\n    /**\n     * If not specified, group is not collapsible.\n     *\n     * If `true`, group is collapsible and collapsed by default\n     *\n     * If `false`, group is collapsible but expanded by default\n     */\n    collapsed?: boolean\n\n    /**\n     * Base path for the children items.\n     */\n    base?: string\n\n    /**\n     * Customize text that appears on the footer of previous/next page.\n     */\n    docFooterText?: string\n\n    rel?: string\n    target?: string\n  }\n\n  // edit link -----------------------------------------------------------------\n\n  export interface EditLink {\n    /**\n     * Pattern for edit link.\n     *\n     * @example 'https://github.com/vuejs/vitepress/edit/main/docs/:path'\n     * @example ({ filePath }) => { ... }\n     */\n    pattern: string | ((payload: PageData) => string)\n\n    /**\n     * Custom text for edit link.\n     *\n     * @default 'Edit this page'\n     */\n    text?: string\n  }\n\n  // prev-next -----------------------------------------------------------------\n\n  export interface DocFooter {\n    /**\n     * Custom label for previous page button. Can be set to `false` to disable.\n     *\n     * @default 'Previous page'\n     */\n    prev?: string | boolean\n\n    /**\n     * Custom label for next page button. Can be set to `false` to disable.\n     *\n     * @default 'Next page'\n     */\n    next?: string | boolean\n  }\n\n  // social link ---------------------------------------------------------------\n\n  export interface SocialLink {\n    icon: SocialLinkIcon\n    link: string\n    ariaLabel?: string\n  }\n\n  export type SocialLinkIcon = string | { svg: string }\n\n  // footer --------------------------------------------------------------------\n\n  export interface Footer {\n    message?: string\n    copyright?: string\n  }\n\n  // team ----------------------------------------------------------------------\n\n  export interface TeamMember {\n    avatar: string\n    name: string\n    title?: string\n    org?: string\n    orgLink?: string\n    desc?: string\n    links?: SocialLink[]\n    sponsor?: string\n    actionText?: string\n  }\n\n  // outline -------------------------------------------------------------------\n\n  export interface Outline {\n    level?: number | [number, number] | 'deep'\n    label?: string\n  }\n\n  export type OutlineItem = Omit<Header, 'slug' | 'children'> & {\n    element: HTMLHeadElement\n    children?: OutlineItem[]\n  }\n\n  // local search --------------------------------------------------------------\n\n  export interface LocalSearchOptions {\n    /**\n     * @default false\n     * @deprecated Use `detailedView: false` instead.\n     */\n    disableDetailedView?: boolean\n\n    /**\n     * If `true`, the detailed view will be enabled by default.\n     * If `false`, the detailed view will be disabled.\n     * If `'auto'`, the detailed view will be disabled by default, but can be enabled by the user.\n     *\n     * @default 'auto'\n     */\n    detailedView?: boolean | 'auto'\n\n    /**\n     * @default false\n     */\n    disableQueryPersistence?: boolean\n\n    translations?: LocalSearchTranslations\n    locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>>\n\n    miniSearch?: MiniSearchOptions\n  }\n\n  interface MiniSearchOptions {\n    /**\n     * @see https://lucaong.github.io/minisearch/types/MiniSearch.Options.html\n     */\n    options?: Pick<\n      _MiniSearchOptions,\n      'extractField' | 'tokenize' | 'processTerm'\n    >\n    /**\n     * @see https://lucaong.github.io/minisearch/types/MiniSearch.SearchOptions.html\n     */\n    searchOptions?: _MiniSearchOptions['searchOptions']\n  }\n\n  // algolia -------------------------------------------------------------------\n\n  /**\n   * Algolia search options. Partially copied from\n   * `@docsearch/react/dist/esm/DocSearch.d.ts`\n   */\n  export interface AlgoliaSearchOptions extends DocSearchProps {\n    /**\n     * Locale-specific overrides for Algolia search options.\n     * These options will be deeply merged with the root options,\n     * except for `searchParameters`, which is fully replaced.\n     */\n    locales?: Record<string, Partial<DocSearchProps>>\n  }\n\n  // carbon ads ----------------------------------------------------------------\n\n  export interface CarbonAdsOptions {\n    code: string\n    placement: string\n  }\n\n  // last updated --------------------------------------------------------------\n\n  export interface LastUpdatedOptions {\n    /**\n     * Set custom last updated text.\n     *\n     * @default 'Last updated'\n     */\n    text?: string\n\n    /**\n     * Set options for last updated time formatting.\n     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options\n     *\n     * @default\n     * { dateStyle: 'short', timeStyle: 'short' }\n     */\n    formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean }\n  }\n\n  // not found -----------------------------------------------------------------\n\n  export interface NotFoundOptions {\n    /**\n     * Set custom not found message.\n     *\n     * @default 'PAGE NOT FOUND'\n     */\n    title?: string\n\n    /**\n     * Set custom not found description.\n     *\n     * @default \"But if you don't change your direction, and if you keep looking, you may end up where you are heading.\"\n     */\n    quote?: string\n\n    /**\n     * Target of the home link.\n     *\n     * @default '/'\n     */\n    link?: string\n\n    /**\n     * Set aria label for home link.\n     *\n     * @default 'go to home'\n     */\n    linkLabel?: string\n\n    /**\n     * Set custom home link text.\n     *\n     * @default 'Take me home'\n     */\n    linkText?: string\n\n    /**\n     * @default '404'\n     */\n    code?: string\n  }\n}\n"
  },
  {
    "path": "types/docsearch.d.ts",
    "content": "import { type DocSearchProps as DocSearchPropsJS } from '@docsearch/js'\nimport { type SidepanelProps as SidepanelPropsBase } from '@docsearch/sidepanel-js'\n\nexport type DocSearchProps = Partial<\n  Pick<\n    DocSearchPropsJS,\n    | 'appId'\n    | 'apiKey'\n    | 'placeholder'\n    | 'maxResultsPerGroup'\n    | 'disableUserPersonalization'\n    | 'initialQuery'\n    | 'translations'\n    | 'recentSearchesLimit'\n    | 'recentSearchesWithFavoritesLimit'\n  >\n> & {\n  /**\n   * Name of the algolia index to query.\n   */\n  indexName?: string\n  /**\n   * Additional algolia search parameters to merge into each query.\n   */\n  searchParameters?: DocSearchPropsJS['searchParameters']\n  /**\n   * Insights client integration options to send analytics events.\n   */\n  insights?: boolean\n  /**\n   * Configuration or assistant id to enable ask ai mode. Pass a string assistant id or a full config object.\n   */\n  askAi?: DocSearchAskAi | string\n  /**\n   * Ask AI side panel integration mode.\n   *\n   * - 'auto': infer hybrid vs sidePanel-only from provided config\n   * - 'sidePanel': force sidePanel-only even if keyword search is configured\n   * - 'hybrid': force hybrid (error if keyword search is not configured)\n   * - 'modal': force modal even if sidePanel is configured (ask ai in modal stays in modal)\n   *\n   * @default 'auto'\n   */\n  mode?: 'auto' | 'sidePanel' | 'hybrid' | 'modal'\n}\n\nexport type DocSearchAskAi = Partial<\n  Exclude<DocSearchPropsJS['askAi'], string | undefined>\n> & {\n  /**\n   * Ask AI side panel configuration.\n   */\n  sidePanel?: boolean | SidepanelProps\n}\n\nexport type SidepanelProps = Partial<\n  Pick<SidepanelPropsBase, 'button' | 'keyboardShortcuts'>\n> & {\n  /**\n   * Props specific to the Sidepanel panel.\n   */\n  panel?: Omit<NonNullable<SidepanelPropsBase['panel']>, 'portalContainer'>\n}\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "export * from '../dist/client/index.js'\nexport * from '../dist/node/index.js'\nexport * from './shared.js'\n"
  },
  {
    "path": "types/local-search.d.ts",
    "content": "export interface LocalSearchTranslations {\n  button?: ButtonTranslations\n  modal?: ModalTranslations\n}\n\nexport interface ButtonTranslations {\n  buttonText?: string\n  buttonAriaLabel?: string\n}\n\nexport interface ModalTranslations {\n  displayDetails?: string\n  resetButtonTitle?: string\n  backButtonTitle?: string\n  noResultsText?: string\n  footer?: FooterTranslations\n}\n\nexport interface FooterTranslations {\n  selectText?: string\n  selectKeyAriaLabel?: string\n  navigateText?: string\n  navigateUpKeyAriaLabel?: string\n  navigateDownKeyAriaLabel?: string\n  closeText?: string\n  closeKeyAriaLabel?: string\n}\n\nexport interface PageSplitSection {\n  anchor?: string\n  titles: string[]\n  text: string\n}\n"
  },
  {
    "path": "types/shared.d.ts",
    "content": "// types shared between server and client\nimport type { UseDarkOptions } from '@vueuse/core'\nimport type { SSRContext } from 'vue/server-renderer'\nexport type { DefaultTheme } from './default-theme.js'\n\nexport type Awaitable<T> = T | PromiseLike<T>\n\ntype DeepPartial<T> =\n  T extends Record<string, any>\n    ? T extends\n        | Date\n        | RegExp\n        | Function\n        | ReadonlyMap<any, any>\n        | ReadonlySet<any>\n        | ReadonlyArray<any>\n      ? T\n      : { [P in keyof T]?: DeepPartial<T[P]> }\n    : T\n\nexport interface PageData {\n  relativePath: string\n  /**\n   * differs from relativePath in case of path rewrites\n   * empty string if the page is virtual (e.g. 404 page)\n   */\n  filePath: string\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  headers: Header[]\n  frontmatter: Record<string, any>\n  params?: Record<string, any>\n  isNotFound?: boolean\n  lastUpdated?: number\n}\n\n/**\n * SFC block extracted from markdown\n */\nexport interface SfcBlock {\n  /**\n   * The type of the block\n   */\n  type: string\n  /**\n   * The content, including open-tag and close-tag\n   */\n  content: string\n  /**\n   * The content that stripped open-tag and close-tag off\n   */\n  contentStripped: string\n  /**\n   * The open-tag\n   */\n  tagOpen: string\n  /**\n   * The close-tag\n   */\n  tagClose: string\n}\n\nexport interface MarkdownSfcBlocks {\n  /**\n   * The `<template>` block\n   */\n  template: SfcBlock | null\n  /**\n   * The common `<script>` block\n   */\n  script: SfcBlock | null\n  /**\n   * The `<script setup>` block\n   */\n  scriptSetup: SfcBlock | null\n  /**\n   * All `<script>` blocks.\n   *\n   * By default, SFC only allows one `<script>` block and one `<script setup>` block.\n   * However, some tools may support different types of `<script>`s, so we keep all of them here.\n   */\n  scripts: SfcBlock[]\n  /**\n   * All `<style>` blocks.\n   */\n  styles: SfcBlock[]\n  /**\n   * All custom blocks.\n   */\n  customBlocks: SfcBlock[]\n}\n\nexport interface Header {\n  /**\n   * The level of the header\n   *\n   * `1` to `6` for `<h1>` to `<h6>`\n   */\n  level: number\n  /**\n   * The title of the header\n   */\n  title: string\n  /**\n   * The slug of the header\n   *\n   * Typically the `id` attr of the header anchor\n   */\n  slug: string\n  /**\n   * Link of the header\n   *\n   * Typically using `#${slug}` as the anchor hash\n   */\n  link: string\n  /**\n   * The children of the header\n   */\n  children: Header[]\n}\n\nexport interface SiteData<ThemeConfig = any> {\n  base: string\n  cleanUrls?: boolean\n  lang: string\n  dir: string\n  title: string\n  titleTemplate?: string | boolean\n  description: string\n  head: HeadConfig[]\n  appearance:\n    | boolean\n    | 'dark'\n    | 'force-dark'\n    | 'force-auto'\n    | (Omit<UseDarkOptions, 'initialValue'> & { initialValue?: 'dark' })\n  themeConfig: ThemeConfig\n  scrollOffset:\n    | number\n    | string\n    | string[]\n    | { selector: string | string[]; padding: number }\n  locales: LocaleConfig<ThemeConfig>\n  localeIndex?: string\n  contentProps?: Record<string, any>\n  router: {\n    prefetchLinks: boolean\n  }\n  additionalConfig?:\n    | AdditionalConfigDict<ThemeConfig>\n    | AdditionalConfigLoader<ThemeConfig>\n}\n\nexport type HeadConfig =\n  | [string, Record<string, string>]\n  | [string, Record<string, string>, string]\n\nexport interface PageDataPayload {\n  path: string\n  pageData: PageData\n}\n\nexport interface SSGContext extends SSRContext {\n  content: string\n  /** @experimental */\n  vpSocialIcons: Set<string>\n}\n\nexport interface LocaleSpecificConfig<ThemeConfig = any> {\n  lang?: string\n  dir?: string\n  title?: string\n  titleTemplate?: string | boolean\n  description?: string\n  head?: HeadConfig[]\n  themeConfig?: DeepPartial<ThemeConfig>\n}\n\nexport type LocaleConfig<ThemeConfig = any> = Record<\n  string,\n  LocaleSpecificConfig<ThemeConfig> & { label: string; link?: string }\n>\n\nexport type AdditionalConfig<ThemeConfig = any> =\n  LocaleSpecificConfig<ThemeConfig>\n\nexport type AdditionalConfigDict<ThemeConfig = any> = Record<\n  string,\n  AdditionalConfig<ThemeConfig>\n>\n\nexport type AdditionalConfigLoader<ThemeConfig = any> = (\n  relativePath: string\n) => AdditionalConfig<ThemeConfig>[] | void\n\n// Manually declaring all properties as rollup-plugin-dts\n// is unable to merge augmented module declarations\nexport interface MarkdownEnv {\n  /**\n   * The raw Markdown content without frontmatter\n   */\n  content?: string\n  /**\n   * The excerpt that extracted by `@mdit-vue/plugin-frontmatter`\n   *\n   * - Would be the rendered HTML when `renderExcerpt` is enabled\n   * - Would be the raw Markdown when `renderExcerpt` is disabled\n   */\n  excerpt?: string\n  /**\n   * The frontmatter that extracted by `@mdit-vue/plugin-frontmatter`\n   */\n  frontmatter?: Record<string, unknown>\n  /**\n   * The headers that extracted by `@mdit-vue/plugin-headers`\n   */\n  headers?: Header[]\n  /**\n   * SFC blocks that extracted by `@mdit-vue/plugin-sfc`\n   */\n  sfcBlocks?: MarkdownSfcBlocks\n  /**\n   * The title that extracted by `@mdit-vue/plugin-title`\n   */\n  title?: string\n  path: string\n  relativePath: string\n  cleanUrls: boolean\n  links?: string[]\n  includes?: string[]\n  realPath?: string\n  localeIndex?: string\n}\n"
  }
]