From e409ece6fd11920500b038722966924a2752ab37 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Tue, 20 Feb 2024 01:40:11 +0800 Subject: [PATCH 1/5] feat: add `plugin-search` (power by minisearch) --- plugins/plugin-search/LICENSE | 21 + plugins/plugin-search/README.md | 26 + plugins/plugin-search/package.json | 63 ++ .../src/client/components/Search.vue | 72 ++ .../src/client/components/SearchBox.vue | 703 ++++++++++++++++++ .../src/client/components/SearchButton.vue | 188 +++++ .../src/client/components/icons/BackIcon.vue | 17 + .../src/client/components/icons/ClearIcon.vue | 17 + .../client/components/icons/SearchIcon.vue | 19 + .../src/client/composables/index.ts | 1 + .../src/client/composables/locale.ts | 31 + .../src/client/composables/searchIndex.ts | 19 + plugins/plugin-search/src/client/config.ts | 21 + plugins/plugin-search/src/client/index.ts | 7 + plugins/plugin-search/src/client/shim.d.ts | 20 + plugins/plugin-search/src/client/utils/lru.ts | 39 + plugins/plugin-search/src/node/index.ts | 8 + .../src/node/prepareSearchIndex.ts | 196 +++++ .../plugin-search/src/node/searchPlugin.ts | 45 ++ plugins/plugin-search/src/shared/index.ts | 47 ++ plugins/plugin-search/tsconfig.build.json | 14 + 21 files changed, 1574 insertions(+) create mode 100644 plugins/plugin-search/LICENSE create mode 100644 plugins/plugin-search/README.md create mode 100644 plugins/plugin-search/package.json create mode 100644 plugins/plugin-search/src/client/components/Search.vue create mode 100644 plugins/plugin-search/src/client/components/SearchBox.vue create mode 100644 plugins/plugin-search/src/client/components/SearchButton.vue create mode 100644 plugins/plugin-search/src/client/components/icons/BackIcon.vue create mode 100644 plugins/plugin-search/src/client/components/icons/ClearIcon.vue create mode 100644 plugins/plugin-search/src/client/components/icons/SearchIcon.vue create mode 100644 plugins/plugin-search/src/client/composables/index.ts create mode 100644 plugins/plugin-search/src/client/composables/locale.ts create mode 100644 plugins/plugin-search/src/client/composables/searchIndex.ts create mode 100644 plugins/plugin-search/src/client/config.ts create mode 100644 plugins/plugin-search/src/client/index.ts create mode 100644 plugins/plugin-search/src/client/shim.d.ts create mode 100644 plugins/plugin-search/src/client/utils/lru.ts create mode 100644 plugins/plugin-search/src/node/index.ts create mode 100644 plugins/plugin-search/src/node/prepareSearchIndex.ts create mode 100644 plugins/plugin-search/src/node/searchPlugin.ts create mode 100644 plugins/plugin-search/src/shared/index.ts create mode 100644 plugins/plugin-search/tsconfig.build.json diff --git a/plugins/plugin-search/LICENSE b/plugins/plugin-search/LICENSE new file mode 100644 index 00000000..9f677c90 --- /dev/null +++ b/plugins/plugin-search/LICENSE @@ -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. diff --git a/plugins/plugin-search/README.md b/plugins/plugin-search/README.md new file mode 100644 index 00000000..5634a110 --- /dev/null +++ b/plugins/plugin-search/README.md @@ -0,0 +1,26 @@ +# `@vuepress-plume/plugin-search` + +使用 [`minisearch`](https://lucaong.github.io/minisearch/) 实现的本地 全文模糊搜索 插件。 + +## Install + +```sh +npm install @vuepress-plume/plugin-search +# or +pnpm add @vuepress-plume/plugin-search +# or +yarn add @vuepress-plume/plugin-search +``` +## Usage +``` js +// .vuepress/config.[jt]s +import { searchPlugin } from '@vuepress-plume/plugin-search' + +export default { + // ... + plugins: [ + searchPlugin() + ] + // ... +} +``` diff --git a/plugins/plugin-search/package.json b/plugins/plugin-search/package.json new file mode 100644 index 00000000..6162a825 --- /dev/null +++ b/plugins/plugin-search/package.json @@ -0,0 +1,63 @@ +{ + "name": "@vuepress-plume/plugin-search", + "type": "module", + "version": "1.0.0-rc.35", + "description": "The Plugin for VuePres 2 - mini search", + "author": "pengzhanbo ", + "license": "MIT", + "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", + "directory": "plugins/plugin-search" + }, + "bugs": { + "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" + }, + "exports": { + ".": { + "types": "./lib/node/index.d.ts", + "import": "./lib/node/index.js" + }, + "./client": { + "types": "./lib/client/index.d.ts", + "import": "./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", + "dev": "pnpm copy --watch", + "clean": "rimraf --glob ./lib ./*.tsbuildinfo", + "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", + "ts": "tsc -b tsconfig.build.json" + }, + "peerDependencies": { + "vuepress": "2.0.0-rc.7" + }, + "dependencies": { + "@vuepress/helper": "2.0.0-rc.14", + "@vueuse/core": "^10.7.2", + "@vueuse/integrations": "^10.7.2", + "chokidar": "^3.6.0", + "focus-trap": "^7.5.4", + "mark.js": "^8.11.1", + "minisearch": "^6.3.0", + "p-map": "^7.0.1", + "vue": "^3.4.19" + }, + "publishConfig": { + "access": "public" + }, + "keyword": [ + "VuePress", + "vuepress plugin", + "mini search", + "vuepress-plugin-search" + ] +} diff --git a/plugins/plugin-search/src/client/components/Search.vue b/plugins/plugin-search/src/client/components/Search.vue new file mode 100644 index 00000000..b7e7d671 --- /dev/null +++ b/plugins/plugin-search/src/client/components/Search.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/plugins/plugin-search/src/client/components/SearchBox.vue b/plugins/plugin-search/src/client/components/SearchBox.vue new file mode 100644 index 00000000..ef94a45f --- /dev/null +++ b/plugins/plugin-search/src/client/components/SearchBox.vue @@ -0,0 +1,703 @@ + + + + + + + diff --git a/plugins/plugin-search/src/client/components/SearchButton.vue b/plugins/plugin-search/src/client/components/SearchButton.vue new file mode 100644 index 00000000..44252e63 --- /dev/null +++ b/plugins/plugin-search/src/client/components/SearchButton.vue @@ -0,0 +1,188 @@ + + + + + diff --git a/plugins/plugin-search/src/client/components/icons/BackIcon.vue b/plugins/plugin-search/src/client/components/icons/BackIcon.vue new file mode 100644 index 00000000..a20c906a --- /dev/null +++ b/plugins/plugin-search/src/client/components/icons/BackIcon.vue @@ -0,0 +1,17 @@ + diff --git a/plugins/plugin-search/src/client/components/icons/ClearIcon.vue b/plugins/plugin-search/src/client/components/icons/ClearIcon.vue new file mode 100644 index 00000000..c1fc86d8 --- /dev/null +++ b/plugins/plugin-search/src/client/components/icons/ClearIcon.vue @@ -0,0 +1,17 @@ + diff --git a/plugins/plugin-search/src/client/components/icons/SearchIcon.vue b/plugins/plugin-search/src/client/components/icons/SearchIcon.vue new file mode 100644 index 00000000..8a2b65a9 --- /dev/null +++ b/plugins/plugin-search/src/client/components/icons/SearchIcon.vue @@ -0,0 +1,19 @@ + diff --git a/plugins/plugin-search/src/client/composables/index.ts b/plugins/plugin-search/src/client/composables/index.ts new file mode 100644 index 00000000..f7bc56cf --- /dev/null +++ b/plugins/plugin-search/src/client/composables/index.ts @@ -0,0 +1 @@ +export * from './searchIndex.js' diff --git a/plugins/plugin-search/src/client/composables/locale.ts b/plugins/plugin-search/src/client/composables/locale.ts new file mode 100644 index 00000000..50aad5cf --- /dev/null +++ b/plugins/plugin-search/src/client/composables/locale.ts @@ -0,0 +1,31 @@ +import type { MaybeRef } from 'vue' +import { useRouteLocale } from 'vuepress/client' +import { computed, toRef } from 'vue' +import type { SearchBoxLocales } from '../../shared/index.js' + +const defaultLocales: SearchBoxLocales = { + '/': { + placeholder: 'Search', + resetButtonTitle: 'Reset search', + backButtonTitle: 'Close search', + noResultsText: 'No results for', + footer: { + selectText: 'to select', + selectKeyAriaLabel: 'enter', + navigateText: 'to navigate', + navigateUpKeyAriaLabel: 'up arrow', + navigateDownKeyAriaLabel: 'down arrow', + closeText: 'to close', + closeKeyAriaLabel: 'escape', + }, + }, +} + +export function useLocale(locales: MaybeRef) { + const localesRef = toRef(locales) + const routeLocale = useRouteLocale() + + const locale = computed(() => localesRef.value[routeLocale.value] ?? defaultLocales[routeLocale.value] ?? defaultLocales['/']) + + return locale +} diff --git a/plugins/plugin-search/src/client/composables/searchIndex.ts b/plugins/plugin-search/src/client/composables/searchIndex.ts new file mode 100644 index 00000000..5b136422 --- /dev/null +++ b/plugins/plugin-search/src/client/composables/searchIndex.ts @@ -0,0 +1,19 @@ +import { searchIndex } from '@internal/minisearchIndex' +import { shallowRef } from 'vue' + +declare const __VUE_HMR_RUNTIME__: Record + +const searchIndexData = shallowRef(searchIndex) + +export function useSearchIndex() { + return searchIndexData +} + +if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { + __VUE_HMR_RUNTIME__.updateSearchIndex = (data) => { + searchIndexData.value = data + } + __VUE_HMR_RUNTIME__.updateSearchIndex = (data) => { + searchIndexData.value = data + } +} diff --git a/plugins/plugin-search/src/client/config.ts b/plugins/plugin-search/src/client/config.ts new file mode 100644 index 00000000..57fda3e3 --- /dev/null +++ b/plugins/plugin-search/src/client/config.ts @@ -0,0 +1,21 @@ +import { defineClientConfig } from 'vuepress/client' +import type { ClientConfig } from 'vuepress/client' +import { h } from 'vue' +import type { SearchBoxLocales, SearchOptions } from '../shared/index.js' +import Search from './components/Search.vue' + +declare const __SEARCH_LOCALES__: SearchBoxLocales +declare const __SEARCH_OPTIONS__: SearchOptions + +const locales = __SEARCH_LOCALES__ +const searchOptions = __SEARCH_OPTIONS__ + +export default defineClientConfig({ + enhance({ app }) { + app.component('SearchBox', props => h(Search, { + locales, + options: searchOptions, + ...props, + })) + }, +}) as ClientConfig diff --git a/plugins/plugin-search/src/client/index.ts b/plugins/plugin-search/src/client/index.ts new file mode 100644 index 00000000..e56355ad --- /dev/null +++ b/plugins/plugin-search/src/client/index.ts @@ -0,0 +1,7 @@ +import SearchBox from './components/Search.vue' +import { useSearchIndex } from './composables/index.js' + +export { + SearchBox, + useSearchIndex, +} diff --git a/plugins/plugin-search/src/client/shim.d.ts b/plugins/plugin-search/src/client/shim.d.ts new file mode 100644 index 00000000..9174445f --- /dev/null +++ b/plugins/plugin-search/src/client/shim.d.ts @@ -0,0 +1,20 @@ +declare module '*.vue' { + import type { ComponentOptions } from 'vue' + + const comp: ComponentOptions + export default comp +} + +declare module '@internal/minisearchIndex' { + const searchIndex: Record Promise<{ default: string }>> + export { + searchIndex, + } +} + +declare module 'mark.js/src/vanilla.js' { + import type Mark from 'mark.js' + + const mark: typeof Mark + export default mark +} diff --git a/plugins/plugin-search/src/client/utils/lru.ts b/plugins/plugin-search/src/client/utils/lru.ts new file mode 100644 index 00000000..191a6f0c --- /dev/null +++ b/plugins/plugin-search/src/client/utils/lru.ts @@ -0,0 +1,39 @@ +// adapted from https://stackoverflow.com/a/46432113/11613622 + +export class LRUCache { + private max: number + private cache: Map + + constructor(max: number = 10) { + this.max = max + this.cache = new Map() + } + + get(key: K): V | undefined { + const item = this.cache.get(key) + if (item !== undefined) { + // refresh key + this.cache.delete(key) + this.cache.set(key, item) + } + return item + } + + set(key: K, val: V): void { + // refresh key + if (this.cache.has(key)) + this.cache.delete(key) + // evict oldest + else if (this.cache.size === this.max) + this.cache.delete(this.first()!) + this.cache.set(key, val) + } + + first(): K | undefined { + return this.cache.keys().next().value + } + + clear(): void { + this.cache.clear() + } +} diff --git a/plugins/plugin-search/src/node/index.ts b/plugins/plugin-search/src/node/index.ts new file mode 100644 index 00000000..3f3c644c --- /dev/null +++ b/plugins/plugin-search/src/node/index.ts @@ -0,0 +1,8 @@ +import { searchPlugin } from './searchPlugin.js' + +export { prepareSearchIndex } from './prepareSearchIndex.js' +export * from '../shared/index.js' + +export { + searchPlugin, +} diff --git a/plugins/plugin-search/src/node/prepareSearchIndex.ts b/plugins/plugin-search/src/node/prepareSearchIndex.ts new file mode 100644 index 00000000..ff531e98 --- /dev/null +++ b/plugins/plugin-search/src/node/prepareSearchIndex.ts @@ -0,0 +1,196 @@ +import type { App, Page } from 'vuepress/core' +import MiniSearch from 'minisearch' +import pMap from 'p-map' +import type { SearchOptions, SearchPluginOptions } from '../shared/index.js' + +export interface SearchIndexOptions { + app: App + searchOptions: SearchOptions + isSearchable: SearchPluginOptions['isSearchable'] +} + +interface IndexObject { + id: string + text: string + title: string + titles: string[] +} + +const SEARCH_INDEX_DIR = 'internal/minisearchIndex/' +const indexByLocales = new Map>() +const indexCache = new Map() + +function getIndexByLocale(locale: string, options: SearchIndexOptions['searchOptions']) { + let index = indexByLocales.get(locale) + if (!index) { + index = new MiniSearch({ + fields: ['title', 'titles', 'text'], + storeFields: ['title', 'titles'], + ...options.miniSearch?.options, + }) + indexByLocales.set(locale, index) + } + return index +} + +function getIndexCache(filepath: string) { + let index = indexCache.get(filepath) + if (!index) { + index = [] + indexCache.set(filepath, index) + } + return index +} + +export async function prepareSearchIndex({ + app, + isSearchable, + searchOptions, +}: SearchIndexOptions) { + const pages = isSearchable ? app.pages.filter(isSearchable) : app.pages + await pMap(pages, p => indexFile(p, searchOptions), { + concurrency: 64, + }) + await writeTemp(app) +} + +export async function onSearchIndexUpdated( + filepath: string, + { + app, + isSearchable, + searchOptions, + }: SearchIndexOptions, +) { + const pages = isSearchable ? app.pages.filter(isSearchable) : app.pages + if (pages.some(p => p.filePathRelative?.endsWith(filepath))) { + await indexFile(app.pages.find(p => p.filePathRelative?.endsWith(filepath))!, searchOptions) + await writeTemp(app) + } +} + +export async function onSearchIndexRemoved( + filepath: string, + { + app, + isSearchable, + searchOptions, + }: SearchIndexOptions, +) { + const pages = isSearchable ? app.pages.filter(isSearchable) : app.pages + if (pages.some(p => p.filePathRelative?.endsWith(filepath))) { + const page = app.pages.find(p => p.filePathRelative?.endsWith(filepath))! + const fileId = page.path + const locale = page.pathLocale + const index = getIndexByLocale(locale, searchOptions) + const cache = getIndexCache(fileId) + index.removeAll(cache) + await writeTemp(app) + } +} + +async function writeTemp(app: App) { + const records: string[] = [] + for (const [locale] of indexByLocales) { + const index = indexByLocales.get(locale)! + const localeName = locale.replace(/^\/|\/$/g, '').replace(/\//g, '_') || 'default' + const filename = `searchBox-${localeName}.js` + records.push(`${JSON.stringify(locale)}: () => import('@${SEARCH_INDEX_DIR}${filename}')`) + await app.writeTemp( + `${SEARCH_INDEX_DIR}${filename}`, + `export default ${JSON.stringify( + JSON.stringify(index) ?? {}, + )}`, + ) + } + await app.writeTemp( + `${SEARCH_INDEX_DIR}index.js`, + `export const searchIndex = {${records.join(',')}}${app.env.isDev ? `\n${genHmrCode('searchIndex')}` : ''}`, + ) +} + +async function indexFile(page: Page, options: SearchIndexOptions['searchOptions']) { + // get file metadata + const fileId = page.path + const locale = page.pathLocale + const index = getIndexByLocale(locale, options) + const cache = getIndexCache(fileId) + // retrieve file and split into "sections" + const html = page.contentRendered + const sections = splitPageIntoSections(html) + + if (cache && cache.length) + index.removeAll(cache) + + // add sections to the locale index + for await (const section of sections) { + if (!section || !(section.text || section.titles)) + break + const { anchor, text, titles } = section + const id = anchor ? [fileId, anchor].join('#') : fileId + const item = { + id, + text, + title: titles.at(-1)!, + titles: titles.slice(0, -1), + } + index.add(item) + cache.push(item) + } +} + +const headingRegex = /(.*?<\/a>)<\/h\1>/gi +const headingContentRegex = /(.*?)<\/a>/i + +/** + * Splits HTML into sections based on headings + */ +function* splitPageIntoSections(html: string) { + const result = html.split(headingRegex) + result.shift() + let parentTitles: string[] = [] + for (let i = 0; i < result.length; i += 3) { + const level = Number.parseInt(result[i]) - 1 + const heading = result[i + 1] + const headingResult = headingContentRegex.exec(heading) + const title = clearHtmlTags(headingResult?.[2] ?? '').trim() + const anchor = headingResult?.[1] ?? '' + const content = result[i + 2] + if (!title || !content) + continue + const titles = parentTitles.slice(0, level) + titles[level] = title + yield { anchor, titles, text: getSearchableText(content) } + if (level === 0) + parentTitles = [title] + else + parentTitles[level] = title + } +} + +function getSearchableText(content: string) { + content = clearHtmlTags(content) + return content +} + +function clearHtmlTags(str: string) { + return str.replace(/<[^>]*>/g, '') +} + +function genHmrCode(m: string) { + const func = `update${m[0].toUpperCase()}${m.slice(1)}` + return ` +if (import.meta.webpackHot) { + import.meta.webpackHot.accept() + if (__VUE_HMR_RUNTIME__.${m}) { + __VUE_HMR_RUNTIME__.${func}(${m}) + } +} + +if (import.meta.hot) { + import.meta.hot.accept(({ ${m} }) => { + __VUE_HMR_RUNTIME__.${func}(${m}) + }) +} +` +} diff --git a/plugins/plugin-search/src/node/searchPlugin.ts b/plugins/plugin-search/src/node/searchPlugin.ts new file mode 100644 index 00000000..134f9eea --- /dev/null +++ b/plugins/plugin-search/src/node/searchPlugin.ts @@ -0,0 +1,45 @@ +import chokidar from 'chokidar' +import type { Plugin } from 'vuepress/core' +import { getDirname, path } from 'vuepress/utils' +import { addViteOptimizeDepsInclude } from '@vuepress/helper' +import type { SearchPluginOptions } from '../shared/index.js' +import { onSearchIndexRemoved, onSearchIndexUpdated, prepareSearchIndex } from './prepareSearchIndex.js' + +const __dirname = getDirname(import.meta.url) + +export function searchPlugin({ + locales = {}, + isSearchable, + ...searchOptions +}: SearchPluginOptions = {}): Plugin { + return app => ({ + name: '@vuepress-plume/plugin-search', + clientConfigFile: path.resolve(__dirname, '../client/config.js'), + define: { + __SEARCH_LOCALES__: locales, + __SEARCH_OPTIONS__: searchOptions, + }, + extendsBundlerOptions(bundlerOptions) { + addViteOptimizeDepsInclude(bundlerOptions, app, ['mark.js/src/vanilla.js', '@vueuse/integrations/useFocusTrap', 'minisearch']) + }, + onPrepared: async (app) => { + await prepareSearchIndex({ app, isSearchable, searchOptions }) + }, + onWatched: async (app, watchers) => { + const searchIndexWatcher = chokidar.watch('pages/**/*.js', { + cwd: app.dir.temp(), + ignoreInitial: true, + }) + searchIndexWatcher.on('add', (filepath) => { + onSearchIndexUpdated(filepath, { app, isSearchable, searchOptions }) + }) + searchIndexWatcher.on('change', (filepath) => { + onSearchIndexUpdated(filepath, { app, isSearchable, searchOptions }) + }) + searchIndexWatcher.on('unlink', (filepath) => { + onSearchIndexRemoved(filepath, { app, isSearchable, searchOptions }) + }) + watchers.push(searchIndexWatcher) + }, + }) +} diff --git a/plugins/plugin-search/src/shared/index.ts b/plugins/plugin-search/src/shared/index.ts new file mode 100644 index 00000000..688c255b --- /dev/null +++ b/plugins/plugin-search/src/shared/index.ts @@ -0,0 +1,47 @@ +import type { LocaleConfig, Page } from 'vuepress/core' +import type { Options as MiniSearchOptions } from 'minisearch' + +export type SearchBoxLocales = LocaleConfig<{ + placeholder: string + buttonText: string + resetButtonTitle: string + backButtonTitle: string + noResultsText: string + footer: { + selectText: string + selectKeyAriaLabel: string + navigateText: string + navigateUpKeyAriaLabel: string + navigateDownKeyAriaLabel: string + closeText: string + closeKeyAriaLabel: string + } +}> + +export interface SearchPluginOptions extends SearchOptions { + locales?: SearchBoxLocales + + isSearchable?: (page: Page) => boolean + +} + +export interface SearchOptions { + /** + * @default false + */ + disableQueryPersistence?: boolean + + miniSearch?: { + /** + * @see https://lucaong.github.io/minisearch/modules/_minisearch_.html#options + */ + options?: Pick< + MiniSearchOptions, + 'extractField' | 'tokenize' | 'processTerm' + > + /** + * @see https://lucaong.github.io/minisearch/modules/_minisearch_.html#searchoptions-1 + */ + searchOptions?: MiniSearchOptions['searchOptions'] + } +} diff --git a/plugins/plugin-search/tsconfig.build.json b/plugins/plugin-search/tsconfig.build.json new file mode 100644 index 00000000..39382ae6 --- /dev/null +++ b/plugins/plugin-search/tsconfig.build.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "./src", + "types": [ + "vuepress/client-types", + "vite/client", + "webpack-env" + ], + "outDir": "./lib" + }, + "include": ["./src"] +} From 5159c5a434adb3be3b02c5bdc5fa8d28d196f191 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Tue, 20 Feb 2024 01:41:09 +0800 Subject: [PATCH 2/5] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- theme/src/client/styles/search.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/theme/src/client/styles/search.scss b/theme/src/client/styles/search.scss index cc6c9f7c..41b3d9d7 100644 --- a/theme/src/client/styles/search.scss +++ b/theme/src/client/styles/search.scss @@ -141,6 +141,11 @@ font-size: 12px; color: var(--docsearch-muted-color); letter-spacing: normal; + content: "Ctrl"; +} + +.mac .DocSearch-Button .DocSearch-Button-Key:first-child::after { + content: "\2318"; } .DocSearch-Button .DocSearch-Button-Key:first-child > * { From cec3191adc4854a2f4beacad968019f5baba26e0 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Tue, 20 Feb 2024 01:42:00 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(theme):=20=E5=88=87=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E5=86=85=E9=83=A8=E6=90=9C=E7=B4=A2=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vuepress/theme.ts | 10 +- plugins/tsconfig.build.json | 3 +- pnpm-lock.yaml | 138 ++++++++++++++++++++++---- theme/package.json | 2 +- theme/src/node/plugins.ts | 2 +- theme/src/node/searchPluginOptions.ts | 34 ++++++- theme/src/node/theme.ts | 11 +- theme/src/shared/options/plugins.ts | 2 +- 8 files changed, 167 insertions(+), 35 deletions(-) diff --git a/docs/.vuepress/theme.ts b/docs/.vuepress/theme.ts index ab688ba6..bdd70673 100644 --- a/docs/.vuepress/theme.ts +++ b/docs/.vuepress/theme.ts @@ -30,10 +30,10 @@ export const theme: Theme = themePlume({ }, }, plugins: { - docsearch: { - apiKey: '111', - appId: '111', - indexName: '1234', - }, + // docsearch: { + // apiKey: '111', + // appId: '111', + // indexName: '1234', + // }, }, }) diff --git a/plugins/tsconfig.build.json b/plugins/tsconfig.build.json index 1f591418..a3ed6c22 100644 --- a/plugins/tsconfig.build.json +++ b/plugins/tsconfig.build.json @@ -14,7 +14,8 @@ { "path": "./plugin-notes-data/tsconfig.build.json" }, { "path": "./plugin-page-collection/tsconfig.build.json" }, { "path": "./plugin-shikiji/tsconfig.build.json" }, - { "path": "./plugin-content-update/tsconfig.build.json" } + { "path": "./plugin-content-update/tsconfig.build.json" }, + { "path": "./plugin-search/tsconfig.build.json" } ], "files": [] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 608ca32f..740e2003 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -274,6 +274,39 @@ importers: specifier: workspace:* version: link:../plugin-netlify-functions + plugins/plugin-search: + dependencies: + '@vuepress/helper': + specifier: 2.0.0-rc.14 + version: 2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7) + '@vueuse/core': + specifier: ^10.7.2 + version: 10.7.2(vue@3.4.19) + '@vueuse/integrations': + specifier: ^10.7.2 + version: 10.7.2(focus-trap@7.5.4)(vue@3.4.19) + chokidar: + specifier: ^3.6.0 + version: 3.6.0 + focus-trap: + specifier: ^7.5.4 + version: 7.5.4 + mark.js: + specifier: ^8.11.1 + version: 8.11.1 + minisearch: + specifier: ^6.3.0 + version: 6.3.0 + p-map: + specifier: ^7.0.1 + version: 7.0.1 + vue: + specifier: ^3.4.19 + version: 3.4.19(typescript@5.3.3) + vuepress: + specifier: 2.0.0-rc.7 + version: 2.0.0-rc.7(@vuepress/bundler-vite@2.0.0-rc.7)(@vuepress/bundler-webpack@2.0.0-rc.7)(typescript@5.3.3)(vue@3.4.19) + plugins/plugin-shikiji: dependencies: '@shikijs/transformers': @@ -321,6 +354,9 @@ importers: '@vuepress-plume/plugin-notes-data': specifier: workspace:* version: link:../plugins/plugin-notes-data + '@vuepress-plume/plugin-search': + specifier: workspace:* + version: link:../plugins/plugin-search '@vuepress-plume/plugin-shikiji': specifier: workspace:* version: link:../plugins/plugin-shikiji @@ -351,9 +387,6 @@ importers: '@vuepress/plugin-reading-time': specifier: 2.0.0-rc.14 version: 2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7) - '@vuepress/plugin-search': - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7) '@vuepress/plugin-seo': specifier: 2.0.0-rc.14 version: 2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7) @@ -3997,7 +4030,7 @@ packages: '@vue/shared': 3.4.19 estree-walker: 2.0.2 magic-string: 0.30.7 - postcss: 8.4.33 + postcss: 8.4.35 source-map-js: 1.0.2 /@vue/compiler-ssr@3.4.19: @@ -4328,19 +4361,6 @@ packages: - typescript dev: false - /@vuepress/plugin-search@2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7): - resolution: {integrity: sha512-os2Kzj1hePpX5rxmJUSLs783G0EVTuiwFT2gPPBw/3yZbRCXCTnAM6xAVK2vv36Ysa4fgfFETLG4omg1b3rOvQ==} - peerDependencies: - vuepress: 2.0.0-rc.7 - dependencies: - chokidar: 3.6.0 - vue: 3.4.19(typescript@5.3.3) - vue-router: 4.2.5(vue@3.4.19) - vuepress: 2.0.0-rc.7(@vuepress/bundler-vite@2.0.0-rc.7)(@vuepress/bundler-webpack@2.0.0-rc.7)(typescript@5.3.3)(vue@3.4.19) - transitivePeerDependencies: - - typescript - dev: false - /@vuepress/plugin-seo@2.0.0-rc.14(typescript@5.3.3)(vuepress@2.0.0-rc.7): resolution: {integrity: sha512-ffYc6XObhei863X/g3BTlJrx+EIWRPmtv/NLp9EDKO72KJX3C+MsDKDJOx54iL3X0DT63F/PMTMg0Y+ZhJ4qCw==} peerDependencies: @@ -4424,6 +4444,56 @@ packages: - vue dev: false + /@vueuse/integrations@10.7.2(focus-trap@7.5.4)(vue@3.4.19): + resolution: {integrity: sha512-+u3RLPFedjASs5EKPc69Ge49WNgqeMfSxFn+qrQTzblPXZg6+EFzhjarS5edj2qAf6xQ93f95TUxRwKStXj/sQ==} + peerDependencies: + async-validator: '*' + axios: '*' + change-case: '*' + drauu: '*' + focus-trap: '*' + fuse.js: '*' + idb-keyval: '*' + jwt-decode: '*' + nprogress: '*' + qrcode: '*' + sortablejs: '*' + universal-cookie: '*' + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + dependencies: + '@vueuse/core': 10.7.2(vue@3.4.19) + '@vueuse/shared': 10.7.2(vue@3.4.19) + focus-trap: 7.5.4 + vue-demi: 0.14.6(vue@3.4.19) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + /@vueuse/metadata@10.7.2: resolution: {integrity: sha512-kCWPb4J2KGrwLtn1eJwaJD742u1k5h6v/St5wFe8Quih90+k2a0JP8BS4Zp34XUuJqS2AxFYMb1wjUL8HfhWsQ==} dev: false @@ -6989,8 +7059,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dependencies: is-url: 1.2.4 - postcss: 8.4.33 - postcss-values-parser: 6.0.2(postcss@8.4.33) + postcss: 8.4.35 + postcss-values-parser: 6.0.2(postcss@8.4.35) dev: false /detective-sass@5.0.0: @@ -8453,6 +8523,12 @@ packages: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} dev: false + /focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + dependencies: + tabbable: 6.2.0 + dev: false + /folder-walker@3.2.0: resolution: {integrity: sha512-VjAQdSLsl6AkpZNyrQJfO7BXLo4chnStqb055bumZMbRUPpVuPN3a4ktsnRCmrFZjtMlYLkyXiR5rAs4WOpC4Q==} dependencies: @@ -10765,6 +10841,10 @@ packages: object-visit: 1.0.1 dev: false + /mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + dev: false + /markdown-it-anchor@8.6.7(@types/markdown-it@13.0.7)(markdown-it@14.0.0): resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} peerDependencies: @@ -11095,6 +11175,10 @@ packages: resolution: {integrity: sha512-ibvbqeslVFur0IAvTxLMvsbtvVcMo6gwvOnj0YZHV7aeDLu091VQRrETT2QuiG9P6aZWRcxeNGJChRKVPCp9VQ==} dev: false + /minisearch@6.3.0: + resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==} + dev: false + /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -11956,6 +12040,11 @@ packages: resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} engines: {node: '>=16'} + /p-map@7.0.1: + resolution: {integrity: sha512-2wnaR0XL/FDOj+TgpDuRb2KTjLnu3Fma6b1ZUwGY7LcqenMcvP/YFpjpbPKY6WVGsbuJZRuoUz8iPrt8ORnAFw==} + engines: {node: '>=18'} + dev: false + /p-reduce@3.0.0: resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==} engines: {node: '>=12'} @@ -12447,7 +12536,7 @@ packages: /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - /postcss-values-parser@6.0.2(postcss@8.4.33): + /postcss-values-parser@6.0.2(postcss@8.4.35): resolution: {integrity: sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==} engines: {node: '>=10'} peerDependencies: @@ -12455,7 +12544,7 @@ packages: dependencies: color-name: 1.1.4 is-url-superb: 4.0.0 - postcss: 8.4.33 + postcss: 8.4.35 quote-unquote: 1.0.0 dev: false @@ -12466,6 +12555,7 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: true /postcss@8.4.35: resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} @@ -13217,7 +13307,7 @@ packages: engines: {node: '>=14.0.0'} hasBin: true dependencies: - chokidar: 3.5.3 + chokidar: 3.6.0 immutable: 4.1.0 source-map-js: 1.0.2 dev: false @@ -14192,6 +14282,10 @@ packages: picocolors: 1.0.0 dev: false + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + /table@6.8.1: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} diff --git a/theme/package.json b/theme/package.json index a7d43490..10ff2e03 100644 --- a/theme/package.json +++ b/theme/package.json @@ -64,6 +64,7 @@ "@vuepress-plume/plugin-copy-code": "workspace:*", "@vuepress-plume/plugin-iconify": "workspace:*", "@vuepress-plume/plugin-notes-data": "workspace:*", + "@vuepress-plume/plugin-search": "workspace:*", "@vuepress-plume/plugin-shikiji": "workspace:*", "@vuepress/plugin-active-header-links": "2.0.0-rc.14", "@vuepress/plugin-container": "2.0.0-rc.12", @@ -74,7 +75,6 @@ "@vuepress/plugin-nprogress": "2.0.0-rc.14", "@vuepress/plugin-palette": "2.0.0-rc.14", "@vuepress/plugin-reading-time": "2.0.0-rc.14", - "@vuepress/plugin-search": "2.0.0-rc.14", "@vuepress/plugin-seo": "2.0.0-rc.14", "@vuepress/plugin-sitemap": "2.0.0-rc.14", "@vuepress/plugin-theme-data": "2.0.0-rc.14", diff --git a/theme/src/node/plugins.ts b/theme/src/node/plugins.ts index 1351462b..74a764d3 100644 --- a/theme/src/node/plugins.ts +++ b/theme/src/node/plugins.ts @@ -6,7 +6,6 @@ import { gitPlugin } from '@vuepress/plugin-git' import { mediumZoomPlugin } from '@vuepress/plugin-medium-zoom' import { nprogressPlugin } from '@vuepress/plugin-nprogress' import { palettePlugin } from '@vuepress/plugin-palette' -import { searchPlugin } from '@vuepress/plugin-search' import { themeDataPlugin } from '@vuepress/plugin-theme-data' import { autoFrontmatterPlugin } from '@vuepress-plume/plugin-auto-frontmatter' import { baiduTongjiPlugin } from '@vuepress-plume/plugin-baidu-tongji' @@ -22,6 +21,7 @@ import { readingTimePlugin } from '@vuepress/plugin-reading-time' import { seoPlugin } from '@vuepress/plugin-seo' import { sitemapPlugin } from '@vuepress/plugin-sitemap' import { contentUpdatePlugin } from '@vuepress-plume/plugin-content-update' +import { searchPlugin } from '@vuepress-plume/plugin-search' import type { PlumeThemeLocaleOptions, PlumeThemePluginOptions, diff --git a/theme/src/node/searchPluginOptions.ts b/theme/src/node/searchPluginOptions.ts index 76b8336b..a4a887d1 100644 --- a/theme/src/node/searchPluginOptions.ts +++ b/theme/src/node/searchPluginOptions.ts @@ -1,5 +1,5 @@ import type { DocsearchPluginOptions } from '@vuepress/plugin-docsearch' -import type { SearchPluginOptions } from '@vuepress/plugin-search' +import type { SearchPluginOptions } from '@vuepress-plume/plugin-search' import type { App } from 'vuepress/core' import { deepMerge } from '@pengzhanbo/utils' import { resolvedAppLocales } from './resolveLocaleOptions.js' @@ -50,8 +50,36 @@ const defaultDocsearchLocales: NonNullable = } const defaultSearchLocales: NonNullable = { - 'zh-CN': { placeholder: '搜索' }, - 'en-US': { placeholder: 'Search' }, + 'zh-CN': { + placeholder: '搜索文档', + resetButtonTitle: '重置搜索', + backButtonTitle: '关闭', + noResultsText: '无搜索结果:', + footer: { + selectText: '选择', + selectKeyAriaLabel: '输入', + navigateText: '切换', + navigateUpKeyAriaLabel: '向上', + navigateDownKeyAriaLabel: '向下', + closeText: '关闭', + closeKeyAriaLabel: '退出', + }, + }, + 'en-US': { + placeholder: 'Search', + resetButtonTitle: 'Reset search', + backButtonTitle: 'Close search', + noResultsText: 'No results for', + footer: { + selectText: 'to select', + selectKeyAriaLabel: 'enter', + navigateText: 'to navigate', + navigateUpKeyAriaLabel: 'up arrow', + navigateDownKeyAriaLabel: 'down arrow', + closeText: 'to close', + closeKeyAriaLabel: 'escape', + }, + }, } export function resolvedDocsearchOption(app: App, options: DocsearchPluginOptions): DocsearchPluginOptions { diff --git a/theme/src/node/theme.ts b/theme/src/node/theme.ts index 5efefb0b..891067d1 100644 --- a/theme/src/node/theme.ts +++ b/theme/src/node/theme.ts @@ -24,7 +24,16 @@ export function plumeTheme({ clientConfigFile: resolve('client/config.js'), plugins: setupPlugins(app, pluginsOptions, localeOptions), onInitialized: app => setupPage(app, localeOptions), - extendsPage: page => extendsPageData(app, page as Page, localeOptions), + extendsPage: (page) => { + extendsPageData(app, page as Page, localeOptions) + + page.frontmatter.head ??= [] + page.frontmatter.head?.push([ + 'script', + { id: 'check-mac-os' }, + `document.documentElement.classList.toggle('mac', /Mac|iPhone|iPod|iPad/i.test(navigator.platform))`, + ]) + }, templateBuildRenderer(template, context) { template = template .replace('{{ themeVersion }}', pkg.version || '') diff --git a/theme/src/shared/options/plugins.ts b/theme/src/shared/options/plugins.ts index 1e8b07c5..aea22b10 100644 --- a/theme/src/shared/options/plugins.ts +++ b/theme/src/shared/options/plugins.ts @@ -1,5 +1,5 @@ import type { DocsearchOptions } from '@vuepress/plugin-docsearch' -import type { SearchPluginOptions } from '@vuepress/plugin-search' +import type { SearchPluginOptions } from '@vuepress-plume/plugin-search' import type { AutoFrontmatterOptions } from '@vuepress-plume/plugin-auto-frontmatter' import type { BaiduTongjiOptions } from '@vuepress-plume/plugin-baidu-tongji' import type { CanIUsePluginOptions } from '@vuepress-plume/plugin-caniuse' From 89c8a0e1d5946c769036901fd3649c03fa1fb77a Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Wed, 21 Feb 2024 00:35:13 +0800 Subject: [PATCH 4/5] perf: bump shiki to latest --- plugins/plugin-shikiji/package.json | 6 ++-- pnpm-lock.yaml | 46 ++++++++++++++--------------- theme/src/node/container.ts | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/plugins/plugin-shikiji/package.json b/plugins/plugin-shikiji/package.json index 5c99d3f8..571d16d5 100644 --- a/plugins/plugin-shikiji/package.json +++ b/plugins/plugin-shikiji/package.json @@ -36,10 +36,10 @@ "vuepress": "2.0.0-rc.7" }, "dependencies": { - "@shikijs/transformers": "^1.1.3", - "@shikijs/twoslash": "^1.1.3", + "@shikijs/transformers": "^1.1.6", + "@shikijs/twoslash": "^1.1.6", "nanoid": "^5.0.5", - "shiki": "^1.1.3" + "shiki": "^1.1.6" }, "publishConfig": { "access": "public" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 740e2003..8622e2f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -310,17 +310,17 @@ importers: plugins/plugin-shikiji: dependencies: '@shikijs/transformers': - specifier: ^1.1.3 - version: 1.1.3 + specifier: ^1.1.6 + version: 1.1.6 '@shikijs/twoslash': - specifier: ^1.1.3 - version: 1.1.3(typescript@5.3.3) + specifier: ^1.1.6 + version: 1.1.6(typescript@5.3.3) nanoid: specifier: ^5.0.5 version: 5.0.5 shiki: - specifier: ^1.1.3 - version: 1.1.3 + specifier: ^1.1.6 + version: 1.1.6 vuepress: specifier: 2.0.0-rc.7 version: 2.0.0-rc.7(@vuepress/bundler-vite@2.0.0-rc.7)(@vuepress/bundler-webpack@2.0.0-rc.7)(typescript@5.3.3)(vue@3.4.19) @@ -3218,21 +3218,21 @@ packages: requiresBuild: true optional: true - /@shikijs/core@1.1.3: - resolution: {integrity: sha512-1QWSvWcPbvZXsDxB1F7ejW+Kuxp3z/JHs944hp/f8BYOlFd5gplzseFIkE/GTu/qytFef3zNME4qw1oHbQ0j2A==} + /@shikijs/core@1.1.6: + resolution: {integrity: sha512-kt9hhvrWTm0EPtRDIsoAZnSsFlIDBVBBI5CQewpA/NZCPin+MOKRXg+JiWc4y+8fZ/v0HzfDhu/UC+OTZGMt7A==} dev: false - /@shikijs/transformers@1.1.3: - resolution: {integrity: sha512-jv71dQFTucv2RK2pafAxca4hgKP6Uv5ukKrVjH/vGZ8jGH0j2AcLVCcM76ieamwJ1p5WkZcA0X/Bq2qpjhEUSg==} + /@shikijs/transformers@1.1.6: + resolution: {integrity: sha512-R+eI1I9sQv0MCJyfR4kAG1G1SKSctw5ILszP0tHVrAgzSHWTpaHbXreZrDueahqtUCNHjt+MKmKJ8EMFtiitOQ==} dependencies: - shiki: 1.1.3 + shiki: 1.1.6 dev: false - /@shikijs/twoslash@1.1.3(typescript@5.3.3): - resolution: {integrity: sha512-7NUEqRasZ15wWdUIusm2rQMenV2dIpNNOoCiNx7GZ4VzJxy7AwULQxgDVtYfn0u4BCgiUWqtdMYuO9uts8JSmg==} + /@shikijs/twoslash@1.1.6(typescript@5.3.3): + resolution: {integrity: sha512-0HJK7Il7HevTpRvpPlnJ0ow8UyoQxhvxQ0/lhfw1C0xW/7eLtSAtZfSKdel5Nch6HgbbtfucEzuUFmRIRXUFUg==} dependencies: - '@shikijs/core': 1.1.3 - twoslash: 0.2.3(typescript@5.3.3) + '@shikijs/core': 1.1.6 + twoslash: 0.2.4(typescript@5.3.3) transitivePeerDependencies: - supports-color - typescript @@ -13516,10 +13516,10 @@ packages: /shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - /shiki@1.1.3: - resolution: {integrity: sha512-k/B4UvtWmGcHMLp6JnQminlex3Go5MHKXEiormmzTJECAiSQiwSon6USuwTyto8EMUQc9aYRJ7HojkfVLbBk+g==} + /shiki@1.1.6: + resolution: {integrity: sha512-j4pcpvaQWHb42cHeV+W6P+X/VcK7Y2ctvEham6zB8wsuRQroT6cEMIkiUmBU2Nqg2qnHZDH6ZyRdVldcy0l6xw==} dependencies: - '@shikijs/core': 1.1.3 + '@shikijs/core': 1.1.6 dev: false /side-channel@1.0.4: @@ -14697,17 +14697,17 @@ packages: safe-buffer: 5.2.1 dev: false - /twoslash-protocol@0.2.3: - resolution: {integrity: sha512-pvNVFaYvZ2S5AvG3dN91NSxTt+JxeoJju/1ezOGhmHB+Wpa5xZuWY5nuvOkeBpqcwvwTvpjtw5d/xSV19ZMzJA==} + /twoslash-protocol@0.2.4: + resolution: {integrity: sha512-AEGTJj4mFGfvQc/M6qi0+s82Zq+mxLcjWZU+EUHGG8LQElyHDs+uDR+/3+m1l+WP7WL+QmWrVzFXgFX+hBg+bg==} dev: false - /twoslash@0.2.3(typescript@5.3.3): - resolution: {integrity: sha512-96vxkRz/IiOwrRDNniBuLLi29q9F5Vv0BAb0Jx/lhF3EhG71hcm0he4fvQllhf/ZPzUGMt/QfJX6o0cTwnZhJQ==} + /twoslash@0.2.4(typescript@5.3.3): + resolution: {integrity: sha512-hc3y11BjLHP4kV37TR6lUKksxpZp0LQi9kCy95ka6qobye/gV49PqXZIuWlRaRVGNvp4AJBMg8aiwkp0M8x/nQ==} peerDependencies: typescript: '*' dependencies: '@typescript/vfs': 1.5.0 - twoslash-protocol: 0.2.3 + twoslash-protocol: 0.2.4 typescript: 5.3.3 transitivePeerDependencies: - supports-color diff --git a/theme/src/node/container.ts b/theme/src/node/container.ts index fa9ad7f2..77410641 100644 --- a/theme/src/node/container.ts +++ b/theme/src/node/container.ts @@ -1,4 +1,4 @@ -import containerPlugin from '@vuepress/plugin-container' +import { containerPlugin } from '@vuepress/plugin-container' import type { Plugin } from 'vuepress/core' export const customContainers: Plugin[] = [ From 979d4d645f81bd6871b41a2169513a1cccd28033 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Wed, 21 Feb 2024 03:52:35 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat(theme):=20=E6=96=B0=E5=A2=9E=20`force-?= =?UTF-8?q?dark`=20=E5=A4=96=E8=A7=82=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- theme/src/client/components/Nav/NavBar.vue | 1 + .../components/Nav/NavBarAppearance.vue | 5 ++++- .../src/client/components/Nav/NavBarExtra.vue | 2 +- .../components/Nav/NavScreenAppearance.vue | 5 ++++- theme/src/node/theme.ts | 22 +++++++++++++++++++ theme/src/shared/options/locale.ts | 2 +- theme/templates/build.html | 11 ---------- 7 files changed, 33 insertions(+), 15 deletions(-) diff --git a/theme/src/client/components/Nav/NavBar.vue b/theme/src/client/components/Nav/NavBar.vue index 8296a251..b5c44f68 100644 --- a/theme/src/client/components/Nav/NavBar.vue +++ b/theme/src/client/components/Nav/NavBar.vue @@ -189,6 +189,7 @@ watchPostEffect(() => { .menu + .appearance::before, .menu + .social-links::before, .translations + .appearance::before, +.translations + .social-links::before, .appearance + .social-links::before { width: 1px; height: 24px; diff --git a/theme/src/client/components/Nav/NavBarAppearance.vue b/theme/src/client/components/Nav/NavBarAppearance.vue index b04ed1fd..3c830cca 100644 --- a/theme/src/client/components/Nav/NavBarAppearance.vue +++ b/theme/src/client/components/Nav/NavBarAppearance.vue @@ -6,7 +6,10 @@ const theme = useThemeLocaleData() diff --git a/theme/src/client/components/Nav/NavBarExtra.vue b/theme/src/client/components/Nav/NavBarExtra.vue index bd2860be..5a49bca9 100644 --- a/theme/src/client/components/Nav/NavBarExtra.vue +++ b/theme/src/client/components/Nav/NavBarExtra.vue @@ -30,7 +30,7 @@ const hasExtraContent = computed( -
+

{{ theme.appearanceText || 'Appearance' }} diff --git a/theme/src/client/components/Nav/NavScreenAppearance.vue b/theme/src/client/components/Nav/NavScreenAppearance.vue index c1b8ddbb..cc4acced 100644 --- a/theme/src/client/components/Nav/NavScreenAppearance.vue +++ b/theme/src/client/components/Nav/NavScreenAppearance.vue @@ -6,7 +6,10 @@ const theme = useThemeLocaleData()