-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(breadcrumbs): add vitepress breadcrumbs plugin (#327)
* add breadcrumbs plugin * use rollup instead of mkdist * fix naming issues * add spaces to different markdown blocks * refactor: use a single function instead create a class * add spaces between different markdown blocks * add missing css class prefix * fix broken lockfile
- Loading branch information
1 parent
0145f42
commit 99d7970
Showing
10 changed files
with
372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# @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 { generateBreadcrumbsData } from '@nolebase/vitepress-plugin-breadcrumbs' | ||
import { defineConfig } from 'vitepress' | ||
|
||
export default defineConfig({ | ||
// other config... | ||
transformPageData(pageData, context) { | ||
generateBreadcrumbsData(pageData, context) | ||
// 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 { NolebaseBreadcrumbs } 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(NolebaseBreadcrumbs), | ||
}) | ||
}, | ||
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> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
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: 'rollup', input: './src/vitepress/index', outDir: 'dist/vitepress/' }, | ||
], | ||
rollup: { | ||
emitCJS: true, | ||
}, | ||
clean: true, | ||
sourcemap: true, | ||
declaration: true, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"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": "[email protected]", | ||
"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.cjs" | ||
}, | ||
"./vitepress": { | ||
"types": "./dist/vitepress/index.d.ts", | ||
"import": "./dist/vitepress/index.mjs", | ||
"require": "./dist/vitepress/index.cjs" | ||
}, | ||
"./client": { | ||
"types": "./dist/client/index.d.ts", | ||
"import": "./dist/client/index.mjs", | ||
"require": "./dist/client/index.js" | ||
} | ||
}, | ||
"main": "./dist/vitepress/index.cjs", | ||
"module": "./dist/vitepress/index.mjs", | ||
"types": "./dist/vitepress/index.d.ts", | ||
"files": [ | ||
"README.md", | ||
"dist", | ||
"package.json" | ||
], | ||
"scripts": { | ||
"dev": "unbuild --stub", | ||
"stub": "unbuild --stub", | ||
"build": "unbuild", | ||
"package:publish": "pnpm build && pnpm publish --access public --no-git-checks" | ||
}, | ||
"dependencies": { | ||
"vitepress": "^1.5.0" | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
packages/vitepress-plugin-breadcrumbs/src/client/components/NolebaseBreadcrumbs.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<script setup lang="ts"> | ||
import { useData } from 'vitepress' | ||
const { frontmatter } = useData() | ||
</script> | ||
|
||
<template> | ||
<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> | ||
</span> | ||
</div> | ||
</template> | ||
|
||
<style scoped> | ||
.vp-nolebase-breadcrumbs { | ||
display: flex; | ||
gap: 8px; | ||
font-size: 14px; | ||
margin-bottom: 2rem; | ||
} | ||
.vp-nolebase-breadcrumbs span { | ||
transition: color 0.25s, opacity 0.25s; | ||
color: var(--vp-c-text-2); | ||
} | ||
.vp-nolebase-breadcrumbs span:hover { | ||
color: var(--vp-c-brand-1); | ||
} | ||
.vp-nolebase-breadcrumbs span:last-child { | ||
color: var(--vp-c-text-1); | ||
} | ||
.vp-nolebase-breadcrumbs span:last-child:hover { | ||
color: var(--vp-c-brand-1); | ||
} | ||
.vp-nolebase-breadcrumbs span:not(:first-child)::before { | ||
content: '/'; | ||
padding-right: 8px; | ||
color: var(--vp-c-text-3); | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import NolebaseBreadcrumbs from './components/NolebaseBreadcrumbs.vue' | ||
|
||
export { NolebaseBreadcrumbs } |
57 changes: 57 additions & 0 deletions
57
packages/vitepress-plugin-breadcrumbs/src/test/breadcrumbs-data-generator.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import type { PageData, TransformPageContext } from 'vitepress' | ||
import { expect, it } from 'vitest' | ||
import { generateBreadcrumbsData } from '../vitepress' | ||
|
||
it('page is not index', () => { | ||
const pageData = { | ||
relativePath: 'a/b/c/d.md', | ||
filePath: 'a/b/c/d.md', | ||
title: 'd', | ||
frontmatter: {}, | ||
} as PageData | ||
|
||
const context = { | ||
siteConfig: { | ||
site: { | ||
title: 'Home', | ||
}, | ||
pages: ['a', 'a/b', 'a/b/index.md', 'a/b/c/d.md'], | ||
}, | ||
} as TransformPageContext | ||
|
||
generateBreadcrumbsData(pageData, context) | ||
|
||
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 = { | ||
relativePath: 'a/b/c/d/index.md', | ||
filePath: 'a/b/c/d/index.md', | ||
title: 'd', | ||
frontmatter: {}, | ||
} 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' }, | ||
{ title: 'b', link: '/a/b' }, | ||
{ title: 'c', link: '' }, | ||
{ title: 'd', link: '/a/b/c/d' }, | ||
]) | ||
}) |
51 changes: 51 additions & 0 deletions
51
packages/vitepress-plugin-breadcrumbs/src/vitepress/breadcrumbs-data-generator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
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])}` | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { generateBreadcrumbsData } from './breadcrumbs-data-generator' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
] | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.