Skip to content

Расширение стандартной темы

Стандартная тема VitePress оптимизирована для документации и может быть настроена. См. Обзор конфигурации стандартной темы для получения полного списка опций.

Однако есть ряд случаев, когда конфигурация в одиночку не будет достаточной. Например:

  1. Вам нужно изменить стили CSS;
  2. Вам нужно изменить экземпляр приложения Vue, например, для регистрации глобальных компонентов;
  3. Вам нужно внедрить пользовательский контент в тему через слоты макета.

Эти продвинутые настройки потребуют использования пользовательской темы, которая "расширяет" стандартную тему.

Подсказка

Перед продолжением убедитесь, что вы прочитали Использование пользовательской темы, чтобы понять, как работают пользовательские темы.

Настройка 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 стандартной темы, которые можно переопределить.

Использование разных шрифтов

VitePress использует 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/custom.css */
:root {
  --vp-font-family-base: /* шрифт обычного текста */
  --vp-font-family-mono: /* шрифт кода */
}

WARNING

Если вы используете дополнительные компоненты, такие как Страница команды, убедитесь, что вы также импортируете их из vitepress/theme-without-fonts!

Если ваш шрифт - это локальный файл, на который ссылается через @font-face, он будет обработан как ресурс и включен в .vitepress/dist/assets с хешированным именем файла. Чтобы предзагрузить этот файл, используйте хук сборки transformHead:

js
// .vitepress/config.js
export default {
  transformHead({ assets }) {
    // настройте регулярное выражение соответственно, чтобы соответствовать вашему шрифту
    const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
    if (myFontFile) {
      return [
        [
          'link',
          {
            rel: 'preload',
            href: myFontFile,
            as: 'font',
            type: 'font/woff2',
            crossorigin: ''
          }
        ]
      ]
    }
  }
}

Регистрация глобальных компонентов

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, чтобы автоматически зарегистрировать директорию компонент

ов.

Слоты макета

Компонент <Layout/> стандартной темы имеет несколько слотов, которые можно использовать для внедрения контента в определенные места страницы. Вот пример внедрения компонента в верхнюю часть боковой панели:

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-->
<script setup>
import DefaultTheme from 'vitepress/theme'

const { Layout } = DefaultTheme
</script>

<template>
  <Layout>
    <template #aside-outline-before>
      Мой пользовательский контент в верхней части боковой панели
    </template>
  </Layout>
</template>

Или вы можете использовать функцию рендеринга:

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)
    })
  }
}

Полный список слотов, доступных в макете стандартной темы:

  • Когда через frontmatter включен 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
  • Когда через frontmatter включен layout: 'home':
    • home-hero-before
    • home-hero-info-before
    • home-hero-info
    • home-hero-info-after
    • home-hero-actions-after
    • home-hero-image
    • home-hero-after
    • home-features-before
    • home-features-after
  • Когда через frontmatter включен layout: 'page':
    • page-top
    • page-bottom
  • На странице не найдено (404):
    • 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

Использование API переходов между представлениями

При переключении режима отображения

Вы можете расширить стандартную тему, чтобы предоставить пользовательский переход при переключении режима цвета. Пример:

vue
<!-- .vitepress/theme/Layout.vue -->

<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { nextTick, provide } from 'vue'

const { isDark } = useData()

const enableTransitions = () =>
  'startViewTransition' in document &&
  window.matchMedia('(prefers-reduced-motion: no-preference)').matches

provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
  if (!enableTransitions()) {
    isDark.value = !isDark.value
    return
  }

  const clipPath = [
    `circle(0px at ${x}px ${y}px)`,
    `circle(${Math.hypot(
      Math.max(x, innerWidth - x),
      Math.max(y, innerHeight - y)
    )}px at ${x}px ${y}px)`
  ]

  await document.startViewTransition(async () => {
    isDark.value = !isDark.value
    await nextTick()
  }).ready

  document.documentElement.animate(
    { clipPath: isDark.value ? clipPath.reverse() : clipPath },
    {
      duration: 300,
      easing: 'ease-in',
      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
    }
  )
})
</script>

<template>
  <DefaultTheme.Layout />
</template>

<style>
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-old(root),
.dark::view-transition-new(root) {
  z-index: 1;
}

::view-transition-new(root),
.dark::view-transition-old(root) {
  z-index: 9999;
}

.VPSwitchAppearance {
  width: 22px !important;
}

.VPSwitchAppearance .check {
  transform: none !important;
}
</style>

Результат (внимание!: мигающие цвета, внезапные движения, яркие света):

Демо
Демо переключения режима отображения

См. Документацию Chrome для получения дополнительной информации о переходах между представлениями.

При изменении маршрута

Скоро будет.

Переопределение внутренних компонентов

Вы можете использовать алиасы Vite для замены компонентов стандартной темы на ваши собственные:

ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'

export default defineConfig({
  vite: {
    resolve: {
      alias: [
        {
          find: /^.*\/VPNavBar\.vue$/,
          replacement: fileURLToPath(
            new URL('./components/CustomNavBar.vue', import.meta.url)
          )
        }
      ]
    }
  }
})

Чтобы узнать точное имя компонента, обратитесь к нашему исходному коду. Поскольку компоненты являются внутренними, есть небольшая вероятность, что их имя будет обновлено между минорными релизами.

Содержание доступно по лицензии MIT