mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
commit
4f914d8eee
10
package.json
10
package.json
@ -3,7 +3,7 @@
|
||||
"type": "module",
|
||||
"version": "1.0.0-rc.6",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.12.1",
|
||||
"packageManager": "pnpm@8.13.1",
|
||||
"author": "pengzhanbo",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
@ -18,7 +18,6 @@
|
||||
"pnpm": ">=7"
|
||||
},
|
||||
"scripts": {
|
||||
"autoUpdate": "node scripts/autoInstall.js",
|
||||
"build": "pnpm run build:package",
|
||||
"build:package": "pnpm --filter=!vuepress-theme-plume-monorepo --filter=!docs run -r --stream build",
|
||||
"commit": "cz",
|
||||
@ -36,8 +35,7 @@
|
||||
"release:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
||||
"release:check": "pnpm lint && pnpm build",
|
||||
"release:publish": "pnpm -r publish",
|
||||
"release:version": "bumpp package.json plugins/*/package.json theme/package.json --execute=\"pnpm release:changelog\" --commit \"build: publish v%s\" --all --tag --push",
|
||||
"up": "taze -r major"
|
||||
"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",
|
||||
@ -62,10 +60,10 @@
|
||||
"lint-staged": "^15.2.0",
|
||||
"minimist": "^1.2.8",
|
||||
"ora": "^8.0.1",
|
||||
"pnpm": "^8.12.1",
|
||||
"pnpm": "^8.13.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"sort-package-json": "^2.6.0",
|
||||
"taze": "^0.13.0",
|
||||
"taze": "^0.13.1",
|
||||
"tsconfig-vuepress": "^4.5.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.10"
|
||||
|
||||
21
plugins/plugin-content-update/LICENSE
Normal file
21
plugins/plugin-content-update/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2021 - PRESENT by pengzhanbo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
21
plugins/plugin-content-update/README.md
Normal file
21
plugins/plugin-content-update/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# `@vuepress-plume/plugin-content-update`
|
||||
|
||||
替换 `@vuepress/client` 的 `<Content />` 组件,注入 `onContentUpdated` 生命周期。
|
||||
实现当页面内容发生更新时,触发 `onContentUpdated` 事件。
|
||||
|
||||
## Install
|
||||
```
|
||||
yarn add @vuepress-plume/plugin-content-update
|
||||
```
|
||||
## Usage
|
||||
``` js
|
||||
// .vuepress/config.js
|
||||
const { contentUpdatePlugin } = require('@vuepress-plume/plugin-content-update')
|
||||
module.exports = {
|
||||
// ...
|
||||
plugins: [
|
||||
contentUpdatePlugin()
|
||||
]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
49
plugins/plugin-content-update/package.json
Normal file
49
plugins/plugin-content-update/package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@vuepress-plume/plugin-content-update",
|
||||
"type": "module",
|
||||
"version": "1.0.0-rc.6",
|
||||
"description": "The Plugin for VuePres 2",
|
||||
"author": "pengzhanbo <volodymyr@foxmail.com>",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues"
|
||||
},
|
||||
"exports": {
|
||||
".": "./lib/node/index.js",
|
||||
"./client": "./lib/client/index.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"main": "lib/node/index.js",
|
||||
"types": "./lib/node/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm run clean && pnpm run copy && pnpm run ts",
|
||||
"clean": "rimraf lib *.tsbuildinfo",
|
||||
"copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib",
|
||||
"ts": "tsc -b tsconfig.build.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vuepress/client": "2.0.0-rc.0",
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"vue": "^3.3.13",
|
||||
"vue-router": "4.2.5"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keyword": [
|
||||
"VuePress",
|
||||
"vuepress plugin",
|
||||
"content-update",
|
||||
"vuepress-plugin-plugin-content-update"
|
||||
]
|
||||
}
|
||||
11
plugins/plugin-content-update/src/client/clientConfig.ts
Normal file
11
plugins/plugin-content-update/src/client/clientConfig.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { defineClientConfig } from '@vuepress/client'
|
||||
import { Content } from './components/Content.js'
|
||||
|
||||
export default defineClientConfig({
|
||||
enhance({ app }) {
|
||||
if (app._context.components.Content)
|
||||
delete app._context.components.Content
|
||||
|
||||
app.component('Content', Content)
|
||||
},
|
||||
})
|
||||
@ -0,0 +1,42 @@
|
||||
import { pagesComponents } from '@internal/pagesComponents'
|
||||
import { computed, defineComponent, h } from 'vue'
|
||||
import { usePageData } from '@vuepress/client'
|
||||
import { runCallbacks } from '../composables/index.js'
|
||||
|
||||
declare const __VUEPRESS_DEV__: boolean
|
||||
|
||||
/**
|
||||
* Markdown rendered content
|
||||
*/
|
||||
export const Content = defineComponent({
|
||||
|
||||
name: 'Content',
|
||||
|
||||
props: {
|
||||
pageKey: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const page = usePageData()
|
||||
const pageComponent = computed(
|
||||
() => pagesComponents[props.pageKey || page.value.key],
|
||||
)
|
||||
return () =>
|
||||
pageComponent.value
|
||||
? h(pageComponent.value, {
|
||||
onVnodeMounted: runCallbacks,
|
||||
onVnodeUpdated: runCallbacks,
|
||||
onVnodeBeforeUnmount: runCallbacks,
|
||||
})
|
||||
: h(
|
||||
'div',
|
||||
__VUEPRESS_DEV__
|
||||
? 'Page does not exist. This is a fallback content.'
|
||||
: '404 Not Found',
|
||||
)
|
||||
},
|
||||
})
|
||||
@ -0,0 +1,19 @@
|
||||
import { onUnmounted } from 'vue'
|
||||
|
||||
// eslint-disable-next-line import/no-mutable-exports
|
||||
export let contentUpdatedCallbacks: (() => any)[] = []
|
||||
|
||||
/**
|
||||
* Register callback that is called every time the markdown content is updated
|
||||
* in the DOM.
|
||||
*/
|
||||
export function onContentUpdated(fn: () => any) {
|
||||
contentUpdatedCallbacks.push(fn)
|
||||
onUnmounted(() => {
|
||||
contentUpdatedCallbacks = contentUpdatedCallbacks.filter(f => f !== fn)
|
||||
})
|
||||
}
|
||||
|
||||
export function runCallbacks() {
|
||||
contentUpdatedCallbacks.forEach(fn => fn())
|
||||
}
|
||||
2
plugins/plugin-content-update/src/client/index.ts
Normal file
2
plugins/plugin-content-update/src/client/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './components/Content.js'
|
||||
export { onContentUpdated } from './composables/index.js'
|
||||
5
plugins/plugin-content-update/src/node/index.ts
Normal file
5
plugins/plugin-content-update/src/node/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { contentUpdatePlugin } from './plugin.js'
|
||||
|
||||
export { contentUpdatePlugin }
|
||||
|
||||
export default contentUpdatePlugin
|
||||
11
plugins/plugin-content-update/src/node/plugin.ts
Normal file
11
plugins/plugin-content-update/src/node/plugin.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { Plugin } from '@vuepress/core'
|
||||
import { getDirname, path } from '@vuepress/utils'
|
||||
|
||||
const __dirname = getDirname(import.meta.url)
|
||||
|
||||
export function contentUpdatePlugin(): Plugin {
|
||||
return {
|
||||
name: '@vuepress-plume/plugin-content-update',
|
||||
clientConfigFile: path.resolve(__dirname, '../client/clientConfig.js'),
|
||||
}
|
||||
}
|
||||
4
plugins/plugin-content-update/src/shim.d.ts
vendored
Normal file
4
plugins/plugin-content-update/src/shim.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module '@internal/pagesComponents' {
|
||||
const pagesComponents: Record<string, any>
|
||||
export { pagesComponents }
|
||||
}
|
||||
8
plugins/plugin-content-update/tsconfig.build.json
Normal file
8
plugins/plugin-content-update/tsconfig.build.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../tsconfig.build.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib"
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
@ -30,12 +30,12 @@
|
||||
"ts": "tsc -b tsconfig.build.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vuepress-plume/plugin-content-update": "workspace:*",
|
||||
"@vuepress/client": "2.0.0-rc.0",
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"vue": "^3.3.13",
|
||||
"vue-router": "4.2.5"
|
||||
"vue": "^3.3.13"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { defineClientConfig } from '@vuepress/client'
|
||||
import { setupCopyCode } from './composables/index.js'
|
||||
import { setupCopyCode } from './setupCopyCode.js'
|
||||
|
||||
import './styles/button.scss'
|
||||
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
export function copyToClipboard(str: string): void {
|
||||
const selection = document.getSelection()
|
||||
const selectedRange
|
||||
= selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : false
|
||||
|
||||
const textEl = document.createElement('textarea')
|
||||
|
||||
textEl.value = str
|
||||
textEl.setAttribute('readonly', '')
|
||||
textEl.style.position = 'absolute'
|
||||
textEl.style.top = '-9999px'
|
||||
document.body.appendChild(textEl)
|
||||
|
||||
textEl.select()
|
||||
document.execCommand('copy')
|
||||
|
||||
document.body.removeChild(textEl)
|
||||
|
||||
if (selectedRange && selection) {
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(selectedRange)
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './setup.js'
|
||||
@ -1,67 +0,0 @@
|
||||
import { onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { CopyCodeOptions } from '../../shared/index.js'
|
||||
import { copyToClipboard } from './copyToClipboard.js'
|
||||
|
||||
declare const __COPY_CODE_OPTIONS__: CopyCodeOptions
|
||||
|
||||
const options = __COPY_CODE_OPTIONS__
|
||||
|
||||
function isMobile(): boolean {
|
||||
return navigator
|
||||
? /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/iu.test(
|
||||
navigator.userAgent,
|
||||
)
|
||||
: false
|
||||
}
|
||||
|
||||
export function setupCopyCode(): void {
|
||||
const route = useRoute()
|
||||
|
||||
const insertBtn = (codeBlockEl: HTMLElement): void => {
|
||||
if (codeBlockEl.hasAttribute('has-copy-code'))
|
||||
return
|
||||
const button = document.createElement('button')
|
||||
button.className = 'copy-code-button'
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
copyToClipboard(codeBlockEl.textContent || '')
|
||||
button.classList.add('copied')
|
||||
options.duration
|
||||
&& setTimeout(() => {
|
||||
button.classList.remove('copied')
|
||||
}, options.duration)
|
||||
})
|
||||
|
||||
if (codeBlockEl.parentElement)
|
||||
codeBlockEl.parentElement.insertBefore(button, codeBlockEl)
|
||||
|
||||
codeBlockEl.setAttribute('has-copy-code', '')
|
||||
}
|
||||
|
||||
const generateButton = (): void => {
|
||||
const { selector, delay } = options
|
||||
setTimeout(() => {
|
||||
if (typeof selector === 'string') {
|
||||
document.querySelectorAll<HTMLElement>(selector).forEach(insertBtn)
|
||||
}
|
||||
else if (Array.isArray(selector)) {
|
||||
selector.forEach((item) => {
|
||||
document.querySelectorAll<HTMLElement>(item).forEach(insertBtn)
|
||||
})
|
||||
}
|
||||
}, delay)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!isMobile() || options.showInMobile)
|
||||
generateButton()
|
||||
})
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
if (!isMobile() || options.showInMobile)
|
||||
generateButton()
|
||||
},
|
||||
)
|
||||
}
|
||||
142
plugins/plugin-copy-code/src/client/setupCopyCode.ts
Normal file
142
plugins/plugin-copy-code/src/client/setupCopyCode.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import { nextTick, onMounted } from 'vue'
|
||||
import { onContentUpdated } from '@vuepress-plume/plugin-content-update/client'
|
||||
import type { CopyCodeOptions } from '../shared/index.js'
|
||||
|
||||
declare const __COPY_CODE_OPTIONS__: CopyCodeOptions
|
||||
|
||||
const options = __COPY_CODE_OPTIONS__
|
||||
const RE_LANGUAGE = /language-([\w]+)/
|
||||
const RE_START_CODE = /^ *(\$|>)/gm
|
||||
const shells = ['shellscript', 'shell', 'bash', 'sh', 'zsh']
|
||||
const ignoredNodes = ['.diff.remove']
|
||||
|
||||
function isMobile(): boolean {
|
||||
return navigator
|
||||
? /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/iu.test(
|
||||
navigator.userAgent,
|
||||
)
|
||||
: false
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export function setupCopyCode(): void {
|
||||
const insertBtn = (codeBlockEl: HTMLElement): void => {
|
||||
if (codeBlockEl.hasAttribute('has-copy-code'))
|
||||
return
|
||||
const button = document.createElement('button')
|
||||
button.className = 'copy-code-button'
|
||||
const parent = codeBlockEl.parentElement
|
||||
|
||||
if (parent) {
|
||||
parent.insertBefore(button, codeBlockEl)
|
||||
const classes = parent.className
|
||||
const match = classes.match(RE_LANGUAGE) || []
|
||||
if (match[1])
|
||||
button.setAttribute('data-lang', match[1])
|
||||
}
|
||||
|
||||
codeBlockEl.setAttribute('has-copy-code', '')
|
||||
}
|
||||
|
||||
const generateButton = async () => {
|
||||
const { selector, delay } = options
|
||||
await nextTick()
|
||||
await sleep(delay || 0)
|
||||
const selectors = Array.isArray(selector) ? selector : [selector!]
|
||||
selectors.forEach((item) => {
|
||||
document.querySelectorAll<HTMLElement>(item).forEach(insertBtn)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!isMobile() || options.showInMobile) {
|
||||
await generateButton()
|
||||
|
||||
const timeoutIdMap: WeakMap<HTMLElement, NodeJS.Timeout> = new WeakMap()
|
||||
window.addEventListener('click', (e) => {
|
||||
const el = e.target as HTMLElement
|
||||
if (el.matches('div[class*="language-"] > button.copy-code-button')) {
|
||||
const parent = el.parentElement
|
||||
const sibling = el.nextElementSibling
|
||||
if (!parent || !sibling)
|
||||
return
|
||||
|
||||
// Clone the node and remove the ignored nodes
|
||||
const clone = sibling.cloneNode(true) as HTMLElement
|
||||
clone
|
||||
.querySelectorAll(ignoredNodes.join(','))
|
||||
.forEach(node => node.remove())
|
||||
|
||||
let text = clone.textContent || ''
|
||||
const lang = el.getAttribute('data-lang') || ''
|
||||
if (lang && shells.includes(lang))
|
||||
text = text.replace(RE_START_CODE, '').trim()
|
||||
|
||||
copyToClipboard(text).then(() => {
|
||||
el.classList.add('copied')
|
||||
clearTimeout(timeoutIdMap.get(el))
|
||||
const timeoutId = setTimeout(() => {
|
||||
el.classList.remove('copied')
|
||||
el.blur()
|
||||
timeoutIdMap.delete(el)
|
||||
}, options.duration)
|
||||
timeoutIdMap.set(el, timeoutId)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onContentUpdated(() => {
|
||||
if (!isMobile() || options.showInMobile)
|
||||
generateButton()
|
||||
})
|
||||
}
|
||||
|
||||
async function copyToClipboard(text: string) {
|
||||
try {
|
||||
return navigator.clipboard.writeText(text)
|
||||
}
|
||||
catch {
|
||||
const element = document.createElement('textarea')
|
||||
const previouslyFocusedElement = document.activeElement
|
||||
|
||||
element.value = text
|
||||
|
||||
// Prevent keyboard from showing on mobile
|
||||
element.setAttribute('readonly', '')
|
||||
|
||||
element.style.contain = 'strict'
|
||||
element.style.position = 'absolute'
|
||||
element.style.left = '-9999px'
|
||||
element.style.fontSize = '12pt' // Prevent zooming on iOS
|
||||
|
||||
const selection = document.getSelection()
|
||||
const originalRange = selection
|
||||
? selection.rangeCount > 0 && selection.getRangeAt(0)
|
||||
: null
|
||||
|
||||
document.body.appendChild(element)
|
||||
element.select()
|
||||
|
||||
// Explicit selection workaround for iOS
|
||||
element.selectionStart = 0
|
||||
element.selectionEnd = text.length
|
||||
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(element)
|
||||
|
||||
if (originalRange) {
|
||||
selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy
|
||||
selection!.addRange(originalRange)
|
||||
}
|
||||
|
||||
// Get the focus back on the previously focused element, if any
|
||||
if (previouslyFocusedElement) {
|
||||
; (previouslyFocusedElement as HTMLElement).focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,7 +50,8 @@ html[lang='zh-CN'] {
|
||||
}
|
||||
|
||||
[class*='language-']:hover > .copy-code-button,
|
||||
[class*='language-'] > .copy-code-button:focus {
|
||||
[class*='language-'] > .copy-code-button:focus,
|
||||
[class*='language-'] > .copy-code-button.copied {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
@ -53,9 +53,6 @@ declare const __VUEPRESS_PLUGIN_ICONIFY_DEFAULT_COLOR__: string
|
||||
class="vp-iconify"
|
||||
:style="iconStyle"
|
||||
/>
|
||||
<span v-else class="vp-iconify" :style="{ ...iconStyle, fontSize: size }">
|
||||
{{ props.name }}
|
||||
</span>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import type { IconifyIcon } from '@iconify/vue'
|
||||
import { loadIcon } from '@iconify/vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
const iconCache: Ref<Record<string, IconifyIcon>> = ref({})
|
||||
|
||||
export function useIconify(name: ComputedRef<string> | Ref<string>) {
|
||||
const icon = computed(() => iconCache.value[name.value])
|
||||
const loaded = ref(true)
|
||||
export function useIconify(name: Ref<string>) {
|
||||
const icon = ref<IconifyIcon | null>(null)
|
||||
const loaded = ref(false)
|
||||
|
||||
async function loadIconComponent() {
|
||||
if (icon.value)
|
||||
@ -16,7 +14,8 @@ export function useIconify(name: ComputedRef<string> | Ref<string>) {
|
||||
if (!__VUEPRESS_SSR__) {
|
||||
try {
|
||||
loaded.value = false
|
||||
iconCache.value[name.value] = await loadIcon(name.value)
|
||||
const cached = await loadIcon(name.value)
|
||||
icon.value = cached
|
||||
}
|
||||
finally {
|
||||
loaded.value = true
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
{ "path": "./plugin-netlify-functions/tsconfig.build.json" },
|
||||
{ "path": "./plugin-notes-data/tsconfig.build.json" },
|
||||
{ "path": "./plugin-page-collection/tsconfig.build.json" },
|
||||
{ "path": "./plugin-shikiji/tsconfig.build.json" }
|
||||
{ "path": "./plugin-shikiji/tsconfig.build.json" },
|
||||
{ "path": "./plugin-content-update/tsconfig.build.json" }
|
||||
],
|
||||
"files": []
|
||||
}
|
||||
|
||||
172
pnpm-lock.yaml
generated
172
pnpm-lock.yaml
generated
@ -75,8 +75,8 @@ importers:
|
||||
specifier: ^8.0.1
|
||||
version: 8.0.1
|
||||
pnpm:
|
||||
specifier: ^8.12.1
|
||||
version: 8.12.1
|
||||
specifier: ^8.13.1
|
||||
version: 8.13.1
|
||||
rimraf:
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.5
|
||||
@ -84,8 +84,8 @@ importers:
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0
|
||||
taze:
|
||||
specifier: ^0.13.0
|
||||
version: 0.13.0
|
||||
specifier: ^0.13.1
|
||||
version: 0.13.1
|
||||
tsconfig-vuepress:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0
|
||||
@ -222,7 +222,7 @@ importers:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
|
||||
plugins/plugin-copy-code:
|
||||
plugins/plugin-content-update:
|
||||
dependencies:
|
||||
'@vuepress/client':
|
||||
specifier: 2.0.0-rc.0
|
||||
@ -243,6 +243,27 @@ importers:
|
||||
specifier: 4.2.5
|
||||
version: 4.2.5(vue@3.3.13)
|
||||
|
||||
plugins/plugin-copy-code:
|
||||
dependencies:
|
||||
'@vuepress-plume/plugin-content-update':
|
||||
specifier: workspace:*
|
||||
version: link:../plugin-content-update
|
||||
'@vuepress/client':
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/core':
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/shared':
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0
|
||||
'@vuepress/utils':
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0
|
||||
vue:
|
||||
specifier: ^3.3.13
|
||||
version: 3.3.13(typescript@5.3.3)
|
||||
|
||||
plugins/plugin-iconify:
|
||||
dependencies:
|
||||
'@iconify/vue':
|
||||
@ -390,6 +411,9 @@ importers:
|
||||
|
||||
theme:
|
||||
dependencies:
|
||||
'@pengzhanbo/utils':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
'@vuepress-plume/plugin-auto-frontmatter':
|
||||
specifier: workspace:*
|
||||
version: link:../plugins/plugin-auto-frontmatter
|
||||
@ -402,6 +426,9 @@ importers:
|
||||
'@vuepress-plume/plugin-caniuse':
|
||||
specifier: workspace:*
|
||||
version: link:../plugins/plugin-caniuse
|
||||
'@vuepress-plume/plugin-content-update':
|
||||
specifier: workspace:*
|
||||
version: link:../plugins/plugin-content-update
|
||||
'@vuepress-plume/plugin-copy-code':
|
||||
specifier: workspace:*
|
||||
version: link:../plugins/plugin-copy-code
|
||||
@ -460,8 +487,8 @@ importers:
|
||||
specifier: 2.0.0-rc.0
|
||||
version: 2.0.0-rc.0
|
||||
'@vueuse/core':
|
||||
specifier: ^10.7.0
|
||||
version: 10.7.0(vue@3.3.13)
|
||||
specifier: ^10.7.1
|
||||
version: 10.7.1(vue@3.3.13)
|
||||
date-fns:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
@ -481,20 +508,20 @@ importers:
|
||||
specifier: 4.2.5
|
||||
version: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-comment2:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.7
|
||||
version: 2.0.0-rc.7(typescript@5.3.3)
|
||||
vuepress-plugin-md-enhance:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(markdown-it@13.0.2)(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.7
|
||||
version: 2.0.0-rc.7(markdown-it@13.0.2)(typescript@5.3.3)
|
||||
vuepress-plugin-reading-time2:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.7
|
||||
version: 2.0.0-rc.7(typescript@5.3.3)
|
||||
vuepress-plugin-seo2:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.7
|
||||
version: 2.0.0-rc.7(typescript@5.3.3)
|
||||
vuepress-plugin-sitemap2:
|
||||
specifier: 2.0.0-rc.6
|
||||
version: 2.0.0-rc.6(typescript@5.3.3)
|
||||
specifier: 2.0.0-rc.7
|
||||
version: 2.0.0-rc.7(typescript@5.3.3)
|
||||
devDependencies:
|
||||
'@types/lodash.merge':
|
||||
specifier: ^4.6.9
|
||||
@ -3832,6 +3859,12 @@ packages:
|
||||
- vue-eslint-parser
|
||||
dev: true
|
||||
|
||||
/@pengzhanbo/utils@1.1.1:
|
||||
resolution: {integrity: sha512-gY4nPqvkOpP7aCzrxVEurkOXe9VGT0OmUBpTj2TNU/Jycvxbs5u2IrUXMgAATauab/qMHS6/EpvAqneo7EYEsw==}
|
||||
dependencies:
|
||||
throttle-debounce: 5.0.0
|
||||
dev: false
|
||||
|
||||
/@pkgjs/parseargs@0.11.0:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
@ -4868,7 +4901,7 @@ packages:
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.5.1
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vueuse/core': 10.7.0(vue@3.3.13)
|
||||
'@vueuse/core': 10.7.1(vue@3.3.13)
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
transitivePeerDependencies:
|
||||
@ -4954,7 +4987,7 @@ packages:
|
||||
'@vuepress/core': 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
'@vueuse/core': 10.7.0(vue@3.3.13)
|
||||
'@vueuse/core': 10.7.1(vue@3.3.13)
|
||||
ts-debounce: 4.0.0
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
@ -5106,24 +5139,24 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@vueuse/core@10.7.0(vue@3.3.13):
|
||||
resolution: {integrity: sha512-4EUDESCHtwu44ZWK3Gc/hZUVhVo/ysvdtwocB5vcauSV4B7NiGY5972WnsojB3vRNdxvAt7kzJWE2h9h7C9d5w==}
|
||||
/@vueuse/core@10.7.1(vue@3.3.13):
|
||||
resolution: {integrity: sha512-74mWHlaesJSWGp1ihg76vAnfVq9NTv1YT0SYhAQ6zwFNdBkkP+CKKJmVOEHcdSnLXCXYiL5e7MaewblfiYLP7g==}
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.20
|
||||
'@vueuse/metadata': 10.7.0
|
||||
'@vueuse/shared': 10.7.0(vue@3.3.13)
|
||||
'@vueuse/metadata': 10.7.1
|
||||
'@vueuse/shared': 10.7.1(vue@3.3.13)
|
||||
vue-demi: 0.14.6(vue@3.3.13)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/metadata@10.7.0:
|
||||
resolution: {integrity: sha512-GlaH7tKP2iBCZ3bHNZ6b0cl9g0CJK8lttkBNUX156gWvNYhTKEtbweWLm9rxCPIiwzYcr/5xML6T8ZUEt+DkvA==}
|
||||
/@vueuse/metadata@10.7.1:
|
||||
resolution: {integrity: sha512-jX8MbX5UX067DYVsbtrmKn6eG6KMcXxLRLlurGkZku5ZYT3vxgBjui2zajvUZ18QLIjrgBkFRsu7CqTAg18QFw==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@10.7.0(vue@3.3.13):
|
||||
resolution: {integrity: sha512-kc00uV6CiaTdc3i1CDC4a3lBxzaBE9AgYNtFN87B5OOscqeWElj/uza8qVDmk7/U8JbqoONLbtqiLJ5LGRuqlw==}
|
||||
/@vueuse/shared@10.7.1(vue@3.3.13):
|
||||
resolution: {integrity: sha512-v0jbRR31LSgRY/C5i5X279A/WQjD6/JsMzGa+eqt658oJ75IvQXAeONmwvEMrvJQKnRElq/frzBR7fhmWY5uLw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.6(vue@3.3.13)
|
||||
transitivePeerDependencies:
|
||||
@ -6208,7 +6241,7 @@ packages:
|
||||
minipass-pipeline: 1.2.4
|
||||
p-map: 4.0.0
|
||||
ssri: 10.0.4
|
||||
tar: 6.1.13
|
||||
tar: 6.2.0
|
||||
unique-filename: 3.0.0
|
||||
dev: true
|
||||
|
||||
@ -12553,7 +12586,7 @@ packages:
|
||||
npmlog: 6.0.2
|
||||
rimraf: 3.0.2
|
||||
semver: 7.5.4
|
||||
tar: 6.1.13
|
||||
tar: 6.2.0
|
||||
which: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
@ -13188,8 +13221,8 @@ packages:
|
||||
semver: 7.5.4
|
||||
dev: false
|
||||
|
||||
/pacote@17.0.4:
|
||||
resolution: {integrity: sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==}
|
||||
/pacote@17.0.5:
|
||||
resolution: {integrity: sha512-TAE0m20zSDMnchPja9vtQjri19X3pZIyRpm2TJVeI+yU42leJBBDTRYhOcWFsPhaMxf+3iwQkFiKz16G9AEeeA==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@ -13210,7 +13243,7 @@ packages:
|
||||
read-package-json-fast: 3.0.2
|
||||
sigstore: 2.1.0
|
||||
ssri: 10.0.4
|
||||
tar: 6.1.13
|
||||
tar: 6.2.0
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
@ -13467,8 +13500,8 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/pnpm@8.12.1:
|
||||
resolution: {integrity: sha512-ZwXqGWattlhwU+bP5v3cN3+BBmIo2vc2xEkAEvRPL/G/DHE7uPMUX84OPvZpx8FfGaWawVeDiVHyNMF7gcplXQ==}
|
||||
/pnpm@8.13.1:
|
||||
resolution: {integrity: sha512-dYvrxpictkYsUTgSmEAZOxDCWN3NsKtD7g753Yd4S8IY1uQctb7qw2K4zjPx+LCAJbWZkzwLzoIFCpo2uEdNQw==}
|
||||
engines: {node: '>=16.14'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@ -15431,18 +15464,6 @@ packages:
|
||||
streamx: 2.15.0
|
||||
dev: false
|
||||
|
||||
/tar@6.1.13:
|
||||
resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
chownr: 2.0.0
|
||||
fs-minipass: 2.1.0
|
||||
minipass: 4.2.7
|
||||
minizlib: 2.1.2
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/tar@6.2.0:
|
||||
resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -15454,8 +15475,8 @@ packages:
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
|
||||
/taze@0.13.0:
|
||||
resolution: {integrity: sha512-o17Y6miF+44sDJ7haRHTqZefTlGOaBSdDHRwRcrt+s3WeGSPBUtPSG18XNwToIXN//eh58hyYnyDwTnpYLp4sg==}
|
||||
/taze@0.13.1:
|
||||
resolution: {integrity: sha512-viIeTWEezE1mtQ9M9dtvIwfF7WkNRXVZP7g/NsGDFxwwzJIVJReSiZiyfsJccdJo6XUe7FaYzvrG1VD6Tnj4Jg==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@antfu/ni': 0.21.12
|
||||
@ -15464,7 +15485,7 @@ packages:
|
||||
deepmerge: 4.3.1
|
||||
detect-indent: 7.0.1
|
||||
execa: 8.0.1
|
||||
pacote: 17.0.4
|
||||
pacote: 17.0.5
|
||||
picocolors: 1.0.0
|
||||
prompts: 2.4.2
|
||||
semver: 7.5.4
|
||||
@ -15589,6 +15610,11 @@ packages:
|
||||
long: 2.4.0
|
||||
dev: false
|
||||
|
||||
/throttle-debounce@5.0.0:
|
||||
resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==}
|
||||
engines: {node: '>=12.22'}
|
||||
dev: false
|
||||
|
||||
/through2-filter@3.0.0:
|
||||
resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==}
|
||||
dependencies:
|
||||
@ -16388,8 +16414,8 @@ packages:
|
||||
typescript: 5.3.3
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-comment2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-NOGhWS9jrmcFgkaNd5AGtuERok3mbSPBQQ5CV8Uegs0409Zm1L0kmhOPB959Z1KwLxfoNvhD97XruWcQ29bhUw==}
|
||||
/vuepress-plugin-comment2@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-bZ5BhJ/dQdc24GDc1T95nRCnkjZZo05wpSSU2pI7sRZSeX6MjbpJLMNJPKH3BIMQQQaQUZUIzKLl4U0ja9B07A==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
'@waline/client': ^2.15.8 || ^3.0.0-alpha.8
|
||||
@ -16421,16 +16447,16 @@ packages:
|
||||
giscus: 1.4.0
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.7(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-md-enhance@2.0.0-rc.6(markdown-it@13.0.2)(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-cEsMccjqdNFq4UjnFbg9OlBwrIF9Ducr2MX2G+6p4h17yJ8yf7NctpGZwnVMh2FGmQ7oYjcIpkuUDrkLn4elzw==}
|
||||
/vuepress-plugin-md-enhance@2.0.0-rc.7(markdown-it@13.0.2)(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-UHcsPNbbg9itmIndTKn5nObjy/eVzbNo+6A9P1JaOPfNukkC6H7LaHHgwMlPXNsmaeYZmR18ZA+NCSTGcRDTvQ==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
'@types/reveal.js': ^4.4.5
|
||||
@ -16511,13 +16537,13 @@ packages:
|
||||
'@vuepress/client': 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
'@vueuse/core': 10.7.0(vue@3.3.13)
|
||||
'@vueuse/core': 10.7.1(vue@3.3.13)
|
||||
balloon-css: 1.2.0
|
||||
js-yaml: 4.1.0
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vue-router: 4.2.5(vue@3.3.13)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-plugin-sass-palette: 2.0.0-rc.7(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- markdown-it
|
||||
@ -16525,8 +16551,8 @@ packages:
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-reading-time2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-GgyKWS66QvlrXV2zMF0qhgtEpELvN0kSOEAqgGn8mR+01TgLirdq+k9rExp1zab7UH7h8FjtRgWlcYgfPUbGEA==}
|
||||
/vuepress-plugin-reading-time2@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-OBFxXNZQGOyhzIx2ZfJ/nPBiFJYRGOCT+1GrZRjeW0cfrdvgYZo6x2jDBDtmrrzT3TlhZRpQDZB6QMbiORQhPQ==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16542,15 +16568,15 @@ packages:
|
||||
dependencies:
|
||||
'@vuepress/client': 2.0.0-rc.0(typescript@5.3.3)
|
||||
vue: 3.3.13(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-sass-palette@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-/LAcJvznI5C/cSO0IM2btGivA9IgOON+YwpEzHGhkZKwBKx/lLqOpHH4ghaKmC/hX72QISyM1pjQJ/9pjOQEOg==}
|
||||
/vuepress-plugin-sass-palette@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-xi8UDaPGS67MVzUDoaQN67dZoTjkW30KpHQJH8R/6DybOz9hC0oVqvkZM9waPPCCdcPytxVUfVDdincARZ4eHw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
sass-loader: ^13.3.2
|
||||
@ -16571,15 +16597,15 @@ packages:
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
chokidar: 3.5.3
|
||||
sass: 1.69.5
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-seo2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-ZvYQNV/aZV5iCi7D7qg1Bz7rrQ00f9exPQ+m/JEsJr+uH0g1frAbCI46Ilu0Y42+XTU6id/wO23yKoS0GFQ8jw==}
|
||||
/vuepress-plugin-seo2@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-WHn4s1N2cHPQZQh+rZyiH9mDtGYFh9E2F5ZUV3LT2IddGuHluzuwVScIxix9q76AvbdCl4rhg7vr97oc8oPoUA==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16595,15 +16621,15 @@ packages:
|
||||
dependencies:
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-plugin-sitemap2@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-b9gNdmaUsXRBpE1OKkTmp/WhCBKQgkHQHhEK1oK9oZiCEAP4Xhmnob5UhtS7WeBK9HBsjCCCUwAEBbNZ8WdiEw==}
|
||||
/vuepress-plugin-sitemap2@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-Vc13ucmamsXu0PD9Gu1lRm0NKOAwV/h3hZA+h2jAnavsiAqkAUF1WmvjNLPMWCVz77lez3knQNpWDoHZVBoxLQ==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16620,15 +16646,15 @@ packages:
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
sitemap: 7.1.1
|
||||
vuepress-shared: 2.0.0-rc.6(typescript@5.3.3)
|
||||
vuepress-shared: 2.0.0-rc.7(typescript@5.3.3)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/vuepress-shared@2.0.0-rc.6(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-bcEBxOX0ulWtCeRCBOdIpvFC+m4HvyWGLm6CPXedPiHaSl6avp/S6akYNcj2dyBPXxC5v3WfiGJDumis0fqYbg==}
|
||||
/vuepress-shared@2.0.0-rc.7(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-1EUgbOe8/VK0yuzau2mtL22Av2547zVJP/q2niCoCyBTzMrn0agaWSRIDhhQx+e4xPlE5Mi3FsCHDXTfkWSuIw==}
|
||||
engines: {node: '>=18.16.0', npm: '>=8', pnpm: '>=7', yarn: '>=2'}
|
||||
peerDependencies:
|
||||
vuepress: 2.0.0-rc.0
|
||||
@ -16645,7 +16671,7 @@ packages:
|
||||
'@vuepress/client': 2.0.0-rc.0(typescript@5.3.3)
|
||||
'@vuepress/shared': 2.0.0-rc.0
|
||||
'@vuepress/utils': 2.0.0-rc.0
|
||||
'@vueuse/core': 10.7.0(vue@3.3.13)
|
||||
'@vueuse/core': 10.7.1(vue@3.3.13)
|
||||
cheerio: 1.0.0-rc.12
|
||||
dayjs: 1.11.10
|
||||
execa: 8.0.1
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
## scripts/autoInstall
|
||||
|
||||
检查各个 workspace package 中的 vuepress 相关依赖,并更新到最新版本。
|
||||
|
||||
``` sh
|
||||
pnpm autoUpdate
|
||||
```
|
||||
|
||||
## scripts/create
|
||||
|
||||
在 `packages/` 目录下生成一个新的 插件包
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import process from 'node:process'
|
||||
import { execa } from 'execa'
|
||||
import ora from 'ora'
|
||||
import chalk from 'chalk'
|
||||
|
||||
const _dirname
|
||||
= typeof __dirname !== 'undefined'
|
||||
? __dirname
|
||||
: path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const packages = [
|
||||
...fs
|
||||
.readdirSync(path.join(_dirname, '../packages'))
|
||||
.filter(file => file !== '.DS_Store' && file !== 'tsconfig.build.json')
|
||||
.map(dir => path.join('../packages', dir)),
|
||||
'../docs',
|
||||
]
|
||||
|
||||
const dependencies = packages.map((dir) => {
|
||||
const pkg = fs.readFileSync(
|
||||
path.join(_dirname, dir, 'package.json'),
|
||||
'utf-8',
|
||||
)
|
||||
const { dependencies, devDependencies } = JSON.parse(pkg)
|
||||
return {
|
||||
dirname: path.join(_dirname, dir),
|
||||
dependencies: filterVuePress(Object.keys(dependencies || {})),
|
||||
devDependencies: filterVuePress(Object.keys(devDependencies || {})),
|
||||
}
|
||||
})
|
||||
|
||||
function filterVuePress(dependencies) {
|
||||
const vuepress = dependencies
|
||||
.filter(
|
||||
dependence =>
|
||||
dependence.startsWith('@vuepress/'),
|
||||
)
|
||||
.map(dependence => `${dependence}@next`)
|
||||
const includes = ['vue', 'vue-router']
|
||||
const vue = dependencies
|
||||
.filter(dependence => includes.includes(dependence))
|
||||
.map(dependence => `${dependence}@latest`)
|
||||
return [...vue, ...vuepress]
|
||||
}
|
||||
|
||||
const options = []
|
||||
dependencies.forEach(({ dirname, dependencies, devDependencies }) => {
|
||||
if (dependencies.length)
|
||||
options.push(['pnpm', ['add', ...dependencies], { cwd: dirname }])
|
||||
|
||||
if (devDependencies.length)
|
||||
options.push(['pnpm', ['add', '-D', ...devDependencies], { cwd: dirname }])
|
||||
})
|
||||
|
||||
async function install(index = 0) {
|
||||
if (index >= options.length)
|
||||
return
|
||||
const spinner = ora()
|
||||
const opt = options[index]
|
||||
const dir = opt[2].cwd.split('/').slice(-2).join('/')
|
||||
console.log('Installing ', chalk.cyan(dir))
|
||||
console.log(chalk.gray(opt[0], opt[1].join(' ')))
|
||||
console.log('\n')
|
||||
const current = execa(opt[0], opt[1], opt[2])
|
||||
current?.stdout?.pipe(process.stdout)
|
||||
try {
|
||||
await current
|
||||
spinner.succeed('Installed.')
|
||||
await install(index + 1)
|
||||
}
|
||||
catch (e) {
|
||||
spinner.fail('Install Fail.')
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
install()
|
||||
@ -43,10 +43,12 @@
|
||||
"ts:watch": "tsc -b tsconfig.build.json --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pengzhanbo/utils": "^1.1.1",
|
||||
"@vuepress-plume/plugin-auto-frontmatter": "workspace:*",
|
||||
"@vuepress-plume/plugin-baidu-tongji": "workspace:*",
|
||||
"@vuepress-plume/plugin-blog-data": "workspace:*",
|
||||
"@vuepress-plume/plugin-caniuse": "workspace:*",
|
||||
"@vuepress-plume/plugin-content-update": "workspace:*",
|
||||
"@vuepress-plume/plugin-copy-code": "workspace:*",
|
||||
"@vuepress-plume/plugin-iconify": "workspace:*",
|
||||
"@vuepress-plume/plugin-notes-data": "workspace:*",
|
||||
@ -66,18 +68,18 @@
|
||||
"@vuepress/plugin-toc": "2.0.0-rc.0",
|
||||
"@vuepress/shared": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"@vueuse/core": "^10.7.0",
|
||||
"@vueuse/core": "^10.7.1",
|
||||
"date-fns": "^3.0.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"nanoid": "^5.0.4",
|
||||
"ts-debounce": "^4.0.0",
|
||||
"vue": "^3.3.13",
|
||||
"vue-router": "4.2.5",
|
||||
"vuepress-plugin-comment2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-md-enhance": "2.0.0-rc.6",
|
||||
"vuepress-plugin-reading-time2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-seo2": "2.0.0-rc.6",
|
||||
"vuepress-plugin-sitemap2": "2.0.0-rc.6"
|
||||
"vuepress-plugin-comment2": "2.0.0-rc.7",
|
||||
"vuepress-plugin-md-enhance": "2.0.0-rc.7",
|
||||
"vuepress-plugin-reading-time2": "2.0.0-rc.7",
|
||||
"vuepress-plugin-seo2": "2.0.0-rc.7",
|
||||
"vuepress-plugin-sitemap2": "2.0.0-rc.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash.merge": "^4.6.9"
|
||||
|
||||
@ -15,6 +15,7 @@ const route = useRoute()
|
||||
const avatar = computed(() => theme.value.avatar)
|
||||
const { hasBlogExtract, tags, archives } = useBlogExtract()
|
||||
const open = ref(false)
|
||||
const lazyOpen = ref(false)
|
||||
|
||||
const isLocked = useScrollLock(inBrowser ? document.body : null)
|
||||
|
||||
@ -22,6 +23,15 @@ watch(() => route.path, () => {
|
||||
open.value = false
|
||||
})
|
||||
|
||||
watch(open, async () => {
|
||||
if (open.value) {
|
||||
setTimeout(() => {
|
||||
lazyOpen.value = true
|
||||
}, 200)
|
||||
}
|
||||
else { lazyOpen.value = false }
|
||||
})
|
||||
|
||||
watch(
|
||||
[() => open.value],
|
||||
() => {
|
||||
@ -39,34 +49,38 @@ const showBlogExtract = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="showBlogExtract" class="blog-extract" @click="open = !open">
|
||||
<IconBlogExt class="icon" />
|
||||
</div>
|
||||
<div v-if="showBlogExtract" class="blog-modal" :class="{ open }" @click.self="open = false">
|
||||
<div class="blog-modal-container">
|
||||
<div v-if="avatar" class="avatar-profile">
|
||||
<p v-if="avatar.url" class="avatar">
|
||||
<img :src="avatar.url" :alt="avatar.name">
|
||||
</p>
|
||||
<div>
|
||||
<h3>{{ avatar.name }}</h3>
|
||||
<p class="desc">
|
||||
{{ avatar.description }}
|
||||
</p>
|
||||
<template v-if="showBlogExtract">
|
||||
<div class="blog-extract" @click="open = !open">
|
||||
<IconBlogExt class="icon" />
|
||||
</div>
|
||||
<Transition name="fade">
|
||||
<div v-show="open" class="blog-modal" @click.self="open = false">
|
||||
<div class="blog-modal-container" :class="{ open: lazyOpen }">
|
||||
<div v-if="avatar" class="avatar-profile">
|
||||
<p v-if="avatar.url" class="avatar">
|
||||
<img :src="avatar.url" :alt="avatar.name">
|
||||
</p>
|
||||
<div>
|
||||
<h3>{{ avatar.name }}</h3>
|
||||
<p class="desc">
|
||||
{{ avatar.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hasBlogExtract" class="blog-nav">
|
||||
<AutoLink class="nav-link" :href="tags.link">
|
||||
<IconTag class="icon" />
|
||||
<span>{{ tags.text }}</span>
|
||||
</AutoLink>
|
||||
<AutoLink class="nav-link" :href="archives.link">
|
||||
<IconArchive class="icon" />
|
||||
<span>{{ archives.text }}</span>
|
||||
</AutoLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hasBlogExtract" class="blog-nav">
|
||||
<AutoLink class="nav-link" :href="tags.link">
|
||||
<IconTag class="icon" />
|
||||
<span>{{ tags.text }}</span>
|
||||
</AutoLink>
|
||||
<AutoLink class="nav-link" :href="archives.link">
|
||||
<IconArchive class="icon" />
|
||||
<span>{{ archives.text }}</span>
|
||||
</AutoLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@ -104,19 +118,18 @@ const showBlogExtract = computed(() => {
|
||||
left: 0;
|
||||
z-index: var(--vp-z-index-sidebar);
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
transform: translateY(100%);
|
||||
transition: opacity 0.25s, transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
opacity: 1;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.blog-modal.open {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateY(0);
|
||||
transition: opacity 0.25s, transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
.blog-modal.fade-enter-from,
|
||||
.blog-modal.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.blog-modal.fade-leave-active,
|
||||
.blog-modal.fade-enter-active {
|
||||
transition: opacity 0.5s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
|
||||
.blog-modal-container {
|
||||
@ -125,8 +138,15 @@ const showBlogExtract = computed(() => {
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
background-color: var(--vp-c-bg);
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
box-shadow: 0 -3px 12px rgba(0, 0, 0, 0.1), 0 -1px 4px rgba(0, 0, 0, 0.1);;
|
||||
transform: translateY(100%);
|
||||
transition: transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
|
||||
.blog-modal-container.open {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.avatar-profile {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { usePageData } from '@vuepress/client'
|
||||
import { computed, ref } from 'vue'
|
||||
import { onContentUpdated } from '@vuepress-plume/plugin-content-update/client'
|
||||
import { useActiveAnchor, useThemeLocaleData } from '../composables/index.js'
|
||||
import IconPrint from './icons/IconPrint.vue'
|
||||
import PageAsideItem from './PageAsideItem.vue'
|
||||
@ -8,9 +9,13 @@ import PageAsideItem from './PageAsideItem.vue'
|
||||
const page = usePageData()
|
||||
const theme = useThemeLocaleData()
|
||||
|
||||
const headers = computed(() => page.value.headers)
|
||||
const headers = ref(page.value.headers)
|
||||
const hasOutline = computed(() => headers.value.length > 0)
|
||||
|
||||
onContentUpdated(() => {
|
||||
headers.value = page.value.headers
|
||||
})
|
||||
|
||||
const container = ref()
|
||||
const marker = ref()
|
||||
|
||||
|
||||
@ -52,16 +52,20 @@ const {
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color: var(--vp-c-brand-2);
|
||||
color: var(--vp-c-bg);
|
||||
background-color: var(--vp-c-brand-2);
|
||||
border-color: var(--vp-c-brand-2);
|
||||
}
|
||||
.btn[disabled] {
|
||||
.btn[disabled],
|
||||
.btn[disabled]:hover {
|
||||
color: var(--vp-c-gray-1);
|
||||
border-color: var(--vp-c-divider);
|
||||
background-color: transparent;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
color: var(--vp-c-brand-2);
|
||||
color: var(--vp-c-text-3);
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -11,14 +11,16 @@ defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="post-list">
|
||||
<p v-for="post in postList" :key="post.path">
|
||||
<AutoLink class="post-title" :href="post.path">
|
||||
{{ post.title }}
|
||||
</AutoLink>
|
||||
<ul class="post-list">
|
||||
<li v-for="post in postList" :key="post.path">
|
||||
<p class="post-title">
|
||||
<AutoLink class="post-link" :href="post.path">
|
||||
{{ post.title }}
|
||||
</AutoLink>
|
||||
</p>
|
||||
<span class="post-time">{{ post.createTime }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@ -27,7 +29,7 @@ defineProps<{
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.post-list p {
|
||||
.post-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@ -37,7 +39,7 @@ defineProps<{
|
||||
|
||||
.post-list .post-title {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
margin-right: 14px;
|
||||
font-weight: 600;
|
||||
transition: all var(--t-color);
|
||||
display: -webkit-box;
|
||||
@ -52,10 +54,10 @@ defineProps<{
|
||||
transition: all var(--t-color);
|
||||
}
|
||||
|
||||
.post-list p:hover .post-title {
|
||||
.post-list li:hover .post-title {
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
.post-list p:hover .post-time {
|
||||
.post-list li:hover .post-time {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -8,7 +8,7 @@ const { tags: tagsLink } = useBlogExtract()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tags-wrapper">
|
||||
<div class="tags-wrapper" :class="{ 'has-list': postList.length > 0 }">
|
||||
<h2 class="tags-title">
|
||||
<IconTag class="icon" />
|
||||
<span>{{ tagsLink.text }}</span>
|
||||
@ -22,26 +22,34 @@ const { tags: tagsLink } = useBlogExtract()
|
||||
@click="handleTagClick(tag.name)"
|
||||
>
|
||||
<span class="tag-name">{{ tag.name }}</span>
|
||||
<span class="tag-count">({{ tag.count }})</span>
|
||||
<span class="tag-count">{{ tag.count }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3 v-if="currentTag" class="tag-title">
|
||||
{{ currentTag }}
|
||||
</h3>
|
||||
|
||||
<ShortPostList v-if="postList.length" :post-list="postList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tags-wrapper {
|
||||
padding: 32px 24px;
|
||||
padding: 32px 24px 168px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tags-wrapper.has-list {
|
||||
padding-bottom: 64px;
|
||||
}
|
||||
.tags-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-brand-1);
|
||||
margin-bottom: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.tags-title .icon {
|
||||
width: 1em;
|
||||
@ -55,20 +63,25 @@ const { tags: tagsLink } = useBlogExtract()
|
||||
align-items: center;
|
||||
}
|
||||
.tags .tag {
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
word-wrap: break-word;
|
||||
margin: 8px;
|
||||
padding: 2px 10px;
|
||||
padding: 6px 6px 6px 10px;
|
||||
background-color: var(--vp-c-default-soft);
|
||||
color: var(--vp-c-text-3);
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all var(--t-color);
|
||||
}
|
||||
.tags .tag:hover,
|
||||
.tags .tag.active {
|
||||
background-color: var(--vp-c-brand-1);
|
||||
color: var(--vp-c-bg);
|
||||
|
||||
.tag-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
padding-bottom: 8px;
|
||||
margin: 20px 12px -10px 12px;
|
||||
}
|
||||
|
||||
.tag-name {
|
||||
@ -76,6 +89,22 @@ const { tags: tagsLink } = useBlogExtract()
|
||||
}
|
||||
|
||||
.tag-count {
|
||||
display: inline-block;
|
||||
border-left: 1px solid var(--vp-c-divider);
|
||||
padding-left: 6px;
|
||||
margin-left: 4px;
|
||||
color: var(--vp-c-text-3);
|
||||
transition: all var(--t-color);
|
||||
}
|
||||
|
||||
.tags .tag:hover,
|
||||
.tags .tag.active {
|
||||
background-color: var(--vp-c-brand-1);
|
||||
color: var(--vp-c-bg);
|
||||
}
|
||||
|
||||
.tags .tag:hover .tag-count,
|
||||
.tags .tag.active .tag-count {
|
||||
color: var(--vp-bg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
import { usePageData } from '@vuepress/client'
|
||||
import type { PageHeader } from '@vuepress/client'
|
||||
import type { PropType, VNode } from 'vue'
|
||||
import { computed, defineComponent, h, toRefs } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { scrollTo } from '../utils/index.js'
|
||||
|
||||
export type TocPropsHeaders = PageHeader[]
|
||||
|
||||
export interface TocPropsOptions {
|
||||
containerTag: string
|
||||
containerClass: string
|
||||
listClass: string
|
||||
itemClass: string
|
||||
linkClass: string
|
||||
linkActiveClass: string
|
||||
linkChildrenActiveClass: string
|
||||
}
|
||||
|
||||
export interface TocProps {
|
||||
headers: TocPropsHeaders
|
||||
options: TocPropsOptions
|
||||
}
|
||||
|
||||
function renderLink(header: PageHeader, options: TocPropsOptions, route: RouteLocationNormalizedLoaded): VNode {
|
||||
const hash = `#${header.slug}`
|
||||
const linkClass = [options.linkClass]
|
||||
|
||||
if (options.linkActiveClass && route.hash === hash)
|
||||
linkClass.push(options.linkActiveClass)
|
||||
|
||||
if (
|
||||
options.linkChildrenActiveClass
|
||||
&& header.children.some(item => `#${item.slug}` === route.hash)
|
||||
)
|
||||
linkClass.push(options.linkChildrenActiveClass)
|
||||
|
||||
const setActiveRouteHash = (): void => {
|
||||
const headerAnchors: HTMLAnchorElement[] = Array.from(
|
||||
document.querySelectorAll('.header-anchor'),
|
||||
)
|
||||
const anchor = headerAnchors.find(
|
||||
anchor => decodeURI(anchor.hash) === hash,
|
||||
)
|
||||
if (!anchor)
|
||||
return
|
||||
const el = document.documentElement
|
||||
const top = anchor.getBoundingClientRect().top - 80 + el.scrollTop
|
||||
scrollTo(document, top)
|
||||
}
|
||||
|
||||
return h(
|
||||
'a',
|
||||
{
|
||||
href: hash,
|
||||
class: linkClass,
|
||||
ariaLabel: header.title,
|
||||
onClick: (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
setActiveRouteHash()
|
||||
},
|
||||
},
|
||||
header.title,
|
||||
)
|
||||
}
|
||||
|
||||
function renderHeaders(headers: PageHeader[], options: TocPropsOptions, route: RouteLocationNormalizedLoaded): VNode[] {
|
||||
if (headers.length === 0)
|
||||
return []
|
||||
|
||||
return [
|
||||
h(
|
||||
'ul',
|
||||
{ class: options.listClass },
|
||||
headers.map(header =>
|
||||
h('li', { class: options.itemClass }, [
|
||||
renderLink(header, options, route),
|
||||
renderHeaders(header.children, options, route),
|
||||
]),
|
||||
),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
const Toc = defineComponent({
|
||||
name: 'Toc',
|
||||
props: {
|
||||
headers: {
|
||||
type: Array as PropType<TocPropsHeaders>,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
options: {
|
||||
type: Object as PropType<TocPropsOptions>,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { headers: propsHeaders, options: propsOptions } = toRefs(props)
|
||||
|
||||
const defaultOptions: TocPropsOptions = {
|
||||
containerTag: 'nav',
|
||||
containerClass: 'theme-plume-toc',
|
||||
listClass: 'theme-plume-toc-list',
|
||||
itemClass: 'theme-plume-toc-item',
|
||||
linkClass: 'theme-plume-toc-link',
|
||||
linkActiveClass: 'active',
|
||||
linkChildrenActiveClass: 'active',
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const page = usePageData()
|
||||
const headers = computed<TocPropsHeaders>(() => {
|
||||
const headerToUse = propsHeaders.value || page.value.headers
|
||||
|
||||
return headerToUse[0]?.level === 1 ? headerToUse[0].children : headerToUse
|
||||
})
|
||||
const options = computed<TocPropsOptions>(() => ({
|
||||
...defaultOptions,
|
||||
...propsOptions.value,
|
||||
}))
|
||||
|
||||
return () => {
|
||||
const renderedHeaders = renderHeaders(headers.value, options.value, route)
|
||||
if (options.value.containerTag) {
|
||||
return h(
|
||||
options.value.containerTag,
|
||||
{ class: options.value.containerClass },
|
||||
renderedHeaders,
|
||||
)
|
||||
}
|
||||
return renderedHeaders
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export default Toc
|
||||
@ -44,11 +44,12 @@ const { hasSidebar } = useSidebar()
|
||||
.plume-footer :deep(a) {
|
||||
text-decoration-line: underline;
|
||||
text-underline-offset: 2px;
|
||||
transition: color 0.25s;
|
||||
transition: color, text-underline-offset 0.25s;
|
||||
}
|
||||
|
||||
.plume-footer :deep(a:hover) {
|
||||
color: var(--vp-c-text-1);
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
||||
@ -146,7 +146,7 @@ export function useTags() {
|
||||
}).map(item => ({
|
||||
title: item.title,
|
||||
path: item.path,
|
||||
createTime: item.createTime.split(' ')[0],
|
||||
createTime: item.createTime.split(' ')[0].replace(/\//g, '-'),
|
||||
}))
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ export function useArchives() {
|
||||
current.list.push({
|
||||
title: item.title,
|
||||
path: item.path,
|
||||
createTime: createTime.slice(year.length + 1),
|
||||
createTime: createTime.slice(year.length + 1).replace(/\//g, '-'),
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -11,8 +11,10 @@ import NotFound from './layouts/NotFound.vue'
|
||||
export default defineClientConfig({
|
||||
enhance({ app, router }) {
|
||||
// global component
|
||||
|
||||
app.component('Badge', Badge)
|
||||
|
||||
if (app._context.components.ExternalLinkIcon)
|
||||
delete app._context.components.ExternalLinkIcon
|
||||
app.component('ExternalLinkIcon', ExternalLinkIcon)
|
||||
|
||||
app.component('DocSearch', () => {
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import type { App } from '@vuepress/core'
|
||||
import { resolveLocalePath } from '@vuepress/shared'
|
||||
import type {
|
||||
@ -8,28 +6,13 @@ import type {
|
||||
FrontmatterArray,
|
||||
FrontmatterObject,
|
||||
} from '@vuepress-plume/plugin-auto-frontmatter'
|
||||
import type { NotesItem } from '@vuepress-plume/plugin-notes-data'
|
||||
import { format } from 'date-fns'
|
||||
import { customAlphabet } from 'nanoid'
|
||||
import { uniq } from '@pengzhanbo/utils'
|
||||
import type {
|
||||
PlumeThemeLocaleOptions,
|
||||
PlumeThemePluginOptions,
|
||||
} from '../shared/index.js'
|
||||
|
||||
const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
|
||||
function getPackage() {
|
||||
let pkg = {} as any
|
||||
try {
|
||||
const content = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')
|
||||
pkg = JSON.parse(content)
|
||||
}
|
||||
catch {}
|
||||
return pkg
|
||||
}
|
||||
|
||||
function normalizePath(dir: string) {
|
||||
return dir.replace(/\\+/g, '/')
|
||||
}
|
||||
import { getCurrentDirname, getPackage, nanoid, pathJoin } from './utils.js'
|
||||
|
||||
export default function autoFrontmatter(
|
||||
app: App,
|
||||
@ -38,17 +21,17 @@ export default function autoFrontmatter(
|
||||
): AutoFrontmatterOptions {
|
||||
const sourceDir = app.dir.source()
|
||||
const pkg = getPackage()
|
||||
const articlePrefix = localeOption.article || '/article/'
|
||||
const { locales = {}, avatar, article: articlePrefix = '/article/' } = localeOption
|
||||
const { frontmatter } = options
|
||||
|
||||
const locales = (app.siteData.locales || {}) as PlumeThemeLocaleOptions
|
||||
const localesNotesDirs = Object.keys(locales)
|
||||
const localesNotesDirs = Object.keys(app.siteData.locales || {})
|
||||
.map((locale) => {
|
||||
// fixed: #15
|
||||
const notes = localeOption.locales?.[locale]?.notes
|
||||
const notes = locales[locale]?.notes
|
||||
if (!notes)
|
||||
return ''
|
||||
const dir = notes.dir
|
||||
return dir ? normalizePath(path.join(locale, dir)).replace(/^\//, '') : ''
|
||||
|
||||
return notes.dir ? pathJoin(locale, notes.dir).replace(/^\//, '') : ''
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
@ -58,7 +41,7 @@ export default function autoFrontmatter(
|
||||
return author
|
||||
if (data.friends)
|
||||
return
|
||||
return localeOption.avatar?.name || pkg.author || ''
|
||||
return avatar?.name || pkg.author || ''
|
||||
},
|
||||
createTime(formatTime: string, { createTime }, data: any) {
|
||||
if (formatTime)
|
||||
@ -70,20 +53,20 @@ export default function autoFrontmatter(
|
||||
}
|
||||
|
||||
const resolveLocale = (filepath: string) => {
|
||||
const file = normalizePath(
|
||||
path.join('/', path.relative(sourceDir, filepath)),
|
||||
)
|
||||
const file = pathJoin('/', path.relative(sourceDir, filepath))
|
||||
|
||||
return resolveLocalePath(localeOption.locales!, file)
|
||||
}
|
||||
const notesByLocale = (locale: string) => {
|
||||
const notes = localeOption.locales![locale]?.notes || localeOption.notes
|
||||
const notes = locales[locale]?.notes || localeOption.notes
|
||||
if (notes === false)
|
||||
return undefined
|
||||
return notes
|
||||
}
|
||||
|
||||
const findNote = (filepath: string) => {
|
||||
const file = path.join('/', path.relative(sourceDir, filepath))
|
||||
const locale = resolveLocalePath(localeOption.locales!, normalizePath(file))
|
||||
const file = pathJoin('/', path.relative(sourceDir, filepath))
|
||||
const locale = resolveLocalePath(locales, file)
|
||||
const notes = notesByLocale(locale)
|
||||
if (!notes)
|
||||
return undefined
|
||||
@ -94,22 +77,15 @@ export default function autoFrontmatter(
|
||||
)
|
||||
}
|
||||
|
||||
const getCurrentDirname = (note: NotesItem | undefined, filepath: string) => {
|
||||
const dirList = normalizePath(note?.dir || path.dirname(filepath))
|
||||
.replace(/^\/|\/$/g, '')
|
||||
.split('/')
|
||||
return dirList.length > 0 ? dirList[dirList.length - 1] : ''
|
||||
}
|
||||
return {
|
||||
include: options.frontmatter?.include ?? ['**/*.md'],
|
||||
exclude: options.frontmatter?.exclude ?? ['.vuepress/**/*', 'node_modules'],
|
||||
frontmatter: options.frontmatter?.frontmatter ?? [
|
||||
include: frontmatter?.include ?? ['**/*.md'],
|
||||
exclude: uniq(['.vuepress/**/*', 'node_modules', ...(frontmatter?.exclude ?? [])]),
|
||||
|
||||
frontmatter: [
|
||||
localesNotesDirs.length
|
||||
? {
|
||||
// note 首页链接
|
||||
include: localesNotesDirs.map(dir =>
|
||||
normalizePath(path.join(dir, '**/{readme,README,index}.md')),
|
||||
),
|
||||
include: localesNotesDirs.map(dir => pathJoin(dir, '**/{readme,README,index}.md')),
|
||||
frontmatter: {
|
||||
title(title: string, { filepath }) {
|
||||
if (title)
|
||||
@ -117,7 +93,7 @@ export default function autoFrontmatter(
|
||||
const note = findNote(filepath)
|
||||
if (note?.text)
|
||||
return note.text
|
||||
return getCurrentDirname(note, filepath) || ''
|
||||
return getCurrentDirname(note?.dir, filepath) || ''
|
||||
},
|
||||
...baseFrontmatter,
|
||||
permalink(permalink: string, { filepath }, data: any) {
|
||||
@ -128,13 +104,11 @@ export default function autoFrontmatter(
|
||||
const locale = resolveLocale(filepath)
|
||||
const notes = notesByLocale(locale)
|
||||
const note = findNote(filepath)
|
||||
return normalizePath(
|
||||
path.join(
|
||||
locale,
|
||||
notes?.link || '',
|
||||
note?.link || getCurrentDirname(note, filepath),
|
||||
'/',
|
||||
),
|
||||
return pathJoin(
|
||||
locale,
|
||||
notes?.link || '',
|
||||
note?.link || getCurrentDirname(note?.dir, filepath),
|
||||
'/',
|
||||
)
|
||||
},
|
||||
},
|
||||
@ -142,9 +116,7 @@ export default function autoFrontmatter(
|
||||
: '',
|
||||
localesNotesDirs.length
|
||||
? {
|
||||
include: localesNotesDirs.map(dir =>
|
||||
normalizePath(path.join(dir, '**/**.md')),
|
||||
),
|
||||
include: localesNotesDirs.map(dir => pathJoin(dir, '**/**.md')),
|
||||
frontmatter: {
|
||||
title(title: string, { filepath }) {
|
||||
if (title)
|
||||
@ -161,14 +133,12 @@ export default function autoFrontmatter(
|
||||
const locale = resolveLocale(filepath)
|
||||
const note = findNote(filepath)
|
||||
const notes = notesByLocale(locale)
|
||||
return normalizePath(
|
||||
path.join(
|
||||
locale,
|
||||
notes?.link || '',
|
||||
note?.link || getCurrentDirname(note, filepath),
|
||||
nanoid(),
|
||||
'/',
|
||||
),
|
||||
return pathJoin(
|
||||
locale,
|
||||
notes?.link || '',
|
||||
note?.link || getCurrentDirname(note?.dir, filepath),
|
||||
nanoid(),
|
||||
'/',
|
||||
)
|
||||
},
|
||||
},
|
||||
@ -192,9 +162,7 @@ export default function autoFrontmatter(
|
||||
if (permalink)
|
||||
return permalink
|
||||
const locale = resolveLocale(filepath)
|
||||
return normalizePath(
|
||||
path.join(locale, articlePrefix, nanoid(), '/'),
|
||||
)
|
||||
return pathJoin(locale, articlePrefix, nanoid(), '/')
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -18,10 +18,11 @@ import { iconifyPlugin } from '@vuepress-plume/plugin-iconify'
|
||||
import { notesDataPlugin } from '@vuepress-plume/plugin-notes-data'
|
||||
import { shikijiPlugin } from '@vuepress-plume/plugin-shikiji'
|
||||
import { commentPlugin } from 'vuepress-plugin-comment2'
|
||||
import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
|
||||
import { useReadingTimePlugin } from 'vuepress-plugin-reading-time2'
|
||||
import { type MarkdownEnhanceOptions, mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
|
||||
import { readingTimePlugin } from 'vuepress-plugin-reading-time2'
|
||||
import { seoPlugin } from 'vuepress-plugin-seo2'
|
||||
import { sitemapPlugin } from 'vuepress-plugin-sitemap2'
|
||||
import { contentUpdatePlugin } from '@vuepress-plume/plugin-content-update'
|
||||
import type {
|
||||
PlumeThemeLocaleOptions,
|
||||
PlumeThemePluginOptions,
|
||||
@ -41,10 +42,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
if (options.readingTime !== false)
|
||||
useReadingTimePlugin(app, options.readingTime || {}, true)
|
||||
|
||||
return [
|
||||
const plugins: PluginConfig = [
|
||||
palettePlugin({ preset: 'sass' }),
|
||||
|
||||
themeDataPlugin({
|
||||
@ -55,6 +53,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
: undefined,
|
||||
} as any,
|
||||
}),
|
||||
|
||||
autoFrontmatterPlugin(autoFrontmatter(app, options, localeOptions)),
|
||||
|
||||
blogDataPlugin({
|
||||
@ -85,113 +84,134 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
},
|
||||
}),
|
||||
|
||||
localeOptions.notes ? notesDataPlugin(localeOptions.notes) : [],
|
||||
|
||||
iconifyPlugin(),
|
||||
|
||||
contentUpdatePlugin(),
|
||||
|
||||
activeHeaderLinksPlugin({
|
||||
headerLinkSelector: 'a.outline-link',
|
||||
headerAnchorSelector: '.header-anchor',
|
||||
delay: 200,
|
||||
offset: 20,
|
||||
}),
|
||||
|
||||
options.nprogress !== false ? nprogressPlugin() : [],
|
||||
|
||||
options.git !== false
|
||||
? gitPlugin({
|
||||
createdTime: false,
|
||||
updatedTime: localeOptions.lastUpdated !== false,
|
||||
contributors: localeOptions.contributors !== false,
|
||||
})
|
||||
: [],
|
||||
|
||||
options.mediumZoom !== false
|
||||
? mediumZoomPlugin({
|
||||
selector: '.plume-content > img, .plume-content :not(a) > img',
|
||||
zoomOptions: {
|
||||
background: 'var(--vp-c-bg)',
|
||||
},
|
||||
delay: 300,
|
||||
})
|
||||
: [],
|
||||
|
||||
options.caniuse !== false
|
||||
? caniusePlugin(
|
||||
options.caniuse || {
|
||||
mode: 'embed',
|
||||
},
|
||||
)
|
||||
: [],
|
||||
|
||||
options.externalLinkIcon !== false
|
||||
? externalLinkIconPlugin({
|
||||
locales: Object.entries(localeOptions.locales || {}).reduce(
|
||||
(result: Record<string, any>, [key, value]) => {
|
||||
result[key] = {
|
||||
openInNewWindow:
|
||||
value.openInNewWindow ?? localeOptions.openInNewWindow,
|
||||
}
|
||||
return result
|
||||
},
|
||||
{},
|
||||
),
|
||||
})
|
||||
: [],
|
||||
|
||||
options.search !== false ? searchPlugin(options.search) : [],
|
||||
options.docsearch !== false && !options.search
|
||||
? docsearchPlugin(options.docsearch!)
|
||||
: [],
|
||||
|
||||
options.shikiji !== false
|
||||
? shikijiPlugin({
|
||||
theme: { light: 'vitesse-light', dark: 'vitesse-dark' },
|
||||
...(options.shikiji ?? {}),
|
||||
})
|
||||
: [],
|
||||
|
||||
options.copyCode !== false
|
||||
? copyCodePlugin({
|
||||
selector: '.plume-content div[class*="language-"] pre',
|
||||
...options.copyCode,
|
||||
})
|
||||
: [],
|
||||
|
||||
options.markdownEnhance !== false
|
||||
? mdEnhancePlugin(
|
||||
Object.assign(
|
||||
{
|
||||
hint: true, // info note tip warning danger details d
|
||||
codetabs: true,
|
||||
tabs: true,
|
||||
align: true,
|
||||
mark: true,
|
||||
tasklist: true,
|
||||
demo: true,
|
||||
attrs: true,
|
||||
},
|
||||
options.markdownEnhance || {},
|
||||
),
|
||||
)
|
||||
: [],
|
||||
|
||||
options.comment !== false ? commentPlugin(options.comment || {}) : [],
|
||||
|
||||
options.baiduTongji !== false && options.baiduTongji?.key
|
||||
? baiduTongjiPlugin(options.baiduTongji)
|
||||
: [],
|
||||
|
||||
options.sitemap !== false && localeOptions.hostname && isProd
|
||||
? sitemapPlugin({
|
||||
hostname: localeOptions.hostname,
|
||||
})
|
||||
: [],
|
||||
options.seo !== false && localeOptions.hostname && isProd
|
||||
? seoPlugin({
|
||||
hostname: localeOptions.hostname || '',
|
||||
author: localeOptions.avatar?.name,
|
||||
})
|
||||
: [],
|
||||
]
|
||||
|
||||
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,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.mediumZoom !== false) {
|
||||
plugins.push(mediumZoomPlugin({
|
||||
selector: '.plume-content > img, .plume-content :not(a) > img',
|
||||
zoomOptions: {
|
||||
background: 'var(--vp-c-bg)',
|
||||
},
|
||||
delay: 300,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.caniuse !== false) {
|
||||
plugins.push(caniusePlugin(
|
||||
options.caniuse || {
|
||||
mode: 'embed',
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
if (options.externalLinkIcon !== false) {
|
||||
plugins.push(externalLinkIconPlugin({
|
||||
locales: Object.entries(localeOptions.locales || {}).reduce(
|
||||
(result: Record<string, any>, [key, value]) => {
|
||||
result[key] = {
|
||||
openInNewWindow:
|
||||
value.openInNewWindow ?? localeOptions.openInNewWindow,
|
||||
}
|
||||
return result
|
||||
},
|
||||
{},
|
||||
),
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.search !== false)
|
||||
plugins.push(searchPlugin(options.search))
|
||||
|
||||
if (options.docsearch !== false && !options.search) {
|
||||
if (options.docsearch?.appId && options.docsearch?.apiKey) {
|
||||
plugins.push(docsearchPlugin(options.docsearch))
|
||||
}
|
||||
else {
|
||||
console.error(
|
||||
'docsearch plugin: appId and apiKey are both required',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (options.shikiji !== false) {
|
||||
plugins.push(shikijiPlugin({
|
||||
theme: { light: 'vitesse-light', dark: 'vitesse-dark' },
|
||||
...(options.shikiji ?? {}),
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.copyCode !== false) {
|
||||
plugins.push(copyCodePlugin({
|
||||
selector: '.plume-content div[class*="language-"] pre',
|
||||
...options.copyCode,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.markdownEnhance !== false) {
|
||||
plugins.push(mdEnhancePlugin(
|
||||
Object.assign(
|
||||
{
|
||||
hint: true, // info note tip warning danger details
|
||||
codetabs: true,
|
||||
tabs: true,
|
||||
align: true,
|
||||
mark: true,
|
||||
tasklist: true,
|
||||
demo: true,
|
||||
attrs: true,
|
||||
sup: true,
|
||||
sub: true,
|
||||
} as MarkdownEnhanceOptions,
|
||||
options.markdownEnhance || {},
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
if (options.comment !== false)
|
||||
plugins.push(commentPlugin(options.comment || {}))
|
||||
|
||||
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,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.seo !== false && localeOptions.hostname && isProd) {
|
||||
plugins.push(seoPlugin({
|
||||
hostname: localeOptions.hostname || '',
|
||||
author: localeOptions.avatar?.name,
|
||||
}))
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
@ -6,10 +6,7 @@ import type {
|
||||
PlumeThemeLocaleOptions,
|
||||
PlumeThemePageData,
|
||||
} from '../shared/index.js'
|
||||
|
||||
function normalizePath(dir: string) {
|
||||
return dir.replace(/\\+/g, '/')
|
||||
}
|
||||
import { normalizePath } from './utils.js'
|
||||
|
||||
export async function setupPage(
|
||||
app: App,
|
||||
|
||||
@ -23,8 +23,7 @@ export function plumeTheme({
|
||||
plugins: setupPlugins(app, themePlugins, localeOptions),
|
||||
onInitialized: async app => await setupPage(app, localeOptions),
|
||||
extendsPage: (page: Page<PlumeThemePageData>) =>
|
||||
extendsPageData(app, page, localeOptions)
|
||||
,
|
||||
extendsPageData(app, page, localeOptions),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
theme/src/node/utils.ts
Normal file
33
theme/src/node/utils.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { customAlphabet } from 'nanoid'
|
||||
|
||||
export const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
|
||||
|
||||
export function getPackage() {
|
||||
let pkg = {} as any
|
||||
try {
|
||||
const content = fs.readFileSync(path.join(process.cwd(), '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, '/')
|
||||
}
|
||||
|
||||
export function pathJoin(...args: string[]) {
|
||||
return normalizePath(path.join(...args))
|
||||
}
|
||||
|
||||
const RE_START_END_SLASH = /^\/|\/$/g
|
||||
export function getCurrentDirname(basePath: string | undefined, filepath: string) {
|
||||
const dirList = normalizePath(basePath || path.dirname(filepath))
|
||||
.replace(RE_START_END_SLASH, '')
|
||||
.split('/')
|
||||
return dirList.length > 0 ? dirList[dirList.length - 1] : ''
|
||||
}
|
||||
@ -50,7 +50,7 @@ export interface PlumeThemePluginOptions {
|
||||
|
||||
baiduTongji?: false | BaiduTongjiOptions
|
||||
|
||||
frontmatter?: AutoFrontmatterOptions
|
||||
frontmatter?: Omit<AutoFrontmatterOptions, 'frontmatter'>
|
||||
|
||||
readingTime?: false | ReadingTimeOptions
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
"@internal/notesData": [
|
||||
"./plugins/plugin-notes-data/src/client/notesData.d.ts"
|
||||
],
|
||||
"@internal/pageComponents": ["./docs/.vuepress/.temp/internal/pageComponents.js"],
|
||||
"@internal/*": ["./docs/.vuepress/.temp/internal/*"],
|
||||
"@vuepress-plume/*": ["./plugins/*/src/node/index.ts"],
|
||||
"vuepress-theme-plume": ["./theme/src/node/index.ts"],
|
||||
@ -25,5 +26,5 @@
|
||||
"docs/.vuepress/**/*",
|
||||
"scripts/**/*"
|
||||
],
|
||||
"exclude": ["node_modules", ".temp", ".cache", "lib", "dist"]
|
||||
"exclude": ["node_modules", ".cache", "lib", "dist"]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user