From 02c62f7875429f15cf13764477c1bcea3ff9058c Mon Sep 17 00:00:00 2001 From: Lukas Leisten Date: Fri, 14 Mar 2025 15:33:07 +0100 Subject: [PATCH 1/4] feat(sidebar): Change component to SidebarTextItem --- docs/en/reference/default-theme-nav.md | 21 +++++++++++++++++++ src/client/app/components/SidebarTextItem.ts | 17 +++++++++++++++ src/client/app/index.ts | 2 ++ .../components/VPSidebarItem.vue | 4 ++-- 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/client/app/components/SidebarTextItem.ts diff --git a/docs/en/reference/default-theme-nav.md b/docs/en/reference/default-theme-nav.md index b55a63cb1b5e..ff579021d84f 100644 --- a/docs/en/reference/default-theme-nav.md +++ b/docs/en/reference/default-theme-nav.md @@ -161,6 +161,27 @@ export default { Refer [`socialLinks`](./default-theme-config#sociallinks). +## Custom Text Item Component + +If you want to use the default theme but modify only the text of the items, you can override the `SidebarTextItem` inside the `enhanceApp` function. For example: + +```js +// .vitepress/theme/index.js +import DefaultTheme from 'vitepress/theme'; +import CustomSidebarTextItem from './components/CustomSidebarTextItem.vue'; + +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + app.component('SidebarTextItem', CustomSidebarTextItem); + } +}; +``` + +### Creating a Custom `SidebarTextItem` + +To create your own `SidebarTextItem`, define a Vue component that accepts a `content` prop and renders it inside a chosen HTML tag. This allows you to fully customize how the text appears while maintaining compatibility with the default theme. + ## Custom Components You can include custom components in the navigation bar by using the `component` option. The `component` key should be the Vue component name, and must be registered globally using [Theme.enhanceApp](../guide/custom-theme#theme-interface). diff --git a/src/client/app/components/SidebarTextItem.ts b/src/client/app/components/SidebarTextItem.ts new file mode 100644 index 000000000000..d482367c5518 --- /dev/null +++ b/src/client/app/components/SidebarTextItem.ts @@ -0,0 +1,17 @@ +import { defineComponent, h } from 'vue' + +export const SidebarTextItem = defineComponent({ + props: { + content: { + type: String, + required: true + }, + is: { + type: [Object, String], + default: 'p' + } + }, + render() { + return h(this.is, { innerHTML: this.content }) + } +}) diff --git a/src/client/app/index.ts b/src/client/app/index.ts index 1f1e8069597b..2c38b416cc58 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -17,6 +17,7 @@ import { usePrefetch } from './composables/preFetch' import { dataSymbol, initData, siteDataRef, useData } from './data' import { RouterSymbol, createRouter, scrollTo, type Router } from './router' import { inBrowser, pathToFile } from './utils' +import { SidebarTextItem } from './components/SidebarTextItem' function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme { if (theme.extends) { @@ -78,6 +79,7 @@ export async function createApp() { // install global components app.component('Content', Content) app.component('ClientOnly', ClientOnly) + app.component('SidebarTextItem', SidebarTextItem) // expose $frontmatter & $params Object.defineProperties(app.config.globalProperties, { diff --git a/src/client/theme-default/components/VPSidebarItem.vue b/src/client/theme-default/components/VPSidebarItem.vue index 022584e31d6e..112c2377c481 100644 --- a/src/client/theme-default/components/VPSidebarItem.vue +++ b/src/client/theme-default/components/VPSidebarItem.vue @@ -77,9 +77,9 @@ function onCaretClick() { :rel="item.rel" :target="item.target" > - + - +
Date: Fri, 14 Mar 2025 16:42:51 +0100 Subject: [PATCH 2/4] feat(search): Change span to LocalSearchBoxItem --- docs/en/reference/default-theme-search.md | 21 +++++++++++++++++++ .../app/components/LocalSearchBoxItem.ts | 13 ++++++++++++ src/client/app/index.ts | 2 ++ .../components/VPLocalSearchBox.vue | 4 ++-- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/client/app/components/LocalSearchBoxItem.ts diff --git a/docs/en/reference/default-theme-search.md b/docs/en/reference/default-theme-search.md index d647e32ed252..9bae9ce7903a 100644 --- a/docs/en/reference/default-theme-search.md +++ b/docs/en/reference/default-theme-search.md @@ -187,6 +187,27 @@ export default defineConfig({ }) ``` +### Custom Local Search Box Item Component + +If you want to customize the search result items in the local search page, you can override the `LocalSearchBoxItem` component similarly: + +```js +// .vitepress/theme/index.js +import DefaultTheme from 'vitepress/theme'; +import CustomLocalSearchBoxItem from './components/CustomLocalSearchBoxItem.vue'; + +export default { + extends: DefaultTheme, + enhanceApp({ app }) { + app.component('LocalSearchBoxItem', CustomLocalSearchBoxItem); + } +}; +``` + +#### Creating a Custom `LocalSearchBoxItem` + +To create your own `LocalSearchBoxItem`, define a Vue component that accepts a `content` prop and renders it inside a chosen HTML tag, such as a ``. This allows you to control how search results are displayed while keeping the default functionality. + ## 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: diff --git a/src/client/app/components/LocalSearchBoxItem.ts b/src/client/app/components/LocalSearchBoxItem.ts new file mode 100644 index 000000000000..f2a1c4c9ca9a --- /dev/null +++ b/src/client/app/components/LocalSearchBoxItem.ts @@ -0,0 +1,13 @@ +import { defineComponent, h } from 'vue' + +export const LocalSearchBoxItem = defineComponent({ + props: { + content: { + type: String, + required: true + } + }, + render() { + return h('span', { innerHTML: this.content }) + } +}) diff --git a/src/client/app/index.ts b/src/client/app/index.ts index 2c38b416cc58..7524fa5ac329 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -18,6 +18,7 @@ import { dataSymbol, initData, siteDataRef, useData } from './data' import { RouterSymbol, createRouter, scrollTo, type Router } from './router' import { inBrowser, pathToFile } from './utils' import { SidebarTextItem } from './components/SidebarTextItem' +import { LocalSearchBoxItem } from './components/LocalSearchBoxItem' function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme { if (theme.extends) { @@ -80,6 +81,7 @@ export async function createApp() { app.component('Content', Content) app.component('ClientOnly', ClientOnly) app.component('SidebarTextItem', SidebarTextItem) + app.component('LocalSearchBoxItem', LocalSearchBoxItem) // expose $frontmatter & $params Object.defineProperties(app.config.globalProperties, { diff --git a/src/client/theme-default/components/VPLocalSearchBox.vue b/src/client/theme-default/components/VPLocalSearchBox.vue index b348de54659f..54e4e12445b3 100644 --- a/src/client/theme-default/components/VPLocalSearchBox.vue +++ b/src/client/theme-default/components/VPLocalSearchBox.vue @@ -526,11 +526,11 @@ function onMouseMove(e: MouseEvent) { :key="index" class="title" > - + - +
From f6414d319aba03bb9179e25f18bccb8d4a121e72 Mon Sep 17 00:00:00 2001 From: Lukas Leisten Date: Fri, 14 Mar 2025 16:43:25 +0100 Subject: [PATCH 3/4] feat(alias): Use esm-bundler as default --- src/node/alias.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/node/alias.ts b/src/node/alias.ts index ad9eae4b0860..9f2aefaf5610 100644 --- a/src/node/alias.ts +++ b/src/node/alias.ts @@ -44,22 +44,24 @@ export function resolveAliases( } ] + let vuePath = 'vue/dist/vue.esm-bundler.js' + if (!ssr) { // Prioritize vue installed in project root and fallback to // vue that comes with vitepress itself. // Only do this when not running SSR build, since `vue` needs to be // externalized during SSR - let vuePath try { vuePath = require.resolve(vueRuntimePath, { paths: [root] }) } catch (e) { vuePath = require.resolve(vueRuntimePath) } - aliases.push({ - find: /^vue$/, - replacement: vuePath - }) } + aliases.push({ + find: /^vue$/, + replacement: vuePath + }) + return aliases } From 23f13b175d9b988cf0ad468e706205da3ccf39a0 Mon Sep 17 00:00:00 2001 From: Lukas Leisten Date: Tue, 18 Mar 2025 09:46:09 +0100 Subject: [PATCH 4/4] feat(themeConfig):Added skip Title update --- docs/en/reference/default-theme-config.md | 7 +++++++ src/client/app/composables/head.ts | 8 +++++--- src/node/alias.ts | 12 +++++------- types/default-theme.d.ts | 5 +++++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/en/reference/default-theme-config.md b/docs/en/reference/default-theme-config.md index c8afc5544a4d..7c42ee8c00ad 100644 --- a/docs/en/reference/default-theme-config.md +++ b/docs/en/reference/default-theme-config.md @@ -451,6 +451,13 @@ Can be used to customize the aria-label of the language toggle button in navbar. Can be used to customize the label of the skip to content link. This link is shown when the user is navigating the site using a keyboard. +## skipTitleUpdate + +- Type: `boolean` +- Default: `false` + +Can be used to skip the default title update logic so it can be implemented on your own. + ## externalLinkIcon - Type: `boolean` diff --git a/src/client/app/composables/head.ts b/src/client/app/composables/head.ts index 13fb9bb0a256..7a18724dcb1c 100644 --- a/src/client/app/composables/head.ts +++ b/src/client/app/composables/head.ts @@ -56,9 +56,11 @@ export function useUpdateHead(route: Route, siteDataByRouteRef: Ref) { const frontmatterHead = (pageData && pageData.frontmatter.head) || [] // update title and description - const title = createTitle(siteData, pageData) - if (title !== document.title) { - document.title = title + if (!siteData.themeConfig.skipTitleUpdate) { + const title = createTitle(siteData, pageData) + if (title !== document.title) { + document.title = title + } } const description = pageDescription || siteData.description diff --git a/src/node/alias.ts b/src/node/alias.ts index 9f2aefaf5610..ad9eae4b0860 100644 --- a/src/node/alias.ts +++ b/src/node/alias.ts @@ -44,24 +44,22 @@ export function resolveAliases( } ] - let vuePath = 'vue/dist/vue.esm-bundler.js' - if (!ssr) { // Prioritize vue installed in project root and fallback to // vue that comes with vitepress itself. // Only do this when not running SSR build, since `vue` needs to be // externalized during SSR + let vuePath try { vuePath = require.resolve(vueRuntimePath, { paths: [root] }) } catch (e) { vuePath = require.resolve(vueRuntimePath) } + aliases.push({ + find: /^vue$/, + replacement: vuePath + }) } - aliases.push({ - find: /^vue$/, - replacement: vuePath - }) - return aliases } diff --git a/types/default-theme.d.ts b/types/default-theme.d.ts index 5a669c493203..fb736290d260 100644 --- a/types/default-theme.d.ts +++ b/types/default-theme.d.ts @@ -127,6 +127,11 @@ export namespace DefaultTheme { */ skipToContentLabel?: string + /** + * @default false + */ + skipTitleUpdate?: boolean + search?: | { provider: 'local'; options?: LocalSearchOptions } | { provider: 'algolia'; options: AlgoliaSearchOptions }