From 23ce654e069cba4c802e7ce7be82e25219b66dce Mon Sep 17 00:00:00 2001 From: LemonNeko Date: Sun, 10 Nov 2024 16:33:47 +0800 Subject: [PATCH 1/8] add breadcrumbs plugin --- .../vitepress-plugin-breadcrumbs/README.md | 90 +++++++++++++++++++ .../build.config.ts | 14 +++ .../vitepress-plugin-breadcrumbs/package.json | 56 ++++++++++++ .../src/client/components/Breadcrumbs.vue | 46 ++++++++++ .../src/client/index.ts | 3 + .../test/breadcrumbs-data-generator.test.ts | 51 +++++++++++ .../vitepress/breadcrumbs-data-generator.ts | 53 +++++++++++ .../src/vitepress/index.ts | 1 + .../tsconfig.json | 35 ++++++++ pnpm-lock.yaml | 6 ++ 10 files changed, 355 insertions(+) create mode 100644 packages/vitepress-plugin-breadcrumbs/README.md create mode 100644 packages/vitepress-plugin-breadcrumbs/build.config.ts create mode 100644 packages/vitepress-plugin-breadcrumbs/package.json create mode 100644 packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue create mode 100644 packages/vitepress-plugin-breadcrumbs/src/client/index.ts create mode 100644 packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts create mode 100644 packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts create mode 100644 packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts create mode 100644 packages/vitepress-plugin-breadcrumbs/tsconfig.json diff --git a/packages/vitepress-plugin-breadcrumbs/README.md b/packages/vitepress-plugin-breadcrumbs/README.md new file mode 100644 index 00000000..62430f85 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/README.md @@ -0,0 +1,90 @@ +# @nolebase/vitepress-plugin-breadcrumbs + +A VitePress plugin that adds breadcrumbs to your documentation. + +## Get started +Install: +```shell +pnpm install @nolebase/vitepress-plugin-breadcrumbs +# or use bun +bun install @nolebase/vitepress-plugin-breadcrumbs +``` +Generate breadcrumbs data when build your pages in `.vitepress/config.ts`: +```typescript +import { BreadcrumbsDataGenerator } from '@nolebase/vitepress-plugin-breadcrumbs' +import { defineConfig } from 'vitepress' + +const breadcrumbsGenerator = new BreadcrumbsDataGenerator('', '<root dir of your documents>') + +export default defineConfig({ + // other config... + transformPageData(pageData, context) { + breadcrumbsGenerator.generate(pageData, context.siteConfig.pages) + // other transforming... + }, + // other config... +}) +``` +Add default breadcrumb vue component to each page in `.vitepress/theme/index.ts`: +```typescript +import type { Theme as ThemeConfig } from 'vitepress' +import { Breadcrumbs } from '@nolebase/vitepress-plugin-breadcrumbs/client' +import DefaultTheme from 'vitepress/theme' +import { h } from 'vue' + +export const Theme: ThemeConfig = { + extends: DefaultTheme, + Layout: () => { + return h(DefaultTheme.Layout, null, { + // add breadcrumb above document + 'doc-before': () => h(Breadcrumbs), + }) + }, + enhanceApp({ app }) { + app.provide<Options>(InjectionKey, { + spotlight: { + defaultToggle: true + } + }) + } +} + +export default Theme +``` +Add this plugin to `noExternal` and `exclude` properties when building: +```typescript +export default defineConfig({ + vite: { + optimizeDeps: { + exclude: [ + '@nolebase/vitepress-plugin-breadcrumbs/client' + ] + }, + ssr: { + noExternal: [ + '@nolebase/vitepress-plugin-breadcrumbs' + ] + } + }, + // other config... +}) +``` + +## Use custom breadcrumb component +If you don't like the style or other something of default breadcrumb component, you can create your own component, this plugin will inject breadcrumb data into frontmatter of the page, so you can use breadcrumb data like this: +```vue +<script setup lang="ts"> +import { useData } from 'vitepress' + +const { frontmatter } = useData() + +console.log(frontmatter.breadcrumbs) +// and do something other... +</script> + +<template> + <div> + <!-- ui of your own component --> + </div> +</template> +``` diff --git a/packages/vitepress-plugin-breadcrumbs/build.config.ts b/packages/vitepress-plugin-breadcrumbs/build.config.ts new file mode 100644 index 00000000..a5cf1728 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/build.config.ts @@ -0,0 +1,14 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.vue'], loaders: ['vue'] }, + { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] }, + { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] }, + { builder: 'mkdist', input: './src/vitepress', outDir: './dist/vitepress', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] }, + { builder: 'mkdist', input: './src/vitepress', outDir: './dist/vitepress', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] }, + ], + clean: true, + sourcemap: true, + declaration: true, +}) diff --git a/packages/vitepress-plugin-breadcrumbs/package.json b/packages/vitepress-plugin-breadcrumbs/package.json new file mode 100644 index 00000000..3acc08d2 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/package.json @@ -0,0 +1,56 @@ +{ + "name": "@nolebase/vitepress-plugin-breadcrumbs", + "type": "module", + "version": "2.8.1", + "description": "A VitePress plugin that adds breadcrumbs to your documentation.", + "author": { + "name": "Nólëbase", + "email": "nolebase@ayaka.moe", + "url": "https://github.com/nolebase" + }, + "license": "MIT", + "homepage": "https://nolebase-integrations.ayaka.io/pages/en/integrations/vitepress-plugin-breadcrumbs/", + "repository": { + "type": "git", + "url": "https://github.com/nolebase/integrations.git", + "directory": "packages/vitepress-plugin-breadcrumbs" + }, + "keywords": [ + "vitepress", + "nolebase", + "vitepress-plugin", + "nolebase-integration" + ], + "exports": { + ".": { + "types": "./dist/vitepress/index.d.ts", + "import": "./dist/vitepress/index.mjs", + "require": "./dist/vitepress/index.js" + }, + "./vitepress": { + "types": "./dist/vitepress/index.d.ts", + "import": "./dist/vitepress/index.mjs", + "require": "./dist/vitepress/index.js" + }, + "./client": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.mjs", + "require": "./dist/client/index.js" + } + }, + "main": "./dist/vitepress/index.js", + "module": "./dist/vitepress/index.mjs", + "types": "./dist/vitepress/index.d.ts", + "files": [ + "README.md", + "dist", + "package.json" + ], + "scripts": { + "build": "unbuild", + "package:publish": "pnpm build && pnpm publish --access public --no-git-checks" + }, + "dependencies": { + "vitepress": "^1.4.2" + } +} diff --git a/packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue b/packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue new file mode 100644 index 00000000..ce0c59c1 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue @@ -0,0 +1,46 @@ +<script setup lang="ts"> +import { useData } from 'vitepress' + +const { frontmatter } = useData() +</script> + +<template> + <div class="breadcrumbs"> + <span v-for="item in frontmatter.breadcrumbs" :key="item"> + <a v-if="item.link" :href="item.link">{{ item.title }}</a> + <span v-else>{{ item.title }}</span> + </span> + </div> +</template> + +<style scoped> +.breadcrumbs { + display: flex; + gap: 8px; + font-size: 14px; + margin-bottom: 2rem; +} + +.breadcrumbs span { + transition: color 0.25s, opacity 0.25s; + color: var(--vp-c-text-2); +} + +.breadcrumbs span:hover { + color: var(--vp-c-brand-1); +} + +.breadcrumbs span:last-child { + color: var(--vp-c-text-1); +} + +.breadcrumbs span:last-child:hover { + color: var(--vp-c-brand-1); +} + +.breadcrumbs span:not(:first-child)::before { + content: '/'; + padding-right: 8px; + color: var(--vp-c-text-3); +} +</style> diff --git a/packages/vitepress-plugin-breadcrumbs/src/client/index.ts b/packages/vitepress-plugin-breadcrumbs/src/client/index.ts new file mode 100644 index 00000000..e93bd178 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/src/client/index.ts @@ -0,0 +1,3 @@ +import Breadcrumbs from './components/Breadcrumbs.vue' + +export { Breadcrumbs } diff --git a/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts b/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts new file mode 100644 index 00000000..73256568 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts @@ -0,0 +1,51 @@ +import type { PageData } from 'vitepress' +import { expect, it } from 'vitest' +import { BreadcrumbsDataGenerator } from '../vitepress' + +it('page is not index', () => { + const pageData: PageData = { + relativePath: 'a/b/c/d.md', + filePath: 'a/b/c/d.md', + title: 'd', + description: '', + headers: [], + frontmatter: {}, + } + + const pages = ['a', 'a/b', 'a/b/index.md', 'a/b/c/d.md'] + + const generator = new BreadcrumbsDataGenerator('Home', 'a') + + generator.generate(pageData, pages) + + expect(pageData.frontmatter.breadcrumbs).toEqual([ + { title: 'Home', link: '/a' }, + { title: 'b', link: '/a/b' }, + { title: 'c', link: '' }, + { title: 'd', link: '/a/b/c/d' }, + ]) +}) + +it('page is index', () => { + const pageData: PageData = { + relativePath: 'a/b/c/d/index.md', + filePath: 'a/b/c/d/index.md', + title: 'd', + description: '', + headers: [], + frontmatter: {}, + } + + const pages = ['a', 'a/b', 'a/b/index.md', 'a/b/c/d/index.md'] + + const generator = new BreadcrumbsDataGenerator('Home', 'a') + + generator.generate(pageData, pages) + + expect(pageData.frontmatter.breadcrumbs).toEqual([ + { title: 'Home', link: '/a' }, + { title: 'b', link: '/a/b' }, + { title: 'c', link: '' }, + { title: 'd', link: '/a/b/c/d' }, + ]) +}) diff --git a/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts b/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts new file mode 100644 index 00000000..c3117ea5 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts @@ -0,0 +1,53 @@ +import type { PageData } from 'vitepress' + +export class BreadcrumbsDataGenerator { + constructor(private readonly title: string, private readonly rootDirectory: string) { } + + generate(pageData: PageData, pages: string[]) { + const splitPath = pageData.filePath.split('/') + const breadcrumbs: { + title: string + link: string + }[] = [{ + title: this.title, + link: `/${this.rootDirectory}`, + }] + + for (let i = 1; i < splitPath.length; i++) { + let link = '' + let encodedLink = '' + let title = splitPath[i] + if (i === splitPath.length - 1) { + title = pageData.title + } + + for (let j = 0; j <= i; j++) { + link += `${splitPath[j]}` + encodedLink += `${encodeURIComponent(splitPath[j])}` + + if (j !== i) { + link += `/` + encodedLink += `/` + } + } + + if (!pages.includes(link) && !pages.includes(`${link}/index.md`)) { + breadcrumbs.push({ title: splitPath[i], link: '' }) + continue + } + + if (link.endsWith('index.md')) { + continue + } + + if (link.endsWith('.md')) { + encodedLink = encodedLink.slice(0, -3) + } + + breadcrumbs.push({ title, link: `/${encodedLink}` }) + } + + if (splitPath.length) + pageData.frontmatter.breadcrumbs = breadcrumbs + } +} diff --git a/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts b/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts new file mode 100644 index 00000000..20793c82 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts @@ -0,0 +1 @@ +export { BreadcrumbsDataGenerator } from './breadcrumbs-data-generator' diff --git a/packages/vitepress-plugin-breadcrumbs/tsconfig.json b/packages/vitepress-plugin-breadcrumbs/tsconfig.json new file mode 100644 index 00000000..eabd4979 --- /dev/null +++ b/packages/vitepress-plugin-breadcrumbs/tsconfig.json @@ -0,0 +1,35 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "composite": false, + "baseUrl": ".", + "strict": true, + "strictNullChecks": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "declaration": true, + "noEmit": false, + "outDir": "./dist", + "removeComments": false, + "sourceMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.mts", + "src/**/*.d.ts", + "src/**/*.vue", + "src/**/*.tsx" + ], + "exclude": [ + "**/dist/**", + "node_modules" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de325bf7..941110ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -340,6 +340,12 @@ importers: specifier: ^3.3.0 version: 3.3.0 + packages/vitepress-plugin-breadcrumbs: + dependencies: + vitepress: + specifier: ^1.4.2 + version: 1.4.2(@algolia/client-search@4.22.1)(@types/node@22.8.5)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0)(typescript@5.6.3) + packages/vitepress-plugin-enhanced-mark: dependencies: less: From d5628e9e496fdd7e67852f603cb560765580bbe2 Mon Sep 17 00:00:00 2001 From: LemonNeko <chheese048@gmail.com> Date: Sun, 10 Nov 2024 16:45:30 +0800 Subject: [PATCH 2/8] use rollup instead of mkdist --- packages/vitepress-plugin-breadcrumbs/build.config.ts | 6 ++++-- packages/vitepress-plugin-breadcrumbs/package.json | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/vitepress-plugin-breadcrumbs/build.config.ts b/packages/vitepress-plugin-breadcrumbs/build.config.ts index a5cf1728..6d49cb10 100644 --- a/packages/vitepress-plugin-breadcrumbs/build.config.ts +++ b/packages/vitepress-plugin-breadcrumbs/build.config.ts @@ -5,9 +5,11 @@ export default defineBuildConfig({ { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.vue'], loaders: ['vue'] }, { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] }, { builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] }, - { builder: 'mkdist', input: './src/vitepress', outDir: './dist/vitepress', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] }, - { builder: 'mkdist', input: './src/vitepress', outDir: './dist/vitepress', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] }, + { builder: 'rollup', input: './src/vitepress/index', outDir: 'dist/vitepress/' }, ], + rollup: { + emitCJS: true, + }, clean: true, sourcemap: true, declaration: true, diff --git a/packages/vitepress-plugin-breadcrumbs/package.json b/packages/vitepress-plugin-breadcrumbs/package.json index 3acc08d2..db63b242 100644 --- a/packages/vitepress-plugin-breadcrumbs/package.json +++ b/packages/vitepress-plugin-breadcrumbs/package.json @@ -25,12 +25,12 @@ ".": { "types": "./dist/vitepress/index.d.ts", "import": "./dist/vitepress/index.mjs", - "require": "./dist/vitepress/index.js" + "require": "./dist/vitepress/index.cjs" }, "./vitepress": { "types": "./dist/vitepress/index.d.ts", "import": "./dist/vitepress/index.mjs", - "require": "./dist/vitepress/index.js" + "require": "./dist/vitepress/index.cjs" }, "./client": { "types": "./dist/client/index.d.ts", @@ -38,7 +38,7 @@ "require": "./dist/client/index.js" } }, - "main": "./dist/vitepress/index.js", + "main": "./dist/vitepress/index.cjs", "module": "./dist/vitepress/index.mjs", "types": "./dist/vitepress/index.d.ts", "files": [ @@ -47,6 +47,8 @@ "package.json" ], "scripts": { + "dev": "unbuild --stub", + "stub": "unbuild --stub", "build": "unbuild", "package:publish": "pnpm build && pnpm publish --access public --no-git-checks" }, From fe8585c7c9cdb155dd6ad255efb19e7681a94187 Mon Sep 17 00:00:00 2001 From: LemonNekoGH <self@lemonneko.moe> Date: Wed, 13 Nov 2024 20:14:53 +0800 Subject: [PATCH 3/8] fix naming issues --- .../components/{Breadcrumbs.vue => NolebaseBreadcrumbs.vue} | 4 ++-- packages/vitepress-plugin-breadcrumbs/src/client/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename packages/vitepress-plugin-breadcrumbs/src/client/components/{Breadcrumbs.vue => NolebaseBreadcrumbs.vue} (92%) diff --git a/packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue b/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue similarity index 92% rename from packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue rename to packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue index ce0c59c1..34d09cc4 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/client/components/Breadcrumbs.vue +++ b/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue @@ -5,7 +5,7 @@ const { frontmatter } = useData() </script> <template> - <div class="breadcrumbs"> + <div class="vp-nolebase-breadcrumbs"> <span v-for="item in frontmatter.breadcrumbs" :key="item"> <a v-if="item.link" :href="item.link">{{ item.title }}</a> <span v-else>{{ item.title }}</span> @@ -14,7 +14,7 @@ const { frontmatter } = useData() </template> <style scoped> -.breadcrumbs { +.vp-nolebase-breadcrumbs { display: flex; gap: 8px; font-size: 14px; diff --git a/packages/vitepress-plugin-breadcrumbs/src/client/index.ts b/packages/vitepress-plugin-breadcrumbs/src/client/index.ts index e93bd178..9a8eab31 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/client/index.ts +++ b/packages/vitepress-plugin-breadcrumbs/src/client/index.ts @@ -1,3 +1,3 @@ -import Breadcrumbs from './components/Breadcrumbs.vue' +import NolebaseBreadcrumbs from './components/NolebaseBreadcrumbs.vue' -export { Breadcrumbs } +export { NolebaseBreadcrumbs } From 0cc4ff8c6a58c6ee798166c3b228de874d49887a Mon Sep 17 00:00:00 2001 From: LemonNekoGH <self@lemonneko.moe> Date: Wed, 13 Nov 2024 20:16:43 +0800 Subject: [PATCH 4/8] add spaces to different markdown blocks --- packages/vitepress-plugin-breadcrumbs/README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/vitepress-plugin-breadcrumbs/README.md b/packages/vitepress-plugin-breadcrumbs/README.md index 62430f85..fb5d197c 100644 --- a/packages/vitepress-plugin-breadcrumbs/README.md +++ b/packages/vitepress-plugin-breadcrumbs/README.md @@ -3,13 +3,17 @@ A VitePress plugin that adds breadcrumbs to your documentation. ## Get started + Install: + ```shell pnpm install @nolebase/vitepress-plugin-breadcrumbs # or use bun bun install @nolebase/vitepress-plugin-breadcrumbs ``` + Generate breadcrumbs data when build your pages in `.vitepress/config.ts`: + ```typescript import { BreadcrumbsDataGenerator } from '@nolebase/vitepress-plugin-breadcrumbs' import { defineConfig } from 'vitepress' @@ -24,11 +28,12 @@ export default defineConfig({ }, // other config... }) + ``` Add default breadcrumb vue component to each page in `.vitepress/theme/index.ts`: ```typescript import type { Theme as ThemeConfig } from 'vitepress' -import { Breadcrumbs } from '@nolebase/vitepress-plugin-breadcrumbs/client' +import { NolebaseBreadcrumbs } from '@nolebase/vitepress-plugin-breadcrumbs/client' import DefaultTheme from 'vitepress/theme' import { h } from 'vue' @@ -37,7 +42,7 @@ export const Theme: ThemeConfig = { Layout: () => { return h(DefaultTheme.Layout, null, { // add breadcrumb above document - 'doc-before': () => h(Breadcrumbs), + 'doc-before': () => h(NolebaseBreadcrumbs), }) }, enhanceApp({ app }) { @@ -50,8 +55,10 @@ export const Theme: ThemeConfig = { } export default Theme + ``` Add this plugin to `noExternal` and `exclude` properties when building: + ```typescript export default defineConfig({ vite: { @@ -71,7 +78,9 @@ export default defineConfig({ ``` ## Use custom breadcrumb component + If you don't like the style or other something of default breadcrumb component, you can create your own component, this plugin will inject breadcrumb data into frontmatter of the page, so you can use breadcrumb data like this: + ```vue <script setup lang="ts"> import { useData } from 'vitepress' From 87fccb91fd31ffc997a03bd93cb2565f9a81a1d7 Mon Sep 17 00:00:00 2001 From: LemonNekoGH <self@lemonneko.moe> Date: Wed, 13 Nov 2024 20:47:25 +0800 Subject: [PATCH 5/8] refactor: use a single function instead create a class --- .../vitepress-plugin-breadcrumbs/README.md | 6 +- .../test/breadcrumbs-data-generator.test.ts | 46 +++++----- .../vitepress/breadcrumbs-data-generator.ts | 84 +++++++++---------- .../src/vitepress/index.ts | 2 +- 4 files changed, 70 insertions(+), 68 deletions(-) diff --git a/packages/vitepress-plugin-breadcrumbs/README.md b/packages/vitepress-plugin-breadcrumbs/README.md index fb5d197c..4805f950 100644 --- a/packages/vitepress-plugin-breadcrumbs/README.md +++ b/packages/vitepress-plugin-breadcrumbs/README.md @@ -15,15 +15,13 @@ bun install @nolebase/vitepress-plugin-breadcrumbs Generate breadcrumbs data when build your pages in `.vitepress/config.ts`: ```typescript -import { BreadcrumbsDataGenerator } from '@nolebase/vitepress-plugin-breadcrumbs' +import { generateBreadcrumbsData } from '@nolebase/vitepress-plugin-breadcrumbs' import { defineConfig } from 'vitepress' -const breadcrumbsGenerator = new BreadcrumbsDataGenerator('<title of your website>', '<root dir of your documents>') - export default defineConfig({ // other config... transformPageData(pageData, context) { - breadcrumbsGenerator.generate(pageData, context.siteConfig.pages) + generateBreadcrumbsData(pageData, context) // other transforming... }, // other config... diff --git a/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts b/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts index 73256568..576bc2c2 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts +++ b/packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts @@ -1,22 +1,25 @@ -import type { PageData } from 'vitepress' +import type { PageData, TransformPageContext } from 'vitepress' import { expect, it } from 'vitest' -import { BreadcrumbsDataGenerator } from '../vitepress' +import { generateBreadcrumbsData } from '../vitepress' it('page is not index', () => { - const pageData: PageData = { + const pageData = { relativePath: 'a/b/c/d.md', filePath: 'a/b/c/d.md', title: 'd', - description: '', - headers: [], frontmatter: {}, - } + } as PageData - const pages = ['a', 'a/b', 'a/b/index.md', 'a/b/c/d.md'] + const context = { + siteConfig: { + site: { + title: 'Home', + }, + pages: ['a', 'a/b', 'a/b/index.md', 'a/b/c/d.md'], + }, + } as TransformPageContext - const generator = new BreadcrumbsDataGenerator('Home', 'a') - - generator.generate(pageData, pages) + generateBreadcrumbsData(pageData, context) expect(pageData.frontmatter.breadcrumbs).toEqual([ { title: 'Home', link: '/a' }, @@ -27,20 +30,23 @@ it('page is not index', () => { }) it('page is index', () => { - const pageData: PageData = { + const pageData = { relativePath: 'a/b/c/d/index.md', filePath: 'a/b/c/d/index.md', title: 'd', - description: '', - headers: [], frontmatter: {}, - } - - const pages = ['a', 'a/b', 'a/b/index.md', 'a/b/c/d/index.md'] - - const generator = new BreadcrumbsDataGenerator('Home', 'a') - - generator.generate(pageData, pages) + } as PageData + + const context = { + siteConfig: { + site: { + title: 'Home', + }, + pages: ['a', 'a/b', 'a/b/index.md', 'a/b/c/d/index.md'], + }, + } as TransformPageContext + + generateBreadcrumbsData(pageData, context) expect(pageData.frontmatter.breadcrumbs).toEqual([ { title: 'Home', link: '/a' }, diff --git a/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts b/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts index c3117ea5..dfa0eb95 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts +++ b/packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts @@ -1,53 +1,51 @@ -import type { PageData } from 'vitepress' - -export class BreadcrumbsDataGenerator { - constructor(private readonly title: string, private readonly rootDirectory: string) { } - - generate(pageData: PageData, pages: string[]) { - const splitPath = pageData.filePath.split('/') - const breadcrumbs: { - title: string - link: string - }[] = [{ - title: this.title, - link: `/${this.rootDirectory}`, - }] - - for (let i = 1; i < splitPath.length; i++) { - let link = '' - let encodedLink = '' - let title = splitPath[i] - if (i === splitPath.length - 1) { - title = pageData.title - } +import type { PageData, TransformPageContext } from 'vitepress' + +export function generateBreadcrumbsData(pageData: PageData, context: TransformPageContext) { + const splitPath = pageData.filePath.split('/') + const rootDirectory = splitPath[0] + const pages = context.siteConfig.pages + const breadcrumbs: { + title: string + link: string + }[] = [{ + title: context.siteConfig.site.title, + link: `/${rootDirectory}`, + }] + + for (let i = 1; i < splitPath.length; i++) { + let link = '' + let encodedLink = '' + let title = splitPath[i] + if (i === splitPath.length - 1) { + title = pageData.title + } - for (let j = 0; j <= i; j++) { - link += `${splitPath[j]}` - encodedLink += `${encodeURIComponent(splitPath[j])}` + for (let j = 0; j <= i; j++) { + link += `${splitPath[j]}` + encodedLink += `${encodeURIComponent(splitPath[j])}` - if (j !== i) { - link += `/` - encodedLink += `/` - } - } - - if (!pages.includes(link) && !pages.includes(`${link}/index.md`)) { - breadcrumbs.push({ title: splitPath[i], link: '' }) - continue + if (j !== i) { + link += `/` + encodedLink += `/` } + } - if (link.endsWith('index.md')) { - continue - } + if (!pages.includes(link) && !pages.includes(`${link}/index.md`)) { + breadcrumbs.push({ title: splitPath[i], link: '' }) + continue + } - if (link.endsWith('.md')) { - encodedLink = encodedLink.slice(0, -3) - } + if (link.endsWith('index.md')) { + continue + } - breadcrumbs.push({ title, link: `/${encodedLink}` }) + if (link.endsWith('.md')) { + encodedLink = encodedLink.slice(0, -3) } - if (splitPath.length) - pageData.frontmatter.breadcrumbs = breadcrumbs + breadcrumbs.push({ title, link: `/${encodedLink}` }) } + + if (splitPath.length) + pageData.frontmatter.breadcrumbs = breadcrumbs } diff --git a/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts b/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts index 20793c82..d67bce71 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts +++ b/packages/vitepress-plugin-breadcrumbs/src/vitepress/index.ts @@ -1 +1 @@ -export { BreadcrumbsDataGenerator } from './breadcrumbs-data-generator' +export { generateBreadcrumbsData } from './breadcrumbs-data-generator' From 17b886f2781f696fec104ad43592cc761a8ca0ee Mon Sep 17 00:00:00 2001 From: LemonNekoGH <self@lemonneko.moe> Date: Wed, 13 Nov 2024 20:49:55 +0800 Subject: [PATCH 6/8] add spaces between different markdown blocks --- packages/vitepress-plugin-breadcrumbs/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/vitepress-plugin-breadcrumbs/README.md b/packages/vitepress-plugin-breadcrumbs/README.md index 4805f950..17d8239b 100644 --- a/packages/vitepress-plugin-breadcrumbs/README.md +++ b/packages/vitepress-plugin-breadcrumbs/README.md @@ -28,7 +28,9 @@ export default defineConfig({ }) ``` + Add default breadcrumb vue component to each page in `.vitepress/theme/index.ts`: + ```typescript import type { Theme as ThemeConfig } from 'vitepress' import { NolebaseBreadcrumbs } from '@nolebase/vitepress-plugin-breadcrumbs/client' @@ -53,8 +55,8 @@ export const Theme: ThemeConfig = { } export default Theme - ``` + Add this plugin to `noExternal` and `exclude` properties when building: ```typescript From 81ce4cee62f4012f1465822a4ce72550d5de4400 Mon Sep 17 00:00:00 2001 From: LemonNekoGH <self@lemonneko.moe> Date: Wed, 13 Nov 2024 20:52:14 +0800 Subject: [PATCH 7/8] add missing css class prefix --- .../src/client/components/NolebaseBreadcrumbs.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue b/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue index 34d09cc4..9ae1ec25 100644 --- a/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue +++ b/packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue @@ -21,24 +21,24 @@ const { frontmatter } = useData() margin-bottom: 2rem; } -.breadcrumbs span { +.vp-nolebase-breadcrumbs span { transition: color 0.25s, opacity 0.25s; color: var(--vp-c-text-2); } -.breadcrumbs span:hover { +.vp-nolebase-breadcrumbs span:hover { color: var(--vp-c-brand-1); } -.breadcrumbs span:last-child { +.vp-nolebase-breadcrumbs span:last-child { color: var(--vp-c-text-1); } -.breadcrumbs span:last-child:hover { +.vp-nolebase-breadcrumbs span:last-child:hover { color: var(--vp-c-brand-1); } -.breadcrumbs span:not(:first-child)::before { +.vp-nolebase-breadcrumbs span:not(:first-child)::before { content: '/'; padding-right: 8px; color: var(--vp-c-text-3); From 5ca0670e1eb672ff6e58f2177e43a1ae27aa15af Mon Sep 17 00:00:00 2001 From: LemonNeko <chheese048@gmail.com> Date: Wed, 13 Nov 2024 23:00:01 +0800 Subject: [PATCH 8/8] fix broken lockfile --- packages/vitepress-plugin-breadcrumbs/package.json | 2 +- pnpm-lock.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vitepress-plugin-breadcrumbs/package.json b/packages/vitepress-plugin-breadcrumbs/package.json index db63b242..5c895d0c 100644 --- a/packages/vitepress-plugin-breadcrumbs/package.json +++ b/packages/vitepress-plugin-breadcrumbs/package.json @@ -53,6 +53,6 @@ "package:publish": "pnpm build && pnpm publish --access public --no-git-checks" }, "dependencies": { - "vitepress": "^1.4.2" + "vitepress": "^1.5.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 487e1f8e..45b42829 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -355,8 +355,8 @@ importers: packages/vitepress-plugin-breadcrumbs: dependencies: vitepress: - specifier: ^1.4.2 - version: 1.4.2(@algolia/client-search@4.22.1)(@types/node@22.8.5)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0)(typescript@5.6.3) + specifier: ^1.5.0 + version: 1.5.0(@algolia/client-search@4.22.1)(@types/node@22.9.0)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0)(typescript@5.6.3) packages/vitepress-plugin-enhanced-mark: dependencies: