Merge branch 'vitepress-2-upgrade' into vitepress-nitro-plugin

This commit is contained in:
Eric
2026-11-06 12:28:19 +01:00
16 changed files with 187 additions and 628 deletions
+8 -9
View File
@@ -1,18 +1,17 @@
import { fileURLToPath, URL } from 'node:url';
import { defineConfig, UserConfig } from 'vitepress';
import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons';
import sidebar from './sidebar';
import getStructuredData from './getStructuredData';
import sidebar from './sidebar/index.ts';
import nitro from '@analogjs/vite-plugin-nitro';
import nitroConfig from '../nitro.config';
import snackPlayer from './markdown/snackPlayer';
import sandpackPlugin from './markdown/sandpack';
import examplePlugin from './markdown/example';
import nitroConfig from '../nitro.config.ts';
import snackPlayer from './markdown/snackPlayer.ts';
import sandpackPlugin from './markdown/sandpack.ts';
import examplePlugin from './markdown/example.ts';
import { readFile } from 'node:fs/promises';
import { resourcesSidebar } from './sidebar/resources';
import { resourcesSidebar } from './sidebar/resources.ts';
import llmstxt from 'vitepress-plugin-llms';
import { transformPageData } from './transformPageData';
import getHeadConfig from './getHeadConfig';
import { transformPageData } from './transformPageData.ts';
import getHeadConfig from './getHeadConfig.ts';
const defaultSandpackCSS = await readFile(
fileURLToPath(new URL('./theme/sandpack-default.css', import.meta.url)),
+1 -1
View File
@@ -1,6 +1,6 @@
import { promises as fs, constants } from 'fs';
import path from 'path';
import { PackageItem } from '../theme/types';
import { type PackageItem } from '../theme/types.ts';
const fileExist = (filePath) =>
fs
+1 -1
View File
@@ -1,6 +1,6 @@
import { readFileSync } from 'node:fs';
import { dirname, isAbsolute, resolve } from 'node:path';
import type { MarkdownIt, RenderRule } from './types';
import type { MarkdownIt, RenderRule } from './types.ts';
import container from 'markdown-it-container';
type ContainerArgs = [typeof container, string, { render: RenderRule }];
+2 -2
View File
@@ -1,6 +1,6 @@
import type { MarkdownIt, RenderRule, Token } from './types';
import type { MarkdownIt, RenderRule, Token } from './types.ts';
import container from 'markdown-it-container';
import sandpackTheme from '../theme/sandpackTheme.json';
import sandpackTheme from '../theme/sandpackTheme.json' with { type: 'json' };
type SnackParams = {
defaultFiles?: Record<
+1 -1
View File
@@ -16,7 +16,7 @@
* />
*/
import type { MarkdownIt } from './types';
import type { MarkdownIt } from './types.ts';
type SnackParams = Record<string, string>;
+11 -11
View File
@@ -1,15 +1,15 @@
import { DefaultTheme, UserConfig } from 'vitepress';
import { reactSidebar } from './react';
import { vueSidebar } from './vue';
import { svelteSidebar } from './svelte';
import { lucideSidebar } from './lucide';
import { solidSidebar } from './solid';
import { preactSidebar } from './preact';
import { reactNativeSidebar } from './react-native';
import { astroSidebar } from './astro';
import { resourcesSidebar } from './resources';
import { angularSidebar } from './angular';
import { lucideStaticSidebar } from './static';
import { reactSidebar } from './react.ts';
import { vueSidebar } from './vue.ts';
import { svelteSidebar } from './svelte.ts';
import { lucideSidebar } from './lucide.ts';
import { solidSidebar } from './solid.ts';
import { preactSidebar } from './preact.ts';
import { reactNativeSidebar } from './react-native.ts';
import { astroSidebar } from './astro.ts';
import { resourcesSidebar } from './resources.ts';
import { angularSidebar } from './angular.ts';
import { lucideStaticSidebar } from './static.ts';
type Sidebar = UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'];
@@ -17,11 +17,11 @@ function onCategoriesClick() {
}
const categoriesIsActive = computed(() => {
return isActive(page.value.relativePath, '/icons/categories');
return isActive(page.value.relativePath, '', '/icons/categories');
});
const overviewIsActive = computed(() => {
return isActive(page.value.relativePath, '/icons/');
return isActive(page.value.relativePath, '', '/icons/');
});
const headers = computed(() => {
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { ref, watch, onMounted } from 'vue'
import { useAside } from 'vitepress/dist/client/theme-default/composables/aside.js'
import { useMediaQuery } from '@vueuse/core'
import { useData } from 'vitepress/dist/client/theme-default/composables/data.js'
const { page } = useData()
@@ -12,7 +12,7 @@ const props = defineProps<{
const carbonOptions = props.carbonAds
const { isAsideEnabled } = useAside()
const isAsideEnabled = useMediaQuery('(min-width: 80rem)')
const container = ref()
let isInitialized = false
@@ -1,12 +1,12 @@
<script setup lang="ts">
import { useData } from 'vitepress';
import { useSidebar } from 'vitepress/dist/client/theme-default/composables/sidebar.js';
import { useLayout } from 'vitepress/theme';
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue';
import { computed } from 'vue';
import SurveyAskOverlay from '../SurveyAskOverlay.vue';
const { theme } = useData();
const { hasSidebar } = useSidebar();
const { hasSidebar } = useLayout();
const githubLink = computed(
() => theme.value.socialLinks.find(({ icon }) => icon === 'github').link,
@@ -2,31 +2,33 @@
import { ref } from 'vue'
// This component can be rendered more than once on a page (e.g. a hidden
// copy inside `.content-body`). DocSearch mounts into the first `#docsearch`
// in the document, so only a single instance may ever render the search box.
// copy inside `.content-body`). DocSearch mounts into `#vp-docsearch`, so only
// a single instance may ever render the search box.
const loaded = ref(false)
// Shared so that any instance (e.g. the visible input) can open the modal
// rendered by the owning instance.
const openRequest = ref<{ target: 'search'; nonce: number } | null>(null)
let openNonce = 0
// Every instance registers the hotkeys; only handle each event once.
let lastHandledEvent: KeyboardEvent | null = null
</script>
<script lang="ts" setup>
import '@docsearch/css/dist/style.css'
import {
computed,
defineAsyncComponent,
onMounted,
onUnmounted,
} from 'vue'
import { computed, defineAsyncComponent, onMounted } from 'vue'
import { onKeyStroke } from '@vueuse/core'
import type { DefaultTheme } from 'vitepress/theme'
import { useData } from 'vitepress'
import FakeInput from '../base/FakeInput.vue'
const VPAlgoliaSearchBox = defineAsyncComponent(() => import('vitepress/dist/client/theme-default/components/VPAlgoliaSearchBox.vue'));
const VPAlgoliaSearchBox = defineAsyncComponent(
() => import('vitepress/dist/client/theme-default/components/VPAlgoliaSearchBox.vue'),
)
const { theme } = useData<DefaultTheme.Config>()
const algolia = computed(
() =>
(theme.value.search?.options ?? theme.value.algolia) as DefaultTheme.AlgoliaSearchOptions,
const algoliaOptions = computed(
() => (theme.value.search?.options ?? {}) as DefaultTheme.AlgoliaSearchOptions,
)
// whether this instance is the one rendering the (hidden) search box
@@ -36,47 +38,39 @@ const shortcutText = ref('')
// to avoid loading the docsearch js upfront (which is more than 1/3 of the
// payload), we delay initializing it until the user has actually clicked or
// hit the hotkey to invoke it.
const preconnect = () => {
onMounted(() => {
shortcutText.value = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘K' : 'Ctrl+K'
const id = 'VPAlgoliaPreconnect'
if (document.getElementById(id)) return
if (document.getElementById(id) || !algoliaOptions.value.appId) return
const rIC = window.requestIdleCallback || setTimeout
rIC(() => {
const preconnect = document.createElement('link')
preconnect.id = id
preconnect.rel = 'preconnect'
preconnect.href = `https://${algolia.value.appId}-dsn.algolia.net`
preconnect.href = `https://${algoliaOptions.value.appId}-dsn.algolia.net`
preconnect.crossOrigin = ''
document.head.appendChild(preconnect)
})
}
})
onMounted(() => {
preconnect()
shortcutText.value = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘K' : 'Ctrl+K'
// once docsearch is initialized it handles the hotkey itself
const handleSearchHotKey = (event: KeyboardEvent) => {
if (loaded.value) return remove()
if (
(event.key.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) ||
(!isEditingContent(event) && event.key === '/')
) {
event.preventDefault()
open()
remove()
}
onKeyStroke('k', (event) => {
if (event === lastHandledEvent) return
if (event.ctrlKey || event.metaKey) {
lastHandledEvent = event
event.preventDefault()
open()
}
})
const remove = () => {
window.removeEventListener('keydown', handleSearchHotKey)
onKeyStroke('/', (event) => {
if (event === lastHandledEvent) return
if (!isEditingContent(event)) {
lastHandledEvent = event
event.preventDefault()
open()
}
window.addEventListener('keydown', handleSearchHotKey)
onUnmounted(remove)
})
function open() {
@@ -84,23 +78,8 @@ function open() {
loaded.value = true
isOwner.value = true
}
setTimeout(poll, 16)
}
function poll() {
// programmatically open the search box after initialize
const e = new Event('keydown') as any
e.key = 'k'
e.metaKey = true
window.dispatchEvent(e)
setTimeout(() => {
if (!document.querySelector('.DocSearch-Modal')) {
poll()
}
}, 16)
// The search box queues the request until DocSearch is ready.
openRequest.value = { target: 'search', nonce: ++openNonce }
}
function isEditingContent(event: KeyboardEvent): boolean {
@@ -129,7 +108,7 @@ function isEditingContent(event: KeyboardEvent): boolean {
<!-- docsearch renders its own button here; we only need its modal -->
<div v-if="isOwner" class="docsearch-host">
<VPAlgoliaSearchBox :algolia="algolia" />
<VPAlgoliaSearchBox :algolia-options="algoliaOptions" :open-request="openRequest" />
</div>
</div>
</template>
@@ -1,6 +1,6 @@
import packageDataList from '../../../data/packageData.json';
import thirdPartyPackages from '../../../data/packageData.thirdParty.json';
import fetchPackages from '../../../lib/fetchPackages';
import packageDataList from '../../../data/packageData.json' with { type: 'json' };
import thirdPartyPackages from '../../../data/packageData.thirdParty.json' with { type: 'json' };
import fetchPackages from '../../../lib/fetchPackages.ts';
const loader = {
async load() {
+2 -2
View File
@@ -1,6 +1,6 @@
import { type PageData } from 'vitepress';
import getStructuredData, { getFaqStructuredData } from './getStructuredData';
import { createGeneralOGImage, createIconOGImage } from './createOGImage';
import getStructuredData, { getFaqStructuredData } from './getStructuredData.ts';
import { createGeneralOGImage, createIconOGImage } from './createOGImage.ts';
export async function transformPageData(pageData: PageData) {
pageData.frontmatter.head ??= [];
+1 -3
View File
@@ -31,7 +31,6 @@
"author": "Eric Fennis",
"license": "ISC",
"devDependencies": {
"@docsearch/js": "3.8.2",
"@lucide/build-icons": "workspace:*",
"@lucide/helpers": "workspace:*",
"@lucide/shared": "workspace:*",
@@ -53,14 +52,13 @@
"svg-pathdata": "^9.0.0",
"svgson": "^5.3.1",
"typescript": "^6.0.3",
"vitepress": "^1.6.4",
"vitepress": "2.0.0-alpha.21",
"vitepress-plugin-group-icons": "^1.7.6",
"vitepress-plugin-llms": "^1.13.5",
"vue-tsc": "^3.3.11"
},
"dependencies": {
"@analogjs/vite-plugin-nitro": "^2.6.3",
"@docsearch/css": "3.8.2",
"@floating-ui/vue": "^2.0.1",
"@headlessui/vue": "^1.7.23",
"@lucide/vue": "workspace:*",
+1 -1
View File
@@ -35,7 +35,7 @@ const writeIconFiles = Object.entries(iconMetaData).map(async ([iconName, metaDa
import iconNode from '../iconNodes/${iconName}.node.json' with { type: 'json' };
import releaseData from '../releaseMetadata/${iconName}.json' with { type: 'json' };
import popularity from '../iconPopularity/${iconName}.json' with { type: 'json' };
import { IconMetaData, IconNode } from '~/.vitepress/theme/types';
import type { IconMetaData, IconNode } from '~/.vitepress/theme/types.ts';
const metaData: IconMetaData = ${JSON.stringify({ tags, categories, contributors, aliases, deprecated, deprecationReason, toBeRemovedInVersion })};
+1 -1
View File
@@ -47,7 +47,7 @@ try {
await fs.promises.writeFile(
iconIndexFile,
`\
import type { IconNode } from '../../theme/types';
import type { IconNode } from '../../theme/types.ts';
${iconIndexFileImports.join('\n')}
${iconIndexFileNodes.join('\n')}
+112 -529
View File
File diff suppressed because it is too large Load Diff