Extendiendo el Tema por defecto
El tema por defecto de VitePress es optimizado para documentación y puede ser personalizado. Consulte la Visión General de Configuración del Tema por Defecto para una lista completa de opciones.
Sin embargo, hay casos en que apenas la configuración no será suficiente. Por ejemplo:
- Es necesario ajustar los estilos CSS;
- Es necesario modificar la instancia de la aplicación Vue, por ejemplo para registrar componentes globales;
- Es necesario inyectar contenido personalizado en el tema por medio de slots en el layout.
Esas personalizaciones avanzadas exigirán el uso de un tema personalizado que "extiende" el tema por defecto.
TIP
Antes de seguir, asegurese de leer primero Usando un Tema Personalizado para entender como funcionan los temas personalizados.
Personalizando el CSS
El CSS del tema por defecto puede ser personalizado substuyendo las variables CSS a nivel de la raiz:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand-1: #646cff;
--vp-c-brand-2: #747bff;
}
Vea las variables CSS del tema por defecto que pueden ser substituídas.
Usando Fuentes Diferentes
VitePress usa Inter como fuente por defecto e incluirá las fuentes en la salida de compilación. La fuente también es pre-cargada automaticamente en producción. Sin embargo, eso puede no ser deseable se quiere usar una fuente principal diferente.
Para evitar la inclusión de Inter en la salida de compilación, importe el tema de vitepress/theme-without-fonts
:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'
export default DefaultTheme
/* .vitepress/theme/my-fonts.css */
:root {
--vp-font-family-base: /* fuente de texto normal */
--vp-font-family-mono: /* fuente de código */
}
WARNING
Si está usando componentes opcionales como los componentes de la Página del equipo, asegurese de también importarlos de vitepress/theme-without-fonts
!
Si su fuente es un archivo local referenciado via @font-face
, ella será procesada como un asset e incluida en .vitepress/dist/assets
con un nombre de archivo hash. Para pre-cargar ese archivo, use el hook de construcción transformHead:
// .vitepress/config.js
export default {
transformHead({ assets }) {
// ajuste el regex para corresponder a su fuente
const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
if (myFontFile) {
return [
[
'link',
{
rel: 'preload',
href: myFontFile,
as: 'font',
type: 'font/woff2',
crossorigin: ''
}
]
]
}
}
}
Registrando Componentes Globales
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
/** @type {import('vitepress').Theme} */
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// registre sus componentes globales personalizados
app.component('MyGlobalComponent' /* ... */)
}
}
Si está usando TypeScript:
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
// registre sus componentes globales personalizados
app.component('MyGlobalComponent' /* ... */)
}
} satisfies Theme
Como estamos usando Vite, puede también aprovechar la funcionalidad de importación glob de Vite para registrar automaticamente un directorio de componetes.
Slots en el Layout
El componente <Layout/>
del tema por defecto posee algunos slots que pueden ser usados para inyectar contenido en lugares específicos de la página. Aqui un ejemplo de como inyectar un componente antes del esquema:
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'
export default {
extends: DefaultTheme,
// substituya el Layout por un componente wrapper que
// inyecta los slots
Layout: MyLayout
}
<!--.vitepress/theme/MyLayout.vue-->
<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>
<template>
<Layout>
<template #aside-outline-before>
Mi contenido personalizado superior de la barra lateral
</template>
</Layout>
</template>
O puede también usar la función render.
// .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)
})
}
}
Lista completa de slots disponibles en el layout del tema por defecto:
- Cuando
layout: 'doc'
(por defecto) está habilitado via frontmatter: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
- Cuando
layout: 'home'
está habilitado via frontmatter:home-hero-before
home-hero-info-before
home-hero-info
home-hero-actions-after
home-hero-image
home-hero-after
home-features-before
home-features-after
- Cuando
layout: 'page'
está habilitado via frontmatter:page-top
page-bottom
- En la página no encontrada (404):
not-found
- Siempre:
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
Usando el API View Transitions
En la Alternancia de Apariencia
Puede extender el tema por defecto para proporcionar una transición personalizada cuando el modo de color es alternado. Un ejemplo:
<!-- .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>
Resultado (atención!: colores destellantes, movimientos súbitos, luces brillantes):
Demo
Consulte Chrome Docs para mas detalles sobre view transitions.
En el Cambio de Ruta
En breve.
Substituyendo Componentes Internos
Puede usar los aliases Vite para substituir los componentes del tema por defecto por los suyos personalizados:
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)
)
}
]
}
}
})
Para saber el nombre exacto del componente consulte nuestro código fuente. Como los componentes son internos, hay una pequeña chance de que el nombre sea actualizado entre lanzamientos secundarios.