mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
commit
b6783d1198
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
31
.vscode/settings.json
vendored
31
.vscode/settings.json
vendored
@ -11,6 +11,36 @@
|
||||
"css.validate": false,
|
||||
"scss.validate": false,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"eslint.rules.customizations": [
|
||||
{ "rule": "style/*", "severity": "off" },
|
||||
{ "rule": "*-indent", "severity": "off" },
|
||||
{ "rule": "*-spacing", "severity": "off" },
|
||||
{ "rule": "*-spaces", "severity": "off" },
|
||||
{ "rule": "*-order", "severity": "off" },
|
||||
{ "rule": "*-dangle", "severity": "off" },
|
||||
{ "rule": "*-newline", "severity": "off" },
|
||||
{ "rule": "*quotes", "severity": "off" },
|
||||
{ "rule": "*semi", "severity": "off" }
|
||||
],
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit",
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
"editor.formatOnPaste": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue",
|
||||
"html",
|
||||
"markdown",
|
||||
"json",
|
||||
"jsonc",
|
||||
"yaml"
|
||||
],
|
||||
"cSpell.words": [
|
||||
"bumpp",
|
||||
"caniuse",
|
||||
@ -23,6 +53,7 @@
|
||||
"gsap",
|
||||
"iarna",
|
||||
"iconify",
|
||||
"katex",
|
||||
"leancloud",
|
||||
"nprogress",
|
||||
"pnpm",
|
||||
|
||||
@ -3,8 +3,7 @@ import process from 'node:process'
|
||||
import { viteBundler } from '@vuepress/bundler-vite'
|
||||
import { webpackBundler } from '@vuepress/bundler-webpack'
|
||||
import { defineUserConfig } from '@vuepress/cli'
|
||||
import themePlume from 'vuepress-theme-plume'
|
||||
import { enNotes, zhNotes } from './notes.js'
|
||||
import { theme } from './theme.js'
|
||||
|
||||
export default defineUserConfig({
|
||||
base: '/',
|
||||
@ -14,117 +13,9 @@ export default defineUserConfig({
|
||||
source: path.resolve(__dirname, '../'),
|
||||
public: path.resolve(__dirname, 'public'),
|
||||
locales: {
|
||||
'/': {
|
||||
title: 'Plume主题',
|
||||
description: '',
|
||||
lang: 'zh-CN',
|
||||
},
|
||||
'/en/': {
|
||||
title: 'Plume Theme',
|
||||
description: '',
|
||||
lang: 'en',
|
||||
},
|
||||
'/': { title: 'Plume主题', description: '', lang: 'zh-CN' },
|
||||
'/en/': { title: 'Plume Theme', description: '', lang: 'en' },
|
||||
},
|
||||
|
||||
bundler:
|
||||
process.env.DOCS_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(),
|
||||
|
||||
theme: themePlume({
|
||||
logo: 'https://pengzhanbo.cn/g.gif',
|
||||
hostname: 'https://pengzhanbo.cn',
|
||||
repo: 'https://github.com/pengzhanbo/vuepress-theme-plume',
|
||||
docsDir: 'docs',
|
||||
editLink: true,
|
||||
editLinkText: 'Edit this page on GitHub',
|
||||
appearance: true,
|
||||
avatar: {
|
||||
url: '/images/blogger.jpg',
|
||||
name: 'Plume Theme',
|
||||
description: 'The Theme for Vuepress 2.0',
|
||||
},
|
||||
social: [{ icon: 'github', link: 'https://github.com/pengzhanbo' }],
|
||||
notes: zhNotes,
|
||||
navbar: [
|
||||
{ text: '首页', link: '/', icon: 'material-symbols:home-outline' },
|
||||
{
|
||||
text: '博客',
|
||||
link: '/blog/',
|
||||
icon: 'material-symbols:article-outline',
|
||||
},
|
||||
{
|
||||
text: 'VuePress',
|
||||
icon: 'vscode-icons:file-type-vue',
|
||||
items: [
|
||||
{
|
||||
text: 'theme-plume',
|
||||
link: '/note/vuepress-theme-plume/',
|
||||
icon: 'icon-park-outline:theme',
|
||||
},
|
||||
{
|
||||
text: '插件',
|
||||
icon: 'mingcute:plugin-2-line',
|
||||
items: [
|
||||
{
|
||||
text: 'caniuse',
|
||||
link: '/note/vuepress-plugin/caniuse/',
|
||||
icon: 'tabler:brand-css3',
|
||||
},
|
||||
{
|
||||
text: 'netlify-functions',
|
||||
link: '/note/vuepress-plugin/netlify-functions/',
|
||||
icon: 'teenyicons:netlify-outline',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ text: '友情链接', link: '/friends/', icon: 'emojione-monotone:roller-coaster' },
|
||||
],
|
||||
footer: {
|
||||
copyright: 'Copyright © 2022-present pengzhanbo',
|
||||
},
|
||||
themePlugins: {
|
||||
markdownEnhance: { katex: true },
|
||||
search: {
|
||||
locales: {
|
||||
'/': {
|
||||
placeholder: '搜索',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
locales: {
|
||||
'/': { selectLanguageName: '简体中文', selectLanguageText: '选择语言' },
|
||||
'/en/': {
|
||||
selectLanguageName: 'English',
|
||||
selectLanguageText: 'Language',
|
||||
notes: enNotes,
|
||||
navbar: [
|
||||
{ text: 'Home', link: '/en/', icon: 'material-symbols:home-outline' },
|
||||
{
|
||||
text: 'Blog',
|
||||
link: '/en/blog/',
|
||||
icon: 'material-symbols:article-outline',
|
||||
},
|
||||
{
|
||||
text: 'VuePress',
|
||||
icon: 'vscode-icons:file-type-vue',
|
||||
items: [
|
||||
{
|
||||
text: 'Plugin',
|
||||
icon: 'mingcute:plugin-2-line',
|
||||
items: [
|
||||
{
|
||||
text: 'caniuse',
|
||||
link: '/en/note/vuepress-plugin/caniuse/',
|
||||
icon: 'tabler:brand-css3',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
bundler: process.env.DOCS_BUNDLER === 'webpack' ? webpackBundler() : viteBundler(),
|
||||
theme,
|
||||
})
|
||||
|
||||
64
docs/.vuepress/navbar.ts
Normal file
64
docs/.vuepress/navbar.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import type { NavItem } from 'vuepress-theme-plume'
|
||||
|
||||
export const zhNavbar = [
|
||||
{ text: '首页', link: '/', icon: 'material-symbols:home-outline' },
|
||||
{
|
||||
text: '博客',
|
||||
link: '/blog/',
|
||||
icon: 'material-symbols:article-outline',
|
||||
},
|
||||
{
|
||||
text: 'VuePress',
|
||||
icon: 'vscode-icons:file-type-vue',
|
||||
items: [
|
||||
{
|
||||
text: 'theme-plume',
|
||||
link: '/note/vuepress-theme-plume/',
|
||||
icon: 'icon-park-outline:theme',
|
||||
},
|
||||
{
|
||||
text: '插件',
|
||||
icon: 'mingcute:plugin-2-line',
|
||||
items: [
|
||||
{
|
||||
text: 'caniuse',
|
||||
link: '/note/vuepress-plugin/caniuse/',
|
||||
icon: 'tabler:brand-css3',
|
||||
},
|
||||
{
|
||||
text: 'netlify-functions',
|
||||
link: '/note/vuepress-plugin/netlify-functions/',
|
||||
icon: 'teenyicons:netlify-outline',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ text: '友情链接', link: '/friends/', icon: 'emojione-monotone:roller-coaster' },
|
||||
] as NavItem[]
|
||||
|
||||
export const enNavbar = [
|
||||
{ text: 'Home', link: '/en/', icon: 'material-symbols:home-outline' },
|
||||
{
|
||||
text: 'Blog',
|
||||
link: '/en/blog/',
|
||||
icon: 'material-symbols:article-outline',
|
||||
},
|
||||
{
|
||||
text: 'VuePress',
|
||||
icon: 'vscode-icons:file-type-vue',
|
||||
items: [
|
||||
{
|
||||
text: 'Plugin',
|
||||
icon: 'mingcute:plugin-2-line',
|
||||
items: [
|
||||
{
|
||||
text: 'caniuse',
|
||||
link: '/en/note/vuepress-plugin/caniuse/',
|
||||
icon: 'tabler:brand-css3',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
] as NavItem[]
|
||||
@ -5,7 +5,6 @@ export const zhNotes = definePlumeNotesConfig({
|
||||
link: '/note',
|
||||
notes: [
|
||||
{
|
||||
text: '',
|
||||
dir: 'vuepress-theme-plume',
|
||||
link: '/vuepress-theme-plume/',
|
||||
sidebar: [
|
||||
@ -34,7 +33,6 @@ export const zhNotes = definePlumeNotesConfig({
|
||||
},
|
||||
{
|
||||
dir: 'vuepress-plugin',
|
||||
text: '',
|
||||
link: '/vuepress-plugin/',
|
||||
sidebar: [
|
||||
'caniuse/README',
|
||||
@ -50,12 +48,11 @@ export const zhNotes = definePlumeNotesConfig({
|
||||
})
|
||||
|
||||
export const enNotes = definePlumeNotesConfig({
|
||||
dir: 'notes',
|
||||
link: '/note',
|
||||
dir: 'en/notes',
|
||||
link: '/en/note',
|
||||
notes: [
|
||||
{
|
||||
dir: 'vuepress-plugin',
|
||||
text: '',
|
||||
link: '/vuepress-plugin/',
|
||||
sidebar: ['caniuse/README'],
|
||||
},
|
||||
|
||||
49
docs/.vuepress/theme.ts
Normal file
49
docs/.vuepress/theme.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import themePlume from 'vuepress-theme-plume'
|
||||
import { enNotes, zhNotes } from './notes.js'
|
||||
import { enNavbar, zhNavbar } from './navbar.js'
|
||||
|
||||
export const theme = themePlume({
|
||||
logo: 'https://pengzhanbo.cn/g.gif',
|
||||
hostname: 'https://pengzhanbo.cn',
|
||||
repo: 'https://github.com/pengzhanbo/vuepress-theme-plume',
|
||||
docsDir: 'docs',
|
||||
editLink: true,
|
||||
editLinkText: '在 GitHub 编辑此页',
|
||||
appearance: true,
|
||||
avatar: {
|
||||
url: '/images/blogger.jpg',
|
||||
name: 'Plume Theme',
|
||||
description: 'The Theme for Vuepress 2.0',
|
||||
},
|
||||
social: [{ icon: 'github', link: 'https://github.com/pengzhanbo' }],
|
||||
footer: { copyright: 'Copyright © 2022-present pengzhanbo' },
|
||||
|
||||
locales: {
|
||||
'/': {
|
||||
selectLanguageName: '简体中文',
|
||||
selectLanguageText: '选择语言',
|
||||
notes: zhNotes,
|
||||
navbar: zhNavbar,
|
||||
},
|
||||
'/en/': {
|
||||
selectLanguageName: 'English',
|
||||
selectLanguageText: 'Language',
|
||||
editLinkText: 'Edit this page on GitHub',
|
||||
notes: enNotes,
|
||||
navbar: enNavbar,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
markdownEnhance: { katex: true },
|
||||
search: {
|
||||
locales: {
|
||||
'/': {
|
||||
placeholder: '搜索',
|
||||
},
|
||||
'/en/': {
|
||||
placeholder: 'Search',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -17,9 +17,9 @@
|
||||
"anywhere": "^1.6.0",
|
||||
"katex": "^0.16.9",
|
||||
"leancloud-storage": "^4.15.2",
|
||||
"sass": "^1.69.6",
|
||||
"sass": "^1.69.7",
|
||||
"sass-loader": "^13.3.3",
|
||||
"vue": "^3.4.3",
|
||||
"vue": "^3.4.5",
|
||||
"vuepress-theme-plume": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
10
package.json
10
package.json
@ -3,7 +3,7 @@
|
||||
"type": "module",
|
||||
"version": "1.0.0-rc.13",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.13.1",
|
||||
"packageManager": "pnpm@8.14.0",
|
||||
"author": "pengzhanbo",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@ -19,7 +19,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm run build:package",
|
||||
"build:package": "pnpm --filter=!vuepress-theme-plume-monorepo --filter=!docs run -r --stream build",
|
||||
"build:package": "pnpm --filter=!vuepress-theme-plume-monorepo --filter=!docs --filter=!plugin-page-collection run -r --stream build",
|
||||
"commit": "cz",
|
||||
"dev": "concurrently \"pnpm run dev:package\" \"pnpm run docs\"",
|
||||
"dev:package": "pnpm --filter=!vuepress-theme-plume-monorepo --filter=!docs --parallel dev",
|
||||
@ -38,8 +38,8 @@
|
||||
"release:version": "bumpp package.json plugins/*/package.json theme/package.json --execute=\"pnpm release:changelog\" --commit \"build: publish v%s\" --all --tag --push"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.4.3",
|
||||
"@commitlint/config-conventional": "^18.4.3",
|
||||
"@commitlint/cli": "^18.4.4",
|
||||
"@commitlint/config-conventional": "^18.4.4",
|
||||
"@pengzhanbo/eslint-config-vue": "^1.5.1",
|
||||
"@types/minimist": "^1.2.5",
|
||||
"@types/node": "20.9.1",
|
||||
@ -60,7 +60,7 @@
|
||||
"lint-staged": "^15.2.0",
|
||||
"minimist": "^1.2.8",
|
||||
"ora": "^8.0.1",
|
||||
"pnpm": "^8.13.1",
|
||||
"pnpm": "^8.14.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"sort-package-json": "^2.6.0",
|
||||
"taze": "^0.13.1",
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"create-filter": "^1.0.1",
|
||||
"vue": "^3.4.3"
|
||||
"vue": "^3.4.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
"@vuepress/client": "2.0.0-rc.0",
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"vue": "^3.4.3",
|
||||
"vue": "^3.4.5",
|
||||
"vue-router": "4.2.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"vue": "^3.4.3"
|
||||
"vue": "^3.4.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"vue": "^3.4.3"
|
||||
"vue": "^3.4.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
"dotenv": "^16.3.1",
|
||||
"esbuild": "^0.19.11",
|
||||
"execa": "^8.0.1",
|
||||
"netlify-cli": "^17.10.2",
|
||||
"netlify-cli": "^17.11.0",
|
||||
"portfinder": "^1.0.32"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"create-filter": "^1.0.1",
|
||||
"vue": "^3.4.3"
|
||||
"vue": "^3.4.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -3,7 +3,7 @@ import { getDirname, path } from '@vuepress/utils'
|
||||
import type { NotesDataOptions } from '../shared/index.js'
|
||||
import { prepareNotesData, watchNotesData } from './prepareNotesData.js'
|
||||
|
||||
export function notesDataPlugin(options: NotesDataOptions): Plugin {
|
||||
export function notesDataPlugin(options: NotesDataOptions | NotesDataOptions[]): Plugin {
|
||||
return (app: App) => {
|
||||
return {
|
||||
name: '@vuepress-plume/plugin-notes-data',
|
||||
|
||||
@ -5,7 +5,7 @@ import { createFilter } from 'create-filter'
|
||||
import type {
|
||||
NotesData,
|
||||
NotesDataOptions,
|
||||
NotesItem,
|
||||
NotesItemOptions,
|
||||
NotesSidebar,
|
||||
NotesSidebarItem,
|
||||
} from '../shared/index.js'
|
||||
@ -32,10 +32,11 @@ interface NotePage {
|
||||
link: string
|
||||
}
|
||||
|
||||
export async function prepareNotesData(app: App, { include, exclude, notes, dir, link }: NotesDataOptions) {
|
||||
function resolvedNotesData(app: App, options: NotesDataOptions, result: NotesData) {
|
||||
const { include, exclude, notes, dir: _dir, link } = options
|
||||
if (!notes || notes.length === 0)
|
||||
return
|
||||
dir = normalizePath(dir)
|
||||
const dir = normalizePath(_dir)
|
||||
const filter = createFilter(ensureArray(include), ensureArray(exclude), {
|
||||
resolve: false,
|
||||
})
|
||||
@ -47,23 +48,27 @@ export async function prepareNotesData(app: App, { include, exclude, notes, dir,
|
||||
&& page.filePathRelative.startsWith(dir)
|
||||
&& filter(page.filePathRelative),
|
||||
)
|
||||
.map((page) => {
|
||||
return {
|
||||
relativePath: page.filePathRelative?.replace(DIR_PATTERN, '') || '',
|
||||
title: page.title,
|
||||
link: page.path,
|
||||
}
|
||||
})
|
||||
|
||||
const notesData: NotesData = {}
|
||||
.map(page => ({
|
||||
relativePath: page.filePathRelative?.replace(DIR_PATTERN, '') || '',
|
||||
title: page.title,
|
||||
link: page.path,
|
||||
}))
|
||||
notes.forEach((note) => {
|
||||
notesData[normalizePath(path.join('/', link, note.link))] = initSidebar(
|
||||
result[normalizePath(path.join('/', link, note.link))] = initSidebar(
|
||||
note,
|
||||
notesPageList.filter(page =>
|
||||
page.relativePath.startsWith(note.dir.trim().replace(/^\/|\/$/g, '')),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export async function prepareNotesData(app: App, options: NotesDataOptions | NotesDataOptions[]) {
|
||||
const notesData: NotesData = {}
|
||||
const allOptions = ensureArray<NotesDataOptions>(options)
|
||||
|
||||
allOptions.forEach(option => resolvedNotesData(app, option, notesData))
|
||||
|
||||
let content = `
|
||||
export const notesData = ${JSON.stringify(notesData, null, 2)}
|
||||
`
|
||||
@ -73,22 +78,25 @@ export const notesData = ${JSON.stringify(notesData, null, 2)}
|
||||
await app.writeTemp('internal/notesData.js', content)
|
||||
}
|
||||
|
||||
export function watchNotesData(app: App, watchers: any[], options: NotesDataOptions): void {
|
||||
if (!options.notes || options.notes.length === 0 || !options.dir)
|
||||
return
|
||||
const dir = path.join('pages', options.dir, '**/*')
|
||||
export function watchNotesData(app: App, watchers: any[], options: NotesDataOptions | NotesDataOptions[]): void {
|
||||
const allOptions = ensureArray<NotesDataOptions>(options)
|
||||
const [firstLink, ...links] = allOptions.map(option => option.link)
|
||||
|
||||
const dir = path.join('pages', firstLink, '**/*')
|
||||
const watcher = chokidar.watch(dir, {
|
||||
cwd: app.dir.temp(),
|
||||
ignoreInitial: true,
|
||||
})
|
||||
|
||||
links.length && watcher.add(links.map(link => path.join('pages', link, '**/*')))
|
||||
|
||||
watcher.on('add', () => prepareNotesData(app, options))
|
||||
watcher.on('change', () => prepareNotesData(app, options))
|
||||
watcher.on('unlink', () => prepareNotesData(app, options))
|
||||
watchers.push(watcher)
|
||||
}
|
||||
|
||||
function initSidebar(note: NotesItem, pages: NotePage[]): NotesSidebarItem[] {
|
||||
function initSidebar(note: NotesItemOptions, pages: NotePage[]): NotesSidebarItem[] {
|
||||
if (!note.sidebar)
|
||||
return []
|
||||
if (note.sidebar === 'auto')
|
||||
@ -97,7 +105,7 @@ function initSidebar(note: NotesItem, pages: NotePage[]): NotesSidebarItem[] {
|
||||
}
|
||||
|
||||
function initSidebarByAuto(
|
||||
note: NotesItem,
|
||||
note: NotesItemOptions,
|
||||
pages: NotePage[],
|
||||
): NotesSidebarItem[] {
|
||||
pages = pages.sort((prev, next) => {
|
||||
@ -135,7 +143,7 @@ function initSidebarByAuto(
|
||||
}
|
||||
|
||||
function initSidebarByConfig(
|
||||
{ text, dir, sidebar }: NotesItem,
|
||||
{ text, dir, sidebar }: NotesItemOptions,
|
||||
pages: NotePage[],
|
||||
): NotesSidebarItem[] {
|
||||
return (sidebar as NotesSidebar).map((item) => {
|
||||
|
||||
@ -3,9 +3,11 @@ export interface NotesDataOptions {
|
||||
link: string
|
||||
include?: string | string[]
|
||||
exclude?: string | string[]
|
||||
notes: NotesItem[]
|
||||
notes: NotesItemOptions[]
|
||||
}
|
||||
|
||||
export type NotesItemOptions = (Omit<NotesItem, 'text'> & { text?: string })
|
||||
|
||||
export interface NotesItem {
|
||||
dir: string
|
||||
link: string
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"leancloud-storage": "^4.15.2",
|
||||
"vue": "^3.4.3",
|
||||
"vue": "^3.4.5",
|
||||
"vue-router": "4.2.5",
|
||||
"vuepress-plugin-netlify-functions": "workspace:*"
|
||||
},
|
||||
|
||||
@ -36,8 +36,8 @@
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"nanoid": "^5.0.4",
|
||||
"picocolors": "^1.0.0",
|
||||
"shikiji": "^0.9.16",
|
||||
"shikiji-transformers": "^0.9.16"
|
||||
"shikiji": "^0.9.17",
|
||||
"shikiji-transformers": "^0.9.17"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
558
pnpm-lock.yaml
generated
558
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
"name": "vuepress-theme-plume",
|
||||
"type": "module",
|
||||
"version": "1.0.0-rc.13",
|
||||
"description": "A Blog Theme for VuePress 2.0",
|
||||
"description": "A Blog&Document Theme for VuePress 2.0",
|
||||
"author": "pengzhanbo <q942450674@outlook.com> (https://github.com/pengzhanbo/)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://pengzhanbo.cn/note/vuepress-theme-plume",
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"keywords": [
|
||||
"VuePress",
|
||||
"Theme",
|
||||
"theme",
|
||||
"plume",
|
||||
"vuepress-theme",
|
||||
"vuepress-theme-plume",
|
||||
@ -79,10 +79,10 @@
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"@vueuse/core": "^10.7.1",
|
||||
"date-fns": "^3.0.6",
|
||||
"katex": "^0.16.9",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"nanoid": "^5.0.4",
|
||||
"ts-debounce": "^4.0.0",
|
||||
"vue": "^3.4.3",
|
||||
"vue": "^3.4.5",
|
||||
"vue-router": "4.2.5",
|
||||
"vuepress-plugin-comment2": "2.0.0-rc.10",
|
||||
"vuepress-plugin-md-enhance": "2.0.0-rc.10",
|
||||
|
||||
@ -14,7 +14,7 @@ const { currentLang, localeLinks } = useLangs()
|
||||
v-if="localeLinks.length && currentLang.label"
|
||||
class="navbar-translations"
|
||||
:icon="IconLanguages"
|
||||
:label="theme.selectLanguageText || 'change language'"
|
||||
:label="theme.selectLanguageText || 'Change Language'"
|
||||
>
|
||||
<div class="items">
|
||||
<p class="title">
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
import { usePageLang } from '@vuepress/client'
|
||||
import { useBlogPostData } from '@vuepress-plume/plugin-blog-data/client'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
|
||||
import { useLocaleLink, useThemeLocaleData } from '../composables/index.js'
|
||||
import { getRandomColor, toArray } from '../utils/index.js'
|
||||
|
||||
export function usePostListControl() {
|
||||
export function useLocalePostList() {
|
||||
const locale = usePageLang()
|
||||
const list = useBlogPostData()
|
||||
return computed(() => list.value.filter(item => item.lang === locale.value))
|
||||
}
|
||||
|
||||
export function usePostListControl() {
|
||||
const themeData = useThemeLocaleData()
|
||||
|
||||
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
|
||||
const list = useLocalePostList()
|
||||
const blog = computed(() => themeData.value.blog || {})
|
||||
const pagination = computed(() => blog.value.pagination || {})
|
||||
|
||||
@ -29,7 +33,7 @@ export function usePostListControl() {
|
||||
return next.sticky > prev.sticky ? 1 : -1
|
||||
}),
|
||||
...otherList,
|
||||
].filter(item => item.lang === locale.value)
|
||||
]
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
@ -109,15 +113,10 @@ export function useBlogExtract() {
|
||||
export type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
|
||||
|
||||
export function useTags() {
|
||||
const locale = usePageLang()
|
||||
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
|
||||
const filteredList = computed(() =>
|
||||
list.value.filter(item => item.lang === locale.value),
|
||||
)
|
||||
|
||||
const list = useLocalePostList()
|
||||
const tags = computed(() => {
|
||||
const tagMap: Record<string, number> = {}
|
||||
filteredList.value.forEach((item) => {
|
||||
list.value.forEach((item) => {
|
||||
if (item.tags) {
|
||||
toArray(item.tags).forEach((tag) => {
|
||||
if (tagMap[tag])
|
||||
@ -139,7 +138,7 @@ export function useTags() {
|
||||
|
||||
const handleTagClick = (tag: string) => {
|
||||
currentTag.value = tag
|
||||
postList.value = filteredList.value.filter((item) => {
|
||||
postList.value = list.value.filter((item) => {
|
||||
if (item.tags)
|
||||
return toArray(item.tags).includes(tag)
|
||||
|
||||
@ -160,15 +159,11 @@ export function useTags() {
|
||||
}
|
||||
|
||||
export function useArchives() {
|
||||
const locale = usePageLang()
|
||||
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
|
||||
const filteredList = computed(() =>
|
||||
list.value.filter(item => item.lang === locale.value),
|
||||
)
|
||||
const list = useLocalePostList()
|
||||
const archives = computed(() => {
|
||||
const archives: { label: string, list: ShortPostItem[] }[] = []
|
||||
|
||||
filteredList.value.forEach((item) => {
|
||||
list.value.forEach((item) => {
|
||||
const createTime = item.createTime.split(' ')[0]
|
||||
const year = createTime.split('/')[0]
|
||||
let current = archives.find(archive => archive.label === year)
|
||||
@ -186,7 +181,5 @@ export function useArchives() {
|
||||
return archives
|
||||
})
|
||||
|
||||
return {
|
||||
archives,
|
||||
}
|
||||
return { archives }
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { computed } from 'vue'
|
||||
import type { PlumeThemePageData } from '../../shared/index.js'
|
||||
import { ensureStartingSlash } from '../utils/index.js'
|
||||
import { useThemeData } from './themeData.js'
|
||||
import { normalizePath } from './sidebar.js'
|
||||
|
||||
export function useLangs({
|
||||
removeCurrent = true,
|
||||
@ -20,18 +21,34 @@ export function useLangs({
|
||||
}
|
||||
})
|
||||
|
||||
const addPath = computed(() => {
|
||||
if (page.value.frontmatter.home || (page.value.type && page.value.type !== 'friends'))
|
||||
return true
|
||||
|
||||
return correspondingLink
|
||||
})
|
||||
|
||||
const getBlogLink = (locale: string) => {
|
||||
const blog = theme.value.locales?.[`/${locale}/`]?.blog
|
||||
const defaultBlog = theme.value.locales?.['/']?.blog ?? theme.value.blog
|
||||
const link = blog?.link ? blog.link : normalizePath(`${locale}${defaultBlog?.link || 'blog/'}`)
|
||||
return link
|
||||
}
|
||||
|
||||
const localeLinks = computed(() =>
|
||||
Object.entries(theme.value.locales || {}).flatMap(([key, value]) =>
|
||||
removeCurrent && currentLang.value.label === value.selectLanguageName
|
||||
? []
|
||||
: {
|
||||
text: value.selectLanguageName,
|
||||
link: normalizeLink(
|
||||
key,
|
||||
correspondingLink,
|
||||
page.value.path.slice(currentLang.value.link.length - 1),
|
||||
true,
|
||||
),
|
||||
link: page.value.isBlogPost
|
||||
? getBlogLink(key)
|
||||
: normalizeLink(
|
||||
key,
|
||||
addPath.value,
|
||||
page.value.path.slice(currentLang.value.link.length - 1),
|
||||
true,
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@ -13,6 +13,8 @@ import type {
|
||||
PlumeThemePluginOptions,
|
||||
} from '../shared/index.js'
|
||||
import { getCurrentDirname, getPackage, nanoid, pathJoin } from './utils.js'
|
||||
import { resolveNotesList } from './resolveNotesList.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export default function autoFrontmatter(
|
||||
app: App,
|
||||
@ -21,18 +23,12 @@ export default function autoFrontmatter(
|
||||
): AutoFrontmatterOptions {
|
||||
const sourceDir = app.dir.source()
|
||||
const pkg = getPackage()
|
||||
const { locales = {}, avatar, article: articlePrefix = '/article/' } = localeOption
|
||||
const { locales = {}, article: articlePrefix = '/article/' } = localeOption
|
||||
const { frontmatter } = options
|
||||
|
||||
const localesNotesDirs = Object.keys(app.siteData.locales || {})
|
||||
.map((locale) => {
|
||||
// fixed: #15
|
||||
const notes = locales[locale]?.notes
|
||||
if (!notes)
|
||||
return ''
|
||||
|
||||
return notes.dir ? pathJoin(locale, notes.dir).replace(/^\//, '') : ''
|
||||
})
|
||||
const avatar = resolveLocaleOptions(localeOption, 'avatar')
|
||||
const notesList = resolveNotesList(localeOption)
|
||||
const localesNotesDirs = notesList
|
||||
.map(notes => notes.dir?.replace(/^\//, ''))
|
||||
.filter(Boolean)
|
||||
|
||||
const baseFrontmatter: FrontmatterObject = {
|
||||
@ -58,7 +54,7 @@ export default function autoFrontmatter(
|
||||
return resolveLocalePath(localeOption.locales!, file)
|
||||
}
|
||||
const notesByLocale = (locale: string) => {
|
||||
const notes = locales[locale]?.notes || localeOption.notes
|
||||
const notes = resolveLocaleOptions(localeOption, 'notes', locale)
|
||||
if (notes === false)
|
||||
return undefined
|
||||
return notes
|
||||
@ -162,7 +158,13 @@ export default function autoFrontmatter(
|
||||
if (permalink)
|
||||
return permalink
|
||||
const locale = resolveLocale(filepath)
|
||||
return pathJoin(locale, articlePrefix, nanoid(), '/')
|
||||
const prefix = resolveLocaleOptions(localeOption, 'article', locale, false)
|
||||
const args: string[] = []
|
||||
prefix
|
||||
? args.push(prefix)
|
||||
: args.push(locale, articlePrefix)
|
||||
|
||||
return pathJoin(...args, nanoid(), '/')
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,12 +1,23 @@
|
||||
import type {
|
||||
NotesDataOptions,
|
||||
NotesItem,
|
||||
NotesItemOptions,
|
||||
} from '@vuepress-plume/plugin-notes-data'
|
||||
import type { NavItem } from '../shared/index.js'
|
||||
|
||||
export function definePlumeNotesConfig(notes: NotesDataOptions): NotesDataOptions {
|
||||
return notes
|
||||
}
|
||||
|
||||
export const definePlumeNotesItemConfig = (item: NotesItem): NotesItem => item
|
||||
export function definePlumeNotesItemConfig(item: NotesItemOptions): NotesItemOptions {
|
||||
return item
|
||||
}
|
||||
|
||||
export type { NotesDataOptions, NotesItem }
|
||||
export function defineNavbar(navbar: NavItem[]): NavItem[] {
|
||||
return navbar
|
||||
}
|
||||
|
||||
export type {
|
||||
NotesDataOptions,
|
||||
NotesItemOptions,
|
||||
NotesItemOptions as NotesItem,
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import path from 'node:path'
|
||||
import type { App, PluginConfig } from '@vuepress/core'
|
||||
import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links'
|
||||
import { docsearchPlugin } from '@vuepress/plugin-docsearch'
|
||||
@ -28,62 +27,56 @@ import type {
|
||||
PlumeThemePluginOptions,
|
||||
} from '../shared/index.js'
|
||||
import autoFrontmatter from './autoFrontmatter.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
import { pathJoin } from './utils.js'
|
||||
import { resolveNotesList } from './resolveNotesList.js'
|
||||
|
||||
export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeOptions: PlumeThemeLocaleOptions): PluginConfig {
|
||||
export function setupPlugins(
|
||||
app: App,
|
||||
options: PlumeThemePluginOptions,
|
||||
localeOptions: PlumeThemeLocaleOptions,
|
||||
): PluginConfig {
|
||||
const isProd = !app.env.isDev
|
||||
|
||||
const locales = (localeOptions.locales || {}) as PlumeThemeLocaleOptions
|
||||
const localeNotesDirs = Object.keys(locales)
|
||||
.map((locale) => {
|
||||
const dir = locales[locale].notes?.dir || ''
|
||||
return dir
|
||||
? path.join(locale, dir, '**').replace(/\\+/g, '/').replace(/^\//, '')
|
||||
: ''
|
||||
})
|
||||
const notesList = resolveNotesList(localeOptions)
|
||||
const notesDirList = notesList
|
||||
.map(notes => notes.dir && pathJoin(notes.dir, '**').replace(/^\//, ''))
|
||||
.filter(Boolean)
|
||||
|
||||
const blog = resolveLocaleOptions(localeOptions, 'blog')
|
||||
|
||||
const plugins: PluginConfig = [
|
||||
palettePlugin({ preset: 'sass' }),
|
||||
|
||||
themeDataPlugin({
|
||||
themeData: {
|
||||
...localeOptions,
|
||||
notes: localeOptions.notes
|
||||
? { dir: localeOptions.notes.dir, link: localeOptions.notes.link }
|
||||
: undefined,
|
||||
} as any,
|
||||
}),
|
||||
themeDataPlugin({ themeData: localeOptions }),
|
||||
|
||||
autoFrontmatterPlugin(autoFrontmatter(app, options, localeOptions)),
|
||||
|
||||
blogDataPlugin({
|
||||
include: localeOptions.blog?.include ?? ['**/*.md'],
|
||||
include: blog?.include ?? ['**/*.md'],
|
||||
exclude: [
|
||||
'**/{README,readme,index}.md',
|
||||
'.vuepress/',
|
||||
'node_modules/',
|
||||
...(localeOptions.blog?.exclude ?? []),
|
||||
...localeNotesDirs,
|
||||
...(blog?.exclude ?? []),
|
||||
...notesDirList,
|
||||
].filter(Boolean),
|
||||
sortBy: 'createTime',
|
||||
excerpt: true,
|
||||
pageFilter(page: any) {
|
||||
if (page.frontmatter.article !== undefined)
|
||||
return !!page.frontmatter.article
|
||||
|
||||
return true
|
||||
},
|
||||
extendBlogData(page: any) {
|
||||
return {
|
||||
categoryList: page.data.categoryList,
|
||||
tags: page.frontmatter.tags,
|
||||
sticky: page.frontmatter.sticky,
|
||||
createTime: page.data.frontmatter.createTime,
|
||||
lang: page.lang,
|
||||
}
|
||||
},
|
||||
pageFilter: (page: any) => page.frontmatter.article !== undefined
|
||||
? !!page.frontmatter.article
|
||||
: true,
|
||||
extendBlogData: (page: any) => ({
|
||||
categoryList: page.data.categoryList,
|
||||
tags: page.frontmatter.tags,
|
||||
sticky: page.frontmatter.sticky,
|
||||
createTime: page.data.frontmatter.createTime,
|
||||
lang: page.lang,
|
||||
}),
|
||||
}),
|
||||
|
||||
notesDataPlugin(notesList),
|
||||
|
||||
iconifyPlugin(),
|
||||
|
||||
contentUpdatePlugin(),
|
||||
@ -99,37 +92,27 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
if (options.readingTime !== false)
|
||||
plugins.push(readingTimePlugin(options.readingTime || {}))
|
||||
|
||||
if (localeOptions.notes)
|
||||
plugins.push(notesDataPlugin(localeOptions.notes))
|
||||
|
||||
if (options.nprogress !== false)
|
||||
plugins.push(nprogressPlugin())
|
||||
|
||||
if (options.git !== false) {
|
||||
plugins.push(gitPlugin({
|
||||
createdTime: false,
|
||||
updatedTime: localeOptions.lastUpdated !== false,
|
||||
contributors: localeOptions.contributors !== false,
|
||||
updatedTime: resolveLocaleOptions(localeOptions, 'lastUpdated') !== false,
|
||||
contributors: resolveLocaleOptions(localeOptions, 'contributors') !== false,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.mediumZoom !== false) {
|
||||
plugins.push(mediumZoomPlugin({
|
||||
selector: '.plume-content > img, .plume-content :not(a) > img',
|
||||
zoomOptions: {
|
||||
background: 'var(--vp-c-bg)',
|
||||
},
|
||||
zoomOptions: { background: 'var(--vp-c-bg)' },
|
||||
delay: 300,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.caniuse !== false) {
|
||||
plugins.push(caniusePlugin(
|
||||
options.caniuse || {
|
||||
mode: 'embed',
|
||||
},
|
||||
))
|
||||
}
|
||||
if (options.caniuse !== false)
|
||||
plugins.push(caniusePlugin(options.caniuse || { mode: 'embed' }))
|
||||
|
||||
if (options.externalLinkIcon !== false) {
|
||||
plugins.push(externalLinkIconPlugin({
|
||||
@ -150,14 +133,11 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
plugins.push(searchPlugin(options.search))
|
||||
|
||||
if (options.docsearch !== false && !options.search) {
|
||||
if (options.docsearch?.appId && options.docsearch?.apiKey) {
|
||||
if (options.docsearch?.appId && options.docsearch?.apiKey)
|
||||
plugins.push(docsearchPlugin(options.docsearch))
|
||||
}
|
||||
else {
|
||||
console.error(
|
||||
'docsearch plugin: appId and apiKey are both required',
|
||||
)
|
||||
}
|
||||
|
||||
else
|
||||
console.error('docsearch plugin: appId and apiKey are both required')
|
||||
}
|
||||
|
||||
if (options.shikiji !== false) {
|
||||
@ -180,7 +160,6 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
{
|
||||
hint: true, // info note tip warning danger details
|
||||
codetabs: true,
|
||||
tabs: true,
|
||||
align: true,
|
||||
mark: true,
|
||||
tasklist: true,
|
||||
@ -188,6 +167,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
attrs: true,
|
||||
sup: true,
|
||||
sub: true,
|
||||
katex: true,
|
||||
} as MarkdownEnhanceOptions,
|
||||
options.markdownEnhance || {},
|
||||
),
|
||||
@ -200,16 +180,15 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
if (options.baiduTongji !== false && options.baiduTongji?.key)
|
||||
plugins.push(baiduTongjiPlugin(options.baiduTongji))
|
||||
|
||||
if (options.sitemap !== false && localeOptions.hostname && isProd) {
|
||||
plugins.push(sitemapPlugin({
|
||||
hostname: localeOptions.hostname,
|
||||
}))
|
||||
}
|
||||
const hostname = resolveLocaleOptions(localeOptions, 'hostname')
|
||||
|
||||
if (options.seo !== false && localeOptions.hostname && isProd) {
|
||||
if (options.sitemap !== false && hostname && isProd)
|
||||
plugins.push(sitemapPlugin({ hostname }))
|
||||
|
||||
if (options.seo !== false && hostname && isProd) {
|
||||
plugins.push(seoPlugin({
|
||||
hostname: localeOptions.hostname || '',
|
||||
author: localeOptions.avatar?.name,
|
||||
hostname,
|
||||
author: resolveLocaleOptions(localeOptions, 'avatar')?.name,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
26
theme/src/node/resolveLocaleOptions.ts
Normal file
26
theme/src/node/resolveLocaleOptions.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type { PlumeThemeLocaleOptions } from '../shared/index.js'
|
||||
import { normalizePath } from './utils.js'
|
||||
|
||||
export function resolveLocaleOptions<
|
||||
T extends PlumeThemeLocaleOptions = PlumeThemeLocaleOptions,
|
||||
K extends Exclude<keyof T, 'locales'> = Exclude<keyof T, 'locales'>,
|
||||
>(options: T, key: K, locale = '', fallback = true): T[K] | undefined {
|
||||
const locales = options.locales
|
||||
|
||||
if (!locales)
|
||||
return options[key]
|
||||
|
||||
locale = !locale || locale === '/' ? '/' : normalizePath(`/${locale}/`)
|
||||
|
||||
const localeOptions = locales[locale]
|
||||
const fallbackLocaleOptions = locales['/']
|
||||
if (!localeOptions)
|
||||
return fallback ? options[key] : undefined
|
||||
|
||||
const _key = key as keyof typeof localeOptions
|
||||
const fallbackData = (fallbackLocaleOptions[_key] ?? options[key]) as T[K]
|
||||
|
||||
const value = localeOptions[_key] as T[K]
|
||||
|
||||
return value ?? (fallback ? fallbackData : undefined)
|
||||
}
|
||||
15
theme/src/node/resolveNotesList.ts
Normal file
15
theme/src/node/resolveNotesList.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import type { NotesDataOptions } from '@vuepress-plume/plugin-notes-data'
|
||||
import type { PlumeThemeLocaleOptions } from '../shared/index.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export function resolveNotesList(options: PlumeThemeLocaleOptions) {
|
||||
const locales = options.locales || {}
|
||||
const notesList: NotesDataOptions[] = []
|
||||
|
||||
for (const locale of Object.keys(locales)) {
|
||||
const notes = resolveLocaleOptions(options, 'notes', locale, false)
|
||||
notes && notesList.push(notes)
|
||||
}
|
||||
|
||||
return notesList
|
||||
}
|
||||
@ -7,15 +7,16 @@ import type {
|
||||
PlumeThemePageData,
|
||||
} from '../shared/index.js'
|
||||
import { pathJoin } from './utils.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export async function setupPage(
|
||||
app: App,
|
||||
localeOption: PlumeThemeLocaleOptions,
|
||||
) {
|
||||
const locales = Object.keys(app.siteData.locales || {})
|
||||
const defaultBlog = resolveLocaleOptions(localeOption, 'blog')
|
||||
for (const [, locale] of locales.entries()) {
|
||||
const blog = localeOption.locales?.[locale]?.blog
|
||||
const defaultBlog = localeOption.blog
|
||||
const blog = resolveLocaleOptions(localeOption, 'blog', locale, false)
|
||||
const link = blog?.link
|
||||
? blog.link
|
||||
: pathJoin('/', locale, defaultBlog?.link || '/blog/')
|
||||
|
||||
@ -1,47 +1,35 @@
|
||||
import type { App, Page, Theme } from '@vuepress/core'
|
||||
import { fs, getDirname, path, templateRenderer } from '@vuepress/utils'
|
||||
import type { Page, Theme } from '@vuepress/core'
|
||||
import { templateRenderer } from '@vuepress/utils'
|
||||
import type { PlumeThemeOptions, PlumeThemePageData } from '../shared/index.js'
|
||||
import { mergeLocaleOptions } from './defaultOptions.js'
|
||||
import { setupPlugins } from './plugins.js'
|
||||
import { extendsPageData, setupPage } from './setupPages.js'
|
||||
import { getThemePackage, resolve, templates } from './utils.js'
|
||||
|
||||
const __dirname = getDirname(import.meta.url)
|
||||
const name = 'vuepress-theme-plume'
|
||||
const resolve = (...args: string[]) => path.resolve(__dirname, '../', ...args)
|
||||
const templates = (url: string) => resolve('../templates', url)
|
||||
|
||||
function getThemePackage() {
|
||||
let pkg = {} as any
|
||||
try {
|
||||
const content = fs.readFileSync(resolve('../package.json'), 'utf-8')
|
||||
pkg = JSON.parse(content)
|
||||
}
|
||||
catch {}
|
||||
return pkg
|
||||
}
|
||||
const THEME_NAME = 'vuepress-theme-plume'
|
||||
|
||||
export function plumeTheme({
|
||||
themePlugins = {},
|
||||
themePlugins,
|
||||
plugins,
|
||||
...localeOptions
|
||||
}: PlumeThemeOptions = {}): Theme {
|
||||
localeOptions = mergeLocaleOptions(localeOptions)
|
||||
const pluginsOptions = plugins ?? themePlugins ?? {}
|
||||
const pkg = getThemePackage()
|
||||
return (app: App) => {
|
||||
return {
|
||||
name,
|
||||
templateBuild: templates('build.html'),
|
||||
clientConfigFile: resolve('client/config.js'),
|
||||
plugins: setupPlugins(app, themePlugins, localeOptions),
|
||||
onInitialized: app => setupPage(app, localeOptions),
|
||||
extendsPage: (page: Page<PlumeThemePageData>) =>
|
||||
extendsPageData(app, page, localeOptions),
|
||||
templateBuildRenderer(template, context) {
|
||||
template = template
|
||||
.replace('{{ themeVersion }}', pkg.version || '')
|
||||
.replace(/^\s+|\s+$/gm, '')
|
||||
.replace(/\n/g, '')
|
||||
return templateRenderer(template, context)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return app => ({
|
||||
name: THEME_NAME,
|
||||
templateBuild: templates('build.html'),
|
||||
clientConfigFile: resolve('client/config.js'),
|
||||
plugins: setupPlugins(app, pluginsOptions, localeOptions),
|
||||
onInitialized: app => setupPage(app, localeOptions),
|
||||
extendsPage: page => extendsPageData(app, page as Page<PlumeThemePageData>, localeOptions),
|
||||
templateBuildRenderer(template, context) {
|
||||
template = template
|
||||
.replace('{{ themeVersion }}', pkg.version || '')
|
||||
.replace(/^\s+|\s+$/gm, '')
|
||||
.replace(/\n/g, '')
|
||||
return templateRenderer(template, context)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,6 +2,12 @@ import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { customAlphabet } from 'nanoid'
|
||||
import { getDirname } from '@vuepress/utils'
|
||||
|
||||
const __dirname = getDirname(import.meta.url)
|
||||
|
||||
export const resolve = (...args: string[]) => path.resolve(__dirname, '../', ...args)
|
||||
export const templates = (url: string) => resolve('../templates', url)
|
||||
|
||||
export const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
|
||||
|
||||
@ -15,7 +21,17 @@ export function getPackage() {
|
||||
return pkg
|
||||
}
|
||||
|
||||
const RE_SLASH = /\\+/g
|
||||
export function getThemePackage() {
|
||||
let pkg = {} as any
|
||||
try {
|
||||
const content = fs.readFileSync(resolve('../package.json'), 'utf-8')
|
||||
pkg = JSON.parse(content)
|
||||
}
|
||||
catch {}
|
||||
return pkg
|
||||
}
|
||||
|
||||
const RE_SLASH = /(\\|\/)+/g
|
||||
export function normalizePath(dir: string) {
|
||||
return dir.replace(RE_SLASH, '/')
|
||||
}
|
||||
|
||||
@ -5,8 +5,15 @@ import type { PlumeThemePluginOptions } from './plugins.js'
|
||||
export interface PlumeThemeOptions extends PlumeThemeLocaleOptions {
|
||||
/**
|
||||
* 对主题内部使用的插件进行配置
|
||||
* @deprecated 配置项迁移至 `plugins`
|
||||
*/
|
||||
themePlugins?: PlumeThemePluginOptions
|
||||
|
||||
/**
|
||||
* 对主题内部使用的插件进行配置
|
||||
*/
|
||||
plugins?: PlumeThemePluginOptions
|
||||
|
||||
}
|
||||
|
||||
export type PlumeThemeLocaleOptions = PlumeThemeData
|
||||
|
||||
@ -30,8 +30,14 @@ export interface PlumeThemePluginOptions {
|
||||
*/
|
||||
docsearch?: false | DocsearchOptions
|
||||
|
||||
/**
|
||||
* 代码高亮 配置
|
||||
*/
|
||||
shikiji?: false | ShikijiPluginOptions
|
||||
|
||||
/**
|
||||
* git 插件 配置
|
||||
*/
|
||||
git?: false
|
||||
|
||||
nprogress?: false
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user