diff --git a/.github/contributing.md b/.github/contributing.md index 24a4a7456..5738cbc2a 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -23,7 +23,7 @@ Hi! We're really excited that you are interested in contributing to VitePress. B ## Development Setup -You will need [pnpm](https://pnpm.io) +You will need [Node.js](https://nodejs.org) v20 or higher and [pnpm](https://pnpm.io). After cloning the repo, run: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f8cd3d5a9..560d76ff8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,4 +13,4 @@ --- > [!TIP] -> The author of this PR can publish a _preview release_ by commenting `/publish` below. +> The author can publish a _preview release_ by commenting `/publish` after creating the PR. diff --git a/.github/workflows/cr.yml b/.github/workflows/cr.yml index b8b833ef2..7cc01dbb9 100644 --- a/.github/workflows/cr.yml +++ b/.github/workflows/cr.yml @@ -9,6 +9,7 @@ on: types: [opened, synchronize, labeled, ready_for_review] paths-ignore: - '.github/**' + - '!.github/workflows/cr.yml' - '__tests__/**' - 'art/**' - 'docs/**' @@ -17,6 +18,7 @@ on: branches: [main] paths-ignore: - '.github/**' + - '!.github/workflows/cr.yml' - '__tests__/**' - 'art/**' - 'docs/**' @@ -36,11 +38,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v3 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v5 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: pnpm - run: pnpm install - run: pnpm build diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 84a034870..1c6750008 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Create Release for Tag id: release_tag diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f5826155d..dd47c33f4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,12 +1,14 @@ name: Close stale issues and PRs on: + schedule: + - cron: '0 12 1,15 * *' workflow_dispatch: jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: days-before-stale: 30 days-before-close: -1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dc527e355..a89cc38cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,22 +18,22 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node_version: [18, 20, 22] + node_version: [20, 22, 24, latest] include: - os: windows-latest - node_version: 22 + node_version: 24 runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm - uses: pnpm/action-setup@v3 + uses: pnpm/action-setup@v4 - name: Set node version to ${{ matrix.node_version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node_version }} cache: pnpm diff --git a/.gitignore b/.gitignore index 643310524..e6e95ca9e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ node_modules pnpm-global TODOs.md *.timestamp-*.mjs +.claude diff --git a/.npmrc b/.npmrc deleted file mode 100644 index ab9530723..000000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -shell-emulator=true -auto-install-peers=false diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb8681c4..b3c1b6364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,351 @@ +## [2.0.0-alpha.17](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.16...v2.0.0-alpha.17) (2026-03-19) + +### Bug Fixes + +- **build:** `processIncludes` no longer swallows errors ([fb21fdf](https://github.com/vuejs/vitepress/commit/fb21fdf6759b7c88ac98456820b75286936fbf87)) +- **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)) +- **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)) +- disable brotli compression in preview server ([ca1e875](https://github.com/vuejs/vitepress/commit/ca1e87512924acdd8d39ca0f530a424ad933b701)) +- **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)) +- **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)) +- **theme:** close sidebar on resize (closes [#5145](https://github.com/vuejs/vitepress/issues/5145)) ([17696c3](https://github.com/vuejs/vitepress/commit/17696c358b88335c4f6bb516bbcdf774aaf7deee)) +- **theme:** disable text autospace in `
` (closes [#5115](https://github.com/vuejs/vitepress/issues/5115)) ([21a5fb6](https://github.com/vuejs/vitepress/commit/21a5fb6a96549564fcf698d0e7256181eac3919b))
+- **theme:** enable `line-break: strict` for `
  • ` too ([f811d58](https://github.com/vuejs/vitepress/commit/f811d581a164fa330b17cdb85270effa39bdb3fd)) +- **theme:** keep pnum,tnum features in Inter ([f1bef95](https://github.com/vuejs/vitepress/commit/f1bef95eee453bb18cc160741a11513678015cd6)), closes [#5096](https://github.com/vuejs/vitepress/issues/5096) +- **theme:** navbar menu group is incorrectly highlighted ([#5113](https://github.com/vuejs/vitepress/issues/5113)) ([b28667b](https://github.com/vuejs/vitepress/commit/b28667b6b03d50c4be0d509ec5e7d780f29f8042)) +- **theme:** strip system-ui from font-family-base ([#4988](https://github.com/vuejs/vitepress/issues/4988)) ([8096eac](https://github.com/vuejs/vitepress/commit/8096eaca4f1d9eef00101e42f7159da1e12ca3de)) + +### Features + +- **theme:** add `home-hero-actions-before-actions` slot ([#5151](https://github.com/vuejs/vitepress/issues/5151)) ([74a73d8](https://github.com/vuejs/vitepress/commit/74a73d869ca61f2c64f9dcbd9912a0461e8d4bfe)) +- support text-fragments ([#5140](https://github.com/vuejs/vitepress/issues/5140)) ([44e2675](https://github.com/vuejs/vitepress/commit/44e2675889588b54dea771a0c82e2db64739364c)) +- **theme:** add Japanese translation for "copied" label ([#5106](https://github.com/vuejs/vitepress/issues/5106)) ([a01bba0](https://github.com/vuejs/vitepress/commit/a01bba0cad70bb089918adab105f0a5b5ff85918)) +- **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)) +- **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)) + +### BREAKING CHANGES + +Previously, the `` 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. + +For most users, no code changes are required. If you now see errors, it means your includes are broken and were earlier not being reported. + +Users 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. + +## [2.0.0-alpha.16](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) (2026-01-31) + +### Bug Fixes + +- always log error when failed to fetch page ([66cf64e](https://github.com/vuejs/vitepress/commit/66cf64e6d127dd8473e582d11e1133acda6c3bc8)) +- **theme:** add fallback for `heroImageSlotExists` ([#5076](https://github.com/vuejs/vitepress/issues/5076)) ([f119b18](https://github.com/vuejs/vitepress/commit/f119b18e39b545f39e29358913fe9ed1fd69bc55)) +- **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)) +- **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)) +- **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) +- **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) + +### Features + +- **theme:** upgrade DocSearch to 4.5 with sidepanel ([#5092](https://github.com/vuejs/vitepress/issues/5092)) ([0d646a6](https://github.com/vuejs/vitepress/commit/0d646a66cd44e97adef516a6a36e03365f179906)) +- **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)) + +## [2.0.0-alpha.15](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.14...v2.0.0-alpha.15) (2025-11-22) + +### Bug Fixes + +- **theme:** navbar overflowing on mobile devices ([06f0e1a](https://github.com/vuejs/vitepress/commit/06f0e1a5c92e36d86fd2e037c335af04d75384e7)), closes [#5039](https://github.com/vuejs/vitepress/issues/5039) + +## [2.0.0-alpha.14](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2025-11-21) + +### Bug Fixes + +- log dead links in dev mode too ([179ee62](https://github.com/vuejs/vitepress/commit/179ee621d99b3c14e2e098e3b786465cbeaeab9a)), closes [#4419](https://github.com/vuejs/vitepress/issues/4419) +- **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) + +### Features + +- **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) + +## [2.0.0-alpha.13](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2025-11-13) + +### Bug Fixes + +- **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)) +- disable markdown-it-attrs for fenced code blocks ([0899618](https://github.com/vuejs/vitepress/commit/089961855653f862b71747e8179ef2647e06d626)) +- 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)) +- print full path in dead links check ([2b77fb3](https://github.com/vuejs/vitepress/commit/2b77fb3a72058129edbaddd3c6f0f6ee24f983d5)), closes [#4919](https://github.com/vuejs/vitepress/issues/4919) +- rename `markdown.cjkFriendly` to `markdown.cjkFriendlyEmphasis` ([bce0b53](https://github.com/vuejs/vitepress/commit/bce0b53659fa3a57b2ed8431a0861939dadd118a)), closes [#4952](https://github.com/vuejs/vitepress/issues/4952) +- respect markdown.cache = false on build too ([6d7422f](https://github.com/vuejs/vitepress/commit/6d7422f8fa321c641b1d5be3fa0c382400a2b78f)) +- simplify lang extraction logic; use markdown-it plugins in type-safe manner; bump deps ([4e548f5](https://github.com/vuejs/vitepress/commit/4e548f542469a366f327cdef1530bdb1a31542ad)) +- **theme:** add lang and dir attributes to language picker ([f0b29d7](https://github.com/vuejs/vitepress/commit/f0b29d7ef32a33f61c355d19561176411ede4b48)) +- **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) +- **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) +- **theme:** disable whitespace wrapping for VPBadge ([#4968](https://github.com/vuejs/vitepress/issues/4968)) ([113d230](https://github.com/vuejs/vitepress/commit/113d2304784586028d9733036ccb585374731397)) +- **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)) + +### Features + +- export cacheAllGitTimestamps and getGitTimestamp ([31d87e2](https://github.com/vuejs/vitepress/commit/31d87e27387ebdceb22c047cc5f821761276d5f7)) +- **i18n,a11y:** change last update logic ([#4935](https://github.com/vuejs/vitepress/issues/4935)) ([187bf25](https://github.com/vuejs/vitepress/commit/187bf250e6496554fca0b070a5aba55484f7fc0b)) +- **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)) +- prevent `$` symbol selection in shell code ([#5025](https://github.com/vuejs/vitepress/issues/5025)) ([bf2715e](https://github.com/vuejs/vitepress/commit/bf2715ed67f290726fc6d4c85c203ca8f74cc907)) +- **theme:** allow passing functions for nav links ([#4963](https://github.com/vuejs/vitepress/issues/4963)) ([34cfa91](https://github.com/vuejs/vitepress/commit/34cfa91b6f14d8adfaa2d3c9f3eb6ad8b889ef1c)) + +### Performance Improvements + +- 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)) + +### BREAKING CHANGES + +- `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. +- 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. + +## [2.0.0-alpha.12](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.11...v2.0.0-alpha.12) (2025-08-20) + +### Bug Fixes + +- **hmr:** don't load config twice on server restart ([d1a8061](https://github.com/vuejs/vitepress/commit/d1a8061eb438c730ccc62ce2d7158dbe89cc5292)) +- **hmr:** no need for server restart on theme change ([d3a1567](https://github.com/vuejs/vitepress/commit/d3a15673bd0846c7837bcc4ff5a2e3239a02f1f9)) +- **hmr:** hmr not working for snippet imports in dynamic routes ([914467e](https://github.com/vuejs/vitepress/commit/914467e17fb759a9722951a3fd7568eb3bc4d4e6)) +- **theme:** fix local nav alignment and increase touch area ([43b36c0](https://github.com/vuejs/vitepress/commit/43b36c0c19c2b4696f8c38fdaf4318786ea7ae8e)) +- **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) +- **theme:** use clipboard-check instead of clipboard-copy for code copied icon ([1c8815d](https://github.com/vuejs/vitepress/commit/1c8815d53ed2d56b07938260df6566f1514f4bfc)) + +### Features + +- 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) +- make postcssIsolateStyles idempotent ([0944777](https://github.com/vuejs/vitepress/commit/094477789328b80cff45cd973efa16b6a4db0a27)) + +### BREAKING CHANGES + +- [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. +- `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. + +## [2.0.0-alpha.11](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2025-08-14) + +### Bug Fixes + +- hmr working only once for markdown files ([8d8a5ac](https://github.com/vuejs/vitepress/commit/8d8a5ac281f090cd097bece792d9dd3ef00e5545)), closes [#4909](https://github.com/vuejs/vitepress/issues/4909) +- html entities encoded twice in toc plugin ([8abbe29](https://github.com/vuejs/vitepress/commit/8abbe298d545de17d34a9bc1eb72af4c5a4b41b8)), closes [#4908](https://github.com/vuejs/vitepress/issues/4908) + +## [2.0.0-alpha.10](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2025-08-11) + +### Bug Fixes + +- **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) +- hmr of style blocks in dynamic routes ([#4903](https://github.com/vuejs/vitepress/issues/4903)) ([3d0fafb](https://github.com/vuejs/vitepress/commit/3d0fafba545f4b5028cf43d86027dd44dab14421)) +- make paths in `watchedFiles` absolute as mentioned in the docs ([318c14f](https://github.com/vuejs/vitepress/commit/318c14fa7c9fb949d74b7d9fae416e917766cf05)) +- module graph causing unnecessary route regeneration on every update ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43)) +- preserve externally added dynamic routes and pages ([fc267ae](https://github.com/vuejs/vitepress/commit/fc267ae6b787e163d41666e090089821377ead43)) +- **search:** input placeholder being cut off in smaller viewports ([162c6a6](https://github.com/vuejs/vitepress/commit/162c6a69bf56945daa20d126aa034c59ee0c8a2e)) +- **search:** style tweaks for when searches are empty ([8b23217](https://github.com/vuejs/vitepress/commit/8b232171cc321bd3dc86b4357622815269f0b6f4)) +- **types:** externalize markdown-it types ([5bf835b](https://github.com/vuejs/vitepress/commit/5bf835b5074e9567852d552bfb5115c6456026e8)) +- **types:** pass generics deeply to user config ([777e2ca](https://github.com/vuejs/vitepress/commit/777e2caaacd93ce41b046f6c9d5ba80cc43ba37c)) + +### Features + +- add source param to the deadlink check fn ([#4870](https://github.com/vuejs/vitepress/issues/4870)) ([8c027c2](https://github.com/vuejs/vitepress/commit/8c027c2a7c443074fd0d4890f7736b444f9254aa)) +- **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)) + +## [2.0.0-alpha.9](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.8...v2.0.0-alpha.9) (2025-07-26) + +### Bug Fixes + +- **md:** pass container option to gitHubAlertsPlugin ([#4848](https://github.com/vuejs/vitepress/issues/4848)) ([52f0eaa](https://github.com/vuejs/vitepress/commit/52f0eaa0849344aa45efbf7258a6287597e55a9a)) +- **theme:** remove duplicate text in sponsors grid ([3c51b22](https://github.com/vuejs/vitepress/commit/3c51b22ac98a12f193081d23799cb9f3f2ecf682)), closes [#4854](https://github.com/vuejs/vitepress/issues/4854) + +### Features + +- **search:** upgrade search to DocSearch v4-beta ([#4843](https://github.com/vuejs/vitepress/issues/4843)) ([ac61abe](https://github.com/vuejs/vitepress/commit/ac61abe7d7be5ef8b6939f18192896538eba1b8c)) + +### BREAKING CHANGES + +- **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 + +## [2.0.0-alpha.8](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.7...v2.0.0-alpha.8) (2025-07-08) + +### Bug Fixes + +- 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) +- **build:** ignore escaped `:` when splitting selector in `postcssIsolateStyles` ([#4830](https://github.com/vuejs/vitepress/issues/4830)) ([a629b03](https://github.com/vuejs/vitepress/commit/a629b03f0ee8a29d73a18481399d7de1c992faf2)) +- font preload not being generated in rolldown-vite ([ed387e8](https://github.com/vuejs/vitepress/commit/ed387e89d42a08c15a9f45c9c5e11c6750245490)) +- **theme:** remove extra slash when concatenating base with sidebar links ([c8fc80e](https://github.com/vuejs/vitepress/commit/c8fc80e438fffd98feaf7c72263bc3077792c4a2)) + +## [2.0.0-alpha.7](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.6...v2.0.0-alpha.7) (2025-06-24) + +### Bug Fixes + +- **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)) +- resolve pages after setting global vitepress config ([56ba65e](https://github.com/vuejs/vitepress/commit/56ba65e1301454df88f9a3856fa1a70dc052d314)), closes [#4803](https://github.com/vuejs/vitepress/issues/4803) + +### Features + +- **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) +- 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) +- bump to vite 7 ([2ecd607](https://github.com/vuejs/vitepress/commit/2ecd607af15222eeddf0b888a72d0f913f5a3cd2)) + +### Performance Improvements + +- render pages in contentLoader asynchronously ([36148a0](https://github.com/vuejs/vitepress/commit/36148a0bcf3a73d1fe3f0c5f33337b679f700053)) + +### BREAKING CHANGES + +- 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. +- 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. + +## [2.0.0-alpha.6](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.5...v2.0.0-alpha.6) (2025-06-12) + +### Bug Fixes + +- allow AdditionalConfigLoader to return void ([906a44a](https://github.com/vuejs/vitepress/commit/906a44a3ad488a46804757326af95cfb8cac6b75)) +- **build:** avoiding creating separate chunks for vite public assets ([21f24b9](https://github.com/vuejs/vitepress/commit/21f24b9994ea4807ac7e0be38408e9aaa3abe8a9)) +- **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) +- **client:** properly skip removed lines when copying code blocks ([c128baf](https://github.com/vuejs/vitepress/commit/c128baf0c41d5113c1b876f691e0185201b1f500)) +- disable appearance scripts in zero-js mode ([e7f9d05](https://github.com/vuejs/vitepress/commit/e7f9d05c3e2ef4f4c1db3b2c17e586f0fc26a6f6)), closes [#4766](https://github.com/vuejs/vitepress/issues/4766) +- don't preload dynamic imports ([801648a](https://github.com/vuejs/vitepress/commit/801648a4c9d91e7f96302932ac9247d5bdd64ef7)), closes [#4770](https://github.com/vuejs/vitepress/issues/4770) +- gather additional config files even if root .vitepress/config is not present ([26f178c](https://github.com/vuejs/vitepress/commit/26f178cfaa330a017bb69b1ec6bd482d63a100a9)) +- set `preserveEntrySignatures` for rolldown-vite ([#4784](https://github.com/vuejs/vitepress/issues/4784)) ([4351bc0](https://github.com/vuejs/vitepress/commit/4351bc0b831277401e08b350d7d7c0ab9ea0c9ed)) +- 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)) +- **theme/regression:** code blocks not aligned properly in rtl layouts ([a643347](https://github.com/vuejs/vitepress/commit/a64334753079a5b874a482508d9ee255d2a0ea38)) +- **theme:** hide native search input cancel button ([#4723](https://github.com/vuejs/vitepress/issues/4723)) ([2c4944f](https://github.com/vuejs/vitepress/commit/2c4944f06ccf46fcf58fb18a1819fd167c9533cc)) +- **theme:** prevent error in handleSearchHotKey method ([#4782](https://github.com/vuejs/vitepress/issues/4782)) ([21fcecc](https://github.com/vuejs/vitepress/commit/21fcecce0581d0c461bc15e03429f61ff444a655)) +- use v-pre for mathjax instead of isCustomElement ([c9b8928](https://github.com/vuejs/vitepress/commit/c9b89282f3573998cfc4103bbddbd73d2529cb66)) + +### Features + +- 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)) + +## [2.0.0-alpha.5](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.4...v2.0.0-alpha.5) (2025-04-21) + +### Bug Fixes + +- 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) +- 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) +- **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)) + +### Features + +- add `isHome` frontmatter option (#4673) ([544cd81](https://github.com/vuejs/vitepress/commit/544cd8125985b9e3af7fee68ea9592d159799e01)), closes [#4673](https://github.com/vuejs/vitepress/issues/4673) +- 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)) +- add `dir=ltr` by default on code block pre elements instead of relying on css ([19faa16](https://github.com/vuejs/vitepress/commit/19faa16169b44f52bedf1401b4a97b2a8ffdeacb)) +- **default-theme:** make VPButton slottable ([#4689](https://github.com/vuejs/vitepress/issues/4689)) ([0b70397](https://github.com/vuejs/vitepress/commit/0b7039719782e85119ad22be5c89ef3d233ffaae)) +- support distributed config files ([#4660](https://github.com/vuejs/vitepress/issues/4660)) ([c5e2e4d](https://github.com/vuejs/vitepress/commit/c5e2e4db818c06f3c1b458753f22fb6ec1609628)) +- **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)) + +### Performance Improvements + +- call `module.enableCompileCache()` ([70de34c](https://github.com/vuejs/vitepress/commit/70de34c0387d9668ada3ea9a795f9ebee3535f5b)) +- hoist expensive operations in useLayout ([e5ab067](https://github.com/vuejs/vitepress/commit/e5ab0676a9a8dc607e213eb691439b2e4ee472b7)) + +### BREAKING CHANGES + +- `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. +- `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. +- `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. + +## [2.0.0-alpha.4](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.3...v2.0.0-alpha.4) (2025-03-09) + +### Bug Fixes + +- **build/regression:** langAlias not working ([06ae2bf](https://github.com/vuejs/vitepress/commit/06ae2bf3a4ee02351530b0bd055e577ca6509d62)), closes [#4581](https://github.com/vuejs/vitepress/issues/4581) +- don't hardcode `tabindex` attr in table renderer ([#4082](https://github.com/vuejs/vitepress/issues/4082)) ([aadc517](https://github.com/vuejs/vitepress/commit/aadc517c69fb239bdda99173bbc123ace567484b)) +- 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) +- ignore non-text content in permalink generation and fix types of markdown.config ([a8a1800](https://github.com/vuejs/vitepress/commit/a8a1800ae578be88027aa4ec7561ada4d055b888)) +- prevent reload on first server start in fresh installations ([d8a884e](https://github.com/vuejs/vitepress/commit/d8a884ed0f754523765058a70149cdbaf6942341)) +- properly merge classes in custom containers ([#4128](https://github.com/vuejs/vitepress/issues/4128)) ([8aad617](https://github.com/vuejs/vitepress/commit/8aad617446c03d39a65a0b21e9fce43bc484af1e)) +- rebuild dynamic routes cache on server restart ([9f54714](https://github.com/vuejs/vitepress/commit/9f54714e7db69fd4902f1917f927456c71b5a292)), closes [#4525](https://github.com/vuejs/vitepress/issues/4525) + +### Features + +- allow matching region end in snippets without tag ([#4287](https://github.com/vuejs/vitepress/issues/4287)) ([1a2f81d](https://github.com/vuejs/vitepress/commit/1a2f81de4d6549dd1adf86ae131d1a861158bd2d)) +- improve region regexes for snippet plugin ([1a6684c](https://github.com/vuejs/vitepress/commit/1a6684cf1054d326bc1dd6eeb9fb78b150ac2b2a)) +- 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) + +## [2.0.0-alpha.3](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.2...v2.0.0-alpha.3) (2025-02-24) + +### Bug Fixes + +- **build:** `--minify` not working as documented ([9b5c037](https://github.com/vuejs/vitepress/commit/9b5c0377cd3474447c84b2901801287f3caf3d82)), closes [#4523](https://github.com/vuejs/vitepress/issues/4523) +- **build:** deterministic code group ids ([#4565](https://github.com/vuejs/vitepress/issues/4565)) ([b930b8d](https://github.com/vuejs/vitepress/commit/b930b8d5310f1691d8d9f009f45b70122e4ce800)) +- **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) +- **client:** set correct oldURL and newURL for hashchange ([#4573](https://github.com/vuejs/vitepress/issues/4573)) ([d1f2afd](https://github.com/vuejs/vitepress/commit/d1f2afdf0fbb022f12cc12295723b3b7c7ef5cb1)) +- **theme:** allow interactions behind scroll shadow ([#4537](https://github.com/vuejs/vitepress/issues/4537)) ([091d584](https://github.com/vuejs/vitepress/commit/091d5840ae15b64e04e8c07fbc0263a2749571bd)) +- **theme:** code block contrast ratio ([#4487](https://github.com/vuejs/vitepress/issues/4487)) ([5dccaee](https://github.com/vuejs/vitepress/commit/5dccaeef055beb109919f8990032975a0d630384)) +- **build:** fix flaky embedded languages highlighting ([#4566](https://github.com/vuejs/vitepress/issues/4566)) ([1969cf4](https://github.com/vuejs/vitepress/commit/1969cf4f3b93ad105595e4e2f8b030b04eb1c975)) + +### Features + +- **cli:** support custom `srcDir` ([#4270](https://github.com/vuejs/vitepress/issues/4270)) ([518c094](https://github.com/vuejs/vitepress/commit/518c0945f159aae679ef710bb48ae3ab3891cc9f)) +- **cli:** support custom npm scripts prefix ([#4271](https://github.com/vuejs/vitepress/issues/4271)) ([e5a0ee8](https://github.com/vuejs/vitepress/commit/e5a0ee8161752a77c5bb9546245a940cb5f28fb8)) +- **build:** dynamic routes plugin overhaul ([#4525](https://github.com/vuejs/vitepress/issues/4525)) ([a62ea6a](https://github.com/vuejs/vitepress/commit/a62ea6a832a33b756642b24ad5d38c248e08b554)) +- **build:** update to shiki v3 ([#4571](https://github.com/vuejs/vitepress/issues/4571)) ([52c2aa1](https://github.com/vuejs/vitepress/commit/52c2aa178d4b3fa98b863cf28f0ccf6d2aabcd93)) +- **build:** use `markdown-it-async`, remove `synckit` ([#4507](https://github.com/vuejs/vitepress/issues/4507)) ([8062235](https://github.com/vuejs/vitepress/commit/80622356f1d648577ee47ee3a44b04bb015ee462)) + +### BREAKING CHANGES + +- 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`. +- 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. +- shiki is upgraded to v3. There shouldn't be any breaking change but if you see any issue, please report it. + +## [2.0.0-alpha.2](https://github.com/vuejs/vitepress/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2025-01-23) + +### Bug Fixes + +- fix docsearch navigation and rendering ([e035027](https://github.com/vuejs/vitepress/commit/e0350275b39258a61ee867840ce1c6f5b2cecf2a)) +- **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)) + +### Features + +- 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)) +- 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)) + +## [2.0.0-alpha.1](https://github.com/vuejs/vitepress/compare/v1.6.2...v2.0.0-alpha.1) (2025-01-22) + +### Features + +- upgrade vite to v6 ([#4504](https://github.com/vuejs/vitepress/issues/4504)) ([6a2efc3](https://github.com/vuejs/vitepress/commit/6a2efc385c90b088241db05f5263b2f3e1f757cf)) + +## [1.6.3](https://github.com/vuejs/vitepress/compare/v1.6.2...v1.6.3) (2025-01-22) + +### Bug Fixes + +- docsearch not rendering properly ([3e4120e](https://github.com/vuejs/vitepress/commit/3e4120e94805156bf63587fd633162433dbaf260)) + +## [1.6.2](https://github.com/vuejs/vitepress/compare/v1.6.1...v1.6.2) (2025-01-22) + +### Bug Fixes + +- 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)) + +## [1.6.1](https://github.com/vuejs/vitepress/compare/v1.6.0...v1.6.1) (2025-01-20) + +### Bug Fixes + +- **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) +- **theme/regression:** broken hero heading at certain viewports ([37dbe89](https://github.com/vuejs/vitepress/commit/37dbe895d4cf813e6eb1289f24c637945eec0d1f)) + +# [1.6.0](https://github.com/vuejs/vitepress/compare/v1.5.0...v1.6.0) (2025-01-20) + +### Bug Fixes + +- **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) +- **build:** properly strip vpi-social css declaration in debug mode ([c61182a](https://github.com/vuejs/vitepress/commit/c61182ab278350699b5d50461788478a340790aa)) +- **build:** respect `vite.clearScreen` in build ([8ea776a](https://github.com/vuejs/vitepress/commit/8ea776addc2c3bcabf3c707a9a81d6e0080a8fcb)), closes [#4468](https://github.com/vuejs/vitepress/issues/4468) +- **build:** specify mode for iconify ([8a5e8ea](https://github.com/vuejs/vitepress/commit/8a5e8ea4f5b7cba0a6c909d8949f0c20426104a6)) +- **theme:** apply `externalLinkIcon` option on `VPHome` ([#4492](https://github.com/vuejs/vitepress/issues/4492)) ([fe48943](https://github.com/vuejs/vitepress/commit/fe48943640895d859811b81f86d78c3e510dbe54)) +- **theme:** don't show external link icon for images ([096bba1](https://github.com/vuejs/vitepress/commit/096bba19fb61c4b2f8f527046b4b0fe2e91c6bd6)) +- **theme:** ignore footnote-ref for outline ([1832617](https://github.com/vuejs/vitepress/commit/183261753b04c2c96ddb8c10e520c748c6d3e613)), closes [#4402](https://github.com/vuejs/vitepress/issues/4402) +- **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) + +### Features + +- **build:** export normalize function from shared chunk ([616f63f](https://github.com/vuejs/vitepress/commit/616f63f5f08a57347f2800e2d147d5bcd1cd072d)), closes [#4401](https://github.com/vuejs/vitepress/issues/4401) +- **theme:** allow customizing skip to content label ([ff254dc](https://github.com/vuejs/vitepress/commit/ff254dcbe6f2bcc89c34d2d2f4050229dc094400)), closes [#4288](https://github.com/vuejs/vitepress/issues/4288) +- **theme:** export VPNavBarSearch ([23522ab](https://github.com/vuejs/vitepress/commit/23522ab83ff33802d382fa066578dd87eb06789d)), closes [#4476](https://github.com/vuejs/vitepress/issues/4476) +- **theme:** export VPFeatures ([#4356](https://github.com/vuejs/vitepress/issues/4356)) ([6442e17](https://github.com/vuejs/vitepress/commit/6442e174838aec9668325bb1199419908e7dd728)) + +### Miscellaneous + +- **build:** shiki transformers now use v3 [matching algorithm](https://shiki.style/packages/transformers#matching-algorithm) ([373f9b9](https://github.com/vuejs/vitepress/commit/373f9b933ee44f33a15ebdcfcb6db6dfac52f739)) + # [1.5.0](https://github.com/vuejs/vitepress/compare/v1.4.5...v1.5.0) (2024-11-04) ### Features @@ -2093,7 +2441,6 @@ This version uses Vue 3.2.0. ### BREAKING CHANGES - Some config options have changed. - - `vueOptions` renamed to `vue` - `alias` option has been removed. Use `vite.resovle.alias` instead. @@ -2111,7 +2458,6 @@ This version uses Vue 3.2.0. ### BREAKING CHANGES - The following methods are removed. - - `useSiteData` - `useSiteDataByRoute` - `usePageData` diff --git a/README.md b/README.md index 134226a49..027003088 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # VitePress 📝💨 -[![test](https://github.com/vuejs/vitepress/workflows/Test/badge.svg)](https://github.com/vuejs/vitepress/actions) -[![npm](https://img.shields.io/npm/v/vitepress)](https://www.npmjs.com/package/vitepress) +[![test](https://github.com/vuejs/vitepress/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/vuejs/vitepress/actions/workflows/test.yml) +[![npm](https://img.shields.io/npm/v/vitepress/next)](https://www.npmjs.com/package/vitepress/v/next) [![nightly releases](https://img.shields.io/badge/nightly-releases-orange)](https://nightly.akryum.dev/vuejs/vitepress) [![chat](https://img.shields.io/badge/chat-discord-blue?logo=discord)](https://chat.vuejs.org) @@ -26,3 +26,14 @@ Please make sure to read the [Contributing Guide](https://github.com/vuejs/vitep [MIT](https://github.com/vuejs/vitepress/blob/main/LICENSE) Copyright (c) 2019-present, Yuxi (Evan) You + +## Special Thanks + +This project would not be possible without the support of these amazing companies and tools. + +| | | | +| ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| VoidZero's logo | **[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. | +| StackBlitz's logo | **[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. | +| Algolia's logo | **[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. | +| BrowserStack's logo | **[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. | diff --git a/__tests__/e2e/.vitepress/config.ts b/__tests__/e2e/.vitepress/config.ts index 65f845ab3..121761e79 100644 --- a/__tests__/e2e/.vitepress/config.ts +++ b/__tests__/e2e/.vitepress/config.ts @@ -165,13 +165,21 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('local-search/excluded')) return '' return html } } } + }, + vite: { + server: { + watch: { + usePolling: true, + interval: 100 + } + } } }) diff --git a/__tests__/e2e/.vitepress/theme/components/ApiPreference.vue b/__tests__/e2e/.vitepress/theme/components/ApiPreference.vue index 12207764d..c286640bf 100644 --- a/__tests__/e2e/.vitepress/theme/components/ApiPreference.vue +++ b/__tests__/e2e/.vitepress/theme/components/ApiPreference.vue @@ -30,7 +30,7 @@ function removeSpaces(str: string) { diff --git a/__tests__/e2e/.vitepress/theme/components/CustomLayout.vue b/__tests__/e2e/.vitepress/theme/components/CustomLayout.vue new file mode 100644 index 000000000..4a42af445 --- /dev/null +++ b/__tests__/e2e/.vitepress/theme/components/CustomLayout.vue @@ -0,0 +1,14 @@ + + + diff --git a/__tests__/e2e/.vitepress/theme/components/HomeHeroCopy.vue b/__tests__/e2e/.vitepress/theme/components/HomeHeroCopy.vue new file mode 100644 index 000000000..ecc3ba92e --- /dev/null +++ b/__tests__/e2e/.vitepress/theme/components/HomeHeroCopy.vue @@ -0,0 +1,210 @@ + + + + + diff --git a/__tests__/e2e/.vitepress/theme/index.ts b/__tests__/e2e/.vitepress/theme/index.ts index d26297778..9b5c079cd 100644 --- a/__tests__/e2e/.vitepress/theme/index.ts +++ b/__tests__/e2e/.vitepress/theme/index.ts @@ -1,10 +1,12 @@ import type { Theme } from 'vitepress' import DefaultTheme from 'vitepress/theme' +import CustomLayout from './components/CustomLayout.vue' import ApiPreference from './components/ApiPreference.vue' import NavVersion from './components/NavVersion.vue' export default { extends: DefaultTheme, + Layout: CustomLayout, enhanceApp({ app }) { app.component('ApiPreference', ApiPreference) app.component('NavVersion', NavVersion) diff --git a/__tests__/e2e/data-loading/data.test.ts b/__tests__/e2e/data-loading/data.test.ts index 394ab1d23..21cfa061c 100644 --- a/__tests__/e2e/data-loading/data.test.ts +++ b/__tests__/e2e/data-loading/data.test.ts @@ -43,8 +43,7 @@ describe('static data file support in vite 3', () => { `) }) - // TODO: make it `.runIf(!process.env.VITE_TEST_BUILD)` -- it currently works, but is skipped to avoid vite's ecosystem-ci from failing (https://github.com/vitejs/vite/pull/16471#issuecomment-2308437187) - test.skip('hmr works', async () => { + test.runIf(!process.env.VITE_TEST_BUILD)('hmr works', async () => { const a = fileURLToPath(new URL('./data/a.json', import.meta.url)) const b = fileURLToPath(new URL('./data/b.json', import.meta.url)) @@ -53,9 +52,7 @@ describe('static data file support in vite 3', () => { await page.waitForFunction( () => document.querySelector('pre#basic')?.textContent === - JSON.stringify([{ a: false }, { b: true }], null, 2), - undefined, - { timeout: 3000 } + JSON.stringify([{ a: false }, { b: true }], null, 2) ) } finally { await fs.writeFile(a, JSON.stringify({ a: true }, null, 2) + '\n') @@ -68,9 +65,7 @@ describe('static data file support in vite 3', () => { await page.waitForFunction( () => document.querySelector('pre#basic')?.textContent === - JSON.stringify([{ a: true }], null, 2), - undefined, - { timeout: 3000 } + JSON.stringify([{ a: true }], null, 2) ) err = false } finally { @@ -84,9 +79,7 @@ describe('static data file support in vite 3', () => { await page.waitForFunction( () => document.querySelector('pre#basic')?.textContent === - JSON.stringify([{ a: true }, { b: false }], null, 2), - undefined, - { timeout: 3000 } + JSON.stringify([{ a: true }, { b: false }], null, 2) ) } finally { await fs.writeFile(b, JSON.stringify({ b: true }, null, 2) + '\n') diff --git a/__tests__/e2e/dynamic-routes/[id].paths.ts b/__tests__/e2e/dynamic-routes/[id].paths.ts index 3eca4d916..a1cb6fefd 100644 --- a/__tests__/e2e/dynamic-routes/[id].paths.ts +++ b/__tests__/e2e/dynamic-routes/[id].paths.ts @@ -1,8 +1,14 @@ -export default { - async paths() { - return [ - { params: { id: 'foo' }, content: `# Foo` }, - { params: { id: 'bar' }, content: `# Bar` } - ] +import { defineRoutes } from 'vitepress' +import paths from './paths' + +export default defineRoutes({ + async paths(watchedFiles: string[]) { + // console.log('watchedFiles', watchedFiles) + return paths + }, + watch: ['../data-loading/**/*.json'], + async transformPageData(pageData) { + // console.log('transformPageData', pageData.filePath) + pageData.title += ' - transformed' } -} +}) diff --git a/__tests__/e2e/dynamic-routes/paths.ts b/__tests__/e2e/dynamic-routes/paths.ts new file mode 100644 index 000000000..5adb0ed48 --- /dev/null +++ b/__tests__/e2e/dynamic-routes/paths.ts @@ -0,0 +1,4 @@ +export default [ + { params: { id: 'foo' }, content: `# Foo` }, + { params: { id: 'bar' }, content: `# Bar` } +] diff --git a/__tests__/e2e/index.md b/__tests__/e2e/index.md index f35cb331c..2805de36c 100644 --- a/__tests__/e2e/index.md +++ b/__tests__/e2e/index.md @@ -6,6 +6,10 @@ title: VitePress hero: name: VitePress text: Vite & Vue Powered Static Site Generator + image: + src: /vitepress-logo.svg + alt: VitePress + actions: - theme: brand text: Examples diff --git a/__tests__/e2e/local-search/local-search.test.ts b/__tests__/e2e/local-search/local-search.test.ts index 492136b68..9496dc6bf 100644 --- a/__tests__/e2e/local-search/local-search.test.ts +++ b/__tests__/e2e/local-search/local-search.test.ts @@ -4,7 +4,7 @@ describe('local search', () => { }) test('exclude content from search results', async () => { - await page.locator('#local-search button').click() + await page.locator('.VPNavBarSearchButton').click() const input = await page.waitForSelector('input#localsearch-input') await input.type('local') diff --git a/__tests__/e2e/markdown-extensions/header-include.md b/__tests__/e2e/markdown-extensions/header-include.md new file mode 100644 index 000000000..70fac23bd --- /dev/null +++ b/__tests__/e2e/markdown-extensions/header-include.md @@ -0,0 +1,27 @@ +# header 1 + +header 1 content + +## header 1.1 + +header 1.1 content + +### header 1.1.1 + +header 1.1.1 content + +### header 1.1.2 + +header 1.1.2 content + +## header 1.2 + +header 1.2 content + +### header 1.2.1 + +header 1.2.1 content + +### header 1.2.2 + +header 1.2.2 content diff --git a/__tests__/e2e/markdown-extensions/index.md b/__tests__/e2e/markdown-extensions/index.md index 855803f2b..3446b4efd 100644 --- a/__tests__/e2e/markdown-extensions/index.md +++ b/__tests__/e2e/markdown-extensions/index.md @@ -213,6 +213,10 @@ export default config +## Markdown File Inclusion with Header + + + ## Image Lazy Loading -![vitepress logo](/vitepress.png) \ No newline at end of file +![vitepress logo](/vitepress.png) diff --git a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts index e49a137fd..839f953cb 100644 --- a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts +++ b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts @@ -64,8 +64,61 @@ describe('Emoji', () => { describe('Table of Contents', () => { test('render toc', async () => { const items = page.locator('#table-of-contents + nav ul li') - const count = await items.count() - expect(count).toBe(44) + expect( + await items.evaluateAll((elements) => + elements.map((el) => el.childNodes[0].textContent) + ) + ).toMatchInlineSnapshot(` + [ + "Links", + "Internal Links", + "External Links", + "GitHub-Style Tables", + "Emoji", + "Table of Contents", + "Custom Containers", + "Default Title", + "Custom Title", + "Line Highlighting in Code Blocks", + "Single Line", + "Multiple single lines, ranges", + "Comment Highlight", + "Line Numbers", + "Import Code Snippets", + "Basic Code Snippet", + "Specify Region", + "With Other Features", + "Code Groups", + "Basic Code Group", + "With Other Features", + "Markdown File Inclusion", + "Region", + "Markdown At File Inclusion", + "Markdown Nested File Inclusion", + "Region", + "After Foo", + "Sub sub", + "Sub sub sub", + "Markdown File Inclusion with Range", + "Region", + "Markdown File Inclusion with Range without Start", + "Region", + "Markdown File Inclusion with Range without End", + "Region", + "Markdown At File Region Snippet", + "Region Snippet", + "Markdown At File Range Region Snippet", + "Range Region Line 2", + "Markdown At File Range Region Snippet without start", + "Range Region Line 1", + "Markdown At File Range Region Snippet without end", + "Range Region Line 3", + "Markdown File Inclusion with Header", + "header 1.1.1", + "header 1.1.2", + "Image Lazy Loading", + ] + `) }) }) diff --git a/__tests__/e2e/public/vitepress-logo.svg b/__tests__/e2e/public/vitepress-logo.svg new file mode 120000 index 000000000..e2b803559 --- /dev/null +++ b/__tests__/e2e/public/vitepress-logo.svg @@ -0,0 +1 @@ +../../../art/vitepress-logo.svg \ No newline at end of file diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json index 42258a4e4..9cce3a1ef 100644 --- a/__tests__/tsconfig.json +++ b/__tests__/tsconfig.json @@ -2,11 +2,11 @@ "extends": "../tsconfig.json", "compilerOptions": { "isolatedModules": false, - "baseUrl": ".", "types": ["node", "vitest/globals"], "paths": { + "client/*": ["../src/client/*"], "node/*": ["../src/node/*"], - "client/*": ["../src/client/*"] + "shared/*": ["../src/shared/*"] } } } diff --git a/__tests__/unit/client/theme-default/support/docsearch.test.ts b/__tests__/unit/client/theme-default/support/docsearch.test.ts new file mode 100644 index 000000000..4da8f113f --- /dev/null +++ b/__tests__/unit/client/theme-default/support/docsearch.test.ts @@ -0,0 +1,196 @@ +import { + buildAskAiConfig, + hasAskAi, + hasKeywordSearch, + mergeLangFacetFilters, + validateCredentials +} from 'client/theme-default/support/docsearch' + +describe('client/theme-default/support/docsearch', () => { + describe('mergeLangFacetFilters', () => { + test('adds a lang facet filter when none is provided', () => { + expect(mergeLangFacetFilters(undefined, 'en')).toEqual(['lang:en']) + }) + + test('replaces existing lang facet filters', () => { + expect(mergeLangFacetFilters('lang:fr', 'en')).toEqual(['lang:en']) + expect(mergeLangFacetFilters(['foo', 'lang:fr'], 'en')).toEqual([ + 'foo', + 'lang:en' + ]) + }) + + test('handles nested facet filters (OR conditions)', () => { + expect( + mergeLangFacetFilters([['tag:foo', 'tag:bar'], 'lang:fr'], 'en') + ).toEqual([['tag:foo', 'tag:bar'], 'lang:en']) + }) + + test('removes empty nested arrays', () => { + expect(mergeLangFacetFilters([['lang:fr'], 'other'], 'en')).toEqual([ + 'other', + 'lang:en' + ]) + }) + + test('handles multiple lang filters in nested arrays', () => { + expect( + mergeLangFacetFilters([['lang:fr', 'tag:foo'], 'bar'], 'en') + ).toEqual([['tag:foo'], 'bar', 'lang:en']) + }) + }) + + describe('hasKeywordSearch', () => { + test('returns true when all credentials are provided', () => { + expect( + hasKeywordSearch({ + appId: 'app', + apiKey: 'key', + indexName: 'index' + }) + ).toBe(true) + }) + + test('returns false when any credential is missing', () => { + expect( + hasKeywordSearch({ + appId: undefined, + apiKey: 'key', + indexName: 'index' + }) + ).toBe(false) + expect( + hasKeywordSearch({ + appId: 'app', + apiKey: undefined, + indexName: 'index' + }) + ).toBe(false) + expect( + hasKeywordSearch({ + appId: 'app', + apiKey: 'key', + indexName: undefined + }) + ).toBe(false) + }) + }) + + describe('hasAskAi', () => { + test('returns true for valid string assistantId', () => { + expect(hasAskAi('assistant123')).toBe(true) + }) + + test('returns false for empty string assistantId', () => { + expect(hasAskAi('')).toBe(false) + }) + + test('returns true for object with assistantId', () => { + expect(hasAskAi({ assistantId: 'assistant123' } as any)).toBe(true) + }) + + test('returns false for object without assistantId', () => { + expect(hasAskAi({ assistantId: null } as any)).toBe(false) + expect(hasAskAi({} as any)).toBe(false) + }) + + test('returns false for undefined', () => { + expect(hasAskAi(undefined)).toBe(false) + }) + }) + + describe('validateCredentials', () => { + test('validates complete credentials', () => { + const result = validateCredentials({ + appId: 'app', + apiKey: 'key', + indexName: 'index' + }) + expect(result.valid).toBe(true) + expect(result.appId).toBe('app') + expect(result.apiKey).toBe('key') + expect(result.indexName).toBe('index') + }) + + test('invalidates incomplete credentials', () => { + expect( + validateCredentials({ + appId: undefined, + apiKey: 'key', + indexName: 'index' + }).valid + ).toBe(false) + }) + }) + + describe('buildAskAiConfig', () => { + test('builds config from string assistantId', () => { + const result = buildAskAiConfig( + 'assistant123', + { + appId: 'app', + apiKey: 'key', + indexName: 'index' + } as any, + 'en' + ) + expect(result.assistantId).toBe('assistant123') + expect(result.appId).toBe('app') + expect(result.apiKey).toBe('key') + expect(result.indexName).toBe('index') + }) + + test('builds config from object with overrides', () => { + const result = buildAskAiConfig( + { + assistantId: 'assistant123', + appId: 'custom-app', + apiKey: 'custom-key', + indexName: 'custom-index' + } as any, + { + appId: 'default-app', + apiKey: 'default-key', + indexName: 'default-index' + } as any, + 'en' + ) + expect(result.assistantId).toBe('assistant123') + expect(result.appId).toBe('custom-app') + expect(result.apiKey).toBe('custom-key') + expect(result.indexName).toBe('custom-index') + }) + + test('merges facet filters with lang', () => { + const result = buildAskAiConfig( + { + assistantId: 'assistant123', + searchParameters: { + facetFilters: ['tag:docs'] + } + } as any, + { + appId: 'app', + apiKey: 'key', + indexName: 'index' + } as any, + 'en' + ) + expect(result.searchParameters?.facetFilters).toContain('tag:docs') + expect(result.searchParameters?.facetFilters).toContain('lang:en') + }) + + test('always adds lang facet filter to searchParameters', () => { + const result = buildAskAiConfig( + 'assistant123', + { + appId: 'app', + apiKey: 'key', + indexName: 'index' + } as any, + 'en' + ) + expect(result.searchParameters?.facetFilters).toEqual(['lang:en']) + }) + }) +}) diff --git a/__tests__/unit/client/theme-default/support/utils.test.ts b/__tests__/unit/client/theme-default/support/utils.test.ts index 880d4232c..aefc9b8e5 100644 --- a/__tests__/unit/client/theme-default/support/utils.test.ts +++ b/__tests__/unit/client/theme-default/support/utils.test.ts @@ -1,4 +1,7 @@ -import { ensureStartingSlash } from 'client/theme-default/support/utils' +import { + ensureStartingSlash, + isLinkExternal +} from 'client/theme-default/support/utils' describe('client/theme-default/utils', () => { describe('ensureStartingSlash', () => { @@ -9,4 +12,22 @@ describe('client/theme-default/utils', () => { expect(ensureStartingSlash('/path/nested')).toBe('/path/nested') }) }) + + describe('isLinkExternal', () => { + test('it detects external links by default', () => { + expect(isLinkExternal('https://vite.dev')).toBe(true) + expect(isLinkExternal('/guide/')).toBe(false) + }) + + test('it treats _blank targets as external by default', () => { + expect(isLinkExternal('/guide/', '_blank')).toBe(true) + }) + + test('it allows callers to override external detection', () => { + expect(isLinkExternal('https://cn.vite.dev', undefined, false)).toBe( + false + ) + expect(isLinkExternal('/guide/', undefined, true)).toBe(true) + }) + }) }) diff --git a/__tests__/unit/node/markdown/plugins/highlight.test.ts b/__tests__/unit/node/markdown/plugins/highlight.test.ts new file mode 100644 index 000000000..7454dcc16 --- /dev/null +++ b/__tests__/unit/node/markdown/plugins/highlight.test.ts @@ -0,0 +1,26 @@ +import { highlight } from 'node/markdown/plugins/highlight' + +describe('node/markdown/plugins/highlight', () => { + test('passes color replacements through markdown options', async () => { + const [render, dispose] = await highlight( + { light: 'github-light', dark: 'github-dark' }, + { + colorReplacements: { + 'github-light': { + '#005cc5': '#000000' + } + } + } + ) + + try { + const html = await render('const a = 1', 'js', '') + + expect(html).toContain('--shiki-light:#000000') + expect(html).toContain('--shiki-dark:#79B8FF') + expect(html).not.toContain('--shiki-light:#005CC5') + } finally { + dispose() + } + }) +}) diff --git a/__tests__/unit/node/markdown/plugins/link.test.ts b/__tests__/unit/node/markdown/plugins/link.test.ts new file mode 100644 index 000000000..e5e099781 --- /dev/null +++ b/__tests__/unit/node/markdown/plugins/link.test.ts @@ -0,0 +1,51 @@ +import { slugify } from '@mdit-vue/shared' +import { MarkdownItAsync } from 'markdown-it-async' +import { linkPlugin } from 'node/markdown/plugins/link' + +describe('node/markdown/plugins/link', () => { + const md = new MarkdownItAsync() + linkPlugin(md, {}, '/', slugify) + + test('preserves text-fragment hashes on markdown links', async () => { + const html = await md.renderAsync( + '[58-61](/resources/server/user#:~:text=58*,time%20authentication%20token)', + { cleanUrls: false } + ) + + expect(html).toContain( + 'href="/resources/server/user.html#:~:text=58*,time%20authentication%20token"' + ) + }) + + // https://web.dev/articles/text-fragments#mixing_element_and_text_fragments + test('preserves mixed element and text-fragment hashes', async () => { + const html = await md.renderAsync( + '[Section](/guide/getting-started#Hello%20World:~:text=Hello%20World)', + { cleanUrls: false } + ) + + expect(html).toContain( + 'href="/guide/getting-started.html#hello-world:~:text=Hello%20World"' + ) + }) + + test('continues to normalize regular heading hashes', async () => { + const html = await md.renderAsync( + '[Section](/guide/getting-started#Hello%20World)', + { cleanUrls: false } + ) + + expect(html).toContain('href="/guide/getting-started.html#hello-world"') + }) + + test('does not break encoding for text-fragments', async () => { + const html = await md.renderAsync( + '[Section](/foo?title=Cat&oldid=916388819#:~:text=Claws-,Like%20almost,the%20Felidae%2C,-cats)', + { cleanUrls: false } + ) + + expect(html).toContain( + 'href="/foo.html?title=Cat&oldid=916388819#:~:text=Claws-,Like%20almost,the%20Felidae%2C,-cats"' + ) + }) +}) diff --git a/__tests__/unit/node/markdown/plugins/snippet.test.ts b/__tests__/unit/node/markdown/plugins/snippet.test.ts index 0ae97dd2a..ba4b343e1 100644 --- a/__tests__/unit/node/markdown/plugins/snippet.test.ts +++ b/__tests__/unit/node/markdown/plugins/snippet.test.ts @@ -1,4 +1,8 @@ -import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet' +import { + dedent, + findRegion, + rawPathToToken +} from 'node/markdown/plugins/snippet' const removeEmptyKeys = >(obj: T) => { return Object.fromEntries( @@ -94,9 +98,228 @@ describe('node/markdown/plugins/snippet', () => { }) }) - test('rawPathToToken', () => { - rawPathTokenMap.forEach(([rawPath, token]) => { + describe('rawPathToToken', () => { + test.each(rawPathTokenMap)('%s', (rawPath, token) => { expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token) }) }) + + describe('findRegion', () => { + it('returns null when no region markers are present', () => { + const lines = ['function foo() {', ' console.log("hello");', '}'] + expect(findRegion(lines, 'foo')).toBeNull() + }) + + it('ignores non-matching region names', () => { + const lines = [ + '// #region regionA', + 'some code here', + '// #endregion regionA' + ] + expect(findRegion(lines, 'regionC')).toBeNull() + }) + + it('returns null if a region start marker exists without a matching end marker', () => { + const lines = [ + '// #region missingEnd', + 'console.log("inside region");', + 'console.log("still inside");' + ] + expect(findRegion(lines, 'missingEnd')).toBeNull() + }) + + it('returns null if an end marker exists without a preceding start marker', () => { + const lines = [ + '// #endregion ghostRegion', + 'console.log("stray end marker");' + ] + expect(findRegion(lines, 'ghostRegion')).toBeNull() + }) + + it('detects C#/JavaScript style region markers with matching tags', () => { + const lines = [ + 'Console.WriteLine("Before region");', + '#region hello', + 'Console.WriteLine("Hello, World!");', + '#endregion hello', + 'Console.WriteLine("After region");' + ] + const result = findRegion(lines, 'hello') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + } + }) + + it('detects region markers even when the end marker omits the region name', () => { + const lines = [ + 'Console.WriteLine("Before region");', + '#region hello', + 'Console.WriteLine("Hello, World!");', + '#endregion', + 'Console.WriteLine("After region");' + ] + const result = findRegion(lines, 'hello') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + } + }) + + it('handles indented region markers correctly', () => { + const lines = [ + ' Console.WriteLine("Before region");', + ' #region hello', + ' Console.WriteLine("Hello, World!");', + ' #endregion hello', + ' Console.WriteLine("After region");' + ] + const result = findRegion(lines, 'hello') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + ' Console.WriteLine("Hello, World!");' + ) + } + }) + + it('detects TypeScript style region markers', () => { + const lines = [ + 'let regexp: RegExp[] = [];', + '// #region foo', + 'let start = -1;', + '// #endregion foo' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'let start = -1;' + ) + } + }) + + it('detects CSS style region markers', () => { + const lines = [ + '.body-content {', + '/* #region foo */', + ' padding-left: 15px;', + '/* #endregion foo */', + ' padding-right: 15px;', + '}' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + ' padding-left: 15px;' + ) + } + }) + + it('detects HTML style region markers', () => { + const lines = [ + '
    Some content
    ', + '', + '

    Hello world

    ', + '', + '
    Other content
    ' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + '

    Hello world

    ' + ) + } + }) + + it('detects Visual Basic style region markers (with case-insensitive "End")', () => { + const lines = [ + 'Console.WriteLine("VB")', + '#Region VBRegion', + ' Console.WriteLine("Inside region")', + '#End Region VBRegion', + 'Console.WriteLine("Done")' + ] + const result = findRegion(lines, 'VBRegion') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + ' Console.WriteLine("Inside region")' + ) + } + }) + + it('detects Bat style region markers', () => { + const lines = ['::#region foo', 'echo off', '::#endregion foo'] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'echo off' + ) + } + }) + + it('detects C/C++ style region markers using #pragma', () => { + const lines = [ + '#pragma region foo', + 'int a = 1;', + '#pragma endregion foo' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'int a = 1;' + ) + } + }) + + it('returns the first complete region when multiple regions exist', () => { + const lines = [ + '// #region foo', + 'first region content', + '// #endregion foo', + '// #region foo', + 'second region content', + '// #endregion foo' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + expect(lines.slice(result.start, result.end).join('\n')).toBe( + 'first region content' + ) + } + }) + + it('handles nested regions with different names properly', () => { + const lines = [ + '// #region foo', + "console.log('line before nested');", + '// #region bar', + "console.log('nested content');", + '// #endregion bar', + '// #endregion foo' + ] + const result = findRegion(lines, 'foo') + expect(result).not.toBeNull() + if (result) { + const extracted = lines.slice(result.start, result.end).join('\n') + const expected = [ + "console.log('line before nested');", + '// #region bar', + "console.log('nested content');", + '// #endregion bar' + ].join('\n') + expect(extracted).toBe(expected) + } + }) + }) }) diff --git a/__tests__/unit/node/postcss/__snapshots__/isolateStyles.test.ts.snap b/__tests__/unit/node/postcss/__snapshots__/isolateStyles.test.ts.snap new file mode 100644 index 000000000..c781b64c0 --- /dev/null +++ b/__tests__/unit/node/postcss/__snapshots__/isolateStyles.test.ts.snap @@ -0,0 +1,77 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`node/postcss/isolateStyles > transforms selectors and skips keyframes 1`] = ` +" +/* simple classes */ +.example:not(:where(.vp-raw, .vp-raw *)) { color: red; } +.class-a:not(:where(.vp-raw, .vp-raw *)) { color: coral; } +.class-b:not(:where(.vp-raw, .vp-raw *)) { color: deepskyblue; } + +/* escaped colon in class */ +.baz\\:not\\(.bar\\):not(:where(.vp-raw, .vp-raw *)) { display: block; } +.disabled\\:opacity-50:not(:where(.vp-raw, .vp-raw *)):disabled { opacity: .5; } + +/* pseudos (class + element) */ +.button:not(:where(.vp-raw, .vp-raw *)):hover { color: pink; } +.button:not(:where(.vp-raw, .vp-raw *)):focus:hover { color: hotpink; } +.item:not(:where(.vp-raw, .vp-raw *))::before { content: '•'; } +:not(:where(.vp-raw, .vp-raw *))::first-letter { color: pink; } +:not(:where(.vp-raw, .vp-raw *))::before { content: ''; } + +/* universal + :not */ +*:not(:where(.vp-raw, .vp-raw *)) { background-color: red; } +*:not(:where(.vp-raw, .vp-raw *)):not(.b) { text-transform: uppercase; } + +/* combinators */ +.foo:hover .bar:not(:where(.vp-raw, .vp-raw *)) { background: blue; } +ul > li.active:not(:where(.vp-raw, .vp-raw *)) { color: green; } +a + b ~ c:not(:where(.vp-raw, .vp-raw *)) { color: orange; } + +/* ids + attribute selectors */ +#wow:not(:where(.vp-raw, .vp-raw *)) { color: yellow; } +[data-world] .d:not(:where(.vp-raw, .vp-raw *)) { padding: 10px 20px; } + +/* :root and chained tags */ +:not(:where(.vp-raw, .vp-raw *)):root { --bs-blue: #0d6efd; } +:root .a:not(:where(.vp-raw, .vp-raw *)) { --bs-green: #bada55; } +html:not(:where(.vp-raw, .vp-raw *)) { margin: 0; } +body:not(:where(.vp-raw, .vp-raw *)) { padding: 0; } +html body div:not(:where(.vp-raw, .vp-raw *)) { color: blue; } + +/* grouping with commas */ +.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: red; } + +/* multiple repeated groups to ensure stability */ +.a:not(:where(.vp-raw, .vp-raw *)), .b:not(:where(.vp-raw, .vp-raw *)) { color: coral; } +.a:not(:where(.vp-raw, .vp-raw *)) { animation: glow 1s linear infinite alternate; } + +/* nested blocks */ +.foo:not(:where(.vp-raw, .vp-raw *)) { + svg:not(:where(.vp-raw, .vp-raw *)) { display: none; } + .bar:not(:where(.vp-raw, .vp-raw *)) { display: inline; } +} + +/* standalone pseudos */ +:not(:where(.vp-raw, .vp-raw *)):first-child { color: pink; } +:not(:where(.vp-raw, .vp-raw *)):hover { color: blue; } +:not(:where(.vp-raw, .vp-raw *)):active { color: red; } + +/* keyframes (should be ignored) */ +@keyframes fade { + from { opacity: 0; } + to { opacity: 1; } +} +@-webkit-keyframes glow { + from { color: coral; } + to { color: red; } +} +@-moz-keyframes glow { + from { color: coral; } + to { color: red; } +} +@-o-keyframes glow { + from { color: coral; } + to { color: red; } +} +" +`; diff --git a/__tests__/unit/node/postcss/isolateStyles.test.ts b/__tests__/unit/node/postcss/isolateStyles.test.ts new file mode 100644 index 000000000..609a4463a --- /dev/null +++ b/__tests__/unit/node/postcss/isolateStyles.test.ts @@ -0,0 +1,93 @@ +import { postcssIsolateStyles } from 'node/postcss/isolateStyles' +import postcss from 'postcss' + +const INPUT_CSS = ` +/* simple classes */ +.example { color: red; } +.class-a { color: coral; } +.class-b { color: deepskyblue; } + +/* escaped colon in class */ +.baz\\:not\\(.bar\\) { display: block; } +.disabled\\:opacity-50:disabled { opacity: .5; } + +/* pseudos (class + element) */ +.button:hover { color: pink; } +.button:focus:hover { color: hotpink; } +.item::before { content: '•'; } +::first-letter { color: pink; } +::before { content: ''; } + +/* universal + :not */ +* { background-color: red; } +*:not(.b) { text-transform: uppercase; } + +/* combinators */ +.foo:hover .bar { background: blue; } +ul > li.active { color: green; } +a + b ~ c { color: orange; } + +/* ids + attribute selectors */ +#wow { color: yellow; } +[data-world] .d { padding: 10px 20px; } + +/* :root and chained tags */ +:root { --bs-blue: #0d6efd; } +:root .a { --bs-green: #bada55; } +html { margin: 0; } +body { padding: 0; } +html body div { color: blue; } + +/* grouping with commas */ +.a, .b { color: red; } + +/* multiple repeated groups to ensure stability */ +.a, .b { color: coral; } +.a { animation: glow 1s linear infinite alternate; } + +/* nested blocks */ +.foo { + svg { display: none; } + .bar { display: inline; } +} + +/* standalone pseudos */ +:first-child { color: pink; } +:hover { color: blue; } +:active { color: red; } + +/* keyframes (should be ignored) */ +@keyframes fade { + from { opacity: 0; } + to { opacity: 1; } +} +@-webkit-keyframes glow { + from { color: coral; } + to { color: red; } +} +@-moz-keyframes glow { + from { color: coral; } + to { color: red; } +} +@-o-keyframes glow { + from { color: coral; } + to { color: red; } +} +` + +describe('node/postcss/isolateStyles', () => { + test('transforms selectors and skips keyframes', () => { + const out = run(INPUT_CSS) + expect(out.css).toMatchSnapshot() + }) + + test('idempotent (running twice produces identical CSS)', () => { + const first = run(INPUT_CSS).css + const second = run(first).css + expect(second).toBe(first) + }) +}) + +function run(css: string, from = 'src/styles/vp-doc.css') { + return postcss([postcssIsolateStyles()]).process(css, { from }) +} diff --git a/__tests__/unit/node/utils/moduleGraph.test.ts b/__tests__/unit/node/utils/moduleGraph.test.ts new file mode 100644 index 000000000..9b3db9e57 --- /dev/null +++ b/__tests__/unit/node/utils/moduleGraph.test.ts @@ -0,0 +1,72 @@ +import { ModuleGraph } from 'node/utils/moduleGraph' + +describe('node/utils/moduleGraph', () => { + let graph: ModuleGraph + + beforeEach(() => { + graph = new ModuleGraph() + }) + + it('should correctly delete a module and its dependents', () => { + graph.add('A', ['B', 'C']) + graph.add('B', ['D']) + graph.add('C', []) + graph.add('D', []) + + expect(graph.delete('D')).toEqual(new Set(['D', 'B', 'A'])) + }) + + it('should handle shared dependencies correctly', () => { + graph.add('A', ['B', 'C']) + graph.add('B', ['D']) + graph.add('C', ['D']) // Shared dependency + graph.add('D', []) + + expect(graph.delete('D')).toEqual(new Set(['A', 'B', 'C', 'D'])) + }) + + it('merges dependencies correctly', () => { + // Add module A with dependency B + graph.add('A', ['B']) + // Merge new dependency C into module A (B should remain) + graph.add('A', ['C']) + + // Deleting B should remove A as well, since A depends on B. + expect(graph.delete('B')).toEqual(new Set(['B', 'A'])) + }) + + it('handles cycles gracefully', () => { + // Create a cycle: A -> B, B -> C, C -> A. + graph.add('A', ['B']) + graph.add('B', ['C']) + graph.add('C', ['A']) + + // Deleting any module in the cycle should delete all modules in the cycle. + expect(graph.delete('A')).toEqual(new Set(['A', 'B', 'C'])) + }) + + it('cleans up dependencies when deletion', () => { + // Setup A -> B relationship. + graph.add('A', ['B']) + graph.add('B', []) + + // Deleting B should remove both B and A from the graph. + expect(graph.delete('B')).toEqual(new Set(['B', 'A'])) + + // After deletion, add modules again. + graph.add('C', []) + graph.add('A', ['C']) // Now A depends only on C. + + expect(graph.delete('C')).toEqual(new Set(['C', 'A'])) + }) + + it('handles independent modules', () => { + // Modules with no dependencies. + graph.add('X', []) + graph.add('Y', []) + + // Deletion of one should only remove that module. + expect(graph.delete('X')).toEqual(new Set(['X'])) + expect(graph.delete('Y')).toEqual(new Set(['Y'])) + }) +}) diff --git a/__tests__/unit/vitest.config.ts b/__tests__/unit/vitest.config.ts index b028d4ee0..93eb40e1e 100644 --- a/__tests__/unit/vitest.config.ts +++ b/__tests__/unit/vitest.config.ts @@ -12,6 +12,7 @@ export default defineConfig({ { find: '@siteData', replacement: resolve(dir, './shims.ts') }, { find: 'client', replacement: resolve(dir, '../../src/client') }, { find: 'node', replacement: resolve(dir, '../../src/node') }, + { find: 'shared', replacement: resolve(dir, '../../src/shared') }, { find: /^vitepress$/, replacement: resolve(dir, '../../src/client/index.js') diff --git a/art/vitepress-logo.svg b/art/vitepress-logo.svg index 1052015b5..0805ed51f 100644 --- a/art/vitepress-logo.svg +++ b/art/vitepress-logo.svg @@ -1,4 +1,4 @@ - + diff --git a/bin/vitepress.js b/bin/vitepress.js index 7c50ec907..9cf31ae01 100755 --- a/bin/vitepress.js +++ b/bin/vitepress.js @@ -1,2 +1,16 @@ #!/usr/bin/env node +// @ts-check + +import module from 'node:module' + +// https://github.com/vitejs/vite/blob/6c8a5a27e645a182f5b03a4ed6aa726eab85993f/packages/vite/bin/vite.js#L48-L63 +try { + module.enableCompileCache?.() + setTimeout(() => { + try { + module.flushCompileCache?.() + } catch {} + }, 10 * 1000).unref() +} catch {} + import('../dist/node/cli.js') diff --git a/client.d.ts b/client.d.ts index 440251f70..32fcebe2f 100644 --- a/client.d.ts +++ b/client.d.ts @@ -3,3 +3,12 @@ /// export * from './dist/client/index.js' + +declare global { + interface WindowEventMap { + 'vitepress:codeGroupTabActivate': Event & { + /** code block element that was activated */ + detail: Element + } + } +} diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 000000000..b80937139 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,178 @@ +import { + defineConfig, + resolveSiteDataByRoute, + type HeadConfig +} from 'vitepress' +import { + groupIconMdPlugin, + groupIconVitePlugin, + localIconLoader +} from 'vitepress-plugin-group-icons' +import llmstxt from 'vitepress-plugin-llms' + +const prod = !!process.env.NETLIFY +const siteUrl = 'https://vitepress.dev' + +const ogImage = new URL('/vitepress-og.jpg', siteUrl).href + +const localeToOgLocaleMap: Record = { + root: 'en_US', + zh: 'zh_CN', + pt: 'pt_BR', + ru: 'ru_RU', + es: 'es_ES', + ko: 'ko_KR', + fa: 'fa_IR', + ja: 'ja_JP' +} + +export default defineConfig({ + title: 'VitePress', + + rewrites: { + 'en/:rest*': ':rest*' + }, + + lastUpdated: true, + cleanUrls: true, + metaChunk: true, + + markdown: { + math: true, + codeTransformers: [ + // We use `[!!code` and `@@include` in demo to prevent transformation, + // here we revert it back. + { + postprocess(code) { + return code + .replaceAll('[!!code', '[!code') + .replaceAll('@@include', '@include') + } + } + ], + config(md) { + // TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed + const fence = md.renderer.rules.fence! + md.renderer.rules.fence = function (tokens, idx, options, env, self) { + const { localeIndex = 'root' } = env + const codeCopyButtonTitle = (() => { + switch (localeIndex) { + case 'es': + return 'Copiar código' + case 'fa': + return 'کپی کد' + case 'ko': + return '코드 복사' + case 'pt': + return 'Copiar código' + case 'ru': + return 'Скопировать код' + case 'zh': + return '复制代码' + case 'ja': + return 'コードをコピー' + default: + return 'Copy code' + } + })() + return fence(tokens, idx, options, env, self).replace( + '', + `` + ) + } + md.use(groupIconMdPlugin) + } + }, + + sitemap: { + hostname: siteUrl, + transformItems(items) { + return items.filter((item) => !item.url.includes('migration')) + } + }, + + // prettier-ignore + head: [ + ['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }], + ['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }], + ['meta', { name: 'theme-color', content: '#5f67ee' }], + ['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }] + ], + + themeConfig: { + logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 }, + + socialLinks: [ + { icon: 'github', link: 'https://github.com/vuejs/vitepress' } + ], + + search: { + provider: 'algolia', + options: { + appId: '8J64VVRP8K', + apiKey: '52f578a92b88ad6abde815aae2b0ad7c', + indexName: 'vitepress', + askAi: { + assistantId: 'YaVSonfX5bS8', + sidePanel: true + } + } + }, + + carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' } + }, + + locales: { + root: { label: 'English', lang: 'en-US', dir: 'ltr' }, + zh: { label: '简体中文', lang: 'zh-Hans', dir: 'ltr' }, + pt: { label: 'Português', lang: 'pt-BR', dir: 'ltr' }, + ru: { label: 'Русский', lang: 'ru-RU', dir: 'ltr' }, + es: { label: 'Español', lang: 'es', dir: 'ltr' }, + ko: { label: '한국어', lang: 'ko-KR', dir: 'ltr' }, + fa: { label: 'فارسی', lang: 'fa-IR', dir: 'rtl' }, + ja: { label: '日本語', lang: 'ja', dir: 'ltr' } + }, + + vite: { + plugins: [ + groupIconVitePlugin({ + customIcon: { + vitepress: localIconLoader( + import.meta.url, + '../public/vitepress-logo-mini.svg' + ), + firebase: 'logos:firebase' + } + }), + prod && llmstxt({ workDir: 'en', ignoreFiles: ['index.md'] }) + ], + experimental: { + enableNativePlugin: true + } + }, + + // prettier-ignore + transformPageData: prod ? (pageData, ctx) => { + const url = new URL(pageData.relativePath.replace(/(?:(^|\/)index)?\.md$/, '$1'), siteUrl).href + const site = resolveSiteDataByRoute(ctx.siteConfig.site, pageData.relativePath) + const title = pageData.title ? `${pageData.title} | VitePress` : site.title + const description = pageData.description || site.description + const locale = localeToOgLocaleMap[site.localeIndex || 'root'] + + ;((pageData.frontmatter.head ??= []) as HeadConfig[]).push( + ['meta', { property: 'og:url', content: url }], + ['meta', { property: 'og:title', content: title }], + ['meta', { property: 'og:description', content: description }], + ['meta', { property: 'og:type', content: 'website' }], + ['meta', { property: 'og:locale', content: locale }], + ['meta', { property: 'og:site_name', content: 'VitePress' }], + ['meta', { property: 'og:image', content: ogImage }], + ['meta', { property: 'og:image:secure_url', content: ogImage }], + ['meta', { property: 'og:image:type', content: 'image/jpeg' }], + ['meta', { property: 'og:image:width', content: '1280' }], + ['meta', { property: 'og:image:height', content: '640' }], + ['meta', { property: 'og:image:alt', content: 'VitePress' }], + ['link', { rel: 'canonical', href: url }] + ) + } : undefined +}) diff --git a/docs/.vitepress/config/es.ts b/docs/.vitepress/config/es.ts deleted file mode 100644 index d30fc89f8..000000000 --- a/docs/.vitepress/config/es.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const es = defineConfig({ - lang: 'es-CO', - description: 'Generador de Sitios Estaticos desarrollado con Vite y Vue.', - - themeConfig: { - nav: nav(), - - sidebar: { - '/es/guide/': { base: '/es/guide/', items: sidebarGuide() }, - '/es/reference/': { base: '/es/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: 'Editar esta página en GitHub' - }, - - footer: { - message: 'Liberado bajo la licencia MIT', - copyright: `Derechos reservados © 2019-${new Date().getFullYear()} Evan You` - }, - - docFooter: { - prev: 'Anterior', - next: 'Siguiente' - }, - - outline: { - label: 'En esta página' - }, - - lastUpdated: { - text: 'Actualizado en', - formatOptions: { - dateStyle: 'short', - timeStyle: 'medium' - } - }, - - langMenuLabel: 'Cambiar Idioma', - returnToTopLabel: 'Volver arriba', - sidebarMenuLabel: 'Menu Lateral', - darkModeSwitchLabel: 'Tema Oscuro', - lightModeSwitchTitle: 'Cambiar a modo claro', - darkModeSwitchTitle: 'Cambiar a modo oscuro', - skipToContentLabel: 'Saltar al contenido' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: 'Guia', - link: '/es/guide/what-is-vitepress', - activeMatch: '/es/guide/' - }, - { - text: 'Referencia', - link: '/es/reference/site-config', - activeMatch: '/es/reference/' - }, - { - text: pkg.version, - items: [ - { - text: 'Registro de cambios', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: 'Contribuir', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Introducción', - collapsed: false, - items: [ - { text: 'Qué es VitePress?', link: 'what-is-vitepress' }, - { text: 'Iniciando', link: 'getting-started' }, - { text: 'Enrutamiento', link: 'routing' }, - { text: 'Despliegue', link: 'deploy' } - ] - }, - { - text: 'Escribiendo', - collapsed: false, - items: [ - { text: 'Extensiones Markdown', link: 'markdown' }, - { text: 'Manejo de assets', link: 'asset-handling' }, - { text: 'Frontmatter', link: 'frontmatter' }, - { text: 'Usando Vue en Markdown', link: 'using-vue' }, - { text: 'Internacionalización', link: 'i18n' } - ] - }, - { - text: 'Pesonalización', - collapsed: false, - items: [ - { text: 'Usando un tema personalizado', link: 'custom-theme' }, - { - text: 'Extendiendo el tema por defecto', - link: 'extending-default-theme' - }, - { - text: 'Carga de datos en tiempo de compilación', - link: 'data-loading' - }, - { text: 'Compatibilidad SSR', link: 'ssr-compat' }, - { text: 'Conectando a un CMS', link: 'cms' } - ] - }, - { - text: 'Experimental', - collapsed: false, - items: [ - { text: 'Modo MPA', link: 'mpa-mode' }, - { text: 'Generación de Sitemap', link: 'sitemap-generation' } - ] - }, - { - text: 'Configuración y Referencia del API', - base: '/es/reference/', - link: 'site-config' - } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Referencia', - items: [ - { text: 'Configuración del sitio', link: 'site-config' }, - { text: 'Configuración Frontmatter', link: 'frontmatter-config' }, - { text: 'API de tiempo de ejecución', link: 'runtime-api' }, - { text: 'CLI', link: 'cli' }, - { - text: 'Tema por defecto', - base: '/es/reference/default-theme-', - items: [ - { text: 'Visión general', link: 'config' }, - { text: 'Navegación', link: 'nav' }, - { text: 'Barra Lateral', link: 'sidebar' }, - { text: 'Página Inicial', link: 'home-page' }, - { text: 'Pie de página', link: 'footer' }, - { text: 'Layout', link: 'layout' }, - { text: 'Distintivo', link: 'badge' }, - { text: 'Página del equipo', link: 'team-page' }, - { text: 'Links Anterior / Siguiente', link: 'prev-next-links' }, - { text: 'Editar Link', link: 'edit-link' }, - { text: 'Sello temporal de actualización', link: 'last-updated' }, - { text: 'Busqueda', link: 'search' }, - { text: 'Carbon Ads', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - es: { - placeholder: 'Buscar documentos', - translations: { - button: { - buttonText: 'Buscar', - buttonAriaLabel: 'Buscar' - }, - modal: { - searchBox: { - resetButtonTitle: 'Limpiar búsqueda', - resetButtonAriaLabel: 'Limpiar búsqueda', - cancelButtonText: 'Cancelar', - cancelButtonAriaLabel: 'Cancelar' - }, - startScreen: { - recentSearchesTitle: 'Historial de búsqueda', - noRecentSearchesText: 'Ninguna búsqueda reciente', - saveRecentSearchButtonTitle: 'Guardar en el historial de búsqueda', - removeRecentSearchButtonTitle: 'Borrar del historial de búsqueda', - favoriteSearchesTitle: 'Favoritos', - removeFavoriteSearchButtonTitle: 'Borrar de favoritos' - }, - errorScreen: { - titleText: 'No fue posible obtener resultados', - helpText: 'Verifique su conexión de red' - }, - footer: { - selectText: 'Seleccionar', - navigateText: 'Navegar', - closeText: 'Cerrar', - searchByText: 'Busqueda por' - }, - noResultsScreen: { - noResultsText: 'No fue posible encontrar resultados', - suggestedQueryText: 'Puede intentar una nueva búsqueda', - reportMissingResultsText: - 'Deberian haber resultados para esa consulta?', - reportMissingResultsLinkText: 'Click para enviar feedback' - } - } - } - } -} diff --git a/docs/.vitepress/config/fa.ts b/docs/.vitepress/config/fa.ts deleted file mode 100644 index 5c91d0bc7..000000000 --- a/docs/.vitepress/config/fa.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const fa = defineConfig({ - title: 'ویت‌پرس', - lang: 'fa-IR', - description: 'Vite & Vue powered static site generator.', - dir: 'rtl', - markdown: { - container: { - tipLabel: 'نکته', - warningLabel: 'هشدار', - dangerLabel: 'خطر', - infoLabel: 'اطلاعات', - detailsLabel: 'جزئیات' - } - }, - themeConfig: { - nav: nav(), - sidebar: { - '/fa/guide/': { base: '/fa/guide/', items: sidebarGuide() }, - '/fa/reference/': { base: '/fa/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: 'ویرایش این صفحه در گیت‌هاب' - }, - - footer: { - message: 'انتشار یافته تحت لایسنس MIT', - copyright: 'حق نسخه‌برداری © 2019-کنون Evan You' - }, - - docFooter: { - prev: 'قبلی', - next: 'بعدی' - }, - - outline: { - label: 'در این صفحه' - }, - - lastUpdated: { - text: 'آخرین به‌روزرسانی‌', - formatOptions: { - dateStyle: 'short', - timeStyle: 'medium' - } - }, - - langMenuLabel: 'تغییر زبان', - returnToTopLabel: 'بازگشت به بالا', - sidebarMenuLabel: 'منوی جانبی', - darkModeSwitchLabel: 'تم تاریک', - lightModeSwitchTitle: 'رفتن به حالت روشن', - darkModeSwitchTitle: 'رفتن به حالت تاریک', - notFound: { - linkLabel: 'بازگشت به خانه', - linkText: 'بازگشت به خانه', - title: 'صفحه مورد نظر یافت نشد', - code: '۴۰۴', - quote: - 'اما اگر جهت خود را تغییر ندهید و اگر ادامه دهید به دنبال چیزی که دنبال می‌کنید، ممکن است در نهایت به جایی که در حال رفتن به سمتش هستید، برسید.' - }, - siteTitle: 'ویت‌پرس' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: 'راهنما', - link: 'fa/guide/what-is-vitepress', - activeMatch: '/guide/' - }, - { - text: 'مرجع', - link: 'fa/reference/site-config', - activeMatch: '/reference/' - }, - { - text: pkg.version, - items: [ - { - text: 'Changelog', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: 'مشارکت', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'معرفی', - collapsed: false, - items: [ - { text: 'ویت‌پرس چیست؟', link: 'what-is-vitepress' }, - { text: 'شروع کار', link: 'getting-started' }, - { text: 'مسیریابی', link: 'routing' }, - { text: 'استقرار', link: 'deploy' } - ] - }, - { - text: 'نوشتن', - collapsed: false, - items: [ - { text: 'افزونه‌های Markdown', link: 'markdown' }, - { text: 'مدیریت منابع', link: 'asset-handling' }, - { text: 'Frontmatter', link: 'frontmatter' }, - { text: 'استفاده از Vue در Markdown', link: 'using-vue' }, - { text: 'بین‌المللی سازی', link: 'i18n' } - ] - }, - { - text: 'شخصی‌سازی', - collapsed: false, - items: [ - { text: 'استفاده از تم شخصی', link: 'custom-theme' }, - { - text: 'گسترش تم پیش‌فرض', - link: 'extending-default-theme' - }, - { text: 'بارگیری داده در زمان Build', link: 'data-loading' }, - { text: 'سازگاری SSR', link: 'ssr-compat' }, - { text: 'اتصال به CMS', link: 'cms' } - ] - }, - { - text: 'آزمایشی', - collapsed: false, - items: [ - { text: 'حالت MPA', link: 'mpa-mode' }, - { text: 'جنریت کردن Sitemap', link: 'sitemap-generation' } - ] - }, - { text: 'پیکربندی و مرجع API', base: 'fa/reference/', link: 'site-config' } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'مرجع', - base: 'fa/reference/', - items: [ - { text: 'پیکربندی Site', link: 'site-config' }, - { text: 'پیکربندی Frontmatter', link: 'frontmatter-config' }, - { text: 'Runtime API', link: 'runtime-api' }, - { text: 'CLI', link: 'cli' }, - { - text: 'تم پیش‌فرض', - base: 'fa/reference/default-theme-', - items: [ - { text: 'بررسی اجمالی', link: 'config' }, - { text: 'ناوبری', link: 'nav' }, - { text: 'نوار کنار صفحه', link: 'sidebar' }, - { text: 'صفحه اصلی', link: 'home-page' }, - { text: 'پاورقی', link: 'footer' }, - { text: 'طرح', link: 'layout' }, - { text: 'نشان', link: 'badge' }, - { text: 'صفحه تیم', link: 'team-page' }, - { text: 'لینک‌های قبلی / بعدی', link: 'prev-next-links' }, - { text: 'ویرایش لینک', link: 'edit-link' }, - { text: 'Timestamp آخرین به‌روزرسانی', link: 'last-updated' }, - { text: 'جستجو', link: 'search' }, - { text: 'تبلیغات Carbon', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - fa: { - placeholder: 'جستجوی مستندات', - translations: { - button: { - buttonText: 'جستجو', - buttonAriaLabel: 'جستجو' - }, - modal: { - searchBox: { - resetButtonTitle: 'آغاز مجدد جستجو', - resetButtonAriaLabel: 'آغاز مجدد جستجو', - cancelButtonText: 'لغو', - cancelButtonAriaLabel: 'لغو' - }, - startScreen: { - recentSearchesTitle: 'جستجو‌های اخیر', - noRecentSearchesText: 'تاریخچه جستجویی یافت نشد.', - saveRecentSearchButtonTitle: 'ذخیره تاریخچه جستجو', - removeRecentSearchButtonTitle: 'حذف تاریخچه جستجو', - favoriteSearchesTitle: 'موارد دلخواه', - removeFavoriteSearchButtonTitle: 'حذف مورد دلخواه' - }, - errorScreen: { - titleText: 'نتیجه‌ای یافت نشد برای', - helpText: 'اتصال شبکه خود را بررسی کنید' - }, - footer: { - selectText: 'انتخاب', - navigateText: 'رفتن', - closeText: 'بستن', - searchByText: ' جستجو با ' - }, - noResultsScreen: { - noResultsText: 'نتیجه‌ای یافت نشد برای' - } - } - } - } -} diff --git a/docs/.vitepress/config/index.ts b/docs/.vitepress/config/index.ts deleted file mode 100644 index 08a81fb94..000000000 --- a/docs/.vitepress/config/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig } from 'vitepress' -import { shared } from './shared' -import { en } from './en' -import { zh } from './zh' -import { pt } from './pt' -import { ru } from './ru' -import { es } from './es' -import { ko } from './ko' -import { fa } from './fa' - -export default defineConfig({ - ...shared, - locales: { - root: { label: 'English', ...en }, - zh: { label: '简体中文', ...zh }, - pt: { label: 'Português', ...pt }, - ru: { label: 'Русский', ...ru }, - es: { label: 'Español', ...es }, - ko: { label: '한국어', ...ko }, - fa: { label: 'فارسی', ...fa } - } -}) diff --git a/docs/.vitepress/config/ko.ts b/docs/.vitepress/config/ko.ts deleted file mode 100644 index faebabf44..000000000 --- a/docs/.vitepress/config/ko.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const ko = defineConfig({ - lang: 'ko-KR', - description: 'Vite 및 Vue 기반 정적 사이트 생성기.', - - themeConfig: { - nav: nav(), - - sidebar: { - '/ko/guide/': { base: '/ko/guide/', items: sidebarGuide() }, - '/ko/reference/': { base: '/ko/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: '이 페이지 편집 제안하기' - }, - - footer: { - message: 'Released under the MIT License.', - copyright: 'Copyright © 2019-present Evan You' - }, - - docFooter: { - prev: '이전', - next: '다음' - }, - - outline: { - label: '이 페이지 목차' - }, - - lastUpdated: { - text: '업데이트 날짜' - }, - - langMenuLabel: '언어 변경', - returnToTopLabel: '맨 위로 돌아가기', - sidebarMenuLabel: '사이드바 메뉴', - darkModeSwitchLabel: '다크 모드', - lightModeSwitchTitle: '라이트 모드로 변경', - darkModeSwitchTitle: '다크 모드로 변경', - skipToContentLabel: '본문으로 건너뛰기' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: '가이드', - link: '/ko/guide/what-is-vitepress', - activeMatch: '/ko/guide/' - }, - { - text: '레퍼런스', - link: '/ko/reference/site-config', - activeMatch: '/ko/reference/' - }, - { - text: pkg.version, - items: [ - { - text: '변경 로그', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: '기여', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: '소개', - collapsed: false, - items: [ - { - text: 'VitePress란 무엇인가?', - link: 'what-is-vitepress' - }, - { - text: '시작하기', - link: 'getting-started' - }, - { - text: '라우팅', - link: 'routing' - }, - { - text: '배포하기', - link: 'deploy' - } - ] - }, - { - text: '글쓰기', - collapsed: false, - items: [ - { - text: '마크다운 확장 기능', - link: 'markdown' - }, - { - text: '에셋 핸들링', - link: 'asset-handling' - }, - { - text: '전문(Front-matter)', - link: 'frontmatter' - }, - { - text: '마크다운에서 Vue 사용하기', - link: 'using-vue' - }, - { - text: 'i18n', - link: 'i18n' - } - ] - }, - { - text: '커스텀', - collapsed: false, - items: [ - { - text: '커스텀 테마 사용하기', - link: 'custom-theme' - }, - { - text: '기본 테마 확장하기', - link: 'extending-default-theme' - }, - { - text: '빌드할 때 데이터 로딩하기', - link: 'data-loading' - }, - { - text: 'SSR 호환성', - link: 'ssr-compat' - }, - { - text: 'CMS 연결하기', - link: 'cms' - } - ] - }, - { - text: '실험적인', - collapsed: false, - items: [ - { - text: 'MPA 모드', - link: 'mpa-mode' - }, - { - text: '사이트맵 생성', - link: 'sitemap-generation' - } - ] - }, - { - text: '구성 & API 레퍼런스', - base: '/ko/reference/', - link: 'site-config' - } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: '레퍼런스', - items: [ - { text: '사이트 구성', link: 'site-config' }, - { text: '전문(front-matter) 구성', link: 'frontmatter-config' }, - { text: '런타임 API', link: 'runtime-api' }, - { text: 'CLI', link: 'cli' }, - { - text: '기본 테마', - base: '/ko/reference/default-theme-', - items: [ - { text: '개요', link: 'config' }, - { text: '네비게이션 바', link: 'nav' }, - { text: '사이드바', link: 'sidebar' }, - { text: '홈 페이지', link: 'home-page' }, - { text: '푸터', link: 'footer' }, - { text: '레이아웃', link: 'layout' }, - { text: '배지(badge)', link: 'badge' }, - { text: '팀 페이지', link: 'team-page' }, - { text: '이전/다음 링크', link: 'prev-next-links' }, - { text: '편집 링크', link: 'edit-link' }, - { text: '마지막 업데이트 날짜', link: 'last-updated' }, - { text: '검색', link: 'search' }, - { text: '카본 광고', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - ko: { - placeholder: '문서 검색', - translations: { - button: { - buttonText: '검색', - buttonAriaLabel: '검색' - }, - modal: { - searchBox: { - resetButtonTitle: '검색 지우기', - resetButtonAriaLabel: '검색 지우기', - cancelButtonText: '취소', - cancelButtonAriaLabel: '취소' - }, - startScreen: { - recentSearchesTitle: '검색 기록', - noRecentSearchesText: '최근 검색 없음', - saveRecentSearchButtonTitle: '검색 기록에 저장', - removeRecentSearchButtonTitle: '검색 기록에서 삭제', - favoriteSearchesTitle: '즐겨찾기', - removeFavoriteSearchButtonTitle: '즐겨찾기에서 삭제' - }, - errorScreen: { - titleText: '결과를 가져올 수 없습니다', - helpText: '네트워크 연결을 확인하세요' - }, - footer: { - selectText: '선택', - navigateText: '탐색', - closeText: '닫기', - searchByText: '검색 기준' - }, - noResultsScreen: { - noResultsText: '결과를 찾을 수 없습니다', - suggestedQueryText: '새로운 검색을 시도할 수 있습니다', - reportMissingResultsText: '해당 검색어에 대한 결과가 있어야 합니까?', - reportMissingResultsLinkText: '피드백 보내기 클릭' - } - } - } - } -} diff --git a/docs/.vitepress/config/pt.ts b/docs/.vitepress/config/pt.ts deleted file mode 100644 index 12cb52fae..000000000 --- a/docs/.vitepress/config/pt.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const pt = defineConfig({ - lang: 'pt-BR', - description: 'Gerador de Site Estático desenvolvido com Vite e Vue.', - - themeConfig: { - nav: nav(), - - sidebar: { - '/pt/guide/': { base: '/pt/guide/', items: sidebarGuide() }, - '/pt/reference/': { base: '/pt/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: 'Edite esta página no GitHub' - }, - - footer: { - message: 'Lançado sob licença MIT', - copyright: `Direitos reservados © 2019-${new Date().getFullYear()} Evan You` - }, - - docFooter: { - prev: 'Anterior', - next: 'Próximo' - }, - - outline: { - label: 'Nesta página' - }, - - lastUpdated: { - text: 'Atualizado em', - formatOptions: { - dateStyle: 'short', - timeStyle: 'medium' - } - }, - - langMenuLabel: 'Alterar Idioma', - returnToTopLabel: 'Voltar ao Topo', - sidebarMenuLabel: 'Menu Lateral', - darkModeSwitchLabel: 'Tema Escuro', - lightModeSwitchTitle: 'Mudar para Modo Claro', - darkModeSwitchTitle: 'Mudar para Modo Escuro', - skipToContentLabel: 'Pular para o Conteúdo' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: 'Guia', - link: '/pt/guide/what-is-vitepress', - activeMatch: '/pt/guide/' - }, - { - text: 'Referência', - link: '/pt/reference/site-config', - activeMatch: '/pt/reference/' - }, - { - text: pkg.version, - items: [ - { - text: 'Registro de Mudanças', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: 'Contribuindo', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Introdução', - collapsed: false, - items: [ - { text: 'O que é VitePress?', link: 'what-is-vitepress' }, - { text: 'Iniciando', link: 'getting-started' }, - { text: 'Roteamento', link: 'routing' }, - { text: 'Implantação', link: 'deploy' } - ] - }, - { - text: 'Escrevendo', - collapsed: false, - items: [ - { text: 'Extensões Markdown', link: 'markdown' }, - { text: 'Manipulando Ativos', link: 'asset-handling' }, - { text: 'Frontmatter', link: 'frontmatter' }, - { text: 'Usando Vue em Markdown', link: 'using-vue' }, - { text: 'Internacionalização', link: 'i18n' } - ] - }, - { - text: 'Personalização', - collapsed: false, - items: [ - { text: 'Usando um tema personalizado', link: 'custom-theme' }, - { text: 'Estendendo o tema padrão', link: 'extending-default-theme' }, - { - text: 'Carregamento de dados no momento da compilação', - link: 'data-loading' - }, - { text: 'Compatibilidade SSR', link: 'ssr-compat' }, - { text: 'Conectando a um CMS', link: 'cms' } - ] - }, - { - text: 'Experimental', - collapsed: false, - items: [ - { text: 'Modo MPA', link: 'mpa-mode' }, - { text: 'Geração de Sitemap', link: 'sitemap-generation' } - ] - }, - { - text: 'Configuração e Referência da API', - base: '/pt/reference/', - link: 'site-config' - } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Referência', - items: [ - { text: 'Configuração do Site', link: 'site-config' }, - { text: 'Configuração Frontmatter', link: 'frontmatter-config' }, - { text: 'API do tempo de execução', link: 'runtime-api' }, - { text: 'CLI', link: 'cli' }, - { - text: 'Tema padrão', - base: '/pt/reference/default-theme-', - items: [ - { text: 'Visão Geral', link: 'config' }, - { text: 'Navegação', link: 'nav' }, - { text: 'Barra Lateral', link: 'sidebar' }, - { text: 'Página Inicial', link: 'home-page' }, - { text: 'Rodapé', link: 'footer' }, - { text: 'Layout', link: 'layout' }, - { text: 'Distintivo', link: 'badge' }, - { text: 'Página da Equipe', link: 'team-page' }, - { text: 'Links Anterior / Próximo', link: 'prev-next-links' }, - { text: 'Editar Link', link: 'edit-link' }, - { text: 'Selo Temporal de Atualização', link: 'last-updated' }, - { text: 'Busca', link: 'search' }, - { text: 'Carbon Ads', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - pt: { - placeholder: 'Pesquisar documentos', - translations: { - button: { - buttonText: 'Pesquisar', - buttonAriaLabel: 'Pesquisar' - }, - modal: { - searchBox: { - resetButtonTitle: 'Limpar pesquisa', - resetButtonAriaLabel: 'Limpar pesquisa', - cancelButtonText: 'Cancelar', - cancelButtonAriaLabel: 'Cancelar' - }, - startScreen: { - recentSearchesTitle: 'Histórico de Pesquisa', - noRecentSearchesText: 'Nenhuma pesquisa recente', - saveRecentSearchButtonTitle: 'Salvar no histórico de pesquisas', - removeRecentSearchButtonTitle: 'Remover do histórico de pesquisas', - favoriteSearchesTitle: 'Favoritos', - removeFavoriteSearchButtonTitle: 'Remover dos favoritos' - }, - errorScreen: { - titleText: 'Não foi possível obter resultados', - helpText: 'Verifique a sua conexão de rede' - }, - footer: { - selectText: 'Selecionar', - navigateText: 'Navegar', - closeText: 'Fechar', - searchByText: 'Pesquisa por' - }, - noResultsScreen: { - noResultsText: 'Não foi possível encontrar resultados', - suggestedQueryText: 'Você pode tentar uma nova consulta', - reportMissingResultsText: - 'Deveriam haver resultados para essa consulta?', - reportMissingResultsLinkText: 'Clique para enviar feedback' - } - } - } - } -} diff --git a/docs/.vitepress/config/ru.ts b/docs/.vitepress/config/ru.ts deleted file mode 100644 index b75b1b77e..000000000 --- a/docs/.vitepress/config/ru.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const ru = defineConfig({ - lang: 'ru-RU', - description: 'Генератор статических сайтов на основе Vite и Vue.', - - themeConfig: { - nav: nav(), - - sidebar: { - '/ru/guide/': { base: '/ru/guide/', items: sidebarGuide() }, - '/ru/reference/': { base: '/ru/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: 'Редактировать страницу' - }, - - footer: { - message: 'Опубликовано под лицензией MIT.', - copyright: '© 2019 – настоящее время, Эван Ю' - }, - - outline: { label: 'Содержание страницы' }, - - docFooter: { - prev: 'Предыдущая страница', - next: 'Следующая страница' - }, - - lastUpdated: { - text: 'Обновлено' - }, - - darkModeSwitchLabel: 'Оформление', - lightModeSwitchTitle: 'Переключить на светлую тему', - darkModeSwitchTitle: 'Переключить на тёмную тему', - sidebarMenuLabel: 'Меню', - returnToTopLabel: 'Вернуться к началу', - langMenuLabel: 'Изменить язык', - skipToContentLabel: 'Перейти к содержимому' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: 'Руководство', - link: '/ru/guide/what-is-vitepress', - activeMatch: '/ru/guide/' - }, - { - text: 'Справочник', - link: '/ru/reference/site-config', - activeMatch: '/ru/reference/' - }, - { - text: pkg.version, - items: [ - { - text: 'Изменения', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: 'Вклад', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Введение', - collapsed: false, - items: [ - { text: 'Что такое VitePress?', link: 'what-is-vitepress' }, - { text: 'Первые шаги', link: 'getting-started' }, - { text: 'Маршрутизация', link: 'routing' }, - { text: 'Развёртывание', link: 'deploy' } - ] - }, - { - text: 'Написание', - collapsed: false, - items: [ - { text: 'Расширения Markdown', link: 'markdown' }, - { text: 'Обработка ресурсов', link: 'asset-handling' }, - { text: 'Метаданные', link: 'frontmatter' }, - { text: 'Использование Vue в Markdown', link: 'using-vue' }, - { text: 'Интернационализация', link: 'i18n' } - ] - }, - { - text: 'Настройка', - collapsed: false, - items: [ - { text: 'Пользовательская тема', link: 'custom-theme' }, - { - text: 'Расширение темы по умолчанию', - link: 'extending-default-theme' - }, - { - text: 'Загрузка данных в режиме реального времени', - link: 'data-loading' - }, - { text: 'Совместимость с SSR', link: 'ssr-compat' }, - { text: 'Подключение к CMS', link: 'cms' } - ] - }, - { - text: 'Экспериментально', - collapsed: false, - items: [ - { text: 'Режим MPA', link: 'mpa-mode' }, - { text: 'Генерация карты сайта', link: 'sitemap-generation' } - ] - }, - { text: 'Конфигурация и API', base: '/ru/reference/', link: 'site-config' } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: 'Справочник', - items: [ - { text: 'Конфигурация сайта', link: 'site-config' }, - { text: 'Конфигурация метаданных', link: 'frontmatter-config' }, - { text: 'Runtime API', link: 'runtime-api' }, - { text: 'Командная строка', link: 'cli' }, - { - text: 'Тема по умолчанию', - base: '/ru/reference/default-theme-', - items: [ - { text: 'Обзор', link: 'config' }, - { text: 'Навигация', link: 'nav' }, - { text: 'Сайдбар', link: 'sidebar' }, - { text: 'Главная страница', link: 'home-page' }, - { text: 'Футер', link: 'footer' }, - { text: 'Макет', link: 'layout' }, - { text: 'Значки', link: 'badge' }, - { text: 'Страница команды', link: 'team-page' }, - { - text: 'Предыдущая и следующая страницы', - link: 'prev-next-links' - }, - { text: 'Ссылка для редактирования', link: 'edit-link' }, - { text: 'Последнее обновление', link: 'last-updated' }, - { text: 'Поиск', link: 'search' }, - { text: 'Carbon Ads (реклама)', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - ru: { - placeholder: 'Поиск в документации', - translations: { - button: { - buttonText: 'Поиск', - buttonAriaLabel: 'Поиск' - }, - modal: { - searchBox: { - resetButtonTitle: 'Сбросить поиск', - resetButtonAriaLabel: 'Сбросить поиск', - cancelButtonText: 'Отменить поиск', - cancelButtonAriaLabel: 'Отменить поиск' - }, - startScreen: { - recentSearchesTitle: 'История поиска', - noRecentSearchesText: 'Нет истории поиска', - saveRecentSearchButtonTitle: 'Сохранить в истории поиска', - removeRecentSearchButtonTitle: 'Удалить из истории поиска', - favoriteSearchesTitle: 'Избранное', - removeFavoriteSearchButtonTitle: 'Удалить из избранного' - }, - errorScreen: { - titleText: 'Невозможно получить результаты', - helpText: 'Вам может потребоваться проверить подключение к Интернету' - }, - footer: { - selectText: 'выбрать', - navigateText: 'перейти', - closeText: 'закрыть', - searchByText: 'поставщик поиска' - }, - noResultsScreen: { - noResultsText: 'Нет результатов для', - suggestedQueryText: 'Вы можете попытаться узнать', - reportMissingResultsText: - 'Считаете, что поиск даёт ложные результаты?', - reportMissingResultsLinkText: 'Нажмите на кнопку «Обратная связь»' - } - } - } - } -} diff --git a/docs/.vitepress/config/shared.ts b/docs/.vitepress/config/shared.ts deleted file mode 100644 index 1f4961d29..000000000 --- a/docs/.vitepress/config/shared.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { defineConfig } from 'vitepress' -import { - groupIconMdPlugin, - groupIconVitePlugin, - localIconLoader -} from 'vitepress-plugin-group-icons' -import { search as esSearch } from './es' -import { search as faSearch } from './fa' -import { search as koSearch } from './ko' -import { search as ptSearch } from './pt' -import { search as ruSearch } from './ru' -import { search as zhSearch } from './zh' - -export const shared = defineConfig({ - title: 'VitePress', - - rewrites: { - 'en/:rest*': ':rest*' - }, - - lastUpdated: true, - cleanUrls: true, - metaChunk: true, - - markdown: { - math: true, - codeTransformers: [ - // We use `[!!code` in demo to prevent transformation, here we revert it back. - { - postprocess(code) { - return code.replace(/\[\!\!code/g, '[!code') - } - } - ], - config(md) { - // TODO: remove when https://github.com/vuejs/vitepress/issues/4431 is fixed - const fence = md.renderer.rules.fence! - md.renderer.rules.fence = function (tokens, idx, options, env, self) { - const { localeIndex = 'root' } = env - const codeCopyButtonTitle = (() => { - switch (localeIndex) { - case 'es': - return 'Copiar código' - case 'fa': - return 'کپی کد' - case 'ko': - return '코드 복사' - case 'pt': - return 'Copiar código' - case 'ru': - return 'Скопировать код' - case 'zh': - return '复制代码' - default: - return 'Copy code' - } - })() - return fence(tokens, idx, options, env, self).replace( - '', - `` - ) - } - md.use(groupIconMdPlugin) - } - }, - - sitemap: { - hostname: 'https://vitepress.dev', - transformItems(items) { - return items.filter((item) => !item.url.includes('migration')) - } - }, - - /* prettier-ignore */ - head: [ - ['link', { rel: 'icon', type: 'image/svg+xml', href: '/vitepress-logo-mini.svg' }], - ['link', { rel: 'icon', type: 'image/png', href: '/vitepress-logo-mini.png' }], - ['meta', { name: 'theme-color', content: '#5f67ee' }], - ['meta', { property: 'og:type', content: 'website' }], - ['meta', { property: 'og:locale', content: 'en' }], - ['meta', { property: 'og:title', content: 'VitePress | Vite & Vue Powered Static Site Generator' }], - ['meta', { property: 'og:site_name', content: 'VitePress' }], - ['meta', { property: 'og:image', content: 'https://vitepress.dev/vitepress-og.jpg' }], - ['meta', { property: 'og:url', content: 'https://vitepress.dev/' }], - ['script', { src: 'https://cdn.usefathom.com/script.js', 'data-site': 'AZBRSFGG', 'data-spa': 'auto', defer: '' }] - ], - - themeConfig: { - logo: { src: '/vitepress-logo-mini.svg', width: 24, height: 24 }, - - socialLinks: [ - { icon: 'github', link: 'https://github.com/vuejs/vitepress' } - ], - - search: { - provider: 'algolia', - options: { - appId: '8J64VVRP8K', - apiKey: '52f578a92b88ad6abde815aae2b0ad7c', - indexName: 'vitepress', - locales: { - ...zhSearch, - ...ptSearch, - ...ruSearch, - ...esSearch, - ...koSearch, - ...faSearch - } - } - }, - - carbonAds: { code: 'CEBDT27Y', placement: 'vuejsorg' } - }, - vite: { - plugins: [ - groupIconVitePlugin({ - customIcon: { - vitepress: localIconLoader( - import.meta.url, - '../../public/vitepress-logo-mini.svg' - ), - firebase: 'logos:firebase' - } - }) - ] - } -}) diff --git a/docs/.vitepress/config/zh.ts b/docs/.vitepress/config/zh.ts deleted file mode 100644 index e9d5fbcd4..000000000 --- a/docs/.vitepress/config/zh.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' - -const require = createRequire(import.meta.url) -const pkg = require('vitepress/package.json') - -export const zh = defineConfig({ - lang: 'zh-Hans', - description: '由 Vite 和 Vue 驱动的静态站点生成器', - - themeConfig: { - nav: nav(), - - sidebar: { - '/zh/guide/': { base: '/zh/guide/', items: sidebarGuide() }, - '/zh/reference/': { base: '/zh/reference/', items: sidebarReference() } - }, - - editLink: { - pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', - text: '在 GitHub 上编辑此页面' - }, - - footer: { - message: '基于 MIT 许可发布', - copyright: `版权所有 © 2019-${new Date().getFullYear()} 尤雨溪` - }, - - docFooter: { - prev: '上一页', - next: '下一页' - }, - - outline: { - label: '页面导航' - }, - - lastUpdated: { - text: '最后更新于', - formatOptions: { - dateStyle: 'short', - timeStyle: 'medium' - } - }, - - langMenuLabel: '多语言', - returnToTopLabel: '回到顶部', - sidebarMenuLabel: '菜单', - darkModeSwitchLabel: '主题', - lightModeSwitchTitle: '切换到浅色模式', - darkModeSwitchTitle: '切换到深色模式', - skipToContentLabel: '跳转到内容' - } -}) - -function nav(): DefaultTheme.NavItem[] { - return [ - { - text: '指南', - link: '/zh/guide/what-is-vitepress', - activeMatch: '/zh/guide/' - }, - { - text: '参考', - link: '/zh/reference/site-config', - activeMatch: '/zh/reference/' - }, - { - text: pkg.version, - items: [ - { - text: '更新日志', - link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' - }, - { - text: '参与贡献', - link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' - } - ] - } - ] -} - -function sidebarGuide(): DefaultTheme.SidebarItem[] { - return [ - { - text: '简介', - collapsed: false, - items: [ - { text: '什么是 VitePress?', link: 'what-is-vitepress' }, - { text: '快速开始', link: 'getting-started' }, - { text: '路由', link: 'routing' }, - { text: '部署', link: 'deploy' } - ] - }, - { - text: '写作', - collapsed: false, - items: [ - { text: 'Markdown 扩展', link: 'markdown' }, - { text: '资源处理', link: 'asset-handling' }, - { text: 'frontmatter', link: 'frontmatter' }, - { text: '在 Markdown 使用 Vue', link: 'using-vue' }, - { text: '国际化', link: 'i18n' } - ] - }, - { - text: '自定义', - collapsed: false, - items: [ - { text: '自定义主题', link: 'custom-theme' }, - { text: '扩展默认主题', link: 'extending-default-theme' }, - { text: '构建时数据加载', link: 'data-loading' }, - { text: 'SSR 兼容性', link: 'ssr-compat' }, - { text: '连接 CMS', link: 'cms' } - ] - }, - { - text: '实验性功能', - collapsed: false, - items: [ - { text: 'MPA 模式', link: 'mpa-mode' }, - { text: 'sitemap 生成', link: 'sitemap-generation' } - ] - }, - { text: '配置和 API 参考', base: '/zh/reference/', link: 'site-config' } - ] -} - -function sidebarReference(): DefaultTheme.SidebarItem[] { - return [ - { - text: '参考', - items: [ - { text: '站点配置', link: 'site-config' }, - { text: 'frontmatter 配置', link: 'frontmatter-config' }, - { text: '运行时 API', link: 'runtime-api' }, - { text: 'CLI', link: 'cli' }, - { - text: '默认主题', - base: '/zh/reference/default-theme-', - items: [ - { text: '概览', link: 'config' }, - { text: '导航栏', link: 'nav' }, - { text: '侧边栏', link: 'sidebar' }, - { text: '主页', link: 'home-page' }, - { text: '页脚', link: 'footer' }, - { text: '布局', link: 'layout' }, - { text: '徽章', link: 'badge' }, - { text: '团队页', link: 'team-page' }, - { text: '上下页链接', link: 'prev-next-links' }, - { text: '编辑链接', link: 'edit-link' }, - { text: '最后更新时间戳', link: 'last-updated' }, - { text: '搜索', link: 'search' }, - { text: 'Carbon Ads', link: 'carbon-ads' } - ] - } - ] - } - ] -} - -export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = { - zh: { - placeholder: '搜索文档', - translations: { - button: { - buttonText: '搜索文档', - buttonAriaLabel: '搜索文档' - }, - modal: { - searchBox: { - resetButtonTitle: '清除查询条件', - resetButtonAriaLabel: '清除查询条件', - cancelButtonText: '取消', - cancelButtonAriaLabel: '取消' - }, - startScreen: { - recentSearchesTitle: '搜索历史', - noRecentSearchesText: '没有搜索历史', - saveRecentSearchButtonTitle: '保存至搜索历史', - removeRecentSearchButtonTitle: '从搜索历史中移除', - favoriteSearchesTitle: '收藏', - removeFavoriteSearchButtonTitle: '从收藏中移除' - }, - errorScreen: { - titleText: '无法获取结果', - helpText: '你可能需要检查你的网络连接' - }, - footer: { - selectText: '选择', - navigateText: '切换', - closeText: '关闭', - searchByText: '搜索提供者' - }, - noResultsScreen: { - noResultsText: '无法找到相关结果', - suggestedQueryText: '你可以尝试查询', - reportMissingResultsText: '你认为该查询应该有结果?', - reportMissingResultsLinkText: '点击反馈' - } - } - } - } -} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 7208825e9..0e7ba37f0 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,4 +1,5 @@ import Theme from 'vitepress/theme' import 'virtual:group-icons.css' +import './styles.css' export default Theme diff --git a/docs/.vitepress/theme/styles.css b/docs/.vitepress/theme/styles.css new file mode 100644 index 000000000..2635e80dc --- /dev/null +++ b/docs/.vitepress/theme/styles.css @@ -0,0 +1,43 @@ +:root:where(:lang(fa)) { + --vp-font-family-base: + 'Vazirmatn', 'Inter', ui-sans-serif, system-ui, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; +} + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + #bd34fe 30%, + #41d1ff + ); + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #bd34fe 50%, + #47caff 50% + ); + --vp-home-hero-image-filter: blur(44px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +.VPHero .VPImage { + filter: drop-shadow(-2px 4px 6px rgba(0, 0, 0, 0.2)); + padding: 18px; +} + +/* used in reference/default-theme-search */ +img[src='/search.png'] { + width: 100%; + aspect-ratio: 1 / 1; +} diff --git a/docs/.vitepress/config/en.ts b/docs/config.ts similarity index 94% rename from docs/.vitepress/config/en.ts rename to docs/config.ts index 1f6193477..8620d955e 100644 --- a/docs/.vitepress/config/en.ts +++ b/docs/config.ts @@ -1,11 +1,10 @@ import { createRequire } from 'module' -import { defineConfig, type DefaultTheme } from 'vitepress' +import { defineAdditionalConfig, type DefaultTheme } from 'vitepress' const require = createRequire(import.meta.url) const pkg = require('vitepress/package.json') -export const en = defineConfig({ - lang: 'en-US', +export default defineAdditionalConfig({ description: 'Vite & Vue powered static site generator.', themeConfig: { @@ -43,6 +42,10 @@ function nav(): DefaultTheme.NavItem[] { { text: pkg.version, items: [ + { + text: '1.6.4', + link: 'https://vuejs.github.io/vitepress/v1/' + }, { text: 'Changelog', link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' diff --git a/docs/en/guide/asset-handling.md b/docs/en/guide/asset-handling.md index eeedc8c02..00819d1af 100644 --- a/docs/en/guide/asset-handling.md +++ b/docs/en/guide/asset-handling.md @@ -1,3 +1,7 @@ +--- +description: Learn how to reference and handle static assets such as images, media, and fonts in VitePress. +--- + # Asset Handling ## Referencing Static Assets diff --git a/docs/en/guide/cms.md b/docs/en/guide/cms.md index 8694cf0a5..0bff6746f 100644 --- a/docs/en/guide/cms.md +++ b/docs/en/guide/cms.md @@ -1,5 +1,6 @@ --- outline: deep +description: Connect VitePress to a headless CMS using dynamic routes and data loaders. --- # Connecting to a CMS diff --git a/docs/en/guide/custom-theme.md b/docs/en/guide/custom-theme.md index 96943c9fb..c0ce85971 100644 --- a/docs/en/guide/custom-theme.md +++ b/docs/en/guide/custom-theme.md @@ -1,3 +1,7 @@ +--- +description: Create and use a custom theme in VitePress to fully control the look and feel of your site. +--- + # Using a Custom Theme ## Theme Resolving diff --git a/docs/en/guide/data-loading.md b/docs/en/guide/data-loading.md index 10ba8b574..1c11e4698 100644 --- a/docs/en/guide/data-loading.md +++ b/docs/en/guide/data-loading.md @@ -1,3 +1,7 @@ +--- +description: Load arbitrary data at build time using VitePress data loaders and import it from pages or components. +--- + # Build-Time Data Loading VitePress 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. diff --git a/docs/en/guide/deploy.md b/docs/en/guide/deploy.md index a4093df21..9c01d0eec 100644 --- a/docs/en/guide/deploy.md +++ b/docs/en/guide/deploy.md @@ -1,5 +1,6 @@ --- outline: deep +description: Deploy your VitePress site to popular platforms like Netlify, Vercel, GitHub Pages, and more. --- # Deploy Your VitePress Site @@ -105,13 +106,13 @@ Note: the `vercel.json` file should be placed at the root of your **repository** ## Platform Guides -### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render +### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic} Set up a new project and change these settings using your dashboard: - **Build Command:** `npm run docs:build` - **Output Directory:** `docs/.vitepress/dist` -- **Node Version:** `18` (or above) +- **Node Version:** `20` (or above) ::: warning Don'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. @@ -153,17 +154,17 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 # Not needed if lastUpdated is not enabled - # - uses: pnpm/action-setup@v3 # Uncomment this block if you're using pnpm + # - uses: pnpm/action-setup@v4 # Uncomment this block if you're using pnpm # with: # version: 9 # Not needed if you've set "packageManager" in package.json # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 cache: npm # or pnpm / yarn - name: Setup Pages uses: actions/configure-pages@v4 @@ -205,7 +206,7 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f 2. 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: ```yaml [.gitlab-ci.yml] - image: node:18 + image: node:24 pages: cache: paths: @@ -221,7 +222,9 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f - main ``` -### Azure Static Web Apps + + +### Azure 1. Follow the [official documentation](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration). @@ -231,6 +234,10 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f - **`output_location`**: `docs/.vitepress/dist` - **`app_build_command`**: `npm run docs:build` +### CloudRay + +You can deploy your VitePress project with [CloudRay](https://cloudray.io/) by following these [instructions](https://cloudray.io/articles/how-to-deploy-vitepress-site). + ### Firebase 1. Create `firebase.json` and `.firebaserc` at the root of your project: @@ -262,14 +269,6 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f firebase deploy ``` -### Surge - -1. After running `npm run docs:build`, run this command to deploy: - - ```sh - npx surge docs/.vitepress/dist - ``` - ### Heroku 1. Follow documentation and guide given in [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static). @@ -282,11 +281,11 @@ Don't enable options like _Auto Minify_ for HTML code. It will remove comments f } ``` -### Edgio +### Hostinger -Refer [Creating and Deploying a VitePress App To Edgio](https://docs.edg.io/guides/vitepress). +You 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`. -### Kinsta Static Site Hosting +### Kinsta You 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/). @@ -294,6 +293,14 @@ You can deploy your VitePress website on [Kinsta](https://kinsta.com/static-site You can deploy your VitePress project to [Stormkit](https://www.stormkit.io) by following these [instructions](https://stormkit.io/blog/how-to-deploy-vitepress). +### Surge + +1. After running `npm run docs:build`, run this command to deploy: + + ```sh + npx surge docs/.vitepress/dist + ``` + ### Nginx Here 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`. diff --git a/docs/en/guide/extending-default-theme.md b/docs/en/guide/extending-default-theme.md index 799d1773e..5ff15f5b5 100644 --- a/docs/en/guide/extending-default-theme.md +++ b/docs/en/guide/extending-default-theme.md @@ -1,5 +1,6 @@ --- outline: deep +description: Customize and extend the VitePress default theme with custom CSS, components, layouts, and slots. --- # Extending the Default Theme @@ -70,7 +71,7 @@ If your font is a local file referenced via `@font-face`, it will be processed a export default { transformHead({ assets }) { // adjust the regex accordingly to match your font - const myFontFile = assets.find(file => /font-name\.\w+\.woff2/) + const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file)) if (myFontFile) { return [ [ @@ -190,6 +191,7 @@ Full list of slots available in the default theme layout: - `home-hero-info-before` - `home-hero-info` - `home-hero-info-after` + - `home-hero-actions-before-actions` - `home-hero-actions-after` - `home-hero-image` - `home-hero-after` @@ -252,6 +254,7 @@ provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => { { duration: 300, easing: 'ease-in', + fill: 'forwards', pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)` } ) @@ -319,7 +322,7 @@ export default defineConfig({ { find: /^.*\/VPNavBar\.vue$/, replacement: fileURLToPath( - new URL('./components/CustomNavBar.vue', import.meta.url) + new URL('./theme/components/CustomNavBar.vue', import.meta.url) ) } ] diff --git a/docs/en/guide/frontmatter.md b/docs/en/guide/frontmatter.md index c1856ca4b..dc2058164 100644 --- a/docs/en/guide/frontmatter.md +++ b/docs/en/guide/frontmatter.md @@ -1,3 +1,7 @@ +--- +description: Learn how to use YAML frontmatter in VitePress Markdown files to control page-level metadata and behavior. +--- + # Frontmatter ## Usage diff --git a/docs/en/guide/getting-started.md b/docs/en/guide/getting-started.md index 01b64a1bd..e1dc739a8 100644 --- a/docs/en/guide/getting-started.md +++ b/docs/en/guide/getting-started.md @@ -1,3 +1,7 @@ +--- +description: Get up and running with VitePress. Learn how to install, scaffold, and start developing your documentation site. +--- + # Getting Started ## Try It Online @@ -8,7 +12,7 @@ You can try VitePress directly in your browser on [StackBlitz](https://vitepress ### Prerequisites -- [Node.js](https://nodejs.org/) version 18 or higher. +- [Node.js](https://nodejs.org/) version 20 or higher. - Terminal for accessing VitePress via its command line interface (CLI). - Text Editor with [Markdown](https://en.wikipedia.org/wiki/Markdown) syntax support. - [VSCode](https://code.visualstudio.com/) is recommended, along with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar). @@ -18,39 +22,19 @@ VitePress can be used on its own, or be installed into an existing project. In b ::: code-group ```sh [npm] -$ npm add -D vitepress +$ npm add -D vitepress@next ``` ```sh [pnpm] -$ pnpm add -D vitepress +$ pnpm add -D vitepress@next ``` ```sh [yarn] -$ yarn add -D vitepress -``` - -```sh [yarn (pnp)] -$ yarn add -D vitepress vue +$ yarn add -D vitepress@next vue ``` ```sh [bun] -$ bun add -D vitepress -``` - -::: - -::: details Getting missing peer deps warnings? -If using PNPM, you will notice a missing peer warning for `@docsearch/js`. This does not prevent VitePress from working. If you wish to suppress this warning, add the following to your `package.json`: - -```json -"pnpm": { - "peerDependencyRules": { - "ignoreMissing": [ - "@algolia/client-search", - "search-insights" - ] - } -} +$ bun add -D vitepress@next ``` ::: diff --git a/docs/en/guide/i18n.md b/docs/en/guide/i18n.md index f53acef6a..8a57bb78a 100644 --- a/docs/en/guide/i18n.md +++ b/docs/en/guide/i18n.md @@ -1,3 +1,7 @@ +--- +description: Set up internationalization (i18n) in VitePress to support multiple languages for your site. +--- + # Internationalization To use the built-in i18n features, one needs to create a directory structure as follows: diff --git a/docs/en/guide/markdown.md b/docs/en/guide/markdown.md index 06b8b7761..193ab8cf5 100644 --- a/docs/en/guide/markdown.md +++ b/docs/en/guide/markdown.md @@ -1,3 +1,7 @@ +--- +description: VitePress built-in Markdown extensions including custom containers, code blocks with syntax highlighting, line highlighting, code groups, and more. +--- + # Markdown Extensions VitePress comes with built in Markdown Extensions. @@ -255,7 +259,7 @@ This is a special container that can be used to prevent style and router conflic ```md ::: raw -Wraps in a
    +Wraps in a `
    ` ::: ``` @@ -277,11 +281,11 @@ Wraps in a
    } ``` - It uses [`postcss-prefix-selector`](https://github.com/RadValentin/postcss-prefix-selector) under the hood. You can pass its options like this: + You can pass its options like this: ```js postcssIsolateStyles({ - includeFiles: [/vp-doc\.css/] // defaults to /base\.css/ + includeFiles: [/custom\.css/] // defaults to [/vp-doc\.css/, /base\.css/] }) ``` @@ -365,7 +369,7 @@ export default { A [list of valid languages](https://shiki.style/languages) is available on Shiki's repository. -You may also customize syntax highlight theme in app config. Please see [`markdown` options](../reference/site-config#markdown) for more details. +You 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. ## Line Highlighting in Code Blocks @@ -781,7 +785,7 @@ You can also [import snippets](#import-code-snippets) in code groups: You can include a markdown file in another markdown file, even nested. ::: tip -You can also prefix the markdown path with `@`, it will act as the source root. By default, it's the VitePress project root, unless `srcDir` is configured. +You 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. ::: For example, you can include a relative markdown file using this: @@ -793,7 +797,7 @@ For example, you can include a relative markdown file using this: ## Basics - + ``` **Part file** (`parts/basics.md`) @@ -824,17 +828,17 @@ It also supports selecting a line range: **Input** -```md +```md:line-numbers # Docs ## Basics - + ``` **Part file** (`parts/basics.md`) -```md +```md:line-numbers Some getting started stuff. ### Configuration @@ -844,7 +848,7 @@ Can be created using `.foorc.json`. **Equivalent code** -```md +```md:line-numbers # Docs ## Basics @@ -860,18 +864,18 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co **Input** -```md +```md:line-numbers # Docs ## Basics - - + + ``` **Part file** (`parts/basics.md`) -```md +```md:line-numbers ## Usage Line 1 @@ -883,7 +887,7 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co **Equivalent code** -```md +```md:line-numbers # Docs ## Basics @@ -897,12 +901,59 @@ You can also use a [VS Code region](https://code.visualstudio.com/docs/editor/co Note 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. ::: +Instead 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: + +```md +## My Base Section + +Some content here. + +### My Sub Section + +Some more content here. + +## Another Section + +Content outside `My Base Section`. +``` + +You can include the `My Base Section` section like this: + +```md +## My Extended Section + +``` + +**Equivalent code** + +```md +## My Extended Section + +Some content here. + +### My Sub Section + +Some more content here. +``` + +Here, `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: + +```md +## My Base Section {#custom-id} +``` + +and include it like this: + +```md + +``` + ## Math Equations This is currently opt-in. To enable it, you need to install `markdown-it-mathjax3` and set `markdown.math` to `true` in your config file: ```sh -npm add -D markdown-it-mathjax3 +npm add -D markdown-it-mathjax3@^4 ``` ```ts [.vitepress/config.ts] diff --git a/docs/en/guide/mpa-mode.md b/docs/en/guide/mpa-mode.md index 74b6c297a..35f7e4d07 100644 --- a/docs/en/guide/mpa-mode.md +++ b/docs/en/guide/mpa-mode.md @@ -1,3 +1,7 @@ +--- +description: Enable MPA (Multi-Page Application) mode in VitePress for zero-JavaScript pages with better initial performance. +--- + # MPA Mode MPA (Multi-Page Application) mode can be enabled via the command line via `vitepress build --mpa`, or via config through the `mpa: true` option. diff --git a/docs/en/guide/routing.md b/docs/en/guide/routing.md index 1f3569a7c..2631c6329 100644 --- a/docs/en/guide/routing.md +++ b/docs/en/guide/routing.md @@ -1,5 +1,6 @@ --- outline: deep +description: Understand VitePress file-based routing, dynamic routes, clean URLs, and path rewrites. --- # Routing @@ -121,7 +122,7 @@ Alternatively, you can directly use the anchor tag syntax: ::: -## Generating Clean URL +## Generating Clean URLs ::: warning Server Support Required To serve clean URLs with VitePress, server-side support is required. @@ -260,6 +261,30 @@ The generated HTML pages will be: └─ bar.html ``` +### Type-safe loader with `defineRoutes` + +If 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`: + +```ts +// packages/[pkg].paths.ts +import { defineRoutes } from 'vitepress' + +export default defineRoutes({ + watch: ['../data/**/*.json'], + async paths() { + return [ + { params: { pkg: 'foo' } }, + { params: { pkg: 'bar' } } + ] + }, + async transformPageData(pageData) { + pageData.title = `${pageData.title} · Packages` + } +}) +``` + +`defineRoutes` is optional, but recommended when authoring `.paths.ts` files. + ### Multiple Params A dynamic route can contain multiple params: @@ -336,6 +361,46 @@ export default { } ``` +### Watching Template and Data Files + +When 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: + +```js +// posts/[slug].paths.js +import fs from 'node:fs' +import { renderTemplate } from './templates/renderer.js' + +export default { + // Watch for changes to template files and data sources + watch: [ + './templates/**/*.njk', // Template files + '../data/**/*.json' // Data files + ], + + paths(watchedFiles) { + // watchedFiles will be an array of absolute paths of the matched files + // Read data files to generate routes + const dataFiles = watchedFiles.filter(file => file.endsWith('.json')) + + return dataFiles.map(file => { + const data = JSON.parse(fs.readFileSync(file, 'utf-8')) + + return { + params: { slug: data.slug }, + content: renderTemplate(data) // Use template to generate content + } + }) + } +} +``` + +The `watch` option works the same way as in [data loaders](./data-loading#data-from-local-files): + +- Accepts [glob patterns](https://github.com/mrmlnc/fast-glob#pattern-syntax) to match files +- Patterns are relative to the `.paths.js` file itself +- Changes to watched files trigger page regeneration and HMR during development +- In production builds, all pages are generated once regardless of watch configuration + ### Accessing Params in Page You 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: diff --git a/docs/en/guide/sitemap-generation.md b/docs/en/guide/sitemap-generation.md index 4d52984f2..86751bdde 100644 --- a/docs/en/guide/sitemap-generation.md +++ b/docs/en/guide/sitemap-generation.md @@ -1,3 +1,7 @@ +--- +description: Generate a sitemap.xml file for your VitePress site to improve search engine discoverability. +--- + # Sitemap Generation VitePress 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`: diff --git a/docs/en/guide/ssr-compat.md b/docs/en/guide/ssr-compat.md index c1b1ee075..99171ad63 100644 --- a/docs/en/guide/ssr-compat.md +++ b/docs/en/guide/ssr-compat.md @@ -1,5 +1,6 @@ --- outline: deep +description: Ensure your VitePress theme components and custom code are compatible with server-side rendering. --- # SSR Compatibility diff --git a/docs/en/guide/using-vue.md b/docs/en/guide/using-vue.md index 5a82dc756..a9b9a389a 100644 --- a/docs/en/guide/using-vue.md +++ b/docs/en/guide/using-vue.md @@ -1,3 +1,7 @@ +--- +description: Use Vue components and dynamic templating features directly inside Markdown files in VitePress. +--- + # Using Vue in Markdown In 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 ` + + +``` diff --git a/docs/en/reference/default-theme-edit-link.md b/docs/en/reference/default-theme-edit-link.md index ff049d59e..87493f7c4 100644 --- a/docs/en/reference/default-theme-edit-link.md +++ b/docs/en/reference/default-theme-edit-link.md @@ -1,3 +1,7 @@ +--- +description: Display an edit link on doc pages to let users suggest changes on GitHub or GitLab. +--- + # Edit Link ## Site-Level Config diff --git a/docs/en/reference/default-theme-footer.md b/docs/en/reference/default-theme-footer.md index a58e8ac6b..be10ee49d 100644 --- a/docs/en/reference/default-theme-footer.md +++ b/docs/en/reference/default-theme-footer.md @@ -1,3 +1,7 @@ +--- +description: Configure the global footer displayed at the bottom of VitePress pages. +--- + # Footer VitePress will display global footer at the bottom of the page when `themeConfig.footer` is present. diff --git a/docs/en/reference/default-theme-home-page.md b/docs/en/reference/default-theme-home-page.md index f7baecca0..a0392aa06 100644 --- a/docs/en/reference/default-theme-home-page.md +++ b/docs/en/reference/default-theme-home-page.md @@ -1,3 +1,7 @@ +--- +description: Configure the VitePress default theme home page layout with hero sections, features, and custom content. +--- + # Home Page VitePress 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). diff --git a/docs/en/reference/default-theme-last-updated.md b/docs/en/reference/default-theme-last-updated.md index 00fed72a0..ee0ea72a4 100644 --- a/docs/en/reference/default-theme-last-updated.md +++ b/docs/en/reference/default-theme-last-updated.md @@ -1,9 +1,32 @@ +--- +description: Show the last updated timestamp on VitePress pages based on Git commit history. +--- + # Last Updated The 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. -::: tip -You need to commit the markdown file to see the updated time. +::: info +VitePress 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. + +Internally, 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. + +To fix this in **GitHub Actions**, use the following in your workflow: + +```yaml{4} +- name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 +``` + +Other CI/CD platforms have similar settings. + +If such options aren't available, you can prepend the `docs:build` command in your `package.json` with a manual fetch: + +```json +"docs:build": "git fetch --unshallow && vitepress build docs" +``` ::: ## Site-Level Config diff --git a/docs/en/reference/default-theme-layout.md b/docs/en/reference/default-theme-layout.md index 246e20fa9..e412c3c95 100644 --- a/docs/en/reference/default-theme-layout.md +++ b/docs/en/reference/default-theme-layout.md @@ -1,3 +1,7 @@ +--- +description: Choose between doc, page, and home layouts in the VitePress default theme. +--- + # Layout You 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. diff --git a/docs/en/reference/default-theme-nav.md b/docs/en/reference/default-theme-nav.md index b55a63cb1..01ff20903 100644 --- a/docs/en/reference/default-theme-nav.md +++ b/docs/en/reference/default-theme-nav.md @@ -1,3 +1,7 @@ +--- +description: Configure the navigation bar in the VitePress default theme including site title, logo, and menu links. +--- + # Nav The Nav is the navigation bar displayed on top of the page. It contains the site title, global menu links, etc. @@ -55,6 +59,8 @@ export default { The `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 `/`. +The `link` can also be a function that accepts [`PageData`](./runtime-api#usedata) as the argument and returns the path. + Nav links can also be dropdown menus. To do this, set `items` key on link option. ```js diff --git a/docs/en/reference/default-theme-prev-next-links.md b/docs/en/reference/default-theme-prev-next-links.md index 7befe179b..0d0c29cd8 100644 --- a/docs/en/reference/default-theme-prev-next-links.md +++ b/docs/en/reference/default-theme-prev-next-links.md @@ -1,3 +1,7 @@ +--- +description: Customize the previous and next page links displayed at the bottom of doc pages in VitePress. +--- + # Prev Next Links You 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. diff --git a/docs/en/reference/default-theme-search.md b/docs/en/reference/default-theme-search.md index 16bb92895..a31382946 100644 --- a/docs/en/reference/default-theme-search.md +++ b/docs/en/reference/default-theme-search.md @@ -1,12 +1,13 @@ --- outline: deep +description: Set up local or Algolia-powered search for your VitePress site. --- # Search ## Local Search -VitePress supports fuzzy full-text search using a 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: +VitePress 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: ```ts import { defineConfig } from 'vitepress' @@ -29,6 +30,7 @@ Alternatively, you can use [Algolia DocSearch](#algolia-search) or some communit - - - +- ### i18n {#local-search-i18n} @@ -124,9 +126,9 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { + async _render(src, env, md) { // return html string } } @@ -149,8 +151,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -162,7 +164,7 @@ export default defineConfig({ ``` ::: warning Note -In 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.render` is called, so any checks on optional `env` properties like `frontmatter` should be done after that. +In 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. ::: #### Example: Transforming content - adding anchors @@ -175,10 +177,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html return html } } @@ -189,7 +191,7 @@ export default defineConfig({ ## Algolia Search -VitePress supports searching your docs site using [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Refer their getting started guide. In your `.vitepress/config.ts` you'll need to provide at least the following to make it work: +VitePress 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: ```ts import { defineConfig } from 'vitepress' @@ -212,6 +214,19 @@ export default defineConfig({ You can use a config like this to use multilingual search: +
    +View full example + +<<< @/snippets/algolia-i18n.ts + +
    + +Refer [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). + +### Algolia Ask AI Support {#ask-ai} + +If you would like to include **Ask AI**, pass the `askAi` option (or any of the partial fields) inside `options`: + ```ts import { defineConfig } from 'vitepress' @@ -223,46 +238,50 @@ export default defineConfig({ appId: '...', apiKey: '...', indexName: '...', - locales: { - zh: { - placeholder: '搜索文档', - translations: { - button: { - buttonText: '搜索文档', - buttonAriaLabel: '搜索文档' - }, - modal: { - searchBox: { - resetButtonTitle: '清除查询条件', - resetButtonAriaLabel: '清除查询条件', - cancelButtonText: '取消', - cancelButtonAriaLabel: '取消' - }, - startScreen: { - recentSearchesTitle: '搜索历史', - noRecentSearchesText: '没有搜索历史', - saveRecentSearchButtonTitle: '保存至搜索历史', - removeRecentSearchButtonTitle: '从搜索历史中移除', - favoriteSearchesTitle: '收藏', - removeFavoriteSearchButtonTitle: '从收藏中移除' - }, - errorScreen: { - titleText: '无法获取结果', - helpText: '你可能需要检查你的网络连接' - }, - footer: { - selectText: '选择', - navigateText: '切换', - closeText: '关闭', - searchByText: '搜索提供者' - }, - noResultsScreen: { - noResultsText: '无法找到相关结果', - suggestedQueryText: '你可以尝试查询', - reportMissingResultsText: '你认为该查询应该有结果?', - reportMissingResultsLinkText: '点击反馈' - } - } + // askAi: "YOUR-ASSISTANT-ID" + // OR + askAi: { + // at minimum you must provide the assistantId you received from Algolia + assistantId: 'XXXYYY', + // optional overrides – if omitted, the top-level appId/apiKey/indexName values are reused + // apiKey: '...', + // appId: '...', + // indexName: '...' + } + } + } + } +}) +``` + +::: warning Note +If you want to default to keyword search and do not want to use Ask AI, omit the `askAi` property. +::: + +### Ask AI Side Panel {#ask-ai-side-panel} + +DocSearch 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. + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + panel: { + variant: 'floating', // or 'inline' + side: 'right', + width: '360px', + expandedWidth: '580px', + suggestedQuestions: true } } } @@ -272,119 +291,70 @@ export default defineConfig({ }) ``` -[These options](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) can be overridden. Refer official Algolia docs to learn more about them. +If you need to disable the keyboard shortcut, use the `keyboardShortcuts` option at the sidepanel root level: -### Crawler Config +```ts +import { defineConfig } from 'vitepress' -Here is an example config based on what this site uses: +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + keyboardShortcuts: { + 'Ctrl/Cmd+I': false + } + } + } + } + } + } +}) +``` + +#### Mode (auto / sidePanel / hybrid / modal) {#ask-ai-mode} + +You can optionally control how VitePress integrates keyword search and Ask AI: + +- `mode: 'auto'` (default): infer `hybrid` when keyword search is configured, otherwise `sidePanel` when Ask AI side panel is configured. +- `mode: 'sidePanel'`: force side panel only (hides the keyword search button). +- `mode: 'hybrid'`: enable keyword search modal + Ask AI side panel (requires keyword search configuration). +- `mode: 'modal'`: keep Ask AI inside the DocSearch modal (even if you configured the side panel). + +#### Ask AI only (no keyword search) {#ask-ai-only} + +If you want to use **Ask AI side panel only**, you can omit top-level keyword search config and provide credentials under `askAi`: ```ts -new Crawler({ - appId: '...', - apiKey: '...', - rateLimit: 8, - startUrls: ['https://vitepress.dev/'], - renderJavaScript: false, - sitemaps: [], - exclusionPatterns: [], - ignoreCanonicalTo: false, - discoveryPatterns: ['https://vitepress.dev/**'], - schedule: 'at 05:10 on Saturday', - actions: [ - { - indexName: 'vitepress', - pathsToMatch: ['https://vitepress.dev/**'], - recordExtractor: ({ $, helpers }) => { - return helpers.docsearch({ - recordProps: { - lvl1: '.content h1', - content: '.content p, .content li', - lvl0: { - selectors: 'section.has-active div h2', - defaultValue: 'Documentation' - }, - lvl2: '.content h2', - lvl3: '.content h3', - lvl4: '.content h4', - lvl5: '.content h5' - }, - indexHeadings: true - }) +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + mode: 'sidePanel', + askAi: { + assistantId: 'XXXYYY', + appId: '...', + apiKey: '...', + indexName: '...', + sidePanel: true + } } } - ], - initialIndexSettings: { - vitepress: { - attributesForFaceting: ['type', 'lang'], - attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'], - attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'], - attributesToSnippet: ['content:10'], - camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'], - searchableAttributes: [ - 'unordered(hierarchy_radio_camel.lvl0)', - 'unordered(hierarchy_radio.lvl0)', - 'unordered(hierarchy_radio_camel.lvl1)', - 'unordered(hierarchy_radio.lvl1)', - 'unordered(hierarchy_radio_camel.lvl2)', - 'unordered(hierarchy_radio.lvl2)', - 'unordered(hierarchy_radio_camel.lvl3)', - 'unordered(hierarchy_radio.lvl3)', - 'unordered(hierarchy_radio_camel.lvl4)', - 'unordered(hierarchy_radio.lvl4)', - 'unordered(hierarchy_radio_camel.lvl5)', - 'unordered(hierarchy_radio.lvl5)', - 'unordered(hierarchy_radio_camel.lvl6)', - 'unordered(hierarchy_radio.lvl6)', - 'unordered(hierarchy_camel.lvl0)', - 'unordered(hierarchy.lvl0)', - 'unordered(hierarchy_camel.lvl1)', - 'unordered(hierarchy.lvl1)', - 'unordered(hierarchy_camel.lvl2)', - 'unordered(hierarchy.lvl2)', - 'unordered(hierarchy_camel.lvl3)', - 'unordered(hierarchy.lvl3)', - 'unordered(hierarchy_camel.lvl4)', - 'unordered(hierarchy.lvl4)', - 'unordered(hierarchy_camel.lvl5)', - 'unordered(hierarchy.lvl5)', - 'unordered(hierarchy_camel.lvl6)', - 'unordered(hierarchy.lvl6)', - 'content' - ], - distinct: true, - attributeForDistinct: 'url', - customRanking: [ - 'desc(weight.pageRank)', - 'desc(weight.level)', - 'asc(weight.position)' - ], - ranking: [ - 'words', - 'filters', - 'typo', - 'attribute', - 'proximity', - 'exact', - 'custom' - ], - highlightPreTag: '', - highlightPostTag: '', - minWordSizefor1Typo: 3, - minWordSizefor2Typos: 7, - allowTyposOnNumericTokens: false, - minProximity: 1, - ignorePlurals: true, - advancedSyntax: true, - attributeCriteriaComputedByMinProximity: true, - removeWordsIfNoResults: 'allOptional' - } } }) ``` - +### Crawler Config + +Here is an example config based on what this site uses: + +<<< @/snippets/algolia-crawler.js diff --git a/docs/en/reference/default-theme-sidebar.md b/docs/en/reference/default-theme-sidebar.md index 9a64a0744..cd44425d9 100644 --- a/docs/en/reference/default-theme-sidebar.md +++ b/docs/en/reference/default-theme-sidebar.md @@ -1,3 +1,7 @@ +--- +description: Configure the sidebar navigation in the VitePress default theme with groups, collapsible sections, and multiple sidebars. +--- + # Sidebar The sidebar is the main navigation block for your documentation. You can configure the sidebar menu in [`themeConfig.sidebar`](./default-theme-config#sidebar). @@ -180,36 +184,3 @@ export default { } } ``` - -## `useSidebar` - -Returns sidebar-related data. The returned object has the following type: - -```ts -export interface DocSidebar { - isOpen: Ref - sidebar: ComputedRef - sidebarGroups: ComputedRef - hasSidebar: ComputedRef - hasAside: ComputedRef - leftAside: ComputedRef - isSidebarEnabled: ComputedRef - open: () => void - close: () => void - toggle: () => void -} -``` - -**Example:** - -```vue - - - -``` diff --git a/docs/en/reference/default-theme-team-page.md b/docs/en/reference/default-theme-team-page.md index 29b071ff8..de143bece 100644 --- a/docs/en/reference/default-theme-team-page.md +++ b/docs/en/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: Create team pages with member profiles using VitePress built-in team components. +--- + @@ -96,7 +97,7 @@ const ClientComp = defineClientComponent(() => { ``` -Puede también pasar propiedades/hijos/_slots_ para el componente objetivo: +Puede pasar propiedades/hijos/_slots_ al componente objetivo: ```vue - - -``` diff --git a/docs/es/reference/default-theme-team-page.md b/docs/es/reference/default-theme-team-page.md index 1f6492a85..eda461aea 100644 --- a/docs/es/reference/default-theme-team-page.md +++ b/docs/es/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: Crea páginas de equipo con perfiles de miembros usando los componentes de equipo integrados de VitePress. +--- + - - -``` \ No newline at end of file diff --git a/docs/fa/reference/default-theme-team-page.md b/docs/fa/reference/default-theme-team-page.md index ccd9738d8..3993dd433 100644 --- a/docs/fa/reference/default-theme-team-page.md +++ b/docs/fa/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: ایجاد صفحات تیم با پروفایل اعضا با استفاده از کامپوننت‌های داخلی تیم ویت‌پرس. +--- + + + +``` diff --git a/docs/ja/guide/cms.md b/docs/ja/guide/cms.md new file mode 100644 index 000000000..dd3d9ef66 --- /dev/null +++ b/docs/ja/guide/cms.md @@ -0,0 +1,57 @@ +--- +outline: deep +description: 動的ルートとデータローダーを使い、VitePressをヘッドレスCMSと連携する方法。 +--- + +# CMS との接続 {#connecting-to-a-cms} + +## 全体のワークフロー {#general-workflow} + +VitePress を CMS と接続する際は、主に [動的ルーティング](./routing#dynamic-routes) を中心に考えることになります。先にその仕組みを理解しておいてください。 + +CMS ごとに動作が異なるため、ここでは各自の環境に合わせて調整できる汎用的なワークフローのみを示します。 + +1. CMS が認証を必要とする場合は、API トークンを格納するための `.env` を作成し、次のように読み込みます。 + + ```js + // posts/[id].paths.js + import { loadEnv } from 'vitepress' + + const env = loadEnv('', process.cwd()) + ``` + +2. CMS から必要なデータを取得し、適切なパスデータの形式に整形します。 + + ```js + export default { + async paths() { + // 必要に応じて各 CMS のクライアントライブラリを使用 + const data = await (await fetch('https://my-cms-api', { + headers: { + // 必要ならトークン + } + })).json() + + return data.map((entry) => { + return { + params: { id: entry.id, /* title, authors, date など */ }, + content: entry.content + } + }) + } + } + ``` + +3. ページ内でコンテンツをレンダリングします。 + + ```md + # {{ $params.title }} + + - {{ $params.date }} に {{ $params.author }} が作成 + + + ``` + +## 連携ガイドの募集 {#integration-guides} + +特定の CMS と VitePress の連携ガイドを書かれた方は、下部の「Edit this page」リンクからぜひ投稿してください! diff --git a/docs/ja/guide/custom-theme.md b/docs/ja/guide/custom-theme.md new file mode 100644 index 000000000..94064e7be --- /dev/null +++ b/docs/ja/guide/custom-theme.md @@ -0,0 +1,215 @@ +--- +description: VitePressでカスタムテーマを作成・使用し、サイトの外観と動作を完全にカスタマイズする方法。 +--- + +# カスタムテーマを使う {#using-a-custom-theme} + +## テーマの解決 {#theme-resolving} + +カスタムテーマを有効にするには、`.vitepress/theme/index.js` または `.vitepress/theme/index.ts` ファイル(「テーマエントリファイル」)を作成します。 + +``` +. +├─ docs # プロジェクトルート +│ ├─ .vitepress +│ │ ├─ theme +│ │ │ └─ index.js # テーマエントリ +│ │ └─ config.js # 設定ファイル +│ └─ index.md +└─ package.json +``` + +VitePress はテーマエントリファイルを検出すると、常にデフォルトテーマではなくカスタムテーマを使用します。ただし、[デフォルトテーマを拡張](./extending-default-theme) してその上で高度なカスタマイズを行うことも可能です。 + +## テーマインターフェース {#theme-interface} + +VitePress のカスタムテーマは次のインターフェースを持つオブジェクトとして定義されます。 + +```ts +interface Theme { + /** + * すべてのページに適用されるルートレイアウトコンポーネント + * @required + */ + Layout: Component + /** + * Vue アプリインスタンスを拡張 + * @optional + */ + enhanceApp?: (ctx: EnhanceAppContext) => Awaitable + /** + * 別のテーマを拡張し、そのテーマの `enhanceApp` を先に実行 + * @optional + */ + extends?: Theme +} + +interface EnhanceAppContext { + app: App // Vue アプリインスタンス + router: Router // VitePress のルーターインスタンス + siteData: Ref // サイト全体のメタデータ +} +``` + +テーマエントリファイルでは、このテーマをデフォルトエクスポートとして公開します。 + +```js [.vitepress/theme/index.js] +// テーマエントリでは Vue ファイルを直接インポートできます +// VitePress は @vitejs/plugin-vue をあらかじめ設定済みです +import Layout from './Layout.vue' + +export default { + Layout, + enhanceApp({ app, router, siteData }) { + // ... + } +} +``` + +デフォルトエクスポートはカスタムテーマにおける唯一の契約であり、必須なのは `Layout` プロパティだけです。つまり、VitePress のテーマは単一の Vue コンポーネントでも成り立ちます。 + +レイアウトコンポーネントの内部は通常の Vite + Vue 3 アプリケーションと同じように動作します。なお、テーマは [SSR 対応](./ssr-compat) である必要があります。 + +## レイアウトの構築 {#building-a-layout} + +最も基本的なレイアウトコンポーネントには [``](../reference/runtime-api#content) コンポーネントを含める必要があります。 + +```vue [.vitepress/theme/Layout.vue] + +``` + +上記のレイアウトは、すべてのページの Markdown を単純に HTML として描画します。最初の改善点として 404 エラー処理を追加できます。 + +```vue{1-4,9-12} + + + +``` + +[`useData()`](../reference/runtime-api#usedata) ヘルパーを使うと、条件によってレイアウトを切り替えるために必要なすべてのランタイムデータを取得できます。アクセスできるデータのひとつにフロントマターがあります。これを利用すると、ページごとにレイアウトを制御できます。例えば、ユーザーが特別なホームページレイアウトを使いたい場合は以下のように記述します。 + +```md +--- +layout: home +--- +``` + +テーマ側を次のように調整します。 + +```vue{3,12-14} + + + +``` + +もちろんレイアウトをさらにコンポーネントに分割することもできます。 + +```vue{3-5,12-15} + + + +``` + +利用可能なすべての機能は [Runtime API リファレンス](../reference/runtime-api) を参照してください。さらに [ビルド時データ読み込み](./data-loading) を活用すれば、ブログ記事一覧ページのようなデータ駆動型のレイアウトも実現できます。 + +## カスタムテーマの配布 {#distributing-a-custom-theme} + +最も簡単な配布方法は [GitHub のテンプレートリポジトリ](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository) として提供することです。 + +npm パッケージとして配布する場合は、次の手順を踏みます。 + +1. パッケージエントリでテーマオブジェクトをデフォルトエクスポートとして公開する。 +2. 必要であればテーマ設定の型定義を `ThemeConfig` として公開する。 +3. テーマが VitePress 設定の調整を必要とする場合は、パッケージのサブパス(例:`my-theme/config`)としてその設定を公開し、ユーザーが拡張できるようにする。 +4. 設定ファイルやフロントマターを通じて、テーマ設定オプションを文書化する。 +5. テーマの利用方法を明確に説明する(以下を参照)。 + +## カスタムテーマの利用 {#consuming-a-custom-theme} + +外部テーマを利用するには、カスタムテーマエントリからインポートして再エクスポートします。 + +```js [.vitepress/theme/index.js] +import Theme from 'awesome-vitepress-theme' + +export default Theme +``` + +テーマを拡張する必要がある場合: + +```js [.vitepress/theme/index.js] +import Theme from 'awesome-vitepress-theme' + +export default { + extends: Theme, + enhanceApp(ctx) { + // ... + } +} +``` + +テーマが特別な VitePress 設定を必要とする場合は、設定ファイルも拡張する必要があります。 + +```ts [.vitepress/config.ts] +import baseConfig from 'awesome-vitepress-theme/config' + +export default { + // 必要に応じてテーマの基本設定を拡張 + extends: baseConfig +} +``` + +テーマがテーマ設定用の型を提供している場合: + +```ts [.vitepress/config.ts] +import baseConfig from 'awesome-vitepress-theme/config' +import { defineConfigWithTheme } from 'vitepress' +import type { ThemeConfig } from 'awesome-vitepress-theme' + +export default defineConfigWithTheme({ + extends: baseConfig, + themeConfig: { + // 型は `ThemeConfig` + } +}) +``` diff --git a/docs/ja/guide/data-loading.md b/docs/ja/guide/data-loading.md new file mode 100644 index 000000000..47950abb7 --- /dev/null +++ b/docs/ja/guide/data-loading.md @@ -0,0 +1,214 @@ +--- +description: VitePressのデータローダーを使い、ビルド時に任意のデータを読み込んでページやコンポーネントからインポートする方法。 +--- + +# ビルド時のデータの読み込み {#build-time-data-loading} + +VitePress には **データローダー (data loaders)** という機能があり、任意のデータを読み込み、ページやコンポーネントからインポートすることができます。データの読み込みは **ビルド時のみ** 実行され、最終的な JavaScript バンドルには JSON としてシリアライズされたデータが含まれます。 + +データローダーはリモートデータの取得や、ローカルファイルに基づいたメタデータの生成に利用できます。たとえば、ローカルの API ページをすべて解析して API エントリのインデックスを自動生成するといったことが可能です。 + +## 基本的な使い方 {#basic-usage} + +データローダーファイルは `.data.js` または `.data.ts` で終わる必要があります。ファイルは `load()` メソッドを持つオブジェクトをデフォルトエクスポートします。 + +```js [example.data.js] +export default { + load() { + return { + hello: 'world' + } + } +} +``` + +ローダーモジュールは Node.js 上でのみ評価されるため、Node API や npm 依存関係を自由に利用できます。 + +その後、このファイルから `.md` ページや `.vue` コンポーネントで `data` という名前のエクスポートを使ってデータをインポートできます。 + +```vue + + +
    {{ data }}
    +``` + +出力: + +```json +{ + "hello": "world" +} +``` + +データローダー自体は `data` を直接エクスポートしていないことに気づくでしょう。これは VitePress が裏側で `load()` を呼び出し、その結果を暗黙的に `data` として公開しているためです。 + +ローダーが非同期でも動作します。 + +```js +export default { + async load() { + // リモートデータを取得 + return (await fetch('...')).json() + } +} +``` + +## ローカルファイルからのデータ {#data-from-local-files} + +ローカルファイルに基づいたデータを生成する必要がある場合は、データローダー内で `watch` オプションを使用し、ファイルの変更をホットリロードに反映させることが推奨されます。 + +`watch` では [glob パターン](https://github.com/mrmlnc/fast-glob#pattern-syntax) を利用して複数ファイルをマッチさせることができ、パターンはローダーファイルからの相対パスで指定できます。`load()` 関数にはマッチしたファイルの絶対パスが渡されます。 + +以下は CSV ファイルを読み込み [csv-parse](https://github.com/adaltas/node-csv/tree/master/packages/csv-parse/) を使って JSON に変換する例です。このコードはビルド時にのみ実行されるため、CSV パーサーがクライアントに送られることはありません。 + +```js +import fs from 'node:fs' +import { parse } from 'csv-parse/sync' + +export default { + watch: ['./data/*.csv'], + load(watchedFiles) { + return watchedFiles.map((file) => { + return parse(fs.readFileSync(file, 'utf-8'), { + columns: true, + skip_empty_lines: true + }) + }) + } +} +``` + +## `createContentLoader` + +コンテンツ中心のサイトを構築する場合、ブログ記事や API ページなどを一覧表示する「アーカイブ」や「インデックス」ページが必要になることがよくあります。これはデータローダー API を使って直接実装できますが、あまりにも一般的なケースなので VitePress では `createContentLoader` というヘルパーが用意されています。 + +```js [posts.data.js] +import { createContentLoader } from 'vitepress' + +export default createContentLoader('posts/*.md', /* options */) +``` + +このヘルパーは [ソースディレクトリ](./routing#source-directory) からの相対 glob パターンを受け取り、`{ watch, load }` を返すデータローダーオブジェクトを生成します。これをデータローダーファイルのデフォルトエクスポートにできます。開発時のパフォーマンスを向上させるために、ファイルの更新時刻に基づくキャッシュも行われます。 + +このローダーは Markdown ファイルにのみ対応し、それ以外のファイルは無視されます。 + +読み込まれるデータは `ContentData[]` 型の配列です。 + +```ts +interface ContentData { + url: string // ページのマッピング URL(例: /posts/hello.html) + frontmatter: Record // ページのフロントマター + + src: string | undefined + html: string | undefined + excerpt: string | undefined +} +``` + +デフォルトでは `url` と `frontmatter` のみが提供されます。これは読み込まれたデータがクライアントバンドルに JSON としてインライン化されるため、サイズに注意する必要があるためです。 + +以下はデータを使って最小限のブログインデックスページを構築する例です。 + +```vue + + + +``` + +### オプション {#options} + +デフォルトデータが要件に合わない場合は、オプションで変換処理を追加できます。 + +```js [posts.data.js] +import { createContentLoader } from 'vitepress' + +export default createContentLoader('posts/*.md', { + includeSrc: true, // 生の markdown ソースを含める? + render: true, // レンダリングされた HTML を含める? + excerpt: true, // 抜粋を含める? + + transform(rawData) { + return rawData + .sort((a, b) => { + return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date) + }) + .map((page) => { + page.src // 生の markdown ソース + page.html // レンダリングされた HTML + page.excerpt // 抜粋 HTML(最初の `---` までの内容) + return {/* ... */} + }) + } +}) +``` + +[Vue.js ブログ](https://github.com/vuejs/blog/blob/main/.vitepress/theme/posts.data.ts) での使用例も参考になります。 + +`createContentLoader` API は [ビルドフック](../reference/site-config#build-hooks) 内でも利用可能です。 + +```js [.vitepress/config.js] +export default { + async buildEnd() { + const posts = await createContentLoader('posts/*.md').load() + // メタデータを基にファイルを生成(例: RSS フィード) + } +} +``` + +**型定義** + +```ts +interface ContentOptions { + includeSrc?: boolean + render?: boolean + excerpt?: + | boolean + | ((file: { data: { [key: string]: any }; content: string; excerpt?: string }, options?: any) => void) + | string + transform?: (data: ContentData[]) => T | Promise +} +``` + +## 型付きデータローダー {#typed-data-loaders} + +TypeScript を使用する場合は、ローダーと `data` エクスポートを型付けできます。 + +```ts +import { defineLoader } from 'vitepress' + +export interface Data { + // データ型 +} + +declare const data: Data +export { data } + +export default defineLoader({ + watch: ['...'], + async load(): Promise { + // ... + } +}) +``` + +## 設定情報の取得 {#configuration} + +ローダー内で設定情報を取得するには次のようにします。 + +```ts +import type { SiteConfig } from 'vitepress' + +const config: SiteConfig = (globalThis as any).VITEPRESS_CONFIG +``` diff --git a/docs/ja/guide/deploy.md b/docs/ja/guide/deploy.md new file mode 100644 index 000000000..7bf0881f9 --- /dev/null +++ b/docs/ja/guide/deploy.md @@ -0,0 +1,343 @@ +--- +outline: deep +description: Netlify、Vercel、GitHub Pagesなどの主要プラットフォームにVitePressサイトをデプロイする方法。 +--- + +# VitePress サイトをデプロイする {#deploy-your-vitepress-site} + +以下のガイドは、次の前提に基づいています。 + +- VitePress のサイトはプロジェクトの `docs` ディレクトリ内にある。 +- デフォルトのビルド出力ディレクトリ(`.vitepress/dist`)を使用している。 +- VitePress はプロジェクトのローカル依存としてインストールされており、`package.json` に次のスクリプトが設定されている。 + +```json [package.json] +{ + "scripts": { + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" + } +} +``` + +## ローカルでビルドしてテストする {#build-and-test-locally} + +1. 次のコマンドでドキュメントをビルドします。 + + ```sh + $ npm run docs:build + ``` + +2. ビルド後、次のコマンドでローカルプレビューします。 + + ```sh + $ npm run docs:preview + ``` + + `preview` コマンドはローカルの静的 Web サーバーを起動し、出力ディレクトリ `.vitepress/dist` を `http://localhost:4173` で配信します。プロダクションへプッシュする前に見た目を確認できます。 + +3. `--port` 引数でサーバーのポートを設定できます。 + + ```json + { + "scripts": { + "docs:preview": "vitepress preview docs --port 8080" + } + } + ``` + + これで `docs:preview` は `http://localhost:8080` でサーバーを起動します。 + +## 公開ベースパスの設定 {#setting-a-public-base-path} + +デフォルトでは、サイトはドメインのルートパス(`/`)にデプロイされることを想定しています。サイトをサブパス、例:`https://mywebsite.com/blog/` で配信する場合は、VitePress の設定で [`base`](../reference/site-config#base) オプションを `'/blog/'` に設定してください。 + +**例:** GitHub(または GitLab)Pages に `user.github.io/repo/` としてデプロイするなら、`base` を `/repo/` に設定します。 + +## HTTP キャッシュヘッダー {#http-cache-headers} + +本番サーバーの HTTP ヘッダーを制御できる場合は、`cache-control` ヘッダーを設定して、再訪時のパフォーマンスを向上させましょう。 + +本番ビルドでは静的アセット(JavaScript、CSS、`public` 以外のインポートアセット)にハッシュ付きファイル名が使用されます。ブラウザの開発者ツールのネットワークタブで本番プレビューを確認すると、`app.4f283b18.js` のようなファイルが見られます。 + +この `4f283b18` ハッシュはファイル内容から生成されます。同じハッシュの URL は同じ内容を必ず返し、内容が変われば URL も変わります。したがって、これらのファイルには最も強いキャッシュヘッダーを安全に適用できます。これらのファイルは出力ディレクトリ内の `assets/` 配下に配置されるため、次のヘッダーを設定できます。 + +``` +Cache-Control: max-age=31536000,immutable +``` + +::: details Netlify の `_headers` ファイル例 + +``` +/assets/* + cache-control: max-age=31536000 + cache-control: immutable +``` + +注:`_headers` ファイルは [public ディレクトリ](./asset-handling#the-public-directory) に配置します(この例では `docs/public/_headers`)。そうすると、ビルド出力にそのままコピーされます。 + +[Netlify のカスタムヘッダードキュメント](https://docs.netlify.com/routing/headers/) + +::: + +::: details `vercel.json` による Vercel 設定例 + +```json +{ + "headers": [ + { + "source": "/assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "max-age=31536000, immutable" + } + ] + } + ] +} +``` + +注:`vercel.json` は **リポジトリのルート** に配置してください。 + +[Vercel のヘッダー設定ドキュメント](https://vercel.com/docs/concepts/projects/project-configuration#headers) + +::: + +## プラットフォーム別ガイド {#platform-guides} + +### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic} + +新しいプロジェクトを作成し、ダッシュボードで次の設定に変更します。 + +- **Build Command:** `npm run docs:build` +- **Output Directory:** `docs/.vitepress/dist` +- **Node Version:** `20`(以上) + +::: warning +HTML の _Auto Minify_ のようなオプションを有効にしないでください。Vue にとって意味のあるコメントが出力から削除され、削除されるとハイドレーションの不整合エラーが発生する可能性があります。 +::: + +### GitHub Pages + +1. プロジェクトの `.github/workflows` ディレクトリに `deploy.yml` を作成し、以下の内容を記述します。 + + ```yaml [.github/workflows/deploy.yml] + # Sample workflow for building and deploying a VitePress site to GitHub Pages + # + name: Deploy VitePress site to Pages + + on: + # Runs on pushes targeting the `main` branch. Change this to `master` if you're + # using the `master` branch as the default branch. + push: + branches: [main] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages + permissions: + contents: read + pages: write + id-token: write + + # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. + # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. + concurrency: + group: pages + cancel-in-progress: false + + jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 # Not needed if lastUpdated is not enabled + # - uses: pnpm/action-setup@v4 # Uncomment this block if you're using pnpm + # with: + # version: 9 # Not needed if you've set "packageManager" in package.json + # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun + - name: Setup Node + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm # or pnpm / yarn + - name: Setup Pages + uses: actions/configure-pages@v4 + - name: Install dependencies + run: npm ci # or pnpm install / yarn install / bun install + - name: Build with VitePress + run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + name: Deploy + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + ``` + + ::: warning + VitePress の `base` オプションが正しく設定されていることを確認してください。詳細は [公開ベースパスの設定](#公開ベースパスの設定) を参照してください。 + ::: + +2. リポジトリ設定の「Pages」メニューで、「Build and deployment > Source」を「GitHub Actions」に設定します。 + +3. 変更を `main` ブランチにプッシュし、GitHub Actions の完了を待ちます。設定に応じて、サイトは `https://.github.io/[repository]/` または `https:///` にデプロイされます。以後、`main` へのプッシュごとに自動デプロイされます。 + +### GitLab Pages + +1. VitePress の設定で `outDir` を `../public` に設定します。`https://.gitlab.io//` にデプロイする場合は `base` を `'//'` に設定します。カスタムドメイン、ユーザー/グループページ、または GitLab の「Use unique domain」を有効にしている場合は `base` は不要です。 + +2. プロジェクトのルートに `.gitlab-ci.yml` を作成して、以下を追加します。これにより、コンテンツを更新するたびにサイトがビルド・デプロイされます。 + + ```yaml [.gitlab-ci.yml] + image: node:24 + pages: + cache: + paths: + - node_modules/ + script: + # - apk add git # Uncomment this if you're using small docker images like alpine and have lastUpdated enabled + - npm install + - npm run docs:build + artifacts: + paths: + - public + only: + - main + ``` + +### Azure + +1. [公式ドキュメント](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration) に従います。 + +2. 設定ファイルで次の値を指定します(`api_location` のように不要なものは削除)。 + - **`app_location`**: `/` + - **`output_location`**: `docs/.vitepress/dist` + - **`app_build_command`**: `npm run docs:build` + +### CloudRay + +[CloudRay](https://cloudray.io/) でのデプロイ方法は [こちらの手順](https://cloudray.io/articles/how-to-deploy-vitepress-site) を参照してください。 + +### Firebase + +1. プロジェクトのルートに `firebase.json` と `.firebaserc` を作成します。 + + `firebase.json`: + + ```json [firebase.json] + { + "hosting": { + "public": "docs/.vitepress/dist", + "ignore": [] + } + } + ``` + + `.firebaserc`: + + ```json [.firebaserc] + { + "projects": { + "default": "" + } + } + ``` + +2. `npm run docs:build` の後、次のコマンドでデプロイします。 + + ```sh + firebase deploy + ``` + +### Heroku + +1. [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static) のドキュメントとガイドに従います。 + +2. プロジェクトのルートに `static.json` を作成し、以下を記述します。 + + ```json [static.json] + { + "root": "docs/.vitepress/dist" + } + ``` + +### Hostinger + +[Hostinger](https://www.hostinger.com/web-apps-hosting) を使用して VitePress プロジェクトをデプロイするには、こちらの [手順](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/) に従ってください。ビルド設定の構成では、フレームワークに VitePress を選択し、ルートディレクトリを `./docs` に調整してください。 + +### Kinsta + +[VitePress](https://kinsta.com/static-site-hosting/) を [こちらの手順](https://kinsta.com/docs/vitepress-static-site-example/) に従ってデプロイできます。 + +### Stormkit + +[VitePress プロジェクトを Stormkit にデプロイ](https://stormkit.io/blog/how-to-deploy-vitepress) する手順を参照してください。 + +### Surge + +1. `npm run docs:build` の後、次のコマンドでデプロイします。 + + ```sh + npx surge docs/.vitepress/dist + ``` + +### Nginx + +以下は Nginx サーバーブロックの設定例です。一般的なテキスト系アセットの gzip 圧縮、VitePress サイトの静的ファイル配信における適切なキャッシュヘッダー、そして `cleanUrls: true` のハンドリングを含みます。 + +```nginx +server { + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + listen 80; + server_name _; + index index.html; + + location / { + # content location + root /app; + + # exact matches -> reverse clean urls -> folders -> not found + try_files $uri $uri.html $uri/ =404; + + # non existent pages + error_page 404 /404.html; + + # a folder without index.html raises 403 in this setup + error_page 403 /404.html; + + # adjust caching headers + # files in the assets folder have hashes filenames + location ~* ^/assets/ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + } +} +``` + +この設定は、ビルド済みの VitePress サイトがサーバー上の `/app` ディレクトリに配置されていることを想定しています。サイトのファイルが別の場所にある場合は、`root` ディレクティブを適宜変更してください。 + +::: warning index.html をデフォルトにしない +`try_files` の解決先を、他の Vue アプリのように index.html にフォールバックさせないでください。不正なページ状態になります。 +::: + +詳細は [公式 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) を参照してください。 diff --git a/docs/ja/guide/extending-default-theme.md b/docs/ja/guide/extending-default-theme.md new file mode 100644 index 000000000..8e26243cb --- /dev/null +++ b/docs/ja/guide/extending-default-theme.md @@ -0,0 +1,336 @@ +--- +outline: deep +description: VitePressデフォルトテーマをカスタムCSS、コンポーネント、レイアウト、スロットで拡張・カスタマイズする方法。 +--- + +# デフォルトテーマの拡張 {#extending-the-default-theme} + +VitePress のデフォルトテーマはドキュメント向けに最適化されており、カスタマイズ可能です。利用できるオプションの一覧は [デフォルトテーマの概要](../reference/default-theme-config) を参照してください。 + +しかし、設定だけでは不十分なケースもあります。例えば: + +1. CSS のスタイルを微調整したい +2. グローバルコンポーネントの登録など、Vue アプリインスタンスを変更したい +3. レイアウトのスロット経由でテーマに独自コンテンツを挿入したい + +これらの高度なカスタマイズには、デフォルトテーマを「拡張」するカスタムテーマを使用する必要があります。 + +::: tip +先に [カスタムテーマの使用](./custom-theme) を読み、カスタムテーマの仕組みを理解してから進めてください。 +::: + +## CSS のカスタマイズ {#customizing-css} + +デフォルトテーマの CSS は、ルートレベルの CSS 変数をオーバーライドすることでカスタマイズできます。 + +```js [.vitepress/theme/index.js] +import DefaultTheme from 'vitepress/theme' +import './custom.css' + +export default DefaultTheme +``` + +```css +/* .vitepress/theme/custom.css */ +:root { + --vp-c-brand-1: #646cff; + --vp-c-brand-2: #747bff; +} +``` + +上書き可能な [デフォルトテーマの CSS 変数](https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css) を参照してください。 + +## フォントを変更する {#using-different-fonts} + +VitePress はデフォルトフォントとして [Inter](https://rsms.me/inter/) を使用し、ビルド出力にフォントを含めます。プロダクションでは自動でプリロードもされます。しかし、別のメインフォントを使いたい場合には望ましくないことがあります。 + +Inter をビルド出力に含めたくない場合は、`vitepress/theme-without-fonts` からテーマをインポートします。 + +```js [.vitepress/theme/index.js] +import DefaultTheme from 'vitepress/theme-without-fonts' +import './my-fonts.css' + +export default DefaultTheme +``` + +```css +/* .vitepress/theme/my-fonts.css */ +:root { + --vp-font-family-base: /* 通常テキスト用フォント */ + --vp-font-family-mono: /* コード用フォント */ +} +``` + +::: warning +[Team Page](../reference/default-theme-team-page) などのオプションコンポーネントを使う場合も、必ず `vitepress/theme-without-fonts` からインポートしてください。 +::: + +フォントが `@font-face` で参照されるローカルファイルの場合、アセットとして処理され、ハッシュ付きファイル名で `.vitepress/dist/assets` に出力されます。このファイルをプリロードするには、[transformHead](../reference/site-config#transformhead) ビルドフックを使います。 + +```js [.vitepress/config.js] +export default { + transformHead({ assets }) { + // 使うフォントに合わせて正規表現を調整 + const myFontFile = assets.find((file) => + /font-name\.[\w-]+\.woff2/.test(file) + ) + if (myFontFile) { + return [ + [ + 'link', + { + rel: 'preload', + href: myFontFile, + as: 'font', + type: 'font/woff2', + crossorigin: '' + } + ] + ] + } + } +} +``` + +## グローバルコンポーネントの登録 {#registering-global-components} + +```js [.vitepress/theme/index.js] +import DefaultTheme from 'vitepress/theme' + +/** @type {import('vitepress').Theme} */ +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + // 独自のグローバルコンポーネントを登録 + app.component('MyGlobalComponent' /* ... */) + } +} +``` + +TypeScript を使う場合: + +```ts [.vitepress/theme/index.ts] +import type { Theme } from 'vitepress' +import DefaultTheme from 'vitepress/theme' + +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + // 独自のグローバルコンポーネントを登録 + app.component('MyGlobalComponent' /* ... */) + } +} satisfies Theme +``` + +Vite を使っているため、Vite の [glob import 機能](https://vitejs.dev/guide/features.html#glob-import) を利用してディレクトリ内のコンポーネントを自動登録することもできます。 + +## レイアウトスロット {#layout-slots} + +デフォルトテーマの `` コンポーネントには、ページ内の特定の位置にコンテンツを挿入するためのスロットがいくつか用意されています。以下は、アウトラインの前にコンポーネントを挿入する例です。 + +```js [.vitepress/theme/index.js] +import DefaultTheme from 'vitepress/theme' +import MyLayout from './MyLayout.vue' + +export default { + extends: DefaultTheme, + // スロットを注入するラッパーコンポーネントで Layout を上書き + Layout: MyLayout +} +``` + +```vue [.vitepress/theme/MyLayout.vue] + + + +``` + +レンダーファンクションを使う方法もあります。 + +```js [.vitepress/theme/index.js] +import { h } from 'vue' +import DefaultTheme from 'vitepress/theme' +import MyComponent from './MyComponent.vue' + +export default { + extends: DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + 'aside-outline-before': () => h(MyComponent) + }) + } +} +``` + +デフォルトテーマレイアウトで利用可能なスロットの一覧: + +- フロントマターで `layout: 'doc'`(デフォルト)を有効にしているとき: + - `doc-top` + - `doc-bottom` + - `doc-footer-before` + - `doc-before` + - `doc-after` + - `sidebar-nav-before` + - `sidebar-nav-after` + - `aside-top` + - `aside-bottom` + - `aside-outline-before` + - `aside-outline-after` + - `aside-ads-before` + - `aside-ads-after` +- フロントマターで `layout: 'home'` を有効にしているとき: + - `home-hero-before` + - `home-hero-info-before` + - `home-hero-info` + - `home-hero-info-after` + - `home-hero-actions-before-actions` + - `home-hero-actions-after` + - `home-hero-image` + - `home-hero-after` + - `home-features-before` + - `home-features-after` +- フロントマターで `layout: 'page'` を有効にしているとき: + - `page-top` + - `page-bottom` +- 404(Not Found)ページ: + - `not-found` +- 常に利用可能: + - `layout-top` + - `layout-bottom` + - `nav-bar-title-before` + - `nav-bar-title-after` + - `nav-bar-content-before` + - `nav-bar-content-after` + - `nav-screen-content-before` + - `nav-screen-content-after` + +## View Transitions API の利用 + +### 外観切り替え時(ライト/ダーク) {#on-appearance-toggle} + +カラーモード切り替え時にカスタムトランジションを提供するよう、デフォルトテーマを拡張できます。例: + +```vue [.vitepress/theme/Layout.vue] + + + + + +``` + +結果(**注意!**:点滅や急な動き、明るい光を含みます): + +
    +デモ + +![Appearance Toggle Transition Demo](/appearance-toggle-transition.webp) + +
    + +詳細は [Chrome Docs](https://developer.chrome.com/docs/web-platform/view-transitions/) を参照してください。 + +### ルート遷移時 {#on-route-change} + +近日公開。 + +## 内部コンポーネントの置き換え {#overriding-internal-components} + +Vite の [エイリアス](https://vitejs.dev/config/shared-options.html#resolve-alias) を使って、デフォルトテーマのコンポーネントを独自のものに置き換えられます。 + +```ts +import { fileURLToPath, URL } from 'node:url' +import { defineConfig } from 'vitepress' + +export default defineConfig({ + vite: { + resolve: { + alias: [ + { + find: /^.*\/VPNavBar\.vue$/, + replacement: fileURLToPath( + new URL('./theme/components/CustomNavBar.vue', import.meta.url) + ) + } + ] + } + } +}) +``` + +正確なコンポーネント名は [ソースコード](https://github.com/vuejs/vitepress/tree/main/src/client/theme-default/components) を参照してください。内部コンポーネントであるため、マイナーリリース間で名称が更新される可能性があります。 diff --git a/docs/ja/guide/frontmatter.md b/docs/ja/guide/frontmatter.md new file mode 100644 index 000000000..0cd389072 --- /dev/null +++ b/docs/ja/guide/frontmatter.md @@ -0,0 +1,52 @@ +--- +description: VitePressのMarkdownファイルでYAMLフロントマターを使い、ページ単位のメタデータや動作を制御する方法。 +--- + +# フロントマター {#frontmatter} + +## 使い方 {#usage} + +VitePress はすべての Markdown ファイルで YAML フロントマターをサポートしており、[gray-matter](https://github.com/jonschlinkert/gray-matter) で解析します。フロントマターは Markdown ファイルの先頭(` + + +``` + +## RTL サポート(実験的){#rtl-support-experimental} + +RTL をサポートするには、設定で `dir: 'rtl'` を指定し、、または のような RTLCSS 系の PostCSS プラグインを使用してください。CSS の詳細度の問題を避けるため、PostCSS プラグインでは `:where([dir="ltr"])` と `:where([dir="rtl"])` を接頭辞として使うよう設定してください。 diff --git a/docs/ja/guide/markdown.md b/docs/ja/guide/markdown.md new file mode 100644 index 000000000..fc839fc34 --- /dev/null +++ b/docs/ja/guide/markdown.md @@ -0,0 +1,1041 @@ +--- +description: VitePress組み込みのMarkdown拡張機能。カスタムコンテナ、コードブロックのシンタックスハイライト、行ハイライト、コードグループなど。 +--- + +# Markdown 拡張 {#markdown-extensions} + +VitePress には組み込みの Markdown 拡張機能が用意されています。 + +## 見出しアンカー {#header-anchors} + +見出しには自動的にアンカーリンクが付与されます。アンカーのレンダリングは `markdown.anchor` オプションで設定できます。 + +### カスタムアンカー {#custom-anchors} + +自動生成ではなく任意のアンカーを指定したい場合は、見出しの末尾にサフィックスを追加します。 + +```md +# カスタムアンカーを使う {#my-anchor} +``` + +これにより、デフォルトの `#using-custom-anchors` ではなく `#my-anchor` でその見出しにリンクできます。 + +## リンク {#links} + +内部リンクと外部リンクは特別に処理されます。 + +### 内部リンク {#internal-links} + +内部リンクは SPA ナビゲーションのためにルーターリンクへ変換されます。また、各サブディレクトリにある `index.md` は自動的に `index.html` に変換され、URL は対応する `/` になります。 + +次のようなディレクトリ構成があるとします。 + +``` +. +├─ index.md +├─ foo +│ ├─ index.md +│ ├─ one.md +│ └─ two.md +└─ bar + ├─ index.md + ├─ three.md + └─ four.md +``` + +そして、現在編集中のファイルが `foo/one.md` の場合: + +```md +[Home](/) +[foo](/foo/) +[foo の見出し](./#heading) +[bar - three](../bar/three) +[bar - three](../bar/three.md) +[bar - four](../bar/four.html) +``` + +### ページサフィックス {#page-suffix} + +ページと内部リンクはデフォルトで `.html` サフィックス付きで生成されます。 + +### 外部リンク {#external-links} + +外部リンクには自動的に `target="_blank" rel="noreferrer"` が付与されます。 + +- [vuejs.org](https://vuejs.org) +- [VitePress on GitHub](https://github.com/vuejs/vitepress) + +## フロントマター {#frontmatter} + +[YAML フロントマター](https://jekyllrb.com/docs/front-matter/) をそのままサポートしています。 + +```yaml +--- +title: ハッカーのようにブログを書く +lang: ja-JP +--- +``` + +このデータはページ内や、カスタム/テーマコンポーネントからも利用できます。詳しくは [Frontmatter](../reference/frontmatter-config) を参照してください。 + +## GitHub 風テーブル {#github-style-tables} + +**入力** + +```md +| テーブル | は | クール | +| -------- | :-------: | -----: | +| 3列目は | 右寄せ | $1600 | +| 2列目は | 中央 | $12 | +| シマ模様 | neat です | $1 | +``` + +**出力** + +| テーブル | は | クール | +| -------- | :------: | -----: | +| 3列目は | 右寄せ | \$1600 | +| 2列目は | 中央 | \$12 | +| シマ模様 | neatです | \$1 | + +## 絵文字 :tada: {#emoji} + +**入力** + +``` +:tada: :100: +``` + +**出力** + +:tada: :100: + +すべての絵文字の [一覧はこちら](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.mjs)。 + +## 目次 {#table-of-contents} + +**入力** + +``` +[[toc]] +``` + +**出力** + +[[toc]] + +TOC のレンダリングは `markdown.toc` オプションで設定できます。 + +## カスタムコンテナ {#custom-containers} + +タイプ、タイトル、内容を指定してカスタムコンテナを定義できます。 + +### デフォルトタイトル {#default-title} + +**入力** + +```md +::: info +これは情報ボックスです。 +::: + +::: tip +これはヒントです。 +::: + +::: warning +これは警告です。 +::: + +::: danger +これは危険の警告です。 +::: + +::: details +これは詳細ブロックです。 +::: +``` + +**出力** + +::: info +これは情報ボックスです。 +::: + +::: tip +これはヒントです。 +::: + +::: warning +これは警告です。 +::: + +::: danger +これは危険の警告です。 +::: + +::: details +これは詳細ブロックです。 +::: + +### カスタムタイトル {#custom-title} + +コンテナの「タイプ」の直後に文字列を追加することで、タイトルをカスタマイズできます。 + +**入力** + +````md +::: danger 停止 +危険地帯。先に進まないでください。 +::: + +::: details クリックしてコードを表示/非表示 +```js +console.log('こんにちは、VitePress!') +``` +::: +```` + +**出力** + +::: danger 停止 +危険地帯。先に進まないでください。 +::: + +::: details クリックしてコードを表示/非表示 +```js +console.log('こんにちは、VitePress!') +``` +::: + +また、英語以外で執筆する場合などは、サイト設定に以下を追加してタイトル文字列をグローバルに上書きできます。 + +```ts +// config.ts +export default defineConfig({ + // ... + markdown: { + container: { + tipLabel: 'ヒント', + warningLabel: '警告', + dangerLabel: '危険', + infoLabel: '情報', + detailsLabel: '詳細' + } + } + // ... +}) +``` + +### 追加属性 {#additional-attributes} + +カスタムコンテナには追加の属性を付与できます。この機能には [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) を使用しており、ほぼすべての Markdown 要素でサポートされます。たとえば `open` 属性を付けると、details ブロックをデフォルトで開いた状態にできます。 + +**入力** + +````md +::: details クリックしてコードを表示/非表示 {open} +```js +console.log('こんにちは、VitePress!') +``` +::: +```` + +**出力** + +::: details クリックしてコードを表示/非表示 {open} +```js +console.log('こんにちは、VitePress!') +``` +::: + +### `raw` + +これは、VitePress でのスタイルやルーターの衝突を防ぐための特別なコンテナです。コンポーネントライブラリのドキュメント化に特に有用です。より強力な分離が必要であれば、[whyframe](https://whyframe.dev/docs/integrations/vitepress) も検討してください。 + +**構文** + +```md +::: raw +Wraps in a `
    ` +::: +``` + +`vp-raw` クラスは要素に直接付与することも可能です。スタイルの分離は現在オプトインです。 + +- お好みのパッケージマネージャで `postcss` をインストールします: + + ```sh + $ npm add -D postcss + ``` + +- `docs/postcss.config.mjs` を作成し、次を追加します: + + ```js + import { postcssIsolateStyles } from 'vitepress' + + export default { + plugins: [postcssIsolateStyles()] + } + ``` + + オプションは次のように渡せます: + + ```js + postcssIsolateStyles({ + includeFiles: [/custom\.css/] // 既定は [/vp-doc\.css/, /base\.css/] + }) + ``` + +## GitHub 形式のアラート {#github-flavored-alerts} + +VitePress は [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) と同様です。 + +**入力** + +```md +> [!NOTE] +> 流し読みでも目に留めてほしい情報を強調します。 + +> [!TIP] +> 成功の手助けとなる任意の情報です。 + +> [!IMPORTANT] +> 成功に必須の重要情報です。 + +> [!WARNING] +> 危険性があるため即時の注意が必要な重要情報です。 + +> [!CAUTION] +> 行動による望ましくない結果の可能性です。 +``` + +**出力** + +> [!NOTE] +> 流し読みでも目に留めてほしい情報を強調します。 + +> [!TIP] +> 成功の手助けとなる任意の情報です。 + +> [!IMPORTANT] +> 成功に必須の重要情報です。 + +> [!WARNING] +> 危険性があるため即時の注意が必要な重要情報です。 + +> [!CAUTION] +> 行動による望ましくない結果の可能性です。 + +## コードブロックのシンタックスハイライト {#syntax-highlighting-in-code-blocks} + +VitePress は [Shiki](https://github.com/shikijs/shiki) を使って、Markdown のコードブロックに色付きのシンタックスハイライトを適用します。Shiki は多くのプログラミング言語をサポートしています。コードブロックの先頭のバッククォートに有効な言語エイリアスを付けるだけで利用できます。 + +**入力** + +````md +```js +export default { + name: 'MyComponent', + // ... +} +``` +```` + +````md +```html +
      +
    • + {{ todo.text }} +
    • +
    +``` +```` + +**出力** + +```js +export default { + name: 'MyComponent', + // ... +} +``` + +```html +
      +
    • + {{ todo.text }} +
    • +
    +``` + +有効な言語の [一覧](https://shiki.style/languages) は Shiki のリポジトリで確認できます。 + +また、シンタックスハイライトのテーマ変更、言語エイリアスの設定、言語ラベルのカスタマイズなどはアプリ設定の [`markdown` オプション](../reference/site-config#markdown) で行えます。 + +## コードブロックの行ハイライト {#line-highlighting-in-code-blocks} + +**入力** + +````md +```js{4} +export default { + data() { + return { + msg: 'ハイライト!' + } + } +} +``` +```` + +**出力** + +```js{4} +export default { + data() { + return { + msg: 'ハイライト!' + } + } +} +``` + +単一行だけでなく、複数の単一行や範囲、あるいはその組み合わせも指定できます: + +- 行範囲の例: `{5-8}`, `{3-10}`, `{10-17}` +- 複数の単一行: `{4,7,9}` +- 行範囲+単一行: `{4,7-13,16,23-27,40}` + +**入力** + +````md +```js{1,4,6-8} +export default { // Highlighted + data() { + return { + msg: `Highlighted! + This line isn't highlighted, + but this and the next 2 are.`, + motd: 'VitePress is awesome', + lorem: 'ipsum' + } + } +} +``` +```` + +**出力** + +```js{1,4,6-8} +export default { // Highlighted + data() { + return { + msg: `Highlighted! + This line isn't highlighted, + but this and the next 2 are.`, + motd: 'VitePress is awesome', + lorem: 'ipsum' + } + } +} +``` + +代替案として、`// [!code highlight]` コメントを使って行内を直接ハイライトできます。 + +**入力** + +````md +```js +export default { + data() { + return { + msg: 'ハイライト!' // [!code highlight] + } + } +} +``` +```` + +**出力** + +```js +export default { + data() { + return { + msg: 'ハイライト!' // [!code highlight] + } + } +} +``` + +## コードブロックでのフォーカス {#focus-in-code-blocks} + +`// [!code focus]` コメントを行に付けると、その行にフォーカスし、他の部分がぼかされます。 + +また、`// [!code focus:]` を使ってフォーカスする行数を指定することもできます。 + +**入力** + +````md +```js +export default { + data() { + return { + msg: 'フォーカス!' // [!!code focus] + } + } +} +``` +```` + +**出力** + +```js +export default { + data() { + return { + msg: 'フォーカス!' // [!code focus] + } + } +} +``` + +## コードブロックのカラー差分表示 {#colored-diffs-in-code-blocks} + +`// [!code --]` または `// [!code ++]` コメントを行に付けると、その行に差分(削除/追加)スタイルを適用できます。コードブロックの色付けは維持されます。 + +**入力** + +````md +```js +export default { + data() { + return { + msg: 'Removed' // [!!code --] + msg: 'Added' // [!!code ++] + } + } +} +``` +```` + +**出力** + +```js +export default { + data() { + return { + msg: 'Removed' // [!code --] + msg: 'Added' // [!code ++] + } + } +} +``` + +## コードブロック内のエラー/警告表示 {#errors-and-warnings-in-code-blocks} + +行に `// [!code warning]` または `// [!code error]` コメントを付けると、その行が対応する色で表示されます。 + +**入力** + +````md +```js +export default { + data() { + return { + msg: 'Error', // [!!code error] + msg: 'Warning' // [!!code warning] + } + } +} +``` +```` + +**出力** + +```js +export default { + data() { + return { + msg: 'Error', // [!code error] + msg: 'Warning' // [!code warning] + } + } +} +``` + +## 行番号 {#line-numbers} + +設定で、各コードブロックに行番号を表示できます: + +```js +export default { + markdown: { + lineNumbers: true + } +} +``` + +詳しくは [`markdown` オプション](../reference/site-config#markdown) を参照してください。 + +設定値を上書きするために、フェンス付きコードブロックに `:line-numbers` / `:no-line-numbers` マークを付与できます。 + +また、`:line-numbers` の後ろに `=` を付けて開始行番号を指定できます。例:`:line-numbers=2` は行番号が `2` から始まることを意味します。 + +**入力** + +````md +```ts {1} +// 既定では line-numbers は無効 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers {1} +// line-numbers が有効 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers=2 {1} +// line-numbers が有効で、2 から開始 +const line3 = 'This is line 3' +const line4 = 'This is line 4' +``` +```` + +**出力** + +```ts {1} +// 既定では line-numbers は無効 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers {1} +// line-numbers が有効 +const line2 = 'This is line 2' +const line3 = 'This is line 3' +``` + +```ts:line-numbers=2 {1} +// line-numbers が有効で、2 から開始 +const line3 = 'This is line 3' +const line4 = 'This is line 4' +``` + +## コードスニペットのインポート {#import-code-snippets} + +既存ファイルから、次の構文でコードスニペットをインポートできます: + +```md +<<< @/filepath +``` + +また、[行のハイライト](#line-highlighting-in-code-blocks)にも対応しています: + +```md +<<< @/filepath{highlightLines} +``` + +**入力** + +```md +<<< @/snippets/snippet.js{2} +``` + +**コードファイル** + +<<< @/snippets/snippet.js + +**出力** + +<<< @/snippets/snippet.js{2} + +::: tip +`@` の値はソースルートを表します。既定では VitePress プロジェクトのルートですが、`srcDir` を設定している場合はその値になります。代替として、相対パスからのインポートも可能です: + +```md +<<< ../snippets/snippet.js +``` +::: + +また、[VS Code のリージョン](https://code.visualstudio.com/docs/editor/codebasics#_folding)を利用して、コードファイルの該当部分のみを取り込むことができます。ファイルパスの後ろに `#` を付けてカスタムリージョン名を指定します: + +**入力** + +```md +<<< @/snippets/snippet-with-region.js#snippet{1} +``` + +**コードファイル** + +<<< @/snippets/snippet-with-region.js + +**出力** + +<<< @/snippets/snippet-with-region.js#snippet{1} + +中括弧(`{}`)の中で言語を指定することもできます: + +```md +<<< @/snippets/snippet.cs{c#} + + + +<<< @/snippets/snippet.cs{1,2,4-6 c#} + + + +<<< @/snippets/snippet.cs{1,2,4-6 c#:line-numbers} +``` + +これは、ファイル拡張子からソース言語を推論できない場合に有用です。 + +## コードグループ {#code-groups} + +複数のコードブロックを、次のようにグループ化できます。 + +**入力** + +````md +::: code-group + +```js [config.js] +/** + * @type {import('vitepress').UserConfig} + */ +const config = { + // ... +} + +export default config +``` + +```ts [config.ts] +import type { UserConfig } from 'vitepress' + +const config: UserConfig = { + // ... +} + +export default config +``` + +::: +```` + +**出力** + +::: code-group + +```js [config.js] +/** + * @type {import('vitepress').UserConfig} + */ +const config = { + // ... +} + +export default config +``` + +```ts [config.ts] +import type { UserConfig } from 'vitepress' + +const config: UserConfig = { + // ... +} + +export default config +``` + +::: + +コードグループ内でも [スニペットのインポート](#import-code-snippets) が可能です: + +**入力** + +```md +::: code-group + + + +<<< @/snippets/snippet.js + + + +<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [リージョン付きスニペット] + +::: +``` + +**出力** + +::: code-group + +<<< @/snippets/snippet.js + +<<< @/snippets/snippet-with-region.js#snippet{1,2 ts:line-numbers} [リージョン付きスニペット] + +::: + +## Markdown ファイルのインクルード {#markdown-file-inclusion} + +ある Markdown ファイルの中に、別の Markdown ファイルを取り込めます(入れ子も可能)。 + +::: tip +Markdown パスの先頭に `@` を付けることもでき、その場合はソースルートとして扱われます。既定では VitePress プロジェクトのルートですが、`srcDir` を設定している場合はその値になります。 +::: + +例えば、相対パスの Markdown ファイルを次のように取り込めます。 + +**入力** + +```md +# ドキュメント + +## 基本 + + +``` + +**パートファイル**(`parts/basics.md`) + +```md +はじめに知っておきたいこと。 + +### 設定 + +`.foorc.json` を使用して作成できます。 +``` + +**等価なコード** + +```md +# ドキュメント + +## 基本 + +はじめに知っておきたいこと。 + +### 設定 + +`.foorc.json` を使用して作成できます。 +``` + +行範囲の選択にも対応しています。 + +**入力** + +```md:line-numbers +# ドキュメント + +## 基本 + + +``` + +**パートファイル**(`parts/basics.md`) + +```md:line-numbers +はじめに知っておきたいこと。 + +### 設定 + +`.foorc.json` を使って作成できます。 +``` + +**等価なコード** + +```md:line-numbers +# ドキュメント + +## 基本 + +### 設定 + +`.foorc.json` を使って作成できます。 +``` + +選択できる行範囲の書式は、`{3,}`、`{,10}`、`{1,10}` のいずれかです。 + +[VS Code のリージョン](https://code.visualstudio.com/docs/editor/codebasics#_folding)を使って、コードファイルの該当部分だけを取り込むこともできます。ファイルパスの後ろに `#` を付けて、カスタムリージョン名を指定します。 + +**入力** + +```md:line-numbers +# ドキュメント + +## 基本 + + + +``` + +**パートファイル**(`parts/basics.md`) + +```md:line-numbers + +## 使用例 1 + +## 使用例 2 + +## 使用例 3 + +``` + +**等価なコード** + +```md:line-numbers +# ドキュメント + +## 基本 + +## 使用例 1 + +## 使用例 3 +``` + +::: warning +ファイルが存在しない場合でもエラーは発生しません。したがって、この機能を使う際は、期待どおりに内容がレンダリングされているか必ず確認してください。 +::: + +VS Code のリージョンの代わりに、ヘッダーアンカーを使ってファイル内の特定セクションだけを取り込むこともできます。たとえば、Markdown ファイルに次のようなヘッダーがある場合: + +```md +## ベースのセクション + +ここに本文。 + +### サブセクション + +ここに本文(サブ)。 + +## 別のセクション + +`ベースのセクション` の外側の内容。 +``` + +`ベースのセクション` を次のように取り込めます: + +```md +## 拡張セクション + + +``` + +**等価なコード** + +```md +## 拡張セクション + +ここに本文。 + +### サブセクション + +ここに本文(サブ)。 +``` + +ここで `my-base-section` は見出し要素から生成される ID です。推測しづらい場合は、パートファイルをブラウザで開いて見出しのアンカー(ホバー時に見出しの左に表示される `#` 記号)をクリックし、URL バーで ID を確認してください。あるいはブラウザの開発者ツールで要素を検査して確認できます。別案として、パートファイル側で明示的に ID を指定できます: + +```md +## ベースのセクション {#custom-id} +``` + +そして次のように取り込みます: + +```md + +``` + +## 数式 {#math-equations} + +この機能はオプトインです。利用するには `markdown-it-mathjax3` をインストールし、設定ファイルで `markdown.math` を `true` に設定します。 + +```sh +npm add -D markdown-it-mathjax3@^4 +``` + +```ts [.vitepress/config.ts] +export default { + markdown: { + math: true + } +} +``` + +**入力** + +```md +もし $a \ne 0$ のとき、$(ax^2 + bx + c = 0)$ の解は 2 つ存在し、次式で与えられます +$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$ + +**マクスウェル方程式:** + +| 方程式 | 説明 | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| $\nabla \cdot \vec{\mathbf{B}} = 0$ | 磁束密度 $\vec{\mathbf{B}}$ の発散は 0 | +| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | 電場 $\vec{\mathbf{E}}$ の回転は、磁束密度 $\vec{\mathbf{B}}$ の時間変化に比例 | +| $\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$ | _え?_ | +``` + +**出力** + +もし $a \ne 0$ のとき、$(ax^2 + bx + c = 0)$ の解は 2 つ存在し、次式で与えられます +$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$ + +**マクスウェル方程式:** + +| 方程式 | 説明 | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| $\nabla \cdot \vec{\mathbf{B}} = 0$ | 磁束密度 $\vec{\mathbf{B}}$ の発散は 0 | +| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | 電場 $\vec{\mathbf{E}}$ の回転は、磁束密度 $\vec{\mathbf{B}}$ の時間変化に比例 | +| $\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$ | _え?_ | + +## 画像の遅延読み込み {#image-lazy-loading} + +Markdown で追加した各画像に対して遅延読み込みを有効化するには、設定ファイルで `lazyLoading` を `true` にします: + +```js +export default { + markdown: { + image: { + // 既定では画像の遅延読み込みは無効 + lazyLoading: true + } + } +} +``` + +## 高度な設定 {#advanced-configuration} + +VitePress は Markdown レンダラーとして [markdown-it](https://github.com/markdown-it/markdown-it) を使用しています。上記の多くの拡張はカスタムプラグインとして実装されています。`.vitepress/config.js` の `markdown` オプションを使って、`markdown-it` のインスタンスをさらにカスタマイズできます。 + +```js +import { defineConfig } from 'vitepress' +import markdownItAnchor from 'markdown-it-anchor' +import markdownItFoo from 'markdown-it-foo' + +export default defineConfig({ + markdown: { + // markdown-it-anchor のオプション + // https://github.com/valeriangalliat/markdown-it-anchor#usage + anchor: { + permalink: markdownItAnchor.permalink.headerLink() + }, + + // @mdit-vue/plugin-toc のオプション + // https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-toc#options + toc: { level: [1, 2] }, + + config: (md) => { + // markdown-it のプラグインをもっと使えます! + md.use(markdownItFoo) + } + } +}) +``` + +設定可能なプロパティの完全な一覧は、[設定リファレンス: アプリ設定](../reference/site-config#markdown) を参照してください。 diff --git a/docs/ja/guide/mpa-mode.md b/docs/ja/guide/mpa-mode.md new file mode 100644 index 000000000..665e54104 --- /dev/null +++ b/docs/ja/guide/mpa-mode.md @@ -0,0 +1,27 @@ +--- +description: VitePressのMPA(マルチページアプリケーション)モードを有効にし、JavaScriptゼロのページで初期パフォーマンスを向上させる方法。 +--- + +# MPA モード {#mpa-mode} + +MPA(Multi-Page Application)モードは、コマンドラインの `vitepress build --mpa`、または設定で `mpa: true` を指定することで有効化できます。 + +MPA モードでは、既定で **あらゆるページが JavaScript を含まずに** レンダリングされます。結果として、本番サイトは監査ツールにおける初回訪問のパフォーマンススコアが向上しやすくなります。 + +一方、SPA のナビゲーションがないため、ページ間リンクはフルリロードになります。読み込み後のページ遷移は、SPA モードのような即時性はありません。 + +また、「既定で JS なし」ということは、実質的に Vue をサーバーサイドのテンプレート言語としてのみ使うことを意味します。ブラウザ側ではイベントハンドラがアタッチされないため、インタラクティブ性はありません。クライアントサイドの JavaScript を読み込むには、特別な ` + +# Hello +``` + +` +``` + +### 生コンテンツのレンダリング {#rendering-raw-content} + +ページに渡したパラメータはクライアント JavaScript のペイロードにシリアライズされます。そのため、リモート CMS から取得した生の Markdown や HTML など、重いデータをパラメータに含めるのは避けてください。 + +代わりに、各パスオブジェクトの `content` プロパティでコンテンツを渡せます: + +```js +export default { + async paths() { + const posts = await (await fetch('https://my-cms.com/blog-posts')).json() + + return posts.map((post) => { + return { + params: { id: post.id }, + content: post.content // 生の Markdown または HTML + } + }) + } +} +``` + +そのうえで、Markdown ファイル内で次の特別な構文を使って、そのコンテンツを埋め込みます: + +```md + +``` diff --git a/docs/ja/guide/sitemap-generation.md b/docs/ja/guide/sitemap-generation.md new file mode 100644 index 000000000..d74084ca6 --- /dev/null +++ b/docs/ja/guide/sitemap-generation.md @@ -0,0 +1,62 @@ +--- +description: VitePressサイトのsitemap.xmlを生成し、検索エンジンからの発見性を向上させる方法。 +--- + +# サイトマップ生成 {#sitemap-generation} + +VitePress には、サイト用の `sitemap.xml` を生成する機能が標準で用意されています。有効化するには、`.vitepress/config.js` に次を追加します。 + +```ts +export default { + sitemap: { + hostname: 'https://example.com' + } +} +``` + +`siteamp.xml` に `` タグを含めるには、[`lastUpdated`](../reference/default-theme-last-updated) オプションを有効にします。 + +## オプション {#options} + +サイトマップ生成は [`sitemap`](https://www.npmjs.com/package/sitemap) モジュールで行われます。設定ファイルの `sitemap` に、このモジュールがサポートする任意のオプションを渡せます。指定した値はそのまま `SitemapStream` コンストラクタに渡されます。詳しくは [`sitemap` のドキュメント](https://www.npmjs.com/package/sitemap#options-you-can-pass) を参照してください。例: + +```ts +export default { + sitemap: { + hostname: 'https://example.com', + lastmodDateOnly: false + } +} +``` + +設定で `base` を使っている場合は、`hostname` にもそれを付与してください: + +```ts +export default { + base: '/my-site/', + sitemap: { + hostname: 'https://example.com/my-site/' + } +} +``` + +## `transformItems` フック {#transformitems-hook} + +`siteamp.xml` に書き出す直前にサイトマップ項目を加工するには、`sitemap.transformItems` フックを使います。このフックはサイトマップ項目の配列を受け取り、配列を返す必要があります。例: + +```ts +export default { + sitemap: { + hostname: 'https://example.com', + transformItems: (items) => { + // 既存項目の追加・変更・フィルタリングが可能 + items.push({ + url: '/extra-page', + changefreq: 'monthly', + priority: 0.8 + }) + return items + } + } +} +``` diff --git a/docs/ja/guide/ssr-compat.md b/docs/ja/guide/ssr-compat.md new file mode 100644 index 000000000..ec94a4a4d --- /dev/null +++ b/docs/ja/guide/ssr-compat.md @@ -0,0 +1,136 @@ +--- +outline: deep +description: VitePressのテーマコンポーネントやカスタムコードをサーバーサイドレンダリング(SSR)に対応させる方法。 +--- + +# SSR 互換性 {#ssr-compatibility} + +VitePress は本番ビルド時に、Node.js 上で Vue のサーバーサイドレンダリング(SSR)機能を使ってアプリを事前レンダリングします。つまり、テーマコンポーネント内のすべてのカスタムコードは SSR 互換性の対象になります。 + +[公式 Vue ドキュメントの SSR セクション](https://vuejs.org/guide/scaling-up/ssr.html)では、SSR とは何か、SSR と SSG の関係、そして SSR に優しいコードを書く際の一般的な注意点が解説されています。経験則としては、**ブラウザ / DOM API へのアクセスは Vue コンポーネントの `beforeMount` または `mounted` フック内に限定** するのが安全です。 + +## `` {#clientonly} + +SSR に適さないコンポーネント(例:カスタムディレクティブを含むなど)を使用・デモする場合は、組み込みの `` コンポーネントでラップできます。 + +```md + + + +``` + +## インポート時に Browser API にアクセスするライブラリ {#libraries-that-access-browser-api-on-import} + +一部のコンポーネントやライブラリは **インポート時に** ブラウザ API にアクセスします。インポート時にブラウザ環境を前提とするコードを使うには、動的インポートが必要です。 + +### mounted フック内でのインポート {#importing-in-mounted-hook} + +```vue + +``` + +### 条件付きインポート {#conditional-import} + +[`import.meta.env.SSR`](https://vitejs.dev/guide/env-and-mode.html#env-variables) フラグ(Vite の環境変数の一部)を使って、依存関係を条件付きでインポートすることもできます。 + +```js +if (!import.meta.env.SSR) { + import('./lib-that-access-window-on-import').then((module) => { + // ここでコードを利用 + }) +} +``` + +[`Theme.enhanceApp`](./custom-theme#theme-interface) は非同期にできるため、**インポート時に Browser API に触れる Vue プラグイン** を条件付きでインポート・登録できます。 + +```js [.vitepress/theme/index.js] +/** @type {import('vitepress').Theme} */ +export default { + // ... + async enhanceApp({ app }) { + if (!import.meta.env.SSR) { + const plugin = await import('plugin-that-access-window-on-import') + app.use(plugin.default) + } + } +} +``` + +TypeScript を使う場合: + +```ts [.vitepress/theme/index.ts] +import type { Theme } from 'vitepress' + +export default { + // ... + async enhanceApp({ app }) { + if (!import.meta.env.SSR) { + const plugin = await import('plugin-that-access-window-on-import') + app.use(plugin.default) + } + } +} satisfies Theme +``` + +### `defineClientComponent` + +VitePress は、**インポート時に Browser API にアクセスする Vue コンポーネント** を読み込むためのユーティリティを提供します。 + +```vue + + + +``` + +ターゲットコンポーネントに props / children / slots を渡すこともできます。 + +```vue + + + +``` + +ターゲットコンポーネントは、ラッパーコンポーネントの mounted フックで初めてインポートされます。 diff --git a/docs/ja/guide/using-vue.md b/docs/ja/guide/using-vue.md new file mode 100644 index 000000000..9cbc76081 --- /dev/null +++ b/docs/ja/guide/using-vue.md @@ -0,0 +1,292 @@ +--- +description: VitePressのMarkdownファイル内でVueコンポーネントや動的テンプレート機能を直接使用する方法。 +--- + +# MarkdownでVueを使う {#using-vue-in-markdown} + +VitePress では、各 Markdown ファイルはまず HTML にコンパイルされ、その後 [Vue の単一ファイルコンポーネント(SFC)](https://vuejs.org/guide/scaling-up/sfc.html) として処理されます。つまり、Markdown 内で Vue のあらゆる機能が使えます。動的テンプレート、Vue コンポーネントの利用、` + +## Markdown コンテンツ + +現在の値: {{ count }} + + + + +``` + +::: warning Markdown での ` +``` + +## Teleport の利用 {#using-teleports} + +現時点で VitePress は、SSG における Teleport を **body** へのみサポートしています。その他のターゲットへ Teleport したい場合は、組み込みの `` でラップするか、[`postRender` フック](../reference/site-config#postrender)で最終ページ HTML の適切な位置に Teleport のマークアップを注入してください。 + + + +::: details +<<< @/components/ModalDemo.vue +::: + +```md + + +
    + // ... +
    +
    +
    +``` + + + + + +## VS Code の IntelliSense サポート {#vs-code-intellisense-support} + + + +Vue は [Vue - Official VS Code plugin](https://marketplace.visualstudio.com/items?itemName=Vue.volar) により、標準で IntelliSense を提供します。ただし `.md` ファイルでも有効にするには、設定ファイルをいくつか調整する必要があります。 + +1. tsconfig/jsconfig の `include` と `vueCompilerOptions.vitePressExtensions` に `.md` パターンを追加します。 + +::: code-group +```json [tsconfig.json] +{ + "include": [ + "docs/**/*.ts", + "docs/**/*.vue", + "docs/**/*.md" + ], + "vueCompilerOptions": { + "vitePressExtensions": [".md"] + } +} +``` +::: + +2. VS Code の設定で、`vue.server.includeLanguages` に `markdown` を追加します。 + +::: code-group +```json [.vscode/settings.json] +{ + "vue.server.includeLanguages": ["vue", "markdown"] +} +``` +::: diff --git a/docs/ja/guide/what-is-vitepress.md b/docs/ja/guide/what-is-vitepress.md new file mode 100644 index 000000000..1920adafc --- /dev/null +++ b/docs/ja/guide/what-is-vitepress.md @@ -0,0 +1,61 @@ +--- +description: VitePressはViteとVueを基盤とした、高速でコンテンツ中心のWebサイト構築向け静的サイトジェネレーターです。 +--- + +# VitePress とは? {#what-is-vitepress} + +VitePress は、高速でコンテンツ中心の Web サイトを構築するための [静的サイトジェネレーター(SSG)](https://en.wikipedia.org/wiki/Static_site_generator) です。要するに、VitePress は [Markdown](https://en.wikipedia.org/wiki/Markdown) で書かれたソースコンテンツにテーマを適用し、どこにでも簡単にデプロイできる静的 HTML ページを生成します。 + +
    + +まずは試してみたい? [クイックスタート](./getting-started) へどうぞ。 + +
    + +## ユースケース {#use-cases} + +- **ドキュメント** + + 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)のドキュメントサイトで使われています。 + + [公式の Vue.js ドキュメント](https://vuejs.org/) も VitePress をベースにしています(複数言語で共有されるカスタムテーマを使用)。 + +- **ブログ/ポートフォリオ/マーケティングサイト** + + VitePress は [フルカスタムテーマ](./custom-theme) をサポートし、標準的な Vite + Vue アプリ同様の開発体験を提供します。Vite 上に構築されているため、豊富なエコシステムから Vite プラグインを直接活用できます。さらに、[データの読み込み](./data-loading)(ローカル/リモート)や [ルートの動的生成](./routing#dynamic-routes) のための柔軟な API も提供します。ビルド時にデータが確定できる限り、ほとんど何でも構築できます。 + + 公式の [Vue.js ブログ](https://blog.vuejs.org/) は、ローカルコンテンツに基づいてインデックスページを生成するシンプルなブログです。 + +## 開発体験 {#developer-experience} + +VitePress は、Markdown コンテンツを扱う際の優れた開発体験(DX)を目指しています。 + +- **[Vite 駆動](https://vitejs.dev/)**:即時サーバー起動、編集はページリロードなしで常に瞬時(<100ms)に反映。 + +- **[ビルトインの Markdown 拡張](./markdown)**:Frontmatter、表、シンタックスハイライト…必要なものはひと通り。特にコードブロック周りの機能が充実しており、高度な技術ドキュメントに最適です。 + +- **[Vue 拡張 Markdown](./using-vue)**:各 Markdown ページは Vue の [単一ファイルコンポーネント(SFC)](https://vuejs.org/guide/scaling-up/sfc.html) としても機能します。HTML と 100% 互換な Vue テンプレートを活かし、Vue のテンプレート機能やインポートしたコンポーネントで静的コンテンツにインタラクションを埋め込めます。 + +## パフォーマンス {#performance} + +多くの従来型 SSG と異なり、VitePress で生成されたサイトは **初回訪問では静的 HTML** を返し、その後のサイト内ナビゲーションは [シングルページアプリケーション(SPA)](https://en.wikipedia.org/wiki/Single-page_application) として動作します。これはパフォーマンス面で最適なバランスだと考えています。 + +- **初期ロードが速い** + + どのページへの初回訪問でも、静的な事前レンダリング HTML が配信され、高速な読み込みと最適な SEO を実現します。続いて JavaScript バンドルが読み込まれ、ページが Vue の SPA に「ハイドレート」されます。SPA のハイドレーションは遅いという通説に反し、Vue 3 の素のパフォーマンスとコンパイラ最適化により非常に高速です。[PageSpeed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fvitepress.dev%2F) でも、VitePress サイトは低速回線のローエンド端末でもほぼ満点のスコアを達成できます。 + +- **読み込み後のナビゲーションが速い** + + さらに重要なのは、初回ロード**後**の体験が向上することです。サイト内の以降の移動ではフルリロードは発生せず、遷移先のコンテンツを取得して動的に更新します。VitePress はビューポート内のリンクに対してページチャンクを自動プリフェッチするため、ほとんどの場合で遷移は「即時」に感じられます。 + +- **インタラクションのペナルティなし** + + 静的 Markdown に埋め込まれた動的な Vue 部分をハイドレートできるよう、各 Markdown ページは Vue コンポーネントとして処理され JavaScript にコンパイルされます。一見非効率に思えますが、Vue コンパイラは静的部分と動的部分を賢く分離し、ハイドレーションのコストとペイロードを最小化します。初回ロードでは静的部分は自動的に JS ペイロードから除外され、ハイドレーションでもスキップされます。 + +## VuePress はどうなるの? {#what-about-vuepress} + +VitePress は VuePress 1 の精神的後継です。元の VuePress 1 は Vue 2 と webpack をベースとしていました。VitePress は内部に Vue 3 と Vite を採用し、開発体験・本番性能・完成度の高いデフォルトテーマ・より柔軟なカスタマイズ API を提供します。 + +VitePress と VuePress 1 の API の違いは主にテーマやカスタマイズ周りにあります。VuePress 1 でデフォルトテーマを使っている場合は、比較的容易に移行できます。 + +2 つの SSG を並行して維持するのは現実的ではないため、Vue チームは長期的に VitePress を推奨 SSG とする方針に集中しています。現在、VuePress 1 は非推奨となり、VuePress 2 は今後の開発・保守を VuePress コミュニティチームに委ねています。 diff --git a/docs/ja/index.md b/docs/ja/index.md new file mode 100644 index 000000000..b5be770bd --- /dev/null +++ b/docs/ja/index.md @@ -0,0 +1,36 @@ +--- +layout: home +description: VitePressはViteとVueを基盤とした静的サイトジェネレーターで、Markdownから美しいドキュメントサイトを構築できます。 + +hero: + name: VitePress + text: Vite & Vue をベースにした静的サイトジェネレーター + tagline: Markdown から美しいドキュメントを数分で + actions: + - theme: brand + text: VitePress とは? + link: ./guide/what-is-vitepress + - theme: alt + text: クイックスタート + link: ./guide/getting-started + - theme: alt + text: GitHub + link: https://github.com/vuejs/vitepress + image: + src: /vitepress-logo-large.svg + alt: VitePress + +features: + - icon: 📝 + title: コンテンツに集中 + details: Markdown だけで、美しいドキュメントサイトを簡単に作成できます。 + - icon: + title: Vite の開発体験を享受 + details: 即時サーバー起動、超高速ホットリロード、そして Vite エコシステムのプラグイン活用。 + - icon: + title: Vue でカスタマイズ + details: Markdown 内で直接 Vue 構文やコンポーネントを利用したり、Vue で独自テーマを構築できます。 + - icon: 🚀 + title: 高速サイトを公開 + details: 静的 HTML による高速初期ロードと、クライアントサイドルーティングによる快適なページ遷移。 +--- diff --git a/docs/ja/reference/cli.md b/docs/ja/reference/cli.md new file mode 100644 index 000000000..0b3b8b2c0 --- /dev/null +++ b/docs/ja/reference/cli.md @@ -0,0 +1,77 @@ +--- +description: VitePress CLIコマンドのリファレンス。dev、build、preview、initコマンドの使い方。 +--- + +# コマンドラインインターフェイス {#command-line-interface} + +## `vitepress dev` + +指定したディレクトリをルートとして VitePress の開発サーバーを起動します。既定はカレントディレクトリです。カレントディレクトリで実行する場合、`dev` コマンドは省略できます。 + +### 使い方 {#usage} + +```sh +# カレントディレクトリで起動(`dev` を省略) +vitepress + +# サブディレクトリで起動 +vitepress dev [root] +``` + +### オプション {#options} + +| オプション | 説明 | +| --------------- | ----------------------------------------------------- | +| `--open [path]` | 起動時にブラウザを開く(`boolean \| string`) | +| `--port ` | ポート番号を指定(`number`) | +| `--base ` | 公開時のベースパス(既定: `/`)(`string`) | +| `--cors` | CORS を有効化 | +| `--strictPort` | 指定ポートが使用中なら終了(`boolean`) | +| `--force` | 最適化時にキャッシュを無視して再バンドル(`boolean`) | + +## `vitepress build` + +本番用に VitePress サイトをビルドします。 + +### 使い方 {#usage-1} + +```sh +vitepress build [root] +``` + +### オプション {#options-1} + +| オプション | 説明 | +| ------------------------------ | ------------------------------------------------------------------------------------------ | +| `--mpa`(実験的) | クライアント側ハイドレーションなしの [MPA モード](../guide/mpa-mode) でビルド(`boolean`) | +| `--base ` | 公開時のベースパス(既定: `/`)(`string`) | +| `--target ` | トランスパイルターゲット(既定: `"modules"`)(`string`) | +| `--outDir ` | 出力先ディレクトリ(**cwd** からの相対)(既定: `/.vitepress/dist`)(`string`) | +| `--assetsInlineLimit ` | 静的アセットを base64 インライン化する閾値(バイト)(既定: `4096`)(`number`) | + +## `vitepress preview` + +本番ビルドをローカルでプレビューします。 + +### 使い方 {#usage-2} + +```sh +vitepress preview [root] +``` + +### オプション {#options-2} + +| オプション | 説明 | +| --------------- | ------------------------------------------- | +| `--base ` | 公開時のベースパス(既定: `/`)(`string`) | +| `--port ` | ポート番号を指定(`number`) | + +## `vitepress init` + +カレントディレクトリで [セットアップウィザード](../guide/getting-started#setup-wizard) を起動します。 + +### 使い方 {#usage-3} + +```sh +vitepress init +``` diff --git a/docs/ja/reference/default-theme-badge.md b/docs/ja/reference/default-theme-badge.md new file mode 100644 index 000000000..d23186ddb --- /dev/null +++ b/docs/ja/reference/default-theme-badge.md @@ -0,0 +1,73 @@ +--- +description: VitePressドキュメントの見出しにステータスラベルを追加するBadgeコンポーネントの使い方。 +--- + +# バッジ {#badge} + +バッジを使うと、見出しにステータスを追加できます。たとえば、そのセクションの種類や対応バージョンを示すのに便利です。 + +## 使い方 {#usage} + +グローバルに利用可能な `Badge` コンポーネントを使用します。 + +```md +### Title +### Title +### Title +### Title +``` + +上記のコードは次のように表示されます: + +### Title +### Title +### Title +### Title + +## 子要素のカスタマイズ {#custom-children} + +`` は子要素(`children`)を受け取り、バッジ内に表示できます。 + +```md +### Title custom element +``` + +### Title custom element + +## 種類ごとの色をカスタマイズ {#customize-type-color} + +CSS 変数を上書きすることで、バッジのスタイルをカスタマイズできます。以下はデフォルト値です: + +```css +:root { + --vp-badge-info-border: transparent; + --vp-badge-info-text: var(--vp-c-text-2); + --vp-badge-info-bg: var(--vp-c-default-soft); + + --vp-badge-tip-border: transparent; + --vp-badge-tip-text: var(--vp-c-brand-1); + --vp-badge-tip-bg: var(--vp-c-brand-soft); + + --vp-badge-warning-border: transparent; + --vp-badge-warning-text: var(--vp-c-warning-1); + --vp-badge-warning-bg: var(--vp-c-warning-soft); + + --vp-badge-danger-border: transparent; + --vp-badge-danger-text: var(--vp-c-danger-1); + --vp-badge-danger-bg: var(--vp-c-danger-soft); +} +``` + +## `` + +`` コンポーネントは次の props を受け取ります。 + +```ts +interface Props { + // `` が渡された場合、この値は無視されます。 + text?: string + + // 既定値は `tip`。 + type?: 'info' | 'tip' | 'warning' | 'danger' +} +``` diff --git a/docs/ja/reference/default-theme-carbon-ads.md b/docs/ja/reference/default-theme-carbon-ads.md new file mode 100644 index 000000000..db0e76f73 --- /dev/null +++ b/docs/ja/reference/default-theme-carbon-ads.md @@ -0,0 +1,29 @@ +--- +description: デフォルトテーマの組み込みサポートを使い、VitePressサイトにCarbon Adsを統合する方法。 +--- + +# Carbon 広告 {#carbon-ads} + +VitePress は [Carbon Ads](https://www.carbonads.net/) をネイティブにサポートしています。設定で Carbon Ads の認証情報を定義すると、ページ上に広告が表示されます。 + +```js +export default { + themeConfig: { + carbonAds: { + code: 'your-carbon-code', + placement: 'your-carbon-placement', + format: 'classic' + } + } +} +``` + +これらの値は、次のように Carbon の CDN スクリプトを呼び出すために使用されます。 + +`format` オプションには `classic`、`responsive`、`cover` を指定できます。 + +```js +`//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}&format=${format}` +``` + +Carbon Ads の設定について詳しくは、[Carbon Ads のウェブサイト](https://www.carbonads.net/)を参照してください。 diff --git a/docs/ja/reference/default-theme-config.md b/docs/ja/reference/default-theme-config.md new file mode 100644 index 000000000..9da3db106 --- /dev/null +++ b/docs/ja/reference/default-theme-config.md @@ -0,0 +1,502 @@ +--- +description: VitePressデフォルトテーマで利用可能なすべての設定オプションのリファレンス。 +--- + +# デフォルトテーマの設定 {#default-theme-config} + +テーマ設定では、テーマのカスタマイズができます。設定ファイルの `themeConfig` オプションで定義します。 + +```ts +export default { + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + + // テーマ関連の設定 + themeConfig: { + logo: '/logo.svg', + nav: [...], + sidebar: { ... } + } +} +``` + +**このページで説明するオプションは、デフォルトテーマにのみ適用されます。** テーマによって期待する設定は異なります。カスタムテーマを使用する場合、ここで定義したテーマ設定オブジェクトはテーマへ渡され、テーマ側がそれに基づいて条件付きの挙動を定義できます。 + +## i18nRouting + +- 型: `boolean` + +ロケールを `zh` のように切り替えると、URL は `/foo`(または `/en/foo/`)から `/zh/foo` に変わります。`themeConfig.i18nRouting` を `false` に設定すると、この挙動を無効化できます。 + +## logo + +- 型: `ThemeableImage` + +サイトタイトルの直前に、ナビゲーションバーに表示されるロゴ。パス文字列、またはライト/ダークモードで異なるロゴを設定するオブジェクトを受け取ります。 + +```ts +export default { + themeConfig: { + logo: '/logo.svg' + } +} +``` + +```ts +type ThemeableImage = + | string + | { src: string; alt?: string } + | { light: string; dark: string; alt?: string } +``` + +## siteTitle + +- 型: `string | false` + +ナビゲーション内の既定サイトタイトル(アプリ設定の `title`)を置き換えます。`false` の場合、ナビのタイトルを非表示にします。ロゴ自体にサイト名が含まれている場合に便利です。 + +```ts +export default { + themeConfig: { + siteTitle: 'Hello World' + } +} +``` + +## nav + +- 型: `NavItem` + +ナビゲーションメニューの設定。[デフォルトテーマ: ナビ](./default-theme-nav#navigation-links) を参照してください。 + +```ts +export default { + themeConfig: { + nav: [ + { text: 'Guide', link: '/guide' }, + { + text: 'Dropdown Menu', + items: [ + { text: 'Item A', link: '/item-1' }, + { text: 'Item B', link: '/item-2' }, + { text: 'Item C', link: '/item-3' } + ] + } + ] + } +} +``` + +```ts +type NavItem = NavItemWithLink | NavItemWithChildren + +interface NavItemWithLink { + text: string + link: string | ((payload: PageData) => string) + activeMatch?: string + target?: string + rel?: string + noIcon?: boolean +} + +interface NavItemChildren { + text?: string + items: NavItemWithLink[] +} + +interface NavItemWithChildren { + text?: string + items: (NavItemChildren | NavItemWithLink)[] + activeMatch?: string +} +``` + +## sidebar + +- 型: `Sidebar` + +サイドバーメニューの設定。[デフォルトテーマ: サイドバー](./default-theme-sidebar) を参照してください。 + +```ts +export default { + themeConfig: { + sidebar: [ + { + text: 'Guide', + items: [ + { text: 'Introduction', link: '/introduction' }, + { text: 'Getting Started', link: '/getting-started' }, + ... + ] + } + ] + } +} +``` + +```ts +export type Sidebar = SidebarItem[] | SidebarMulti + +export interface SidebarMulti { + [path: string]: SidebarItem[] | { items: SidebarItem[]; base: string } +} + +export type SidebarItem = { + /** + * 項目のテキストラベル + */ + text?: string + + /** + * 項目のリンク + */ + link?: string + + /** + * 子項目 + */ + items?: SidebarItem[] + + /** + * 指定しない場合、グループは折りたたみ不可。 + * + * `true` なら折りたたみ可能でデフォルト折りたたみ + * + * `false` なら折りたたみ可能だがデフォルト展開 + */ + collapsed?: boolean + + /** + * 子項目のベースパス + */ + base?: string + + /** + * 前/次リンクのフッターに表示するテキストをカスタマイズ + */ + docFooterText?: string + + rel?: string + target?: string +} +``` + +## aside + +- 型: `boolean | 'left'` +- 既定値: `true` +- ページごとに [frontmatter](./frontmatter-config#aside) で上書き可能 + +`false` でサイドコンテナの描画を無効化。\ +`true` で右側に表示。\ +`left` で左側に表示。 + +すべてのビューポートで無効にしたい場合は、代わりに `outline: false` を使用してください。 + +## outline + +- 型: `Outline | Outline['level'] | false` +- レベルはページごとに [frontmatter](./frontmatter-config#outline) で上書き可能 + +`false` でアウトラインコンテナの描画を無効化。詳細は以下を参照: + +```ts +interface Outline { + /** + * アウトラインに表示する見出しレベル + * 単一の数値なら、そのレベルのみ表示 + * タプルなら最小レベルと最大レベル + * `'deep'` は `[2, 6]` と同じ(`

    ` 〜 `

    ` を表示) + * + * @default 2 + */ + level?: number | [number, number] | 'deep' + + /** + * アウトラインに表示するタイトル + * + * @default 'On this page' + */ + label?: string +} +``` + +## socialLinks + +- 型: `SocialLink[]` + +ナビゲーションにアイコン付きのソーシャルリンクを表示します。 + +```ts +export default { + themeConfig: { + socialLinks: [ + // simple-icons (https://simpleicons.org/) の任意のアイコンを指定可能 + { icon: 'github', link: 'https://github.com/vuejs/vitepress' }, + { icon: 'twitter', link: '...' }, + // SVG 文字列を渡してカスタムアイコンも可 + { + icon: { + svg: 'Dribbble' + }, + link: '...', + // アクセシビリティ向けにカスタムラベルも指定可(推奨) + ariaLabel: 'cool link' + } + ] + } +} +``` + +```ts +interface SocialLink { + icon: string | { svg: string } + link: string + ariaLabel?: string +} +``` + +## footer + +- 型: `Footer` +- ページごとに [frontmatter](./frontmatter-config#footer) で上書き可能 + +フッター設定。メッセージや著作権表示を追加できますが、ページにサイドバーがある場合はデザイン上表示されません。 + +```ts +export default { + themeConfig: { + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright © 2019-present Evan You' + } + } +} +``` + +```ts +export interface Footer { + message?: string + copyright?: string +} +``` + +## editLink + +- 型: `EditLink` +- ページごとに [frontmatter](./frontmatter-config#editlink) で上書き可能 + +「このページを編集」リンクを表示します(GitHub/GitLab など)。詳細は [デフォルトテーマ: 編集リンク](./default-theme-edit-link) を参照。 + +```ts +export default { + themeConfig: { + editLink: { + pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', + text: 'Edit this page on GitHub' + } + } +} +``` + +```ts +export interface EditLink { + pattern: string + text?: string +} +``` + +## lastUpdated + +- 型: `LastUpdatedOptions` + +最終更新の文言と日付フォーマットをカスタマイズします。 + +```ts +export default { + themeConfig: { + lastUpdated: { + text: 'Updated at', + formatOptions: { + dateStyle: 'full', + timeStyle: 'medium' + } + } + } +} +``` + +```ts +export interface LastUpdatedOptions { + /** + * @default 'Last updated' + */ + text?: string + + /** + * @default + * { dateStyle: 'short', timeStyle: 'short' } + */ + formatOptions?: Intl.DateTimeFormatOptions & { forceLocale?: boolean } +} +``` + +## algolia + +- 型: `AlgoliaSearch` + +[Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) によるサイト内検索の設定。[デフォルトテーマ: 検索](./default-theme-search) を参照。 + +```ts +export interface AlgoliaSearchOptions extends DocSearchProps { + locales?: Record> +} +``` + +完全なオプションは[こちら](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts)。 + +## carbonAds {#carbon-ads} + +- 型: `CarbonAdsOptions` + +[Carbon Ads](https://www.carbonads.net/) を表示します。 + +```ts +export default { + themeConfig: { + carbonAds: { + code: 'your-carbon-code', + placement: 'your-carbon-placement', + format: 'classic' + } + } +} +``` + +`format` オプションには `classic`、`responsive`、`cover` を指定できます。 + +```ts +export interface CarbonAdsOptions { + code: string + placement: string + format?: 'classic' | 'responsive' | 'cover' +} +``` + +詳細は [デフォルトテーマ: Carbon Ads](./default-theme-carbon-ads) を参照。 + +## docFooter + +- 型: `DocFooter` + +前/次リンクの上に表示される文言をカスタマイズします。英語以外のドキュメントで便利。前/次リンク自体をグローバルに無効化することも可能。ページごとに切り替えたい場合は [frontmatter](./default-theme-prev-next-links) を使用します。 + +```ts +export default { + themeConfig: { + docFooter: { + prev: 'Pagina prior', + next: 'Proxima pagina' + } + } +} +``` + +```ts +export interface DocFooter { + prev?: string | false + next?: string | false +} +``` + +## darkModeSwitchLabel + +- 型: `string` +- 既定値: `Appearance` + +ダークモード切替スイッチのラベル(モバイル表示のみ)をカスタマイズします。 + +## lightModeSwitchTitle + +- 型: `string` +- 既定値: `Switch to light theme` + +ホバー時に表示されるライトモード切替のタイトルをカスタマイズします。 + +## darkModeSwitchTitle + +- 型: `string` +- 既定値: `Switch to dark theme` + +ホバー時に表示されるダークモード切替のタイトルをカスタマイズします。 + +## sidebarMenuLabel + +- 型: `string` +- 既定値: `Menu` + +サイドバーメニューのラベル(モバイル表示のみ)をカスタマイズします。 + +## returnToTopLabel + +- 型: `string` +- 既定値: `Return to top` + +トップに戻るボタンのラベル(モバイル表示のみ)をカスタマイズします。 + +## langMenuLabel + +- 型: `string` +- 既定値: `Change language` + +ナビバーの言語切替ボタンの aria-label をカスタマイズします。[i18n](../guide/i18n) を使う場合に有効です。 + +## skipToContentLabel + +- 型: `string` +- 既定値: `Skip to content` + +コンテンツへスキップリンクのラベルをカスタマイズします。キーボード操作時に表示されます。 + +## externalLinkIcon + +- 型: `boolean` +- 既定値: `false` + +Markdown 内の外部リンクの横に外部リンクアイコンを表示するかどうか。 + +## `useLayout` + +レイアウト関連のデータを返します。返り値の型は次のとおりです。 + +```ts +interface { + isHome: ComputedRef + + sidebar: Readonly> + sidebarGroups: ComputedRef + hasSidebar: ComputedRef + isSidebarEnabled: ComputedRef + + hasAside: ComputedRef + leftAside: ComputedRef + + headers: Readonly> + hasLocalNav: ComputedRef +} +``` + +**例:** + +```vue + + + +``` diff --git a/docs/ja/reference/default-theme-edit-link.md b/docs/ja/reference/default-theme-edit-link.md new file mode 100644 index 000000000..1edac3276 --- /dev/null +++ b/docs/ja/reference/default-theme-edit-link.md @@ -0,0 +1,64 @@ +--- +description: GitHubやGitLabでページの編集リンクをドキュメントページに表示する方法。 +--- + +# 編集リンク {#edit-link} + +## サイトレベルの設定 {#site-level-config} + +編集リンクは、GitHub や GitLab などの Git 管理サービスでそのページを編集できるリンクを表示します。有効化するには、設定に `themeConfig.editLink` オプションを追加します。 + +```js +export default { + themeConfig: { + editLink: { + pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path' + } + } +} +``` + +`pattern` オプションはリンクの URL 構造を定義します。`:path` はページパスに置き換えられます。 + +また、引数に [`PageData`](./runtime-api#usedata) を受け取り、URL 文字列を返す純粋関数を指定することもできます。 + +```js +export default { + themeConfig: { + editLink: { + pattern: ({ filePath }) => { + if (filePath.startsWith('packages/')) { + return `https://github.com/acme/monorepo/edit/main/${filePath}` + } else { + return `https://github.com/acme/monorepo/edit/main/docs/${filePath}` + } + } + } + } +} +``` + +この関数はブラウザでシリアライズされ実行されるため、副作用を持たず、スコープ外のものへアクセスしないでください。 + +既定では、ドキュメント下部に「Edit this page」というリンクテキストが表示されます。`text` オプションでこの文言をカスタマイズできます。 + +```js +export default { + themeConfig: { + editLink: { + pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', + text: 'GitHub でこのページを編集' + } + } +} +``` + +## フロントマターでの設定 {#frontmatter-config} + +ページごとに無効化するには、フロントマターで `editLink` オプションを使用します。 + +```yaml +--- +editLink: false +--- +``` diff --git a/docs/ja/reference/default-theme-footer.md b/docs/ja/reference/default-theme-footer.md new file mode 100644 index 000000000..44783ba44 --- /dev/null +++ b/docs/ja/reference/default-theme-footer.md @@ -0,0 +1,59 @@ +--- +description: VitePressページ下部に表示されるグローバルフッターの設定方法。 +--- + +# フッター {#footer} + +`themeConfig.footer` を設定すると、ページ下部にグローバルフッターが表示されます。 + +```ts +export default { + themeConfig: { + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright © 2019-present Evan You' + } + } +} +``` + +```ts +export interface Footer { + // 著作権表示の直前に表示されるメッセージ + message?: string + + // 実際の著作権表記 + copyright?: string +} +``` + +上記の設定は HTML 文字列にも対応しています。たとえば、フッター内のテキストにリンクを含めたい場合は、次のように設定できます。 + +```ts +export default { + themeConfig: { + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright © 2019-present Evan You' + } + } +} +``` + +::: warning +`message` と `copyright` は `

    ` 要素内にレンダリングされるため、 +使用できるのはインライン要素のみです。ブロック要素を追加したい場合は、 +[`layout-bottom`](../guide/extending-default-theme#layout-slots) スロットの利用を検討してください。 +::: + +なお、[SideBar](./default-theme-sidebar) が表示されている場合はフッターは表示されません。 + +## フロントマターでの設定 {#frontmatter-config} + +ページ単位で無効化するには、フロントマターの `footer` オプションを使用します。 + +```yaml +--- +footer: false +--- +``` diff --git a/docs/ja/reference/default-theme-home-page.md b/docs/ja/reference/default-theme-home-page.md new file mode 100644 index 000000000..ccf116208 --- /dev/null +++ b/docs/ja/reference/default-theme-home-page.md @@ -0,0 +1,193 @@ +--- +description: VitePressデフォルトテーマのホームページレイアウトをヒーローセクション、フィーチャー、カスタムコンテンツで設定する方法。 +--- + +# ホームページ {#home-page} + +VitePress のデフォルトテーマにはホームページ用レイアウトが用意されています([このサイトのトップページ](../) でも使われています)。[フロントマター](./frontmatter-config) に `layout: home` を指定すれば、任意のページで利用できます。 + +```yaml +--- +layout: home +--- +``` + +ただし、この指定だけでは多くのことは起きません。`hero` や `features` などの追加オプションを設定して、ホームページにあらかじめ用意された複数の「セクション」を配置できます。 + +## ヒーローセクション {#hero-section} + +ヒーローセクションはホームページの最上部に表示されます。設定例は次のとおりです。 + +```yaml +--- +layout: home + +hero: + name: VitePress + text: Vite & Vue powered static site generator. + tagline: 概要テキスト... + image: + src: /logo.png + alt: VitePress + actions: + - theme: brand + text: はじめる + link: /guide/what-is-vitepress + - theme: alt + text: GitHub で見る + link: https://github.com/vuejs/vitepress +--- +``` + +```ts +interface Hero { + // `text` の上に表示される短い文字列。ブランドカラーで表示。 + // 製品名のような短い文言を想定。 + name?: string + + // ヒーローセクションのメインテキスト。`h1` として出力。 + text: string + + // `text` の下に表示されるタグライン。 + tagline?: string + + // テキストとタグラインの横に表示する画像。 + image?: ThemeableImage + + // ヒーローに表示するアクションボタン。 + actions?: HeroAction[] +} + +type ThemeableImage = + | string + | { src: string; alt?: string } + | { light: string; dark: string; alt?: string } + +interface HeroAction { + // ボタンのカラーテーマ。既定は `brand`。 + theme?: 'brand' | 'alt' + + // ボタンのラベル。 + text: string + + // ボタンのリンク先。 + link: string + + // a 要素の target 属性。 + target?: string + + // a 要素の rel 属性。 + rel?: string +} +``` + +### name の色をカスタマイズする {#customizing-the-name-color} + +`name` にはブランドカラー(`--vp-c-brand-1`)が使われますが、`--vp-home-hero-name-color` 変数を上書きして色を変更できます。 + +```css +:root { + --vp-home-hero-name-color: blue; +} +``` + +さらに、`--vp-home-hero-name-background` を組み合わせると、`name` にグラデーションを適用できます。 + +```css +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe, #41d1ff); +} +``` + +## フィーチャーセクション {#features-section} + +フィーチャーセクションでは、ヒーロー直下に任意の数の機能説明を並べられます。フロントマターに `features` オプションを指定して設定します。 + +各フィーチャーにはアイコン(絵文字または画像)を指定できます。アイコンが画像(svg, png, jpeg など)の場合は、**適切な幅・高さ** を指定してください。必要に応じて説明テキストや実サイズ、ライト/ダーク用の差し替えも指定できます。 + +```yaml +--- +layout: home + +features: + - icon: 🛠️ + title: いつでもシンプル&ミニマル + details: 概要テキスト... + - icon: + src: /cool-feature-icon.svg + title: もうひとつの便利機能 + details: 概要テキスト... + - icon: + dark: /dark-feature-icon.svg + light: /light-feature-icon.svg + title: さらに別の機能 + details: 概要テキスト... +--- +``` + +```ts +interface Feature { + // 各フィーチャーボックスに表示するアイコン。 + icon?: FeatureIcon + + // フィーチャーのタイトル。 + title: string + + // フィーチャーの詳細説明。 + details: string + + // フィーチャーをクリックしたときのリンク(内部・外部どちらも可)。 + // + // 例: `guide/reference/default-theme-home-page` や `https://example.com` + link?: string + + // フィーチャー内に表示するリンクテキスト。 + // `link` と併用するのが最適。 + // + // 例: `Learn more`, `Visit page` など + linkText?: string + + // `link` 用の rel 属性。 + // + // 例: `external` + rel?: string + + // `link` 用の target 属性。 + target?: string +} + +type FeatureIcon = + | string + | { src: string; alt?: string; width?: string; height: string } + | { + light: string + dark: string + alt?: string + width?: string + height: string + } +``` + +## Markdown コンテンツ {#markdown-content} + +`---` で区切るフロントマターの下に Markdown を書くだけで、ホームページに追加コンテンツを表示できます。 + +````md +--- +layout: home + +hero: + name: VitePress + text: Vite & Vue powered static site generator. +--- + +## はじめに + +`npx` を使えば、すぐに VitePress を始められます! + +```sh +npm init +npx vitepress init +``` +```` diff --git a/docs/ja/reference/default-theme-last-updated.md b/docs/ja/reference/default-theme-last-updated.md new file mode 100644 index 000000000..51c38374c --- /dev/null +++ b/docs/ja/reference/default-theme-last-updated.md @@ -0,0 +1,50 @@ +--- +description: Gitコミット履歴に基づいてVitePressページに最終更新日時を表示する方法。 +--- + +# 最終更新日時 {#last-updated} + +ページ右下に、コンテンツの最終更新時刻を表示できます。有効化するには、設定に `lastUpdated` オプションを追加します。 + +::: info +VitePress は各ファイルの **直近の Git コミットのタイムスタンプ** を用いて「最終更新」を表示します。これを有効にするには、対象の Markdown ファイルが Git にコミットされている必要があります。 + +内部的には、各ファイルに対して `git log -1 --pretty="%ai"` を実行してタイムスタンプを取得します。すべてのページで同じ更新時刻が表示される場合、(CI 環境でよくある)**浅いクローン(shallow clone)** により Git の履歴が取得できていない可能性があります。 + +**GitHub Actions** での修正例は次のとおりです。 + +```yaml{4} +- name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 +``` + +他の CI/CD プラットフォームでも同様の設定が用意されています。 + +もしそのようなオプションが使えない場合は、`package.json` のビルドスクリプトで手動フェッチを前置してください。 + +```json +"docs:build": "git fetch --unshallow && vitepress build docs" +``` +::: + +## サイトレベルの設定 {#site-level-config} + +```js +export default { + lastUpdated: true +} +``` + +## フロントマターでの設定 {#frontmatter-config} + +ページ単位で無効化するには、フロントマターで `lastUpdated` を指定します。 + +```yaml +--- +lastUpdated: false +--- +``` + +より詳しくは [デフォルトテーマ: 最終更新](./default-theme-config#lastupdated) を参照してください。テーマレベルで truthy な値を設定すると、サイトまたはページで明示的に無効化しない限り、この機能は有効になります。 diff --git a/docs/ja/reference/default-theme-layout.md b/docs/ja/reference/default-theme-layout.md new file mode 100644 index 000000000..7a6b90592 --- /dev/null +++ b/docs/ja/reference/default-theme-layout.md @@ -0,0 +1,66 @@ +--- +description: VitePressデフォルトテーマのdoc、page、homeレイアウトの選択と使い方。 +--- + +# レイアウト {#layout} + +ページの [フロントマター](./frontmatter-config) の `layout` オプションでページのレイアウトを選択できます。利用可能なレイアウトは `doc`、`page`、`home` の 3 種類です。何も指定しない場合は `doc` として扱われます。 + +```yaml +--- +layout: doc +--- +``` + +## Doc レイアウト {#doc-layout} + +`doc` は既定のレイアウトで、Markdown 全体を「ドキュメント」風にスタイリングします。コンテンツ全体を `vp-doc` という CSS クラスでラップし、その配下の要素にスタイルを適用します。 + +`p` や `h2` などほぼすべての汎用要素に特別なスタイルが当たります。そのため、Markdown 内にカスタム HTML を追加した場合も、これらのスタイルの影響を受ける点に注意してください。 + +また、以下のようなドキュメント特有の機能も提供します。これらはこのレイアウトでのみ有効になります。 + +- 編集リンク(Edit Link) +- 前後リンク(Prev / Next Link) +- アウトライン(Outline) +- [Carbon 広告](./default-theme-carbon-ads) + +## Page レイアウト {#page-layout} + +`page` は「ブランクページ」として扱われます。Markdown はパースされ、[Markdown 拡張](../guide/markdown) も `doc` と同様に機能しますが、既定のスタイルは適用されません。 + +このレイアウトでは、VitePress テーマにマークアップを干渉させず、すべてを自分でスタイルできます。独自のカスタムページを作成したい場合に便利です。 + +なお、このレイアウトでも、ページがサイドバー設定に一致する場合はサイドバーが表示されます。 + +## Home レイアウト {#home-layout} + +`home` はテンプレート化された「ホームページ」を生成します。このレイアウトでは、`hero` や `features` などの追加オプションでコンテンツをさらにカスタマイズできます。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照してください。 + +## レイアウトなし {#no-layout} + +レイアウトを一切適用したくない場合は、フロントマターで `layout: false` を指定します。これは(既定でサイドバー/ナビバー/フッターなしの)完全にカスタマイズ可能なランディングページを作りたい場合に役立ちます。 + +## カスタムレイアウト {#custom-layout} + +カスタムレイアウトを使用することもできます。 + +```md +--- +layout: foo +--- +``` + +これは、コンテキストに登録された `foo` という名前のコンポーネントを探します。たとえば、`.vitepress/theme/index.ts` でグローバル登録できます。 + +```ts +import DefaultTheme from 'vitepress/theme' +import Foo from './Foo.vue' + +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + app.component('foo', Foo) + } +} +``` diff --git a/docs/ja/reference/default-theme-nav.md b/docs/ja/reference/default-theme-nav.md new file mode 100644 index 000000000..3ac7ec17c --- /dev/null +++ b/docs/ja/reference/default-theme-nav.md @@ -0,0 +1,219 @@ +--- +description: VitePressデフォルトテーマのナビゲーションバーにサイトタイトル、ロゴ、メニューリンクを設定する方法。 +--- + +# ナビゲーション {#nav} + +ナビはページ上部に表示されるナビゲーションバーです。サイトタイトル、グローバルメニューリンクなどを含みます。 + +## サイトタイトルとロゴ {#site-title-and-logo} + +既定では、ナビには [`config.title`](./site-config#title) の値が表示されます。ナビに表示する文字列を変更したい場合は、`themeConfig.siteTitle` にカスタム文字列を指定します。 + +```js +export default { + themeConfig: { + siteTitle: 'My Custom Title' + } +} +``` + +サイトのロゴがある場合は、画像へのパスを渡すと表示できます。ロゴは `public` 直下に配置し、絶対パスで指定してください。 + +```js +export default { + themeConfig: { + logo: '/my-logo.svg' + } +} +``` + +ロゴを追加すると、サイトタイトルと並んで表示されます。ロゴだけを表示したい場合は、`siteTitle` を `false` に設定してタイトル文字列を非表示にできます。 + +```js +export default { + themeConfig: { + logo: '/my-logo.svg', + siteTitle: false + } +} +``` + +ダーク/ライトモードでロゴを切り替えたり、`alt` 属性を付けたい場合は、ロゴにオブジェクトを渡すこともできます。詳細は [`themeConfig.logo`](./default-theme-config#logo) を参照してください。 + +## ナビゲーションリンク {#navigation-links} + +`themeConfig.nav` オプションでナビにリンクを追加できます。 + +```js +export default { + themeConfig: { + nav: [ + { text: 'Guide', link: '/guide' }, + { text: 'Config', link: '/config' }, + { text: 'Changelog', link: 'https://github.com/...' } + ] + } +} +``` + +`text` はナビに表示される文字列、`link` はクリック時に遷移するリンクです。内部リンクは `.md` 拡張子を付けず、必ず `/` で始めるようにしてください。 + +`link` には、[`PageData`](./runtime-api#usedata) を受け取ってパスを返す関数を指定することもできます。 + +ナビリンクはドロップダウンメニューにもできます。リンクオプションに `items` を設定してください。 + +```js +export default { + themeConfig: { + nav: [ + { text: 'Guide', link: '/guide' }, + { + text: 'Dropdown Menu', + items: [ + { text: 'Item A', link: '/item-1' }, + { text: 'Item B', link: '/item-2' }, + { text: 'Item C', link: '/item-3' } + ] + } + ] + } +} +``` + +なお、ドロップダウンのタイトル(上の例の `Dropdown Menu`)には `link` は設定できません。ドロップダウンを開くボタンになるためです。 + +さらに、ドロップダウン内を「セクション」に分けることもできます(入れ子の `items` を使います)。 + +```js +export default { + themeConfig: { + nav: [ + { text: 'Guide', link: '/guide' }, + { + text: 'Dropdown Menu', + items: [ + { + // セクションのタイトル + text: 'Section A Title', + items: [ + { text: 'Section A Item A', link: '...' }, + { text: 'Section B Item B', link: '...' } + ] + } + ] + }, + { + text: 'Dropdown Menu', + items: [ + { + // タイトルは省略することも可能 + items: [ + { text: 'Section A Item A', link: '...' }, + { text: 'Section B Item B', link: '...' } + ] + } + ] + } + ] + } +} +``` + +### リンクの「アクティブ」状態をカスタマイズ {#customize-link-s-active-state} + +現在のページが特定のパス配下にあるとき、該当するナビ項目がハイライトされます。一致させるパスをカスタマイズしたい場合は、`activeMatch` に **正規表現文字列** を指定します。 + +```js +export default { + themeConfig: { + nav: [ + // ユーザーが `/config/` 配下にいるときにアクティブになる + { + text: 'Guide', + link: '/guide', + activeMatch: '/config/' + } + ] + } +} +``` + +::: warning +`activeMatch` は正規表現 **オブジェクト** ではなく、**文字列** で指定してください。ビルド時のシリアライズの都合で `RegExp` は使用できません。 +::: + +### リンクの `target` と `rel` をカスタマイズ {#customize-link-s-target-and-rel-attributes} + +既定では、リンクが外部かどうかに応じて VitePress が `target` と `rel` を自動設定します。必要であれば明示的に指定することもできます。 + +```js +export default { + themeConfig: { + nav: [ + { + text: 'Merchandise', + link: 'https://www.thegithubshop.com/', + target: '_self', + rel: 'sponsored' + } + ] + } +} +``` + +## ソーシャルリン� {#social-links} + +[`socialLinks`](./default-theme-config#sociallinks) を参照してください。 + +## カスタムコンポーネント {#custom-components} + +`component` オプションを使って、ナビゲーションバーにカスタムコンポーネントを配置できます。`component` には Vue コンポーネント名を指定し、[Theme.enhanceApp](../guide/custom-theme#theme-interface) で **グローバル登録** しておく必要があります。 + +```js [.vitepress/config.js] +export default { + themeConfig: { + nav: [ + { + text: 'My Menu', + items: [ + { + component: 'MyCustomComponent', + // コンポーネントに渡す任意の props + props: { + title: 'My Custom Component' + } + } + ] + }, + { + component: 'AnotherCustomComponent' + } + ] + } +} +``` + +次に、コンポーネントをグローバル登録します。 + +```js [.vitepress/theme/index.js] +import DefaultTheme from 'vitepress/theme' + +import MyCustomComponent from './components/MyCustomComponent.vue' +import AnotherCustomComponent from './components/AnotherCustomComponent.vue' + +/** @type {import('vitepress').Theme} */ +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + app.component('MyCustomComponent', MyCustomComponent) + app.component('AnotherCustomComponent', AnotherCustomComponent) + } +} +``` + +コンポーネントはナビゲーションバー内にレンダリングされます。VitePress は次の追加 props をコンポーネントに提供します。 + +- `screenMenu`: モバイルのナビメニュー内にあるかどうかを示す任意の boolean + +e2e テスト内の例は[こちら](https://github.com/vuejs/vitepress/tree/main/__tests__/e2e/.vitepress)を参照してください。 diff --git a/docs/ja/reference/default-theme-prev-next-links.md b/docs/ja/reference/default-theme-prev-next-links.md new file mode 100644 index 000000000..5a1e77834 --- /dev/null +++ b/docs/ja/reference/default-theme-prev-next-links.md @@ -0,0 +1,47 @@ +--- +description: VitePressドキュメントページ下部に表示される「前のページ」「次のページ」リンクのカスタマイズ方法。 +--- + +# 前/次リンク {#prev-next-links} + +ドキュメントのフッターに表示される「前のページ」「次のページ」のテキストとリンクをカスタマイズできます。サイドバーに表示しているタイトルとは別の文言を使いたい場合や、フッターを無効化したり、サイドバーに含まれていないページへリンクしたい場合に便利です。 + +## prev + +- 型: `string | false | { text?: string; link?: string }` + +- 詳細: + + 前のページへのリンクに表示するテキスト/リンクを指定します。フロントマターで設定しない場合は、サイドバー設定から自動推測されます。 + +- 例: + + - テキストだけをカスタマイズ: + + ```yaml + --- + prev: 'Get Started | Markdown' + --- + ``` + + - テキストとリンクの両方をカスタマイズ: + + ```yaml + --- + prev: + text: 'Markdown' + link: '/guide/markdown' + --- + ``` + + - 前のページを非表示にする: + + ```yaml + --- + prev: false + --- + ``` + +## next + +`prev` と同様ですが、次のページ用の設定です。 diff --git a/docs/ja/reference/default-theme-search.md b/docs/ja/reference/default-theme-search.md new file mode 100644 index 000000000..e2042f750 --- /dev/null +++ b/docs/ja/reference/default-theme-search.md @@ -0,0 +1,361 @@ +--- +outline: deep +description: VitePressサイトにローカル検索またはAlgolia検索を設定する方法。 +--- + +# 検索 {#search} + +## ローカル検索 {#local-search} + +VitePress は、[minisearch](https://github.com/lucaong/minisearch/) によるブラウザ内インデックスを使った曖昧一致の全文検索をサポートします。有効化するには、`.vitepress/config.ts` で `themeConfig.search.provider` を `'local'` に設定します。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local' + } + } +}) +``` + +表示例: + +![screenshot of the search modal](/search.png) + +代わりに [Algolia DocSearch](#algolia-search) や、次のコミュニティ製プラグインを使うこともできます。 + +- +- +- +- + +### i18n {#local-search-i18n} + +多言語検索を行う設定例です。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local', + options: { + locales: { + ja: { // 既定ロケールを翻訳する場合は `root` にしてください + translations: { + button: { + buttonText: '検索', + buttonAriaLabel: '検索' + }, + modal: { + displayDetails: '詳細一覧を表示', + resetButtonTitle: '検索をリセット', + backButtonTitle: '検索を閉じる', + noResultsText: '結果が見つかりません', + footer: { + selectText: '選択', + selectKeyAriaLabel: 'Enter', + navigateText: '移動', + navigateUpKeyAriaLabel: '上矢印', + navigateDownKeyAriaLabel: '下矢印', + closeText: '閉じる', + closeKeyAriaLabel: 'Esc' + } + } + } + } + } + } + } + } +}) +``` + +### miniSearch のオプション {#minisearch-options} + +MiniSearch の設定例です。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local', + options: { + miniSearch: { + /** + * @type {Pick} + */ + options: { + /* ... */ + }, + /** + * @type {import('minisearch').SearchOptions} + * @default + * { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } } + */ + searchOptions: { + /* ... */ + } + } + } + } + } +}) +``` + +詳しくは [MiniSearch のドキュメント](https://lucaong.github.io/minisearch/classes/MiniSearch.MiniSearch.html) を参照してください。 + +### コンテンツレンダラーのカスタマイズ {#custom-content-renderer} + +インデックス前に Markdown コンテンツをレンダリングする関数をカスタマイズできます。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local', + options: { + /** + * @param {string} src + * @param {import('vitepress').MarkdownEnv} env + * @param {import('markdown-it-async')} md + */ + async _render(src, env, md) { + // HTML 文字列を返す + } + } + } + } +}) +``` + +この関数はクライアント側のサイトデータからは除外されるため、Node.js の API を使用できます。 + +#### 例: 検索対象からページを除外する {#example-excluding-pages-from-search} + +フロントマターに `search: false` を追加すると、そのページを検索対象から除外できます。あるいは次のようにもできます。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local', + options: { + async _render(src, env, md) { + const html = await md.renderAsync(src, env) + if (env.frontmatter?.search === false) return '' + if (env.relativePath.startsWith('some/path')) return '' + return html + } + } + } + } +}) +``` + +::: warning 注意 +カスタムの `_render` 関数を提供する場合、`search: false` の処理は自分で行う必要があります。また、`env` は `md.renderAsync` の呼び出し前には完全ではないため、`frontmatter` などの任意プロパティのチェックはその後に行ってください。 +::: + +#### 例: コンテンツの変換 — 見出しアンカーを追加 {#example-transforming-content-adding-anchors} + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'local', + options: { + async _render(src, env, md) { + const html = await md.renderAsync(src, env) + if (env.frontmatter?.title) + return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html + return html + } + } + } + } +}) +``` + +## Algolia 検索 {#algolia-search} + +VitePress は [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch) によるサイト検索をサポートします。導入は公式のガイドを参照してください。`.vitepress/config.ts` では最低限次の設定が必要です。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...' + } + } + } +}) +``` + +### i18n {#algolia-search-i18n} + +多言語検索の設定例です。 + +

    +クリックして展開 + +<<< @/snippets/algolia-i18n.ts + +
    + +詳しくは[公式 Algolia ドキュメント](https://docsearch.algolia.com/docs/api#translations)を参照してください。すぐに始めるには、このサイトで使っている翻訳を[GitHub リポジトリ](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code)からコピーすることもできます。 + +### Algolia Ask AI のサポート {#ask-ai} + +**Ask AI** を有効にするには、`options` 内に `askAi` オプション(またはその一部)を指定します。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + // askAi: "あなたのアシスタントID" + // または + askAi: { + // 最低限、Algolia から受け取った assistantId を指定する必要があります + assistantId: 'XXXYYY', + // 任意の上書き — 省略した場合は上位の appId/apiKey/indexName を再利用 + // apiKey: '...', + // appId: '...', + // indexName: '...' + } + } + } + } +}) +``` + +::: warning 注意 +キーワード検索を既定にして Ask AI を使わない場合は、`askAi` を指定しないでください。 +::: + +### Ask AI サイドパネル {#ask-ai-side-panel} + +DocSearch v4.5+ はオプションの **Ask AI サイドパネル**をサポートしています。有効にすると、デフォルトで **Ctrl/Cmd+I** で開くことができます。[サイドパネル API リファレンス](https://docsearch.algolia.com/docs/sidepanel/api-reference)にオプションの完全なリストがあります。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + // @docsearch/sidepanel-js SidepanelProps API をミラー + panel: { + variant: 'floating', // または 'inline' + side: 'right', + width: '360px', + expandedWidth: '580px', + suggestedQuestions: true + } + } + } + } + } + } +}) +``` + +キーボードショートカットを無効にする必要がある場合は、サイドパネルの `keyboardShortcuts` オプションを使用してください: + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + keyboardShortcuts: { + 'Ctrl/Cmd+I': false + } + } + } + } + } + } +}) +``` + +#### モード (auto / sidePanel / hybrid / modal) {#ask-ai-mode} + +VitePress がキーワード検索と Ask AI を統合する方法をオプションで制御できます: + +- `mode: 'auto'`(デフォルト):キーワード検索が設定されている場合は `hybrid` を推論し、それ以外の場合は Ask AI サイドパネルが設定されている場合は `sidePanel` を推論します。 +- `mode: 'sidePanel'`:サイドパネルのみを強制(キーワード検索ボタンを非表示)。 +- `mode: 'hybrid'`:キーワード検索モーダル + Ask AI サイドパネルを有効化(キーワード検索設定が必要)。 +- `mode: 'modal'`:Ask AI を DocSearch モーダル内に保持(サイドパネルを設定した場合でも)。 + +#### Ask AI のみ(キーワード検索なし) {#ask-ai-only} + +**Ask AI サイドパネルのみ**を使用する場合は、トップレベルのキーワード検索設定を省略し、`askAi` の下に認証情報を提供できます: + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + mode: 'sidePanel', + askAi: { + assistantId: 'XXXYYY', + appId: '...', + apiKey: '...', + indexName: '...', + sidePanel: true + } + } + } + } +}) +``` + +### クローラー設定 {#crawler-config} + +このサイトで使用している設定を元にした例です。 + +<<< @/snippets/algolia-crawler.js diff --git a/docs/ja/reference/default-theme-sidebar.md b/docs/ja/reference/default-theme-sidebar.md new file mode 100644 index 000000000..1f29e629c --- /dev/null +++ b/docs/ja/reference/default-theme-sidebar.md @@ -0,0 +1,184 @@ +--- +description: VitePressデフォルトテーマのサイドバーナビゲーションをグループ、折りたたみセクション、複数サイドバーで設定する方法。 +--- + +# サイドバー {#sidebar} + +サイドバーはドキュメントの主要なナビゲーションブロックです。[`themeConfig.sidebar`](./default-theme-config#sidebar) でメニューを設定できます。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Guide', + items: [ + { text: 'Introduction', link: '/introduction' }, + { text: 'Getting Started', link: '/getting-started' }, + ... + ] + } + ] + } +} +``` + +## 基本 {#the-basics} + +最もシンプルな構成は、リンクの配列を 1 つ渡す方法です。第 1 階層のアイテムがサイドバーの「セクション」を表します。各セクションは `text`(セクションのタイトル)と、実際のナビゲーションリンクである `items` を持ちます。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Section Title A', + items: [ + { text: 'Item A', link: '/item-a' }, + { text: 'Item B', link: '/item-b' }, + ... + ] + }, + { + text: 'Section Title B', + items: [ + { text: 'Item C', link: '/item-c' }, + { text: 'Item D', link: '/item-d' }, + ... + ] + } + ] + } +} +``` + +各 `link` は `/` で始まる実ファイルへのパスを指定します。リンクの末尾を `/` で終わらせると、対応するディレクトリの `index.md` が表示されます。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Guide', + items: [ + // `/guide/index.md` を表示 + { text: 'Introduction', link: '/guide/' } + ] + } + ] + } +} +``` + +サイドバーのアイテムは、ルートから数えて最大 6 階層まで入れ子にできます。7 階層以上は無視され、表示されません。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Level 1', + items: [ + { + text: 'Level 2', + items: [ + { + text: 'Level 3', + items: [ + ... + ] + } + ] + } + ] + } + ] + } +} +``` + +## 複数のサイドバー {#multiple-sidebars} + +ページのパスに応じて異なるサイドバーを表示できます。たとえば、このサイトのように「Guide」セクションと「Config」セクションでナビゲーションを分けたい場合に便利です。 + +まず、対象のセクションごとにディレクトリを分けてページを配置します。 + +``` +. +├─ guide/ +│ ├─ index.md +│ ├─ one.md +│ └─ two.md +└─ config/ + ├─ index.md + ├─ three.md + └─ four.md +``` + +次に、各セクション用のサイドバーを設定します。この場合、配列ではなくオブジェクトを渡します。 + +```js +export default { + themeConfig: { + sidebar: { + // ユーザーが `guide` ディレクトリ配下にいるときに表示 + '/guide/': [ + { + text: 'Guide', + items: [ + { text: 'Index', link: '/guide/' }, + { text: 'One', link: '/guide/one' }, + { text: 'Two', link: '/guide/two' } + ] + } + ], + + // ユーザーが `config` ディレクトリ配下にいるときに表示 + '/config/': [ + { + text: 'Config', + items: [ + { text: 'Index', link: '/config/' }, + { text: 'Three', link: '/config/three' }, + { text: 'Four', link: '/config/four' } + ] + } + ] + } + } +} +``` + +## 折りたたみ可能なサイドバーグループ {#collapsible-sidebar-groups} + +サイドバーグループに `collapsed` オプションを追加すると、各セクションの開閉トグルが表示されます。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Section Title A', + collapsed: false, + items: [...] + } + ] + } +} +``` + +既定ではすべてのセクションが「開いた」状態です。初回表示時に「閉じた」状態にしたい場合は、`collapsed` を `true` に設定します。 + +```js +export default { + themeConfig: { + sidebar: [ + { + text: 'Section Title A', + collapsed: true, + items: [...] + } + ] + } +} +``` diff --git a/docs/ja/reference/default-theme-team-page.md b/docs/ja/reference/default-theme-team-page.md new file mode 100644 index 000000000..4de340367 --- /dev/null +++ b/docs/ja/reference/default-theme-team-page.md @@ -0,0 +1,259 @@ +--- +description: VitePress組み込みのチームコンポーネントを使い、メンバープロフィール付きのチームページを作成する方法。 +--- + + + +# チームページ {#team-page} + +チームを紹介したい場合は、Team コンポーネント群を使ってチームページを構成できます。使い方は 2 通りあり、ドキュメントページに埋め込む方法と、専用のチームページを作成する方法があります。 + +## ページ内にメンバー一覧を表示する {#show-team-members-in-a-page} + +任意のページでチームメンバーの一覧を表示するには、`vitepress/theme` からエクスポートされている `` コンポーネントを使用します。 + +```html + + +# 私たちのチーム + +私たちの素晴らしいチームを紹介します。 + + +``` + +上記のように、カード風の要素でメンバーが表示されます。下図のような見た目になります。 + + + +`` コンポーネントには `small` と `medium` の 2 種類のサイズがあります。好みによりますが、ドキュメントページ内で使う場合は `small` が馴染みやすいことが多いでしょう。各メンバーに「説明文」や「スポンサー」ボタンなど、追加のプロパティを付けることもできます。詳細は [``](#vpteammembers) を参照してください。 + +小規模なチームで専用ページまでは不要な場合や、文脈上の参考として一部のメンバーのみを紹介したい場合は、ドキュメントページへ埋め込む方法が適しています。 + +メンバーが多い場合や、より広いスペースで紹介したい場合は、[専用のチームページを作成する](#専用のチームページを作成する) ことを検討してください。 + +## 専用のチームページを作成する {#create-a-full-team-page} + +ドキュメントページにメンバーを追加する代わりに、カスタムの [ホームページ](./default-theme-home-page) と同様、専用のチームページを作成することもできます。 + +まず新しい md ファイルを作成します。ファイル名は任意ですが、ここでは `team.md` とします。このファイルでフロントマターに `layout: page` を設定し、その後 `TeamPage` コンポーネント群を使ってページを構成します。 + +```html +--- +layout: page +--- + + + + + + + + + +``` + +専用のチームページを作る際は、必ずすべてのチーム関連コンポーネントを `` でラップしてください。レイアウトや余白などが適切に適用されます。 + +`` はページタイトルのセクションを追加します。タイトルは `

    ` 見出しになります。`#title` と `#lead` スロットでチームについて説明を書きましょう。 + +`` はドキュメントページで使う場合と同様に、メンバー一覧を表示します。 + +### セクションを追加してメンバーを分ける {#add-sections-to-divide-team-members} + +チームページに「セクション」を追加できます。たとえば、コアメンバーとコミュニティパートナーなど、役割ごとにメンバーを分けて説明しやすくできます。 + +そのためには、先ほど作成した `team.md` に `` コンポーネントを追加します。 + +```html +--- +layout: page +--- + + + + + + + + + + + + + + +``` + +`` は `VPTeamPageTitle` と同様に `#title` と `#lead` のスロットを持ち、さらにメンバー表示用の `#members` スロットを備えます。 + +`#members` スロット内に `` を配置するのを忘れないでください。 + +## `` + +`` コンポーネントは、与えられたメンバー配列を表示します。 + +```html + +``` + +```ts +interface Props { + // 各メンバーカードのサイズ。既定は `medium`。 + size?: 'small' | 'medium' + + // 表示するメンバー一覧。 + members: TeamMember[] +} + +interface TeamMember { + // メンバーのアバター画像 + avatar: string + + // メンバー名 + name: string + + // 名前の下に表示する肩書き(例: Developer, Software Engineer など) + title?: string + + // 所属組織名 + org?: string + + // 所属組織への URL + orgLink?: string + + // メンバーの説明 + desc?: string + + // ソーシャルリンク(例: GitHub, Twitter など) + // Social Links オブジェクトを渡せます。 + // 参照: https://vitepress.dev/reference/default-theme-config.html#sociallinks + links?: SocialLink[] + + // メンバーのスポンサー用 URL + sponsor?: string + + // スポンサーボタンのテキスト。既定は 'Sponsor' + actionText?: string +} +``` + +## `` + +専用のチームページを作成する際のルートコンポーネントです。単一のスロットのみを受け取り、渡されたチーム関連コンポーネント全体に適切なスタイルを適用します。 + +## `` + +ページの「タイトル」セクションを追加します。`` の直下に置くのが最適です。`#title` と `#lead` のスロットを受け取ります。 + +```html + + + + + + +``` + +## `` + +チームページ内に「セクション」を作成します。`#title`、`#lead`、`#members` の各スロットを受け取ります。`` の中に必要な数だけ追加できます。 + +```html + + ... + + + + + + +``` diff --git a/docs/ja/reference/frontmatter-config.md b/docs/ja/reference/frontmatter-config.md new file mode 100644 index 000000000..17fa4bb2e --- /dev/null +++ b/docs/ja/reference/frontmatter-config.md @@ -0,0 +1,241 @@ +--- +outline: deep +description: VitePressのMarkdownページで利用可能なすべてのフロントマター設定オプションのリファレンス。 +--- + +# フロントマター設定 {#frontmatter-config} + +フロントマターはページ単位の設定を可能にします。各 Markdown ファイルで、サイト全体やテーマレベルの設定を上書きできます。フロントマターでしか定義できない項目もあります。 + +使用例: + +```md +--- +title: Docs with VitePress +editLink: true +--- +``` + +Vue の式内では、グローバル `$frontmatter` を介してフロントマターデータにアクセスできます。 + +```md +{{ $frontmatter.title }} +``` + +## title + +- 型: `string` + +ページのタイトルです。[config.title](./site-config#title) と同じ意味で、サイトレベルの設定を上書きします。 + +```yaml +--- +title: VitePress +--- +``` + +## titleTemplate + +- 型: `string | boolean` + +タイトルのサフィックスです。[config.titleTemplate](./site-config#titletemplate) と同じ意味で、サイトレベルの設定を上書きします。 + +```yaml +--- +title: VitePress +titleTemplate: Vite & Vue powered static site generator +--- +``` + +## description + +- 型: `string` + +ページの説明です。[config.description](./site-config#description) と同じ意味で、サイトレベルの設定を上書きします。 + +```yaml +--- +description: VitePress +--- +``` + +## head + +- 型: `HeadConfig[]` + +現在のページに追加で挿入する `` タグを指定します。サイトレベル設定で挿入されたタグの後に追加されます。 + +```yaml +--- +head: + - - meta + - name: description + content: hello + - - meta + - name: keywords + content: super duper SEO +--- +``` + +```ts +type HeadConfig = + | [string, Record] + | [string, Record, string] +``` + +## デフォルトテーマ専用 {#default-theme-only} + +以下のフロントマター項目は、デフォルトテーマ使用時にのみ適用されます。 + +### layout + +- 型: `doc | home | page` +- 既定値: `doc` + +ページのレイアウトを決めます。 + +- `doc` — Markdown コンテンツにドキュメント向けの既定スタイルを適用します。 +- `home` — 「ホームページ」用の特別なレイアウト。`hero` や `features` を追加指定して、ランディングページを素早く構築できます。 +- `page` — `doc` と似ていますが、コンテンツにスタイルを適用しません。完全にカスタムなページを作りたい場合に便利です。 + +```yaml +--- +layout: doc +--- +``` + +### hero + +`layout: home` のときのヒーローセクションの内容を定義します。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照。 + +### features + +`layout: home` のときのフィーチャーセクションに表示する項目を定義します。詳しくは [デフォルトテーマ: ホームページ](./default-theme-home-page) を参照。 + +### navbar + +- 型: `boolean` +- 既定値: `true` + +[ナビゲーションバー](./default-theme-nav) を表示するかどうか。 + +```yaml +--- +navbar: false +--- +``` + +### sidebar + +- 型: `boolean` +- 既定値: `true` + +[サイドバー](./default-theme-sidebar) を表示するかどうか。 + +```yaml +--- +sidebar: false +--- +``` + +### aside + +- 型: `boolean | 'left'` +- 既定値: `true` + +`doc` レイアウトでの aside コンポーネントの位置を定義します。 + +この値を `false` にすると aside コンテナを表示しません。\ +`true` にすると右側に表示します。\ +`'left'` にすると左側に表示します。 + +```yaml +--- +aside: false +--- +``` + +### outline + +- 型: `number | [number, number] | 'deep' | false` +- 既定値: `2` + +ページのアウトラインに表示する見出しレベルです。[config.themeConfig.outline.level](./default-theme-config#outline) と同じ意味で、サイトレベルの設定を上書きします。 + +```yaml +--- +outline: [2, 4] +--- +``` + +### lastUpdated + +- 型: `boolean | Date` +- 既定値: `true` + +現在のページのフッターに[最終更新](./default-theme-last-updated)を表示するかどうか。日時を指定した場合は、その日時が Git の最終更新時刻の代わりに表示されます。 + +```yaml +--- +lastUpdated: false +--- +``` + +### editLink + +- 型: `boolean` +- 既定値: `true` + +現在のページのフッターに[編集リンク](./default-theme-edit-link)を表示するかどうか。 + +```yaml +--- +editLink: false +--- +``` + +### footer + +- 型: `boolean` +- 既定値: `true` + +[フッター](./default-theme-footer) を表示するかどうか。 + +```yaml +--- +footer: false +--- +``` + +### pageClass + +- 型: `string` + +特定のページに追加のクラス名を付与します。 + +```yaml +--- +pageClass: custom-page-class +--- +``` + +その後、`.vitepress/theme/custom.css` でこのページ専用のスタイルを記述できます。 + +```css +.custom-page-class { + /* ページ固有のスタイル */ +} +``` + +### isHome + +- 型: `boolean` + +デフォルトテーマは通常、`frontmatter.layout === 'home'` のチェックに基づいてホームページかどうかを判断します。\ +カスタムレイアウトでホームページ用の要素を強制的に表示したい場合に便利です。 + +```yaml +--- +isHome: true +--- +``` diff --git a/docs/ja/reference/runtime-api.md b/docs/ja/reference/runtime-api.md new file mode 100644 index 000000000..3eaed5ace --- /dev/null +++ b/docs/ja/reference/runtime-api.md @@ -0,0 +1,177 @@ +--- +description: VitePressランタイムAPIのリファレンス。コンポーザブル、ヘルパー関数、組み込みコンポーネントを含みます。 +--- + +# ランタイム API {#runtime-api} + +VitePress には、アプリのデータへアクセスするための組み込み API がいくつか用意されています。さらに、グローバルに使用できる組み込みコンポーネントも提供されています。 + +ヘルパーメソッドは `vitepress` からグローバルインポートでき、主にカスタムテーマの Vue コンポーネントで使われます。Markdown ファイルは Vue の [Single File Component](https://vuejs.org/guide/scaling-up/sfc.html) にコンパイルされるため、`.md` ファイル内でも使用できます。 + +`use*` で始まるメソッドは [Vue 3 Composition API](https://vuejs.org/guide/introduction.html#composition-api) の関数(Composable)で、`setup()` または ` + + +``` + +## `useRoute` + +現在のルートオブジェクトを返します。型は次のとおりです。 + +```ts +interface Route { + path: string + data: PageData + component: Component | null +} +``` + +## `useRouter` + +VitePress のルーターインスタンスを返し、プログラムで別ページへ遷移できます。 + +```ts +interface Router { + /** + * 現在のルート + */ + route: Route + /** + * 新しい URL へ遷移 + */ + go: (to?: string) => Promise + /** + * ルートが変わる前に呼ばれる。`false` を返すと遷移をキャンセル + */ + onBeforeRouteChange?: (to: string) => Awaitable + /** + * ページコンポーネントが読み込まれる前(履歴が更新された後)に呼ばれる。 + * `false` を返すと遷移をキャンセル + */ + onBeforePageLoad?: (to: string) => Awaitable + /** + * ページコンポーネントが読み込まれた後(更新前)に呼ばれる + */ + onAfterPageLoad?: (to: string) => Awaitable + /** + * ルートが変わった後に呼ばれる + */ + onAfterRouteChange?: (to: string) => Awaitable +} +``` + +## `withBase` + +- **型**: `(path: string) => string` + +設定された [`base`](./site-config#base) を指定の URL パスに付与します。[Base URL](../guide/asset-handling#base-url) も参照。 + +## `` + +レンダリング済みの Markdown コンテンツを表示します。[独自テーマの作成時](../guide/custom-theme) に便利です。 + +```vue + +``` + +## `` + +スロット内容をクライアント側でのみレンダリングします。 + +VitePress アプリは静的ビルド時に Node.js 上でサーバーレンダリングされるため、Vue の使用はユニバーサルコードの要件に従う必要があります。要するに、ブラウザ/DOM API へのアクセスは beforeMount / mounted フック内に限定してください。 + +SSR 非対応(例: カスタムディレクティブを含む)なコンポーネントを使用・デモする場合は、`ClientOnly` でラップできます。 + +```vue-html + + + +``` + +- 関連: [SSR 互換性](../guide/ssr-compat) + +## `$frontmatter` + +Vue の式内で現在ページの [フロントマター](../guide/frontmatter) に直接アクセスします。 + +```md +--- +title: Hello +--- + +# {{ $frontmatter.title }} +``` + +## `$params` + +Vue の式内で現在ページの [動的ルートのパラメータ](../guide/routing#dynamic-routes) に直接アクセスします。 + +```md +- package name: {{ $params.pkg }} +- version: {{ $params.version }} +``` diff --git a/docs/ja/reference/site-config.md b/docs/ja/reference/site-config.md new file mode 100644 index 000000000..44636f893 --- /dev/null +++ b/docs/ja/reference/site-config.md @@ -0,0 +1,723 @@ +--- +outline: deep +description: VitePressのサイト設定オプションの完全なリファレンス。アプリレベルの設定、テーマ、ビルドオプションを含みます。 +--- + +# サイト設定 {#site-config} + +サイト設定では、サイト全体のグローバル設定を定義します。アプリ設定オプションは、使用するテーマに関係なく、すべての VitePress サイトに適用されます。たとえば、ベースディレクトリやサイトのタイトルなどです。 + +## 概要 {#overview} + +### 設定ファイルの解決 {#config-resolution} + +設定ファイルは常に `/.vitepress/config.[ext]` から解決されます。`` は VitePress の[プロジェクトルート](../guide/routing#root-and-source-directory)で、`[ext]` にはサポートされる拡張子が入ります。TypeScript はそのまま使えます。サポートされる拡張子は `.js`、`.ts`、`.mjs`、`.mts` です。 + +設定ファイルでは ES Modules 構文の使用を推奨します。設定オブジェクトをデフォルトエクスポートしてください。 + +```ts +export default { + // アプリレベルの設定 + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + ... +} +``` + +::: details 動的(非同期)設定 + +設定を動的に生成する必要がある場合は、関数をデフォルトエクスポートすることもできます。例: + +```ts +import { defineConfig } from 'vitepress' + +export default async () => { + const posts = await (await fetch('https://my-cms.com/blog-posts')).json() + + return defineConfig({ + // アプリレベル設定 + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + + // テーマレベル設定 + themeConfig: { + sidebar: [ + ...posts.map((post) => ({ + text: post.name, + link: `/posts/${post.name}` + })) + ] + } + }) +} +``` + +トップレベル `await` も使用できます。例: + +```ts +import { defineConfig } from 'vitepress' + +const posts = await (await fetch('https://my-cms.com/blog-posts')).json() + +export default defineConfig({ + // アプリレベル設定 + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + + // テーマレベル設定 + themeConfig: { + sidebar: [ + ...posts.map((post) => ({ + text: post.name, + link: `/posts/${post.name}` + })) + ] + } +}) +``` + +::: + +### 設定のインテリセンス {#config-intellisense} + +`defineConfig` ヘルパーを使うと、TypeScript による補完が効きます。対応 IDE であれば、JavaScript と TypeScript のどちらでも動作します。 + +```js +import { defineConfig } from 'vitepress' + +export default defineConfig({ + // ... +}) +``` + +### 型付きのテーマ設定 {#typed-theme-config} + +デフォルトでは、`defineConfig` はデフォルトテーマのテーマ設定型を想定します。 + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + // 型は `DefaultTheme.Config` + } +}) +``` + +カスタムテーマを使用しており、そのテーマ設定に型チェックを効かせたい場合は、代わりに `defineConfigWithTheme` を使い、ジェネリクスでカスタムテーマの設定型を渡してください。 + +```ts +import { defineConfigWithTheme } from 'vitepress' +import type { ThemeConfig } from 'your-theme' + +export default defineConfigWithTheme({ + themeConfig: { + // 型は `ThemeConfig` + } +}) +``` + +### Vite・Vue・Markdown の設定 {#vite-vue-markdown-config} + +- **Vite** + + Vite の設定は VitePress 設定の [vite](#vite) オプションで行えます。別途 Vite の設定ファイルを作る必要はありません。 + +- **Vue** + + VitePress には公式の Vue プラグイン([@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue))が同梱されています。オプションは VitePress 設定の [vue](#vue) から指定できます。 + +- **Markdown** + + 既定の [Markdown-It](https://github.com/markdown-it/markdown-it) インスタンスは、VitePress 設定の [markdown](#markdown) オプションでカスタマイズできます。 + +## サイトメタデータ {#site-metadata} + +### title + +- 型: `string` +- 既定値: `VitePress` +- ページ単位での上書き: [frontmatter](./frontmatter-config#title) + +サイトのタイトル。デフォルトテーマではナビバーに表示されます。 + +[`titleTemplate`](#titletemplate) を定義していない場合、個々のページタイトルの既定のサフィックスとしても使われます。各ページの最終タイトルは、そのページの最初の `

    ` 見出しのテキストに、グローバルの `title` をサフィックスとして結合したものになります。次の設定とページ内容の例: + +```ts +export default { + title: 'My Awesome Site' +} +``` + +```md +# Hello +``` + +このページのタイトルは `Hello | My Awesome Site` になります。 + +### titleTemplate + +- 型: `string | boolean` +- ページ単位での上書き: [frontmatter](./frontmatter-config#titletemplate) + +各ページタイトルのサフィックス、またはタイトル全体のカスタマイズができます。例: + +```ts +export default { + title: 'My Awesome Site', + titleTemplate: 'Custom Suffix' +} +``` + +```md +# Hello +``` + +このページのタイトルは `Hello | Custom Suffix` になります。 + +タイトルの描画方法を完全にカスタマイズするには、`titleTemplate` 内で `:title` シンボルを使います。 + +```ts +export default { + titleTemplate: ':title - Custom Suffix' +} +``` + +ここで `:title` はページ先頭の `

    ` から推論されたテキストに置き換えられます。先ほどの例では `Hello - Custom Suffix` になります。 + +`false` を設定するとタイトルのサフィックスを無効にできます。 + +### description + +- 型: `string` +- 既定値: `A VitePress site` +- ページ単位での上書き: [frontmatter](./frontmatter-config#description) + +サイトの説明。ページの HTML に `` タグとして出力されます。 + +```ts +export default { + description: 'A VitePress site' +} +``` + +### head + +- 型: `HeadConfig[]` +- 既定値: `[]` +- ページ単位での追加: [frontmatter](./frontmatter-config#head) + +ページ HTML の `` に追加で出力する要素。ユーザーが追加したタグは、VitePress のタグの後、`` の直前にレンダリングされます。 + +```ts +type HeadConfig = + | [string, Record] + | [string, Record, string] +``` + +#### 例: favicon を追加 {#example-adding-a-favicon} + +```ts +export default { + head: [['link', { rel: 'icon', href: '/favicon.ico' }]] +} // favicon.ico は public に配置。base を設定している場合は /base/favicon.ico を利用 + +/* 出力結果: + +*/ +``` + +#### 例: Google Fonts を追加 {#example-adding-google-fonts} + +```ts +export default { + head: [ + [ + 'link', + { rel: 'preconnect', href: 'https://fonts.googleapis.com' } + ], + [ + 'link', + { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' } + ], + [ + 'link', + { href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', rel: 'stylesheet' } + ] + ] +} + +/* 出力結果: + + + +*/ +``` + +#### 例: Service Worker を登録 {#example-registering-a-service-worker} + +```ts +export default { + head: [ + [ + 'script', + { id: 'register-sw' }, + `;(() => { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.register('/sw.js') + } + })()` + ] + ] +} + +/* 出力結果: + +*/ +``` + +#### 例: Google Analytics を使用 {#example-using-google-analytics} + +```ts +export default { + head: [ + [ + 'script', + { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=TAG_ID' } + ], + [ + 'script', + {}, + `window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'TAG_ID');` + ] + ] +} + +/* 出力結果: + + +*/ +``` + +### lang + +- 型: `string` +- 既定値: `en-US` + +サイトの言語属性。ページ HTML の `` として出力されます。 + +```ts +export default { + lang: 'en-US' +} +``` + +### base + +- 型: `string` +- 既定値: `/` + +サイトをデプロイするベース URL。GitHub Pages などサブパス配下にデプロイする場合に設定が必要です。たとえば `https://foo.github.io/bar/` にデプロイする場合、`base` は `'/bar/'` にします。先頭と末尾は必ずスラッシュにしてください。 + +`/` で始まる他のオプション内の URL には、この `base` が自動的に付与されます。1 回設定すれば十分です。 + +```ts +export default { + base: '/base/' +} +``` + +## ルーティング {#routing} + +### cleanUrls + +- 型: `boolean` +- 既定値: `false` + +`true` にすると、URL の末尾の `.html` を削除します。あわせて [クリーン URL の生成](../guide/routing#generating-clean-urls) も参照してください。 + +::: warning サーバ設定が必要 +ホスティング環境によっては追加の設定が必要です。`/foo` へのアクセス時に **リダイレクトなしで** `/foo.html` を返せるサーバ設定が必要です。 +::: + +### rewrites + +- 型: `Record` + +ディレクトリと URL のカスタム対応を定義します。詳しくは [ルーティング: ルートのリライト](../guide/routing#route-rewrites) を参照。 + +```ts +export default { + rewrites: { + 'source/:page': 'destination/:page' + } +} +``` + +## ビルド {#build} + +### srcDir + +- 型: `string` +- 既定値: `.` + +Markdown ページを置くディレクトリ(プロジェクトルートからの相対パス)。[ルートとソースディレクトリ](../guide/routing#root-and-source-directory) も参照。 + +```ts +export default { + srcDir: './src' +} +``` + +### srcExclude + +- 型: `string[]` +- 既定値: `undefined` + +ソースとして除外したい Markdown ファイルにマッチする [glob パターン](https://github.com/mrmlnc/fast-glob#pattern-syntax)。 + +```ts +export default { + srcExclude: ['**/README.md', '**/TODO.md'] +} +``` + +### outDir + +- 型: `string` +- 既定値: `./.vitepress/dist` + +ビルド出力先([プロジェクトルート](../guide/routing#root-and-source-directory) からの相対パス)。 + +```ts +export default { + outDir: '../public' +} +``` + +### assetsDir + +- 型: `string` +- 既定値: `assets` + +生成されるアセットを配置するサブディレクトリ名。パスは [`outDir`](#outdir) の内部で、相対解決されます。 + +```ts +export default { + assetsDir: 'static' +} +``` + +### cacheDir + +- 型: `string` +- 既定値: `./.vitepress/cache` + +キャッシュファイル用ディレクトリ([プロジェクトルート](../guide/routing#root-and-source-directory) からの相対パス)。参考: [cacheDir](https://vitejs.dev/config/shared-options.html#cachedir) + +```ts +export default { + cacheDir: './.vitepress/.vite' +} +``` + +### ignoreDeadLinks + +- 型: `boolean | 'localhostLinks' | (string | RegExp | ((link: string, source: string) => boolean))[]` +- 既定値: `false` + +`true` にすると、デッドリンクがあってもビルド失敗にしません。 + +`'localhostLinks'` にすると、`localhost` へのリンクはチェック対象外にしつつ、その他のデッドリンクではビルドを失敗させます。 + +```ts +export default { + ignoreDeadLinks: true +} +``` + +正確な URL 文字列、正規表現、カスタムフィルタ関数の配列として指定することもできます。 + +```ts +export default { + ignoreDeadLinks: [ + // 正確に "/playground" を無視 + '/playground', + // すべての localhost リンクを無視 + /^https?:\/\/localhost/, + // パスに "/repl/" を含むリンクを無視 + /\/repl\//, + // カスタム関数: "ignore" を含むリンクを無視 + (url) => { + return url.toLowerCase().includes('ignore') + } + ] +} +``` + +### metaChunk + +- 型: `boolean` +- 既定値: `false` + +`true` にすると、各ページのメタデータを初期 HTML にインラインせず、別の JavaScript チャンクに抽出します。これにより各ページの HTML ペイロードが小さくなり、メタデータをキャッシュ可能にすることで、多数のページがあるサイトでサーバ帯域を削減できます。 + +### mpa + +- 型: `boolean` +- 既定値: `false` + +`true` にすると、本番アプリは [MPA モード](../guide/mpa-mode) でビルドされます。MPA モードは既定でクライアント JavaScript を 0kb で配信する代わりに、クライアントサイドのナビゲーションを無効にし、相互作用には明示的な opt-in が必要です。 + +## テーマ関連 {#theming} + +### appearance + +- 型: `boolean | 'dark' | 'force-dark' | 'force-auto' | import('@vueuse/core').UseDarkOptions` +- 既定値: `true` + +ダークモードを有効にするか(`` に `.dark` クラスを付与)。 + +- `true` の場合、ユーザーの環境設定に従います。 +- `dark` の場合、ユーザーが切り替えない限りダークを既定にします。 +- `false` の場合、ユーザーはテーマを切り替えできません。 +- `'force-dark'` の場合、常にダークで固定(切替不可)。 +- `'force-auto'` の場合、常にユーザーの環境設定に従い(切替不可)。 + +このオプションは、ローカルストレージの `vitepress-theme-appearance` から設定を復元するインラインスクリプトを挿入します。これにより、ページ描画前に `.dark` クラスを適用してフリッカを防ぎます。 + +`appearance.initialValue` は `'dark' | undefined` のみサポート。Ref や getter は使えません。 + +### lastUpdated + +- 型: `boolean` +- 既定値: `false` + +Git を使って各ページの最終更新時刻を取得します。タイムスタンプは各ページのデータに含まれ、[`useData`](./runtime-api#usedata) から参照できます。 + +デフォルトテーマ使用時にこのオプションを有効にすると、各ページの最終更新時刻が表示されます。テキストは [`themeConfig.lastUpdatedText`](./default-theme-config#lastupdatedtext) でカスタマイズ可能です。 + +## カスタマイズ {#customization} + +### markdown + +- 型: `MarkdownOption` + +Markdown パーサの設定。VitePress はパーサに [Markdown-it](https://github.com/markdown-it/markdown-it)、構文ハイライトに [Shiki](https://github.com/shikijs/shiki) を使用しています。必要に応じて Markdown 関連の各種オプションを指定できます。 + +```js +export default { + markdown: {...} +} +``` + +利用可能なオプションは [型定義と JSDoc](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) を参照してください。 + +### vite + +- 型: `import('vite').UserConfig` + +内部の Vite 開発サーバ/バンドラへ生の [Vite Config](https://vitejs.dev/config/) を渡します。 + +```js +export default { + vite: { + // Vite の設定 + } +} +``` + +### vue + +- 型: `import('@vitejs/plugin-vue').Options` + +内部の `@vitejs/plugin-vue` インスタンスへオプションをそのまま渡します。 + +```js +export default { + vue: { + // @vitejs/plugin-vue のオプション + } +} +``` + +## ビルドフック {#build-hooks} + +VitePress のビルドフックを使うと、サイトに機能や振る舞いを追加できます。 + +- サイトマップ +- 検索インデックス +- PWA +- Teleport + +### buildEnd + +- 型: `(siteConfig: SiteConfig) => Awaitable` + +`buildEnd` はビルド CLI フックです。ビルド(SSG)が完了した後、VitePress CLI プロセスが終了する前に実行されます。 + +```ts +export default { + async buildEnd(siteConfig) { + // ... + } +} +``` + +### postRender + +- 型: `(context: SSGContext) => Awaitable` + +`postRender` は SSG のレンダリング完了時に呼ばれるビルドフックです。SSG 中の teleport コンテンツの処理に利用できます。 + +```ts +export default { + async postRender(context) { + // ... + } +} +``` + +```ts +interface SSGContext { + content: string + teleports?: Record + [key: string]: any +} +``` + +### transformHead + +- 型: `(context: TransformContext) => Awaitable` + +`transformHead` は、各ページを生成する前に head を変換するためのビルドフックです。設定ファイルでは静的に追加できない head 要素を追加できます。追加分のみ返せば、既存のものと自動でマージされます。 + +::: warning +`context` 内の値は変更しないでください。 +::: + +```ts +export default { + async transformHead(context) { + // ... + } +} +``` + +```ts +interface TransformContext { + page: string // 例: index.md(srcDir からの相対) + assets: string[] // 解決済みの公開 URL(非 js/css アセット) + siteConfig: SiteConfig + siteData: SiteData + pageData: PageData + title: string + description: string + head: HeadConfig[] + content: string +} +``` + +このフックは静的サイト生成時のみ呼ばれ、開発中には呼ばれません。開発中に動的な head 要素を追加したい場合は、代わりに [`transformPageData`](#transformpagedata) を使用できます。 + +```ts +export default { + transformPageData(pageData) { + pageData.frontmatter.head ??= [] + pageData.frontmatter.head.push([ + 'meta', + { + name: 'og:title', + content: + pageData.frontmatter.layout === 'home' + ? `VitePress` + : `${pageData.title} | VitePress` + } + ]) + } +} +``` + +#### 例: 正規 URL の `` を追加 {#example-adding-a-canonical-url-link} + +```ts +export default { + transformPageData(pageData) { + const canonicalUrl = `https://example.com/${pageData.relativePath}` + .replace(/index\.md$/, '') + .replace(/\.md$/, '.html') + + pageData.frontmatter.head ??= [] + pageData.frontmatter.head.push([ + 'link', + { rel: 'canonical', href: canonicalUrl } + ]) + } +} +``` + +### transformHtml + +- 型: `(code: string, id: string, context: TransformContext) => Awaitable` + +`transformHtml` は、各ページの内容をディスクへ保存する前に変換するためのビルドフックです。 + +::: warning +`context` 内の値は変更しないでください。また、HTML を変更すると実行時のハイドレーション問題を引き起こす可能性があります。 +::: + +```ts +export default { + async transformHtml(code, id, context) { + // ... + } +} +``` + +### transformPageData + +- 型: `(pageData: PageData, context: TransformPageContext) => Awaitable | { [key: string]: any } | void>` + +`transformPageData` は各ページの `pageData` を変換するためのフックです。`pageData` を直接変更するか、変更値を返してマージさせることができます。 + +::: warning +`context` 内の値は変更しないでください。ネットワークリクエストや重い計算(画像生成など)を行うと開発サーバのパフォーマンスに影響します。`process.env.NODE_ENV === 'production'` を用いた条件分岐を検討してください。 +::: + +```ts +export default { + async transformPageData(pageData, { siteConfig }) { + pageData.contributors = await getPageContributors(pageData.relativePath) + } + + // あるいはマージ用の値を返す + async transformPageData(pageData, { siteConfig }) { + return { + contributors: await getPageContributors(pageData.relativePath) + } + } +} +``` + +```ts +interface TransformPageContext { + siteConfig: SiteConfig +} +``` diff --git a/docs/ko/config.ts b/docs/ko/config.ts new file mode 100644 index 000000000..4a076036c --- /dev/null +++ b/docs/ko/config.ts @@ -0,0 +1,367 @@ +import { createRequire } from 'module' +import { defineAdditionalConfig, type DefaultTheme } from 'vitepress' + +const require = createRequire(import.meta.url) +const pkg = require('vitepress/package.json') + +export default defineAdditionalConfig({ + description: 'Vite 및 Vue 기반 정적 사이트 생성기.', + + themeConfig: { + nav: nav(), + + search: { options: searchOptions() }, + + sidebar: { + '/ko/guide/': { base: '/ko/guide/', items: sidebarGuide() }, + '/ko/reference/': { base: '/ko/reference/', items: sidebarReference() } + }, + + editLink: { + pattern: 'https://github.com/vuejs/vitepress/edit/main/docs/:path', + text: '이 페이지 편집 제안하기' + }, + + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright © 2019-present Evan You' + }, + + docFooter: { + prev: '이전', + next: '다음' + }, + + outline: { + label: '이 페이지 목차' + }, + + lastUpdated: { + text: '업데이트 날짜' + }, + + notFound: { + title: '페이지를 찾을 수 없습니다', + quote: + '방향을 바꾸지 않고 계속 찾다 보면 결국 당신이 가고 있는 곳에 도달할 수도 있습니다.', + linkLabel: '홈으로 가기', + linkText: '집으로 데려가줘' + }, + + langMenuLabel: '언어 변경', + returnToTopLabel: '맨 위로 돌아가기', + sidebarMenuLabel: '사이드바 메뉴', + darkModeSwitchLabel: '다크 모드', + lightModeSwitchTitle: '라이트 모드로 변경', + darkModeSwitchTitle: '다크 모드로 변경', + skipToContentLabel: '본문으로 건너뛰기' + } +}) + +function nav(): DefaultTheme.NavItem[] { + return [ + { + text: '가이드', + link: '/ko/guide/what-is-vitepress', + activeMatch: '/ko/guide/' + }, + { + text: '레퍼런스', + link: '/ko/reference/site-config', + activeMatch: '/ko/reference/' + }, + { + text: pkg.version, + items: [ + { + text: '1.6.4', + link: 'https://vuejs.github.io/vitepress/v1/ko/' + }, + { + text: '변경 로그', + link: 'https://github.com/vuejs/vitepress/blob/main/CHANGELOG.md' + }, + { + text: '기여', + link: 'https://github.com/vuejs/vitepress/blob/main/.github/contributing.md' + } + ] + } + ] +} + +function sidebarGuide(): DefaultTheme.SidebarItem[] { + return [ + { + text: '소개', + collapsed: false, + items: [ + { + text: 'VitePress란 무엇인가?', + link: 'what-is-vitepress' + }, + { + text: '시작하기', + link: 'getting-started' + }, + { + text: '라우팅', + link: 'routing' + }, + { + text: '배포하기', + link: 'deploy' + } + ] + }, + { + text: '글쓰기', + collapsed: false, + items: [ + { + text: '마크다운 확장 기능', + link: 'markdown' + }, + { + text: '에셋 핸들링', + link: 'asset-handling' + }, + { + text: '전문(Front-matter)', + link: 'frontmatter' + }, + { + text: '마크다운에서 Vue 사용하기', + link: 'using-vue' + }, + { + text: 'i18n', + link: 'i18n' + } + ] + }, + { + text: '커스텀', + collapsed: false, + items: [ + { + text: '커스텀 테마 사용하기', + link: 'custom-theme' + }, + { + text: '기본 테마 확장하기', + link: 'extending-default-theme' + }, + { + text: '빌드할 때 데이터 로딩하기', + link: 'data-loading' + }, + { + text: 'SSR 호환성', + link: 'ssr-compat' + }, + { + text: 'CMS 연결하기', + link: 'cms' + } + ] + }, + { + text: '실험적인', + collapsed: false, + items: [ + { + text: 'MPA 모드', + link: 'mpa-mode' + }, + { + text: '사이트맵 생성', + link: 'sitemap-generation' + } + ] + }, + { + text: '구성 & API 레퍼런스', + base: '/ko/reference/', + link: 'site-config' + } + ] +} + +function sidebarReference(): DefaultTheme.SidebarItem[] { + return [ + { + text: '레퍼런스', + items: [ + { text: '사이트 구성', link: 'site-config' }, + { text: '전문(front-matter) 구성', link: 'frontmatter-config' }, + { text: '런타임 API', link: 'runtime-api' }, + { text: 'CLI', link: 'cli' }, + { + text: '기본 테마', + base: '/ko/reference/default-theme-', + items: [ + { text: '개요', link: 'config' }, + { text: '네비게이션 바', link: 'nav' }, + { text: '사이드바', link: 'sidebar' }, + { text: '홈 페이지', link: 'home-page' }, + { text: '푸터', link: 'footer' }, + { text: '레이아웃', link: 'layout' }, + { text: '배지(badge)', link: 'badge' }, + { text: '팀 페이지', link: 'team-page' }, + { text: '이전/다음 링크', link: 'prev-next-links' }, + { text: '편집 링크', link: 'edit-link' }, + { text: '마지막 업데이트 날짜', link: 'last-updated' }, + { text: '검색', link: 'search' }, + { text: '카본 광고', link: 'carbon-ads' } + ] + } + ] + } + ] +} + +function searchOptions(): Partial { + return { + translations: { + button: { + buttonText: '검색', + buttonAriaLabel: '검색' + }, + modal: { + searchBox: { + clearButtonTitle: '지우기', + clearButtonAriaLabel: '검색어 지우기', + closeButtonText: '닫기', + closeButtonAriaLabel: '닫기', + placeholderText: '문서를 검색하거나 Ask AI에 질문', + placeholderTextAskAi: '다른 질문하기...', + placeholderTextAskAiStreaming: '답변 중...', + searchInputLabel: '검색', + backToKeywordSearchButtonText: '키워드 검색으로 돌아가기', + backToKeywordSearchButtonAriaLabel: '키워드 검색으로 돌아가기', + newConversationPlaceholder: '질문하기', + conversationHistoryTitle: '내 대화 기록', + startNewConversationText: '새 대화 시작', + viewConversationHistoryText: '대화 기록', + threadDepthErrorPlaceholder: '대화 한도에 도달했습니다' + }, + newConversation: { + newConversationTitle: '오늘 무엇을 도와드릴까요?', + newConversationDescription: + '문서를 검색해 설정 가이드, 기능 설명, 문제 해결 팁을 빠르게 찾아드립니다.' + }, + footer: { + selectText: '선택', + submitQuestionText: '질문 제출', + selectKeyAriaLabel: 'Enter 키', + navigateText: '이동', + navigateUpKeyAriaLabel: '위 화살표', + navigateDownKeyAriaLabel: '아래 화살표', + closeText: '닫기', + backToSearchText: '검색으로 돌아가기', + closeKeyAriaLabel: 'Escape 키', + poweredByText: '제공' + }, + errorScreen: { + titleText: '결과를 불러올 수 없습니다', + helpText: '네트워크 연결을 확인해 주세요.' + }, + startScreen: { + recentSearchesTitle: '최근', + noRecentSearchesText: '최근 검색이 없습니다', + saveRecentSearchButtonTitle: '이 검색 저장', + removeRecentSearchButtonTitle: '기록에서 이 검색 제거', + favoriteSearchesTitle: '즐겨찾기', + removeFavoriteSearchButtonTitle: '즐겨찾기에서 이 검색 제거', + recentConversationsTitle: '최근 대화', + removeRecentConversationButtonTitle: '기록에서 이 대화 제거' + }, + noResultsScreen: { + noResultsText: '다음에 대한 결과를 찾을 수 없습니다', + suggestedQueryText: '다음을 검색해 보세요', + reportMissingResultsText: '이 검색은 결과가 있어야 하나요?', + reportMissingResultsLinkText: '알려주세요.' + }, + resultsScreen: { + askAiPlaceholder: 'AI에게 묻기: ', + noResultsAskAiPlaceholder: '문서에서 찾지 못했나요? Ask AI에 문의: ' + }, + askAiScreen: { + disclaimerText: + '답변은 AI가 생성하며 오류가 있을 수 있습니다. 확인해 주세요.', + relatedSourcesText: '관련 출처', + thinkingText: '생각 중...', + copyButtonText: '복사', + copyButtonCopiedText: '복사됨!', + copyButtonTitle: '복사', + likeButtonTitle: '좋아요', + dislikeButtonTitle: '싫어요', + thanksForFeedbackText: '피드백 감사합니다!', + preToolCallText: '검색 중...', + duringToolCallText: '검색 중...', + afterToolCallText: '검색함', + stoppedStreamingText: '이 응답을 중지했습니다', + errorTitleText: '채팅 오류', + threadDepthExceededMessage: + '정확성을 유지하기 위해 이 대화는 종료되었습니다.', + startNewConversationButtonText: '새 대화 시작' + } + } + }, + askAi: { + sidePanel: { + button: { + translations: { + buttonText: 'AI에게 묻기', + buttonAriaLabel: 'AI에게 묻기' + } + }, + panel: { + translations: { + header: { + title: 'AI에게 묻기', + conversationHistoryTitle: '내 대화 기록', + newConversationText: '새 대화 시작', + viewConversationHistoryText: '대화 기록' + }, + promptForm: { + promptPlaceholderText: '질문하기', + promptAnsweringText: '답변 중...', + promptAskAnotherQuestionText: '다른 질문하기', + promptDisclaimerText: + '답변은 AI가 생성하며 오류가 있을 수 있습니다.', + promptLabelText: 'Enter로 전송, Shift+Enter로 줄바꿈.', + promptAriaLabelText: '프롬프트 입력' + }, + conversationScreen: { + preToolCallText: '검색 중...', + searchingText: '검색 중...', + toolCallResultText: '검색함', + conversationDisclaimer: + '답변은 AI가 생성하며 오류가 있을 수 있습니다. 확인해 주세요.', + reasoningText: '추론 중...', + thinkingText: '생각 중...', + relatedSourcesText: '관련 출처', + stoppedStreamingText: '이 응답을 중지했습니다', + copyButtonText: '복사', + copyButtonCopiedText: '복사됨!', + likeButtonTitle: '좋아요', + dislikeButtonTitle: '싫어요', + thanksForFeedbackText: '피드백 감사합니다!', + errorTitleText: '채팅 오류' + }, + newConversationScreen: { + titleText: '오늘 무엇을 도와드릴까요?', + introductionText: + '문서를 검색해 설정 가이드, 기능 설명, 문제 해결 팁을 빠르게 찾아드립니다.' + }, + logo: { + poweredByText: '제공' + } + } + } + } + } + } +} diff --git a/docs/ko/guide/asset-handling.md b/docs/ko/guide/asset-handling.md index 5f6a35d11..5d7a9bbb5 100644 --- a/docs/ko/guide/asset-handling.md +++ b/docs/ko/guide/asset-handling.md @@ -1,3 +1,7 @@ +--- +description: VitePress에서 이미지, 미디어, 글꼴 등 정적 에셋을 참조하고 처리하는 방법을 알아보세요. +--- + # 에셋 핸들링 {#asset-handling} ## 정적 에셋 참조하기 {#referencing-static-assets} diff --git a/docs/ko/guide/cms.md b/docs/ko/guide/cms.md index 712c24022..4c9d3dda9 100644 --- a/docs/ko/guide/cms.md +++ b/docs/ko/guide/cms.md @@ -1,5 +1,6 @@ --- outline: deep +description: 동적 라우트와 데이터 로더를 사용하여 VitePress를 헤드리스 CMS에 연결하세요. --- # CMS에 연결하기 {#connecting-to-a-cms} diff --git a/docs/ko/guide/custom-theme.md b/docs/ko/guide/custom-theme.md index 9c799f18a..6855959e5 100644 --- a/docs/ko/guide/custom-theme.md +++ b/docs/ko/guide/custom-theme.md @@ -1,3 +1,7 @@ +--- +description: VitePress에서 커스텀 테마를 만들고 사용하여 사이트의 외관과 느낌을 완전히 제어하세요. +--- + # 커스텀 테마 사용하기 {#using-a-custom-theme} ## 테마 사용법 {#theme-resolving} diff --git a/docs/ko/guide/data-loading.md b/docs/ko/guide/data-loading.md index 9ac88f7a7..15cbfebe7 100644 --- a/docs/ko/guide/data-loading.md +++ b/docs/ko/guide/data-loading.md @@ -1,3 +1,7 @@ +--- +description: VitePress 데이터 로더를 사용하여 빌드 시 임의의 데이터를 로드하고 페이지나 컴포넌트에서 가져오세요. +--- + # 빌드할 때 데이터 로딩하기 {#build-time-data-loading} VitePress는 페이지나 컴포넌트에서 임의의 데이터를 로드하고 이를 가져올 수 있는 **데이터 로더** 기능을 제공합니다. 데이터 로딩은 **빌드할 때에만** 실행되며, 결과적으로 생성된 데이터는 최종 JavaScript 번들에 JSON으로 직렬화됩니다. diff --git a/docs/ko/guide/deploy.md b/docs/ko/guide/deploy.md index 797015dae..76c6701b1 100644 --- a/docs/ko/guide/deploy.md +++ b/docs/ko/guide/deploy.md @@ -1,5 +1,6 @@ --- outline: deep +description: Netlify, Vercel, GitHub Pages 등 인기 있는 플랫폼에 VitePress 사이트를 배포하세요. --- # VitePress 사이트 배포하기 {#deploy-your-vitepress-site} @@ -105,13 +106,13 @@ Cache-Control: max-age=31536000,immutable ## 플랫폼 가이드 {#platform-guides} -### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render +### Netlify / Vercel / Cloudflare Pages / AWS Amplify / Render {#generic} 새 프로젝트를 설정하고 대시보드를 사용하여 다음 설정을 변경하세요: - **빌드 명령어:** `npm run docs:build` - **출력 디렉토리:** `docs/.vitepress/dist` -- **노드 버전:** `18` (또는 그 이상) +- **노드 버전:** `20` (또는 그 이상) ::: warning HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 Vue에 의미가 있는 주석을 출력에서 제거할 것입니다. 제거되면 하이드레이션 불일치 오류가 발생할 수 있습니다. @@ -152,17 +153,17 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 # lastUpdated가 활성화되지 않은 경우 필요하지 않음 - # - uses: pnpm/action-setup@v3 # pnpm을 사용하는 경우 주석 해제 + # - uses: pnpm/action-setup@v4 # pnpm을 사용하는 경우 주석 해제 # with: # version: 9 # - uses: oven-sh/setup-bun@v1 # Bun을 사용하는 경우 주석 해제 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 cache: npm # 또는 pnpm / yarn - name: Setup Pages uses: actions/configure-pages@v4 @@ -204,7 +205,7 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 2. 변경 사항을 적용할 때마다 사이트를 빌드하고 배포하도록 하기 위해 프로젝트의 루트에 다음 내용을 가진 `.gitlab-ci.yml` 파일을 생성하세요: ```yaml [.gitlab-ci.yml] - image: node:18 + image: node:24 pages: cache: paths: @@ -220,7 +221,7 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 - main ``` -### Azure 정적 Web 앱 {#azure-static-web-apps} +### Azure 1. [공식 문서](https://docs.microsoft.com/en-us/azure/static-web-apps/build-configuration)를 따르세요. @@ -230,7 +231,11 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 - **`output_location`**: `docs/.vitepress/dist` - **`app_build_command`**: `npm run docs:build` -### Firebase {#firebase} +### CloudRay + +[CloudRay](https://cloudray.io/)로 VitePress 프로젝트를 배포하려면 이 [지침](https://cloudray.io/articles/how-to-deploy-vitepress-site)을 따르세요. + +### Firebase 1. 프로젝트 루트에 `firebase.json`과 `.firebaserc`를 생성하세요: @@ -261,14 +266,6 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 firebase deploy ``` -### Surge - -1. `npm run docs:build`를 실행한 후, 배포하기 위해 이 명령어를 실행하세요: - - ```sh - npx surge docs/.vitepress/dist - ``` - ### Heroku 1. [`heroku-buildpack-static`](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-static)에 제공된 문서와 가이드를 따르세요. @@ -281,11 +278,11 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 } ``` -### Edgio +### Hostinger -[Edgio에 VitePress 앱 생성 및 배포하기](https://docs.edg.io/guides/vitepress)를 참고하세요. +[Hostinger](https://www.hostinger.com/web-apps-hosting)로 VitePress 프로젝트를 배포하려면 이 [지침](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/)을 따르세요. 빌드 설정을 구성할 때 프레임워크로 VitePress를 선택하고 루트 디렉터리를 `./docs`로 조정하세요. -### Kinsta 정적 사이트 호스팅 {#kinsta-static-site-hosting} +### Kinsta [VitePress](https://kinsta.com/static-site-hosting/) 웹사이트를 [Kinsta](https://kinsta.com/static-site-hosting/)에 배포하려면 이 [지침](https://kinsta.com/docs/vitepress-static-site-example/)을 따르세요. @@ -293,6 +290,14 @@ HTML 코드에 대해 _Auto Minify_ 옵션을 활성화하지 마세요. 이는 [VitePress](https://stormkit.io) 프로젝트를 [Stormkit](https://www.stormkit.io)에 배포하려면 이 [지침](https://stormkit.io/blog/how-to-deploy-vitepress)을 따르세요. +### Surge + +1. `npm run docs:build`를 실행한 후, 배포하기 위해 이 명령어를 실행하세요: + + ```sh + npx surge docs/.vitepress/dist + ``` + ### Nginx 다음은 Nginx 서버 블록 구성의 예입니다. 이 설정은 일반적인 텍스트 기반 에셋에 대한 gzip 압축, VitePress 사이트의 정적 파일을 적절한 캐싱 헤더와 함께 제공하는 규칙 및 `cleanUrls: true`를 처리하는 규칙을 포함합니다. diff --git a/docs/ko/guide/extending-default-theme.md b/docs/ko/guide/extending-default-theme.md index 6e64646f8..e87bfa1ac 100644 --- a/docs/ko/guide/extending-default-theme.md +++ b/docs/ko/guide/extending-default-theme.md @@ -1,5 +1,6 @@ --- outline: deep +description: 커스텀 CSS, 컴포넌트, 레이아웃 및 슬롯을 사용하여 VitePress 기본 테마를 커스터마이징하고 확장하세요. --- # 기본 테마 확장하기 {#extending-the-default-theme} @@ -70,7 +71,7 @@ export default DefaultTheme export default { transformHead({ assets }) { // 폰트를 매칭하기 위해 정규식을 적절히 조정하세요 - const myFontFile = assets.find(file => /font-name\.\w+\.woff2/) + const myFontFile = assets.find(file => /font-name\.[\w-]+\.woff2/.test(file)) if (myFontFile) { return [ [ @@ -190,6 +191,7 @@ export default { - `home-hero-info-before` - `home-hero-info` - `home-hero-info-after` + - `home-hero-actions-before-actions` - `home-hero-actions-after` - `home-hero-image` - `home-hero-after` @@ -252,6 +254,7 @@ provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => { { duration: 300, easing: 'ease-in', + fill: 'forwards', pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)` } ) diff --git a/docs/ko/guide/frontmatter.md b/docs/ko/guide/frontmatter.md index 09b1a2cdf..8ff539941 100644 --- a/docs/ko/guide/frontmatter.md +++ b/docs/ko/guide/frontmatter.md @@ -1,3 +1,7 @@ +--- +description: VitePress 마크다운 파일에서 YAML 전문(frontmatter)을 사용하여 페이지 수준의 메타데이터와 동작을 제어하는 방법을 알아보세요. +--- + # 전문 {#frontmatter} ## 사용법 {#usage} diff --git a/docs/ko/guide/getting-started.md b/docs/ko/guide/getting-started.md index ac7e7ca61..5e28c2d86 100644 --- a/docs/ko/guide/getting-started.md +++ b/docs/ko/guide/getting-started.md @@ -1,3 +1,6 @@ +--- +description: VitePress를 시작하세요. 문서 사이트를 설치하고, 스캐폴딩하고, 개발을 시작하는 방법을 알아보세요. +--- # 시작하기 {#getting-started} @@ -9,7 +12,7 @@ ### 사전 준비 사항 {#prerequisites} -- [Node.js](https://nodejs.org/) 버전 18 이상. +- [Node.js](https://nodejs.org/) 버전 20 이상. - VitePress를 명령줄 인터페이스(CLI)를 통해 접근하기 위한 터미널. - [마크다운](https://en.wikipedia.org/wiki/Markdown) 문법 지원이 있는 텍스트 에디터. - [VSCode](https://code.visualstudio.com/)와 [공식 Vue 확장 프로그램](https://marketplace.visualstudio.com/items?itemName=Vue.volar) 사용을 권장합니다. @@ -19,39 +22,19 @@ VitePress는 단독으로 사용하거나 기존 프로젝트에 설치할 수 ::: code-group ```sh [npm] -$ npm add -D vitepress +$ npm add -D vitepress@next ``` ```sh [pnpm] -$ pnpm add -D vitepress +$ pnpm add -D vitepress@next ``` ```sh [yarn] -$ yarn add -D vitepress -``` - -```sh [yarn (pnp)] -$ yarn add -D vitepress vue +$ yarn add -D vitepress@next vue ``` ```sh [bun] -$ bun add -D vitepress -``` - -::: - -::: details "missing peer deps" 경고가 표시되나요? -PNPM을 사용하는 경우 `@docsearch/js`에 대한 "missing peer deps" 경고가 표시됩니다. 이는 VitePress가 작동하는 것을 방해하지 않습니다. 이 경고를 억제하려면 `package.json`에 다음을 추가합니다: - -```json -"pnpm": { - "peerDependencyRules": { - "ignoreMissing": [ - "@algolia/client-search", - "search-insights" - ] - } -} +$ bun add -D vitepress@next ``` ::: diff --git a/docs/ko/guide/i18n.md b/docs/ko/guide/i18n.md index 4f15cdd83..cd449f51e 100644 --- a/docs/ko/guide/i18n.md +++ b/docs/ko/guide/i18n.md @@ -1,3 +1,7 @@ +--- +description: VitePress에서 국제화(i18n)를 설정하여 사이트에서 여러 언어를 지원하세요. +--- + # i18n {#internationalization} 내장된 i18n 기능을 사용하려면 다음과 같은 디렉토리 구조를 만들어야 합니다: diff --git a/docs/ko/guide/markdown.md b/docs/ko/guide/markdown.md index 0e12ff658..12d832dff 100644 --- a/docs/ko/guide/markdown.md +++ b/docs/ko/guide/markdown.md @@ -1,3 +1,7 @@ +--- +description: 커스텀 컨테이너, 구문 강조 코드 블록, 라인 하이라이팅, 코드 그룹 등 VitePress 내장 마크다운 확장 기능을 소개합니다. +--- + # 마크다운 확장 기능 {#markdown-extensions} VitePress는 내장된 마크다운 확장 기능을 제공합니다. @@ -233,7 +237,7 @@ export default defineConfig({ ```md ::: raw -
    로 감쌉니다 +`
    `로 감쌉니다 ::: ``` @@ -255,11 +259,11 @@ export default defineConfig({ } ``` - 이것은 기본적으로 [`postcss-prefix-selector`](https://github.com/RadValentin/postcss-prefix-selector)를 사용합니다. 다음과 같이 옵션을 전달할 수 있습니다: + 다음과 같이 옵션을 전달할 수 있습니다: ```js postcssIsolateStyles({ - includeFiles: [/vp-doc\.css/] // 기본값은 /base\.css/ + includeFiles: [/custom\.css/] // 기본값은 [/vp-doc\.css/, /base\.css/] }) ``` @@ -771,7 +775,7 @@ export default config ## Basics - + ``` **해당 파일** (`parts/basics.md`) @@ -807,7 +811,7 @@ Can be created using `.foorc.json`. ## Basics - + ``` **해당 파일** (`parts/basics.md`) @@ -843,8 +847,8 @@ Can be created using `.foorc.json`. ## Basics - - + + ``` **해당 파일** (`parts/basics.md`) @@ -880,7 +884,7 @@ Can be created using `.foorc.json`. 선택 사항입니다. 활성화하려면 `markdown-it-mathjax3`를 설치하고 설정 파일에서 `markdown.math`를 `true`로 설정해야 합니다: ```sh -npm add -D markdown-it-mathjax3 +npm add -D markdown-it-mathjax3@^4 ``` ```ts [.vitepress/config.ts] diff --git a/docs/ko/guide/mpa-mode.md b/docs/ko/guide/mpa-mode.md index b33087384..6d125b30a 100644 --- a/docs/ko/guide/mpa-mode.md +++ b/docs/ko/guide/mpa-mode.md @@ -1,3 +1,7 @@ +--- +description: VitePress에서 MPA(다중 페이지 애플리케이션) 모드를 활성화하여 JavaScript 없는 페이지로 더 나은 초기 성능을 얻으세요. +--- + # MPA 모드 {#mpa-mode} MPA (다중 페이지 애플리케이션) 모드는 명령줄에서 `vitepress build --mpa`를 통해 활성화할 수 있으며, 구성 파일에서 `mpa: true` 옵션을 통해서도 활성화할 수 있습니다. diff --git a/docs/ko/guide/routing.md b/docs/ko/guide/routing.md index 021f35347..b0a8e23e4 100644 --- a/docs/ko/guide/routing.md +++ b/docs/ko/guide/routing.md @@ -1,5 +1,6 @@ --- outline: deep +description: VitePress의 파일 기반 라우팅, 동적 라우트, 클린 URL 및 경로 재작성을 이해하세요. --- # 라우팅 {#routing} @@ -121,7 +122,7 @@ VitePress로 생성되지 않은 페이지에 연결하려면 전체 URL(새 탭 ::: -## 간결한 URL 생성 {#generating-clean-url} +## 간결한 URL 생성 {#generating-clean-urls} ::: warning 서버 지원 필요 VitePress가 간결한 URL을 제공하려면 서버 측 지원이 필요합니다. diff --git a/docs/ko/guide/sitemap-generation.md b/docs/ko/guide/sitemap-generation.md index 54db8e8a6..44eb54fee 100644 --- a/docs/ko/guide/sitemap-generation.md +++ b/docs/ko/guide/sitemap-generation.md @@ -1,3 +1,7 @@ +--- +description: VitePress 사이트의 sitemap.xml 파일을 생성하여 검색 엔진 검색 가능성을 향상시키세요. +--- + # 사이트맵 생성 {#sitemap-generation} VitePress는 사이트의 `sitemap.xml` 파일 생성을 지원합니다. 이를 활성화하려면 `.vitepress/config.js`에 다음을 추가하십시오: diff --git a/docs/ko/guide/ssr-compat.md b/docs/ko/guide/ssr-compat.md index acf595e1f..9e58ec188 100644 --- a/docs/ko/guide/ssr-compat.md +++ b/docs/ko/guide/ssr-compat.md @@ -1,5 +1,6 @@ --- outline: deep +description: VitePress 테마 컴포넌트와 커스텀 코드가 서버 사이드 렌더링과 호환되도록 하세요. --- # SSR 호환성 {#ssr-compatibility} diff --git a/docs/ko/guide/using-vue.md b/docs/ko/guide/using-vue.md index 5c65eeb7c..9f595b7ff 100644 --- a/docs/ko/guide/using-vue.md +++ b/docs/ko/guide/using-vue.md @@ -1,3 +1,7 @@ +--- +description: VitePress의 마크다운 파일 내에서 직접 Vue 컴포넌트와 동적 템플릿 기능을 사용하세요. +--- + # 마크다운에서 Vue 사용하기 {#using-vue-in-markdown} VitePress에서는 각 마크다운 파일이 HTML로 컴파일된 후 [Vue 단일 파일 컴포넌트](https://vuejs.org/guide/scaling-up/sfc.html)로 처리됩니다. 이는 마크다운 내에서 Vue 컴포넌트를 사용하거나 동적 템플릿을 사용하거나 ` - - -``` diff --git a/docs/ko/reference/default-theme-team-page.md b/docs/ko/reference/default-theme-team-page.md index 2123f3497..a190612eb 100644 --- a/docs/ko/reference/default-theme-team-page.md +++ b/docs/ko/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: VitePress 내장 팀 컴포넌트를 사용하여 멤버 프로필이 있는 팀 페이지를 만드세요. +--- + - - -``` diff --git a/docs/pt/reference/default-theme-team-page.md b/docs/pt/reference/default-theme-team-page.md index 1daa47a55..73e607e90 100644 --- a/docs/pt/reference/default-theme-team-page.md +++ b/docs/pt/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: Crie páginas de equipe com perfis de membros usando os componentes integrados de equipe do VitePress. +--- + + + +``` diff --git a/docs/ru/reference/default-theme-edit-link.md b/docs/ru/reference/default-theme-edit-link.md index a2cd6b007..fc43ca925 100644 --- a/docs/ru/reference/default-theme-edit-link.md +++ b/docs/ru/reference/default-theme-edit-link.md @@ -1,3 +1,7 @@ +--- +description: Отображайте ссылку для редактирования на страницах документации, чтобы пользователи могли предлагать изменения на GitHub или GitLab. +--- + # Ссылка для редактирования {#edit-link} ## Настройка в файле конфигурации {#site-level-config} diff --git a/docs/ru/reference/default-theme-footer.md b/docs/ru/reference/default-theme-footer.md index 99840b3c9..9df01af84 100644 --- a/docs/ru/reference/default-theme-footer.md +++ b/docs/ru/reference/default-theme-footer.md @@ -1,3 +1,7 @@ +--- +description: Настройте глобальный футер, отображаемый в нижней части страниц VitePress. +--- + # Футер {#footer} VitePress будет отображать блок футера внизу страницы, если присутствует объект `themeConfig.footer`. diff --git a/docs/ru/reference/default-theme-home-page.md b/docs/ru/reference/default-theme-home-page.md index fedf2b534..8ce128414 100644 --- a/docs/ru/reference/default-theme-home-page.md +++ b/docs/ru/reference/default-theme-home-page.md @@ -1,3 +1,7 @@ +--- +description: Настройте макет главной страницы темы VitePress по умолчанию с секциями hero, функциями и пользовательским контентом. +--- + # Главная страница {#home-page} Тема VitePress по умолчанию предоставляет макет главной страницы, который вы также можете увидеть на [главной странице этого сайта](../). Вы можете использовать его на любой из своих страниц, указав `layout: home` в [метаданных](./frontmatter-config) страницы. diff --git a/docs/ru/reference/default-theme-last-updated.md b/docs/ru/reference/default-theme-last-updated.md index 7d926dc5b..57a0cb537 100644 --- a/docs/ru/reference/default-theme-last-updated.md +++ b/docs/ru/reference/default-theme-last-updated.md @@ -1,9 +1,32 @@ +--- +description: Отображайте временную метку последнего обновления на страницах VitePress на основе истории коммитов Git. +--- + # Последнее обновление {#last-updated} Время последнего обновления содержимого будет отображаться в правом нижнем углу страницы. Чтобы включить его, добавьте опцию `lastUpdated` в свой конфиг. -::: tip Совет -Чтобы увидеть обновленное время, необходимо зафиксировать файл Markdown. +::: info ПРИМЕЧАНИЕ +VitePress отображает время «последнего обновления» на основе временной метки последнего Git-коммита для каждого файла. Для работы этой функции Markdown-файл должен быть закоммичен в Git. + +Внутри VitePress выполняет команду `git log -1 --pretty="%ai"` для каждого файла, чтобы получить его временную метку. Если все страницы показывают одинаковое время обновления, вероятно, это связано с поверхностным клонированием (часто встречается в CI-средах), которое ограничивает историю Git. + +Чтобы исправить это в **GitHub Actions**, добавьте следующее в ваш workflow-файл: + +```yaml{4} +- name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 +``` + +Другие CI/CD-платформы имеют аналогичные настройки. + +Если такие опции недоступны, вы можете добавить принудительный fetch перед командой `docs:build` в вашем `package.json`: + +```json +"docs:build": "git fetch --unshallow && vitepress build docs" +``` ::: ## Настройка в файле конфигурации {#site-level-config} diff --git a/docs/ru/reference/default-theme-layout.md b/docs/ru/reference/default-theme-layout.md index 346569a1b..1d260adf8 100644 --- a/docs/ru/reference/default-theme-layout.md +++ b/docs/ru/reference/default-theme-layout.md @@ -1,3 +1,7 @@ +--- +description: Выбирайте между макетами doc, page и home в теме VitePress по умолчанию. +--- + # Макет {#layout} Вы можете выбрать макет страницы, установив опцию `layout` в [метаданных](./frontmatter-config). Изначально есть 3 макета: `doc`, `page` и `home`. Если ничего не указано, то страница будет использовать макет `doc`. diff --git a/docs/ru/reference/default-theme-nav.md b/docs/ru/reference/default-theme-nav.md index 41257de85..0dabb064a 100644 --- a/docs/ru/reference/default-theme-nav.md +++ b/docs/ru/reference/default-theme-nav.md @@ -1,3 +1,7 @@ +--- +description: Настройте панель навигации в теме VitePress по умолчанию, включая заголовок сайта, логотип и ссылки меню. +--- + # Навигация {#nav} Ключ `nav` в конфигурации — это панель навигации, отображаемая в верхней части страницы. Она содержит заголовок сайта, ссылки глобального меню и т. д. @@ -55,6 +59,8 @@ export default { `text` — это текст, отображаемый в навигации, а `link` — это ссылка, на которую будет осуществлён переход при нажатии на текст. Для ссылки задайте путь к фактическому файлу без префикса `.md` и всегда начинайте с `/`. +`link` также может быть функцией, которая принимает [`PageData`](./runtime-api#usedata) в качестве аргумента и возвращает путь. + Навигационные ссылки также могут быть выпадающими меню. Для этого установите ключ `items` вместо ключа `link`: ```js diff --git a/docs/ru/reference/default-theme-prev-next-links.md b/docs/ru/reference/default-theme-prev-next-links.md index e25bab8ff..a14995a8b 100644 --- a/docs/ru/reference/default-theme-prev-next-links.md +++ b/docs/ru/reference/default-theme-prev-next-links.md @@ -1,3 +1,7 @@ +--- +description: Настройте ссылки на предыдущую и следующую страницы, отображаемые в нижней части страниц документации VitePress. +--- + # Предыдущая и следующая страницы {#prev-next-links} Вы можете настроить текст и ссылку для предыдущей и следующей страниц (отображаются в нижней части страницы). Это полезно, если вы хотите, чтобы текст отличался от того, что находится в сайдбаре. Кроме того, вы можете счесть полезным отключить футер или ссылку на страницу, которая не включена в сайдбар. diff --git a/docs/ru/reference/default-theme-search.md b/docs/ru/reference/default-theme-search.md index c91e4be46..838e7cea3 100644 --- a/docs/ru/reference/default-theme-search.md +++ b/docs/ru/reference/default-theme-search.md @@ -1,4 +1,5 @@ --- +description: Настройте локальный поиск или поиск на базе Algolia для вашего сайта VitePress. outline: deep --- @@ -29,6 +30,7 @@ export default defineConfig({ - - - +- ### i18n {#local-search-i18n} @@ -43,25 +45,25 @@ export default defineConfig({ provider: 'local', options: { locales: { - ru: { // используйте ключ `root`, если хотите перевести локаль по умолчанию + ru: { // используйте `root`, если хотите перевести локаль по умолчанию translations: { button: { buttonText: 'Поиск', buttonAriaLabel: 'Поиск' }, modal: { - displayDetails: 'Отобразить подробный список', + displayDetails: 'Показать подробный список', resetButtonTitle: 'Сбросить поиск', backButtonTitle: 'Закрыть поиск', - noResultsText: 'Нет результатов по запросу', + noResultsText: 'Нет результатов', footer: { - selectText: 'выбрать', - selectKeyAriaLabel: 'выбрать', - navigateText: 'перейти', - navigateUpKeyAriaLabel: 'стрелка вверх', - navigateDownKeyAriaLabel: 'стрелка вниз', - closeText: 'закрыть', - closeKeyAriaLabel: 'esc' + selectText: 'Выбрать', + selectKeyAriaLabel: 'Enter', + navigateText: 'Навигация', + navigateUpKeyAriaLabel: 'Стрелка вверх', + navigateDownKeyAriaLabel: 'Стрелка вниз', + closeText: 'Закрыть', + closeKeyAriaLabel: 'Esc' } } } @@ -124,10 +126,10 @@ export default defineConfig({ /** * @param {string} src * @param {import('vitepress').MarkdownEnv} env - * @param {import('markdown-it')} md + * @param {import('markdown-it-async')} md */ - _render(src, env, md) { - // возвращаем html + async _render(src, env, md) { + // вернуть строку HTML } } } @@ -149,8 +151,8 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.search === false) return '' if (env.relativePath.startsWith('some/path')) return '' return html @@ -162,7 +164,7 @@ export default defineConfig({ ``` ::: warning ПРИМЕЧАНИЕ -В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.render`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого. +В случае, если предоставляется пользовательская функция `_render`, вам нужно самостоятельно обработать заголовок `search: false`. Кроме того, объект `env` не будет полностью заполнен до вызова `md.renderAsync`, поэтому любые проверки необязательных свойств `env`, таких как `frontmatter`, должны быть выполнены после этого. ::: #### Пример: Преобразование содержимого - добавление якорей {#example-transforming-content-adding-anchors} @@ -175,10 +177,10 @@ export default defineConfig({ search: { provider: 'local', options: { - _render(src, env, md) { - const html = md.render(src, env) + async _render(src, env, md) { + const html = await md.renderAsync(src, env) if (env.frontmatter?.title) - return md.render(`# ${env.frontmatter.title}`) + html + return (await md.renderAsync(`# ${env.frontmatter.title}`)) + html return html } } @@ -212,6 +214,19 @@ export default defineConfig({ Пример конфигурации для использования многоязычного поиска: +
    +Нажмите, чтобы развернуть + +<<< @/snippets/algolia-i18n.ts + +
    + +Подробности см. в [официальной документации Algolia](https://docsearch.algolia.com/docs/api#translations). Чтобы быстрее начать, можно также скопировать переводы, используемые на этом сайте, из [нашего репозитория GitHub](https://github.com/search?q=repo:vuejs/vitepress+%22function+searchOptions%22&type=code). + +### Поддержка Ask AI в Algolia {#ask-ai} + +Если вы хотите добавить функцию **Ask AI**, передайте параметр `askAi` (или любые из его отдельных полей) внутри объекта `options`: + ```ts import { defineConfig } from 'vitepress' @@ -223,49 +238,51 @@ export default defineConfig({ appId: '...', apiKey: '...', indexName: '...', - locales: { - ru: { - placeholder: 'Поиск в документации', - translations: { - button: { - buttonText: 'Поиск', - buttonAriaLabel: 'Поиск' - }, - modal: { - searchBox: { - resetButtonTitle: 'Сбросить поиск', - resetButtonAriaLabel: 'Сбросить поиск', - cancelButtonText: 'Отменить поиск', - cancelButtonAriaLabel: 'Отменить поиск' - }, - startScreen: { - recentSearchesTitle: 'История поиска', - noRecentSearchesText: 'Нет истории поиска', - saveRecentSearchButtonTitle: 'Сохранить в истории поиска', - removeRecentSearchButtonTitle: 'Удалить из истории поиска', - favoriteSearchesTitle: 'Избранное', - removeFavoriteSearchButtonTitle: 'Удалить из избранного' - }, - errorScreen: { - titleText: 'Невозможно получить результаты', - helpText: - 'Вам может потребоваться проверить подключение к Интернету' - }, - footer: { - selectText: 'выбрать', - navigateText: 'перейти', - closeText: 'закрыть', - searchByText: 'поставщик поиска' - }, - noResultsScreen: { - noResultsText: 'Нет результатов для', - suggestedQueryText: 'Вы можете попытаться узнать', - reportMissingResultsText: - 'Считаете, что поиск даёт ложные результаты?', - reportMissingResultsLinkText: - 'Нажмите на кнопку «Обратная связь»' - } - } + // askAi: "ВАШ-ID-АССИСТЕНТА" + // ИЛИ + askAi: { + // как минимум нужно указать assistantId, полученный от Algolia + assistantId: 'XXXYYY', + // необязательные переопределения — если их нет, используются значения appId/apiKey/indexName верхнего уровня + // apiKey: '...', + // appId: '...', + // indexName: '...' + } + } + } + } +}) +``` + +::: warning Примечание +Если вы хотите использовать обычный поиск по ключевым словам без Ask AI, просто не указывайте свойство `askAi` +::: + +### Боковая панель Ask AI {#ask-ai-side-panel} + +DocSearch v4.5+ поддерживает опциональную **боковую панель Ask AI**. Когда она включена, её можно открыть с помощью **Ctrl/Cmd+I** по умолчанию. [Справочник API боковой панели](https://docsearch.algolia.com/docs/sidepanel/api-reference) содержит полный список опций. + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + // Отражает API @docsearch/sidepanel-js SidepanelProps + panel: { + variant: 'floating', // или 'inline' + side: 'right', + width: '360px', + expandedWidth: '580px', + suggestedQuestions: true } } } @@ -275,119 +292,70 @@ export default defineConfig({ }) ``` -[Эти параметры](https://github.com/vuejs/vitepress/blob/main/types/docsearch.d.ts) можно переопределить. Чтобы узнать о них больше, обратитесь к официальной документации Algolia. +Если вам нужно отключить сочетание клавиш, используйте опцию `keyboardShortcuts` боковой панели: -### Конфигурация поискового робота {#crawler-config} +```ts +import { defineConfig } from 'vitepress' -Вот пример конфигурации, основанной на той, что используется на этом сайте: +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + appId: '...', + apiKey: '...', + indexName: '...', + askAi: { + assistantId: 'XXXYYY', + sidePanel: { + keyboardShortcuts: { + 'Ctrl/Cmd+I': false + } + } + } + } + } + } +}) +``` + +#### Режим (auto / sidePanel / hybrid / modal) {#ask-ai-mode} + +Вы можете опционально контролировать, как VitePress интегрирует поиск по ключевым словам и Ask AI: + +- `mode: 'auto'` (по умолчанию): выводит `hybrid`, когда настроен поиск по ключевым словам, иначе `sidePanel`, когда настроена боковая панель Ask AI. +- `mode: 'sidePanel'`: принудительно использовать только боковую панель (скрывает кнопку поиска по ключевым словам). +- `mode: 'hybrid'`: включает модальное окно поиска по ключевым словам + боковую панель Ask AI (требует настройки поиска по ключевым словам). +- `mode: 'modal'`: сохраняет Ask AI внутри модального окна DocSearch (даже если вы настроили боковую панель). + +#### Только Ask AI (без поиска по ключевым словам) {#ask-ai-only} + +Если вы хотите использовать **только боковую панель Ask AI**, вы можете опустить конфигурацию поиска по ключевым словам верхнего уровня и предоставить учётные данные в `askAi`: ```ts -new Crawler({ - appId: '...', - apiKey: '...', - rateLimit: 8, - startUrls: ['https://vitepress.dev/'], - renderJavaScript: false, - sitemaps: [], - exclusionPatterns: [], - ignoreCanonicalTo: false, - discoveryPatterns: ['https://vitepress.dev/**'], - schedule: 'at 05:10 on Saturday', - actions: [ - { - indexName: 'vitepress', - pathsToMatch: ['https://vitepress.dev/**'], - recordExtractor: ({ $, helpers }) => { - return helpers.docsearch({ - recordProps: { - lvl1: '.content h1', - content: '.content p, .content li', - lvl0: { - selectors: 'section.has-active div h2', - defaultValue: 'Documentation' - }, - lvl2: '.content h2', - lvl3: '.content h3', - lvl4: '.content h4', - lvl5: '.content h5' - }, - indexHeadings: true - }) +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + search: { + provider: 'algolia', + options: { + mode: 'sidePanel', + askAi: { + assistantId: 'XXXYYY', + appId: '...', + apiKey: '...', + indexName: '...', + sidePanel: true + } } } - ], - initialIndexSettings: { - vitepress: { - attributesForFaceting: ['type', 'lang'], - attributesToRetrieve: ['hierarchy', 'content', 'anchor', 'url'], - attributesToHighlight: ['hierarchy', 'hierarchy_camel', 'content'], - attributesToSnippet: ['content:10'], - camelCaseAttributes: ['hierarchy', 'hierarchy_radio', 'content'], - searchableAttributes: [ - 'unordered(hierarchy_radio_camel.lvl0)', - 'unordered(hierarchy_radio.lvl0)', - 'unordered(hierarchy_radio_camel.lvl1)', - 'unordered(hierarchy_radio.lvl1)', - 'unordered(hierarchy_radio_camel.lvl2)', - 'unordered(hierarchy_radio.lvl2)', - 'unordered(hierarchy_radio_camel.lvl3)', - 'unordered(hierarchy_radio.lvl3)', - 'unordered(hierarchy_radio_camel.lvl4)', - 'unordered(hierarchy_radio.lvl4)', - 'unordered(hierarchy_radio_camel.lvl5)', - 'unordered(hierarchy_radio.lvl5)', - 'unordered(hierarchy_radio_camel.lvl6)', - 'unordered(hierarchy_radio.lvl6)', - 'unordered(hierarchy_camel.lvl0)', - 'unordered(hierarchy.lvl0)', - 'unordered(hierarchy_camel.lvl1)', - 'unordered(hierarchy.lvl1)', - 'unordered(hierarchy_camel.lvl2)', - 'unordered(hierarchy.lvl2)', - 'unordered(hierarchy_camel.lvl3)', - 'unordered(hierarchy.lvl3)', - 'unordered(hierarchy_camel.lvl4)', - 'unordered(hierarchy.lvl4)', - 'unordered(hierarchy_camel.lvl5)', - 'unordered(hierarchy.lvl5)', - 'unordered(hierarchy_camel.lvl6)', - 'unordered(hierarchy.lvl6)', - 'content' - ], - distinct: true, - attributeForDistinct: 'url', - customRanking: [ - 'desc(weight.pageRank)', - 'desc(weight.level)', - 'asc(weight.position)' - ], - ranking: [ - 'words', - 'filters', - 'typo', - 'attribute', - 'proximity', - 'exact', - 'custom' - ], - highlightPreTag: '', - highlightPostTag: '', - minWordSizefor1Typo: 3, - minWordSizefor2Typos: 7, - allowTyposOnNumericTokens: false, - minProximity: 1, - ignorePlurals: true, - advancedSyntax: true, - attributeCriteriaComputedByMinProximity: true, - removeWordsIfNoResults: 'allOptional' - } } }) ``` - +### Конфигурация поискового робота {#crawler-config} + +Вот пример конфигурации, основанной на той, что используется на этом сайте: + +<<< @/snippets/algolia-crawler.js diff --git a/docs/ru/reference/default-theme-sidebar.md b/docs/ru/reference/default-theme-sidebar.md index 92fd89c14..f1e0e5f96 100644 --- a/docs/ru/reference/default-theme-sidebar.md +++ b/docs/ru/reference/default-theme-sidebar.md @@ -1,3 +1,7 @@ +--- +description: Настройте боковую панель навигации в теме VitePress по умолчанию с группами, сворачиваемыми секциями и множественными сайдбарами. +--- + # Сайдбар {#sidebar} Сайдбар (боковая панель) — основной навигационный блок вашей документации. Меню боковой панели можно настроить в секции [`themeConfig.sidebar`](./default-theme-config#sidebar). @@ -178,36 +182,3 @@ export default { } } ``` - -## `useSidebar` {#usesidebar} - -Возвращает данные, связанные с сайдбаром. Возвращаемый объект имеет следующий тип: - -```ts -export interface DocSidebar { - isOpen: Ref - sidebar: ComputedRef - sidebarGroups: ComputedRef - hasSidebar: ComputedRef - hasAside: ComputedRef - leftAside: ComputedRef - isSidebarEnabled: ComputedRef - open: () => void - close: () => void - toggle: () => void -} -``` - -**Пример:** - -```vue - - - -``` diff --git a/docs/ru/reference/default-theme-team-page.md b/docs/ru/reference/default-theme-team-page.md index 0eebaa24c..125e68984 100644 --- a/docs/ru/reference/default-theme-team-page.md +++ b/docs/ru/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: Создавайте страницы команды с профилями участников, используя встроенные компоненты VitePress. +--- + - - -``` diff --git a/docs/zh/reference/default-theme-team-page.md b/docs/zh/reference/default-theme-team-page.md index 0341f0f26..99d5b1916 100644 --- a/docs/zh/reference/default-theme-team-page.md +++ b/docs/zh/reference/default-theme-team-page.md @@ -1,3 +1,7 @@ +--- +description: 使用 VitePress 内置的团队组件创建包含成员资料的团队页面。 +--- + diff --git a/src/client/theme-default/components/VPCarbonAds.vue b/src/client/theme-default/components/VPCarbonAds.vue index a233d1eff..5b2ed8511 100644 --- a/src/client/theme-default/components/VPCarbonAds.vue +++ b/src/client/theme-default/components/VPCarbonAds.vue @@ -19,9 +19,14 @@ let isInitialized = false function init() { if (!isInitialized) { isInitialized = true + const params = new URLSearchParams({ + serve: carbonOptions.code, + placement: carbonOptions.placement, + format: carbonOptions?.format || 'classic', + }) const s = document.createElement('script') s.id = '_carbonads_js' - s.src = `//cdn.carbonads.com/carbon.js?serve=${carbonOptions.code}&placement=${carbonOptions.placement}` + s.src = `//cdn.carbonads.com/carbon.js?${params.toString()}` s.async = true container.value.appendChild(s) } diff --git a/src/client/theme-default/components/VPContent.vue b/src/client/theme-default/components/VPContent.vue index 3b2dbdf6e..42e11fc84 100644 --- a/src/client/theme-default/components/VPContent.vue +++ b/src/client/theme-default/components/VPContent.vue @@ -1,49 +1,47 @@ @@ -91,8 +91,8 @@ const { hasSidebar } = useSidebar() @media (min-width: 1440px) { .VPContent.has-sidebar { - padding-right: calc((100vw - var(--vp-layout-max-width)) / 2); - padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)); + padding-right: calc((100% - var(--vp-layout-max-width)) / 2); + padding-left: calc((100% - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)); } } diff --git a/src/client/theme-default/components/VPDoc.vue b/src/client/theme-default/components/VPDoc.vue index dd87ee95a..4ac18bd93 100644 --- a/src/client/theme-default/components/VPDoc.vue +++ b/src/client/theme-default/components/VPDoc.vue @@ -2,14 +2,14 @@ import { useRoute } from 'vitepress' import { computed } from 'vue' import { useData } from '../composables/data' -import { useSidebar } from '../composables/sidebar' +import { useLayout } from '../composables/layout' import VPDocAside from './VPDocAside.vue' import VPDocFooter from './VPDocFooter.vue' const { theme } = useData() const route = useRoute() -const { hasSidebar, hasAside, leftAside } = useSidebar() +const { hasSidebar, hasAside, leftAside } = useLayout() const pageName = computed(() => route.path.replace(/[./]+/g, '_').replace(/_html$/, '') @@ -154,6 +154,7 @@ const pageName = computed(() => width: 224px; height: 32px; background: linear-gradient(transparent, var(--vp-c-bg) 70%); + pointer-events: none; } .aside-content { diff --git a/src/client/theme-default/components/VPDocAsideOutline.vue b/src/client/theme-default/components/VPDocAsideOutline.vue index 00ea9bbe9..efaadc095 100644 --- a/src/client/theme-default/components/VPDocAsideOutline.vue +++ b/src/client/theme-default/components/VPDocAsideOutline.vue @@ -1,26 +1,17 @@ @@ -28,7 +19,7 @@ useActiveAnchor(container, marker)
    diff --git a/src/client/theme-default/components/VPDocAsideSponsors.vue b/src/client/theme-default/components/VPDocAsideSponsors.vue index dc9f8d0e1..9e023dbcf 100644 --- a/src/client/theme-default/components/VPDocAsideSponsors.vue +++ b/src/client/theme-default/components/VPDocAsideSponsors.vue @@ -12,6 +12,6 @@ defineProps<{ diff --git a/src/client/theme-default/components/VPDocFooterLastUpdated.vue b/src/client/theme-default/components/VPDocFooterLastUpdated.vue index 5ec3cfeb1..576a87d41 100644 --- a/src/client/theme-default/components/VPDocFooterLastUpdated.vue +++ b/src/client/theme-default/components/VPDocFooterLastUpdated.vue @@ -1,26 +1,38 @@ @@ -28,7 +40,7 @@ onMounted(() => { diff --git a/src/client/theme-default/components/VPDocOutlineItem.vue b/src/client/theme-default/components/VPDocOutlineItem.vue index 89ea9710c..4cff1b384 100644 --- a/src/client/theme-default/components/VPDocOutlineItem.vue +++ b/src/client/theme-default/components/VPDocOutlineItem.vue @@ -1,22 +1,18 @@