diff --git a/docs/ru/config.ts b/docs/ru/config.ts index aec80866..86f8452a 100644 --- a/docs/ru/config.ts +++ b/docs/ru/config.ts @@ -189,7 +189,7 @@ function searchOptions(): Partial { clearButtonAriaLabel: 'Очистить запрос', closeButtonText: 'Закрыть', closeButtonAriaLabel: 'Закрыть', - placeholderText: 'Поиск по документации или задайте вопрос Ask AI', + placeholderText: 'Искать в документации или задать вопрос Ask AI', placeholderTextAskAi: 'Задайте другой вопрос...', placeholderTextAskAiStreaming: 'Отвечаю...', searchInputLabel: 'Поиск', diff --git a/docs/ru/guide/cms.md b/docs/ru/guide/cms.md index c55040c0..b3d12dee 100644 --- a/docs/ru/guide/cms.md +++ b/docs/ru/guide/cms.md @@ -1,5 +1,5 @@ --- -description: Подключите VitePress к безголовой CMS с помощью динамических маршрутов и загрузчиков данных. +description: Подключите VitePress к CMS без встроенного интерфейса с помощью динамических маршрутов и загрузчиков данных. outline: deep --- diff --git a/docs/ru/guide/custom-theme.md b/docs/ru/guide/custom-theme.md index fdbd1caf..3cb62035 100644 --- a/docs/ru/guide/custom-theme.md +++ b/docs/ru/guide/custom-theme.md @@ -67,6 +67,24 @@ export default { } ``` +Значение `router` представляет собой тот же экземпляр маршрутизатора VitePress, который возвращает [`useRouter()`](../reference/runtime-api#userouter). Чтобы отслеживать изменения маршрутов, назначьте обработчики для маршрутизатора: + +```ts [.vitepress/theme/index.ts] +export default { + enhanceApp({ router }) { + router.onBeforeRouteChange = (to) => { + console.log('navigating to', to) + } + + router.onAfterRouteChange = (to) => { + console.log('navigated to', to) + } + } +} +``` + +Верните `false` из `onBeforeRouteChange` или `onBeforePageLoad`, чтобы отменить переход. + Экспорт по умолчанию является единственным контрактом для пользовательской темы, и только свойство `Layout` является обязательным. Таким образом, технически тема VitePress может быть простой, как один компонент Vue. Внутри компонент макета работает так же, как и обычное приложение Vite + Vue 3. Обратите внимание, что тема также должна быть [SSR-совместимой](./ssr-compat). @@ -156,7 +174,7 @@ const { page, frontmatter } = useData() ## Распространение пользовательской темы {#distributing-a-custom-theme} -Самый простой способ распространить пользовательскую тему — предоставить её в виде [репозитория шаблонов на GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository). +Самый простой способ распространить пользовательскую тему — предоставить её в виде [репозитория шаблонов на GitHub](https://docs.github.com/ru/repositories/creating-and-managing-repositories/creating-a-template-repository). Если вы хотите распространить тему в виде пакета npm, выполните следующие действия: diff --git a/docs/ru/guide/deploy.md b/docs/ru/guide/deploy.md index f92761e5..56cc8a0a 100644 --- a/docs/ru/guide/deploy.md +++ b/docs/ru/guide/deploy.md @@ -166,6 +166,13 @@ Cache-Control: max-age=31536000,immutable with: node-version: 24 cache: npm # или pnpm / yarn + - name: Cache VitePress + uses: actions/cache@v4 + with: + path: docs/.vitepress/cache + key: ${{ runner.os }}-vitepress-${{ hashFiles('docs/**', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lockb') }} + restore-keys: | + ${{ runner.os }}-vitepress- - name: Setup Pages uses: actions/configure-pages@v4 - name: Install dependencies diff --git a/docs/ru/guide/getting-started.md b/docs/ru/guide/getting-started.md index 7a4650fb..e88ddc00 100644 --- a/docs/ru/guide/getting-started.md +++ b/docs/ru/guide/getting-started.md @@ -37,6 +37,10 @@ $ yarn add -D vitepress@next vue $ bun add -D vitepress@next ``` +```sh [deno] +$ deno add -D vitepress@next +``` + ::: ::: tip ПРИМЕЧАНИЕ diff --git a/docs/ru/reference/default-theme-config.md b/docs/ru/reference/default-theme-config.md index 99689bd1..796b5bb4 100644 --- a/docs/ru/reference/default-theme-config.md +++ b/docs/ru/reference/default-theme-config.md @@ -25,10 +25,28 @@ export default { ## i18nRouting -- Тип: `boolean` +- Тип: `boolean | ((data: VitePressData, hash: string, targetLocale: string) => string)` При смене локали на `ru` URL изменится с `/foo` (или `/en/foo/`) на `/ru/foo`. Вы можете отключить это поведение, установив для параметра `themeConfig.i18nRouting` значение `false`. +Установите для `themeConfig.i18nRouting` функцию, чтобы настроить ссылки для переключения локали. Эта функция получает текущие данные VitePress, текущий хеш и ключ целевой локали, а затем возвращает ссылку для перехода на неё. + +```ts +import { defineConfig } from 'vitepress' + +export default defineConfig({ + themeConfig: { + i18nRouting(data, hash, targetLocale) { + const target = data.site.value.locales[targetLocale] + const targetLink = + target.link || (targetLocale === 'root' ? '/' : `/${targetLocale}/`) + + return `${targetLink}${data.page.value.relativePath.replace(/\.md$/, '')}${hash}` + } + } +}) +``` + ## logo - Тип: `ThemeableImage` @@ -235,6 +253,7 @@ export default { // Можно добавить любую иконку из simple-icons (https://simpleicons.org/): { icon: 'github', link: 'https://github.com/vuejs/vitepress' }, { icon: 'twitter', link: '...' }, + { icon: 'discord', link: '/community', target: '_self' }, // Можно добавить пользовательские иконки, передав SVG в виде строки: { icon: { @@ -254,6 +273,7 @@ interface SocialLink { icon: string | { svg: string } link: string ariaLabel?: string + target?: string } ``` diff --git a/docs/ru/reference/default-theme-search.md b/docs/ru/reference/default-theme-search.md index 838e7cea..efead057 100644 --- a/docs/ru/reference/default-theme-search.md +++ b/docs/ru/reference/default-theme-search.md @@ -276,7 +276,6 @@ export default defineConfig({ askAi: { assistantId: 'XXXYYY', sidePanel: { - // Отражает API @docsearch/sidepanel-js SidepanelProps panel: { variant: 'floating', // или 'inline' side: 'right', @@ -292,6 +291,8 @@ export default defineConfig({ }) ``` +Используйте `askAi.sidePanel.panel.suggestedQuestions` для настройки рекомендуемых вопросов в боковой панели. В примерах автономного Ask AI от Algolia также упоминается `askAi.suggestedQuestions`, однако одного этого параметра верхнего уровня недостаточно для режима боковой панели VitePress, и он не позволяет встроенному модальному окну поиска по ключевым словам отображать рекомендуемые вопросы при первом открытии. + Если вам нужно отключить сочетание клавиш, используйте опцию `keyboardShortcuts` боковой панели: ```ts diff --git a/docs/ru/reference/runtime-api.md b/docs/ru/reference/runtime-api.md index efbaae88..5157bd67 100644 --- a/docs/ru/reference/runtime-api.md +++ b/docs/ru/reference/runtime-api.md @@ -62,6 +62,8 @@ interface PageData { } ``` +`page.headers` заполняется только в том случае, если включён параметр [markdown.headers](./site-config#markdown). Без него это свойство остаётся пустым массивом. Оглавление в теме по умолчанию получает заголовки из уже отрендеренного содержимого страницы, поэтому оно может отображаться, даже если `page.headers` пуст. + **Пример:** ```vue @@ -122,6 +124,18 @@ interface Router { } ``` +Назначьте обработчики изменения маршрутов для экземпляра маршрутизатора: + +```ts +const router = useRouter() + +router.onBeforeRouteChange = (to) => { + console.log('переход к', to) +} +``` + +В пользовательских темах этот же экземпляр маршрутизатора доступен через [`enhanceApp`](../guide/custom-theme#theme-interface). + ## `withBase` {#withbase} - **Тип**: `(path: string) => string` diff --git a/docs/ru/reference/site-config.md b/docs/ru/reference/site-config.md index d8c0d255..b04a3bdd 100644 --- a/docs/ru/reference/site-config.md +++ b/docs/ru/reference/site-config.md @@ -134,13 +134,43 @@ export default defineConfigWithTheme({ Вы можете настроить базовый экземпляр [Markdown-It](https://github.com/markdown-it/markdown-it) с помощью опции [markdown](#markdown) в конфигурации VitePress. +### Переопределение на уровне страницы {#page-level-overrides} + +Некоторые настройки можно переопределить для отдельных страниц с помощью метаданных. + +Подробности см. в разделе [Конфигурация метаданных](./frontmatter-config). + +### Переопределение на уровне директории {#directory-level-overrides} + +Некоторые параметры конфигурации можно переопределить на уровне директории, что позволяет всем страницам в этой директории использовать общие настройки без необходимости повторять их в блоке метаданных каждой страницы. + +Для этого добавьте файл с именем `config.ts` (или `.js`, `.mjs` или `.mts`) в соответствующую директорию. Этот файл должен экспортировать объект конфигурации с помощью `export default`, аналогично основному файлу конфигурации. + +Вложенные директории наследуют настройки от родительской директории, при этом переопределения конфигурации объединяются соответствующим образом. + +Вспомогательную функцию `defineAdditionalConfig` можно использовать для получения подсказок TypeScript по доступным параметрам, однако, как и в случае с `defineConfig`, её использование необязательно. + +Например, для сайта с несколькими языками может потребоваться разное значение `description` для каждого языка. Мы можем добавить файл `es/config.ts` со следующим содержимым: + +```ts +import { defineAdditionalConfig } from 'vitepress' + +export default defineAdditionalConfig({ + description: 'Generador de Sitios Estáticos desarrollado con Vite y Vue.' +}) +``` + +Этот `description` затем будет использоваться для всех страниц в директории `es`. + +В качестве альтернативы, при использовании встроенных возможностей i18n настройки для директории локали можно переопределить через параметр `locales` в основном файле конфигурации. Подробности см. в разделе [Интернационализация](../guide/i18n). + ## Метаданные сайта {#site-metadata} ### title {#title} - Тип: `string` - По умолчанию: `VitePress` -- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#title) +- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#title) или на [уровне директории](#directory-level-overrides) Название для сайта. При использовании темы по умолчанию оно будет отображаться в панели навигации. @@ -161,7 +191,7 @@ export default { ### titleTemplate {##titletemplate} - Тип: `string | boolean` -- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#titletemplate) +- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#titletemplate) или на [уровне директории](#directory-level-overrides) Позволяет настраивать суффикс заголовка каждой страницы или весь заголовок. Например: @@ -194,7 +224,7 @@ export default { - Тип: `string` - По умолчанию: `A VitePress site` -- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#description) +- Можно переопределить для каждой страницы с помощью [метаданных](./frontmatter-config#description) или на [уровне директории](#directory-level-overrides) Описание для сайта. Это будет отображаться как тег `` в HTML-странице. @@ -208,7 +238,7 @@ export default { - Тип: `HeadConfig[]` - По умолчанию: `[]` -- Можно добавлять на страницу через [метаданные](./frontmatter-config#head) +- Можно добавлять на страницу через [метаданные](./frontmatter-config#head) или на [уровне директории](#directory-level-overrides) Дополнительные элементы для отображения в теге `` в HTML-странице. Добавленные пользователем теги выводятся перед закрывающим тегом `head`, после тегов VitePress. @@ -320,6 +350,7 @@ export default { - Тип: `string` - По умолчанию: `en-US` +- Может быть переопределено [на уровне директории](#directory-level-overrides) Атрибут lang для сайта. Будет выглядеть как тег `` в HTML-странице. @@ -530,6 +561,8 @@ export default { Проверьте [объявление типа и jsdocs](https://github.com/vuejs/vitepress/blob/main/src/node/markdown/markdown.ts) на наличие всех доступных опций. +Установите `markdown.headers` в значение `true` или передайте параметры [`@mdit-vue/plugin-headers`](https://github.com/mdit-vue/mdit-vue/tree/main/packages/plugin-headers), чтобы собирать заголовки в [`useData().page.headers`](./runtime-api#usedata). Этот параметр отключён по умолчанию. + ### vite {#vite} - Тип: `import('vite').UserConfig` @@ -607,7 +640,7 @@ interface SSGContext { - Тип: `(context: TransformContext) => Awaitable` -`transformHead` — это хук сборки для преобразования заголовка перед генерацией каждой страницы. Это позволит вам добавить в конфигурацию VitePress записи, которые не могут быть добавлены статически. Вам нужно только вернуть дополнительные записи, они будут автоматически объединены с существующими. +`transformHead` — это хук сборки для добавления дополнительных тегов в `` каждой страницы. Он позволяет добавлять элементы в head, которые невозможно статически добавить в конфигурацию VitePress. Вам нужно только вернуть дополнительные элементы — они будут автоматически объединены с уже существующими. ::: warning ПРЕДУПРЕЖДЕНИЕ Не мутируйте ничего внутри `context`. @@ -635,44 +668,38 @@ interface TransformContext { } ``` -Обратите внимание, что этот хук вызывается только при статической генерации сайта. Он не вызывается во время разработки. Если вам нужно добавить динамические записи в голову во время разработки, вместо этого вы можете использовать хук [`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` - } - ]) - } -} -``` +Дополнительные теги будут добавлены в статические HTML-файлы, созданные во время сборки. Они не будут обновляться при навигации на стороне клиента. -#### Пример: Добавление канонического URL-адреса `` {#example-adding-a-canonical-url-link} +Во многих случаях более подходящим решением будет использование хука [`transformPageData`](#transformpagedata). Этот хук также применяется как при клиентской навигации, так и в режиме разработки. Однако если генерация тегов head требует значительных вычислительных ресурсов, `transformHead` позволяет избежать этих затрат во время разработки. + +#### Пример: добавление мета-тега `og:image` {#example-adding-og-image-meta} ```ts export default { - transformPageData(pageData) { - const canonicalUrl = `https://example.com/${pageData.relativePath}` - .replace(/index\.md$/, '') - .replace(/\.md$/, '.html') + async transformHead(context) { + if (context.page === '404.md') { + return + } - pageData.frontmatter.head ??= [] - pageData.frontmatter.head.push([ - 'link', - { rel: 'canonical', href: canonicalUrl } - ]) + // Детали реализации `generatePageImage` зависят от ваших требований. + // Здесь мы предполагаем, что она создаёт подходящее изображение + // для каждой страницы и возвращает URL изображения. + const imageUrl = await generatePageImage(context) + + return [[ + 'meta', + { name: 'og:image', content: imageUrl } + ]] } } ``` +Здесь мы предполагаем, что URL изображения является динамическим и требует много времени для генерации. Использование `transformHead` позволяет избежать этих затрат во время разработки. + +Для более простых случаев может быть достаточно использовать параметр [`head`](./frontmatter-config#head) в метаданных или [`transformPageData`](#transformpagedata). + ### transformHtml {#transformhtml} - Тип: `(code: string, id: string, context: TransformContext) => Awaitable` @@ -721,3 +748,39 @@ interface TransformPageContext { siteConfig: SiteConfig } ``` + +#### Пример: добавление `` {#example-adding-a-meta-name-og-title} + +```ts +export default { + transformPageData(pageData) { + const title = pageData.frontmatter.layout === 'home' + ? 'VitePress' + : `${pageData.title} | VitePress` + + pageData.frontmatter.head ??= [] + pageData.frontmatter.head.push([ + 'meta', + { name: 'og:title', content: title } + ]) + } +} +``` + +#### Пример: добавление `` с каноническим 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 } + ]) + } +} +```