diff --git a/docs/.vuepress/notes.ts b/docs/.vuepress/notes.ts index b0e17600..a7f1a73a 100644 --- a/docs/.vuepress/notes.ts +++ b/docs/.vuepress/notes.ts @@ -22,31 +22,36 @@ export const zhNotes = definePlumeNotesConfig({ { text: 'markdown', icon: 'material-symbols:markdown-outline', - dir: 'markdown', + prefix: 'markdown', + collapsed: true, items: ['基础', '扩展', '进阶'], }, { text: '代码块', - dir: '代码', + prefix: '代码', icon: 'ph:code-bold', + collapsed: true, items: ['介绍', '特性支持', '代码组', '导入代码', 'twoslash'], }, { text: '代码演示', - dir: '代码演示', + prefix: '代码演示', icon: 'carbon:demo', + collapsed: true, items: ['前端', 'rust', 'golang', 'kotlin', 'codepen', 'jsFiddle', 'codeSandbox', 'replit'], }, { text: '图表', icon: 'mdi:chart-line', - dir: '图表', + prefix: '图表', + collapsed: true, items: ['chart', 'echarts', 'mermaid', 'flowchart'], }, { text: '资源嵌入', icon: 'dashicons:embed-video', - dir: '嵌入', + prefix: '嵌入', + collapsed: true, items: ['pdf', 'bilibili', 'youtube'], }, ], @@ -55,8 +60,13 @@ export const zhNotes = definePlumeNotesConfig({ text: '功能', icon: 'lucide:box', collapsed: false, - dir: '功能', - items: ['图标', '代码复制', '内容搜索', '评论', '加密', '组件', '文章水印', '友情链接页', 'seo', 'sitemap'], + prefix: '功能', + items: ['图标', '代码复制', '内容搜索', '评论', '加密', '组件', '文章水印', '友情链接页', 'seo', 'sitemap', { + text: '非内置功能', + icon: 'system-uicons:box-add', + collapsed: true, + items: ['repoCard', 'npmBadge'], + }], }, { text: '自定义', @@ -89,13 +99,13 @@ export const zhNotes = definePlumeNotesConfig({ }, { text: 'frontmatter', - dir: 'frontmatter', + prefix: 'frontmatter', collapsed: false, items: ['basic', 'home', 'post', 'friend'], }, { text: '内置插件', - dir: 'plugins', + prefix: 'plugins', collapsed: false, items: ['', '代码高亮', '搜索', '阅读统计', 'markdown增强', 'markdownPower', '百度统计', '水印'], }, @@ -109,7 +119,7 @@ export const zhNotes = definePlumeNotesConfig({ text: '插件', items: [ // 'caniuse', - 'iconify', + // 'iconify', 'shiki', 'md-power', 'content-updated', diff --git a/docs/notes/theme/config/主题配置.md b/docs/notes/theme/config/主题配置.md index 7a14c0d3..68a66509 100644 --- a/docs/notes/theme/config/主题配置.md +++ b/docs/notes/theme/config/主题配置.md @@ -179,6 +179,8 @@ interface BlogOptions { ::: warning 该字段不支持在 [主题配置文件 `plume.config.js`](./配置说明.md#主题配置文件) 中进行配置。 + + 为了使缓存能够生效,您应该 **删除** `package.json` 中 `vuepress dev` 开发服务启动脚本中的 `--clean-cache` 参数。 ::: ### locales diff --git a/docs/notes/theme/guide/功能/npmBadge.md b/docs/notes/theme/guide/功能/npmBadge.md new file mode 100644 index 00000000..e3640aae --- /dev/null +++ b/docs/notes/theme/guide/功能/npmBadge.md @@ -0,0 +1,151 @@ +--- +title: Npm 徽章 +author: pengzhanbo +icon: akar-icons:npm-fill +createTime: 2024/07/26 22:07:23 +permalink: /guide/npm-badge/ +--- + + + +## 概述 + +Npm 徽章组件 用于显示 npm 包信息,并提供相关的链接。 + +徽章由 提供支持。 + +## 使用 + +使用该组件需要你手动导入 `NpmBadge` 或 `NpmBadgeGroup` 组件: + +```md :no-line-numbers + + + + + + + + +``` + + + + + +## `` + +单个 npm badge + +### Props + +| 名称 | 类型 | 必填 | 默认值 | 说明 | +| ---------- | --------------- | --------------- | ----------- | --------------------------------------- | +| name | `string` | 否 | `''` | npm 包名,为空则从 `repo` 中获取 | +| repo | `string` | name 为空时必填 | `''` | 包 github 仓库地址, 格式为 `owner/repo` | +| type | `NpmBadgeType` | 是 | - | 徽章类型 | +| theme | `NpmBadgeTheme` | 否 | `'flat'` | 徽章主题 | +| label | `string` | 否 | `''` | 徽章标签 | +| color | `string` | 否 | `'#32A9C3'` | 徽章颜色 | +| labelColor | `string` | 否 | `'#1B3C4A'` | 徽章标签颜色 | +| branch | `string` | 否 | `'main'` | 仓库分支 | +| dir | `string` | 否 | `''` | 包所在仓库目录,适用于 monorepo 项目 | + +### Types + +```ts +type NpmBadgeType = + // github + | 'source' // github source + | 'stars' // github stars + | 'forks' // github forks + | 'license' // github license + // npm + | 'version' // npm version + | 'dt' // alias d18m + | 'd18m' // npm downloads last 18 months + | 'dw' // npm downloads weekly + | 'dm' // npm downloads monthly + | 'dy' // npm downloads yearly + +type NpmBadgeTheme = 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' | 'social' +``` + +### 示例 + +- `` - +- `` - +- `` - +- `` - +- `` - +- `` - +- `` - +- `` - +- `` - +- `` - + +## `` + +组合多个 npm badge + +### Props + +| 名称 | 类型 | 必填 | 默认值 | 说明 | +| ---------- | --------------- | --------------- | ------ | --------------------------------------- | +| name | `string` | 否 | `''` | npm 包名,为空则从 `repo` 中获取 | +| repo | `string` | name 为空时必填 | `''` | 包 github 仓库地址, 格式为 `owner/repo` | +| items | `string \| NpmBadgeType[]` | 否 | - | 徽章类型列表, 传入 `string` 时用 `','`分隔,会自动转换为 `NpmBadgeType[]` | +| theme | `NpmBadgeTheme` | 否 | `''` | 徽章主题 | +| color | `string` | 否 | `''` | 徽章颜色 | +| labelColor | `string` | 否 | `''` | 徽章标签颜色 | +| branch | `string` | 否 | `''` | 仓库分支 | +| dir | `string` | 否 | `''` | 包所在仓库目录,适用于 monorepo 项目 | + +### Slots + +`` 支持传入 多个 `` 组件。 + +`` 声明的 `Props` 将被注入到 `` 组件中。通过这种方式来实现和简化徽章组合。 + +### 示例 + +**输入:** + +```md :no-line-numbers + +``` + +**输出:** + + + +使用 `` 灵活定义徽章组合: + +**输入:** + +```md :no-line-numbers + + + + + + +``` + +**输出:** + + + + + + + diff --git a/docs/notes/theme/guide/功能/repoCard.md b/docs/notes/theme/guide/功能/repoCard.md new file mode 100644 index 00000000..60535f6d --- /dev/null +++ b/docs/notes/theme/guide/功能/repoCard.md @@ -0,0 +1,91 @@ +--- +title: Repo 卡片 +author: pengzhanbo +icon: octicon:repo-16 +createTime: 2024/07/26 21:11:56 +permalink: /guide/github-repo-card/ +--- + + + +## 概述 + +Repo 卡片组件 用于显示 GitHub 仓库信息。 + +## 使用 + +使用该组件需要你手动导入 `RepoCard` 组件: + +```md :no-line-numbers + + + + + +``` + +注册为全局组件: + +::: code-tabs +@tab .vuepress/client.ts + +```ts +import { defineClientConfig } from 'vuepress/client' +import RepoCard from 'vuepress-theme-plume/features/RepoCard.vue' + +export default defineClientConfig({ + enhance({ app }) { + app.component('RepoCard', RepoCard) + }, +}) +``` + +::: + +全局组件可在 其他任意 markdown 文件中使用 + +```md + +``` + +### Props + +`RepoCard` 组件的 接收一个 `repo` 参数,传入的是仓库的地址,格式为 `owner/repo`。 + +## 示例 + +### 单卡片 + +**输入:** + +```md + +``` + +**输出:** + + + +### 多卡片 + +如果希望以紧凑的方式并排展示多个卡片,可以使用 `CardGrid` 组件。 + +**输入:** + +```md + + + + +``` + +**输出:** + + + + + diff --git a/theme/package.json b/theme/package.json index 9dd17fbc..51293cde 100644 --- a/theme/package.json +++ b/theme/package.json @@ -37,6 +37,9 @@ "types": "./lib/client/composables/index.d.ts", "import": "./lib/client/composables/index.js" }, + "./features/*": { + "import": "./lib/client/features/components/*" + }, "./shared": { "types": "./lib/shared/index.d.ts", "import": "./lib/shared/index.js" diff --git a/theme/src/client/components/VPDoc.vue b/theme/src/client/components/VPDoc.vue index 6346705e..4cc2abfd 100644 --- a/theme/src/client/components/VPDoc.vue +++ b/theme/src/client/components/VPDoc.vue @@ -174,7 +174,7 @@ watch( @media (min-width: 1440px) { .vp-doc-container:not(.has-sidebar) .content { - max-width: 784px; + max-width: 884px; } .vp-doc-container.is-blog:not(.has-sidebar.has-aside) .content { @@ -275,6 +275,6 @@ watch( } .vp-doc-container.has-aside .content-container { - max-width: 688px; + max-width: 788px; } diff --git a/theme/src/client/components/VPIconify.vue b/theme/src/client/components/VPIconify.vue index d2492c09..a4a63fde 100644 --- a/theme/src/client/components/VPIconify.vue +++ b/theme/src/client/components/VPIconify.vue @@ -61,7 +61,7 @@ const bind = computed(() => ({ diff --git a/theme/src/client/composables/langs.ts b/theme/src/client/composables/langs.ts index 994b1149..7aee9516 100644 --- a/theme/src/client/composables/langs.ts +++ b/theme/src/client/composables/langs.ts @@ -29,8 +29,9 @@ export function useLangs({ const { notFound, path } = resolveRoute(targetPath) if (!notFound) return path + const blog = theme.value.blog - if (isBlogPost.value) + if (isBlogPost.value && blog !== false) return withBase(blog?.link || normalizeLink(locale, 'blog/')) const sidebarList = sidebar.value diff --git a/theme/src/client/composables/sidebar.ts b/theme/src/client/composables/sidebar.ts index 7f8fcc3c..226e5fe8 100644 --- a/theme/src/client/composables/sidebar.ts +++ b/theme/src/client/composables/sidebar.ts @@ -16,7 +16,6 @@ import { ref, watch, watchEffect, - watchPostEffect, } from 'vue' import { sidebar as sidebarRaw } from '@internal/sidebar' import { isActive, normalizeLink, normalizePrefix, resolveNavLink } from '../utils/index.js' @@ -368,7 +367,7 @@ export function useSidebarControl(item: ComputedRef): Sideb ) } - watch([page, item, () => route.hash], updateIsActiveLink) + watch([() => page.value.path, item, () => route.hash], updateIsActiveLink) onMounted(updateIsActiveLink) const hasActiveLink = computed(() => { @@ -389,11 +388,11 @@ export function useSidebarControl(item: ComputedRef): Sideb collapsed.value = !!(collapsible.value && item.value.collapsed) }) - watchPostEffect(() => { + watch(() => [page.value.path, isActiveLink.value, hasActiveLink.value], () => { if (isActiveLink.value || hasActiveLink.value) { collapsed.value = false } - }) + }, { immediate: true, flush: 'post' }) const toggle = (): void => { if (collapsible.value) { diff --git a/theme/src/client/features/components/NpmBadge.vue b/theme/src/client/features/components/NpmBadge.vue new file mode 100644 index 00000000..98fcd98c --- /dev/null +++ b/theme/src/client/features/components/NpmBadge.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/theme/src/client/features/components/NpmBadgeGroup.vue b/theme/src/client/features/components/NpmBadgeGroup.vue new file mode 100644 index 00000000..ea684901 --- /dev/null +++ b/theme/src/client/features/components/NpmBadgeGroup.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/theme/src/client/features/components/RepoCard.vue b/theme/src/client/features/components/RepoCard.vue new file mode 100644 index 00000000..efe94170 --- /dev/null +++ b/theme/src/client/features/components/RepoCard.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/theme/src/client/features/composables/github-repo.ts b/theme/src/client/features/composables/github-repo.ts new file mode 100644 index 00000000..aff888bf --- /dev/null +++ b/theme/src/client/features/composables/github-repo.ts @@ -0,0 +1,48 @@ +import { computed, ref, toValue, watch } from 'vue' +import type { MaybeRef } from 'vue' + +export interface GithubRepoInfo { + name: string + fullName: string + description: string + url: string + stars: number + forks: number + watchers: number + language: string + languageColor: string + visibility: 'Private' | 'Public' // private, public + template: boolean + ownerType: 'User' | 'Organization' + license: { + name: string + url: string + } | null +} + +export function useGithubRepo(repo: MaybeRef) { + const repoRef = computed(() => { + const info = toValue(repo) + const [owner = '', name = ''] = info.split('/') + return { owner, name } + }) + const data = ref(null) + const loaded = ref(false) + + async function fetchData() { + const { owner, name } = repoRef.value + if (__VUEPRESS_SSR__ || !owner || !name) + return + + loaded.value = false + const res = await fetch(`https://api.pengzhanbo.cn/github/repo/${owner}/${name}`) + .then(res => res.json()) as GithubRepoInfo + + data.value = res + loaded.value = true + } + + watch(repoRef, fetchData, { immediate: true }) + + return { data, loaded } +} diff --git a/theme/src/client/features/composables/npm-badge.ts b/theme/src/client/features/composables/npm-badge.ts new file mode 100644 index 00000000..919ed869 --- /dev/null +++ b/theme/src/client/features/composables/npm-badge.ts @@ -0,0 +1,175 @@ +import { computed, inject, provide, ref, toValue } from 'vue' +import type { ComputedRef, InjectionKey, Ref } from 'vue' + +const DEFAULT_COLOR = '#32A9C3' +const DEFAULT_LABEL_COLOR = '#1B3C4A' +const BADGE_URL = 'https://img.shields.io' +const GITHUB_URL = 'https://github.com' +const NPM_URL = 'https://www.npmjs.com/package' + +export type NpmBadgeType = + // github + | 'source' // github source + | 'stars' // github stars + | 'forks' // github forks + | 'license' // github license + // npm + | 'version' // npm version + | 'dt' // alias d18m + | 'd18m' // npm downloads last 18 months + | 'dw' // npm downloads weekly + | 'dm' // npm downloads monthly + | 'dy' // npm downloads yearly + +export type NpmBadgeTheme = 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' | 'social' + +export interface NpmBadgeBaseOptions { + // npm package name + name?: string + // github repo + repo?: string + // github branch + branch?: string + // github directory + dir?: string + // text color + color?: string + // label color + labelColor?: string + // badge style + theme?: NpmBadgeTheme +} + +export interface NpmBadgeOptions extends NpmBadgeBaseOptions { + type: NpmBadgeType + // label text + label?: string +} + +export interface NpmBadgeGroupOptions extends Omit { + items?: string | NpmBadgeType | NpmBadgeType[] +} + +export interface NpmBadgeInfo { + badgeUrl: string + link?: string + alt?: string +} + +type NpmBadgeBaseOptionsRef = Ref + +const NpmBadgeSymbol: InjectionKey = Symbol(__VUEPRESS_DEV__ ? 'NpmBadge' : '') + +export function useNpmBadge(opt: Ref): ComputedRef { + const parentOpt = inject(NpmBadgeSymbol, ref({}) as NpmBadgeBaseOptionsRef) + + return computed(() => { + const po = toValue(parentOpt) + const o = toValue(opt) + const res: NpmBadgeOptions = { + name: o.name || po.name, + repo: o.repo || po.repo, + branch: o.branch || po.branch, + dir: o.dir || po.dir, + type: o.type, + color: o.color || po.color, + label: o.label, + labelColor: o.labelColor || po.labelColor, + theme: o.theme || po.theme, + } + return resolveNpmBadgeOptions(res) + }) +} + +export function useNpmBadgeGroup(opt: Ref) { + const baseOptions = computed(() => { + const o = toValue(opt) + return { + name: o.name, + repo: o.repo, + branch: o.branch, + dir: o.dir, + color: o.color, + labelColor: o.labelColor, + theme: o.theme, + } + }) + + provide(NpmBadgeSymbol, baseOptions) +} + +function resolveNpmBadgeOptions(options: NpmBadgeOptions): NpmBadgeInfo { + let { name = '', repo = '', branch = 'main', dir = '', type, color, label, labelColor, theme = '' } = options + name = name || repo.split('/')?.[1] || '' + const normalizeName = encodeURIComponent(name) + + const githubLink = repo ? `${GITHUB_URL}/${repo}${dir ? `/tree/${branch}/${dir}` : ''}` : '' + const npmLink = `${NPM_URL}/${name}` + + const params = new URLSearchParams() + + if (type !== 'source' && type !== 'stars' && type !== 'forks') { + params.append('style', theme || 'flat') + params.append('color', color || DEFAULT_COLOR) + params.append('labelColor', labelColor || DEFAULT_LABEL_COLOR) + } + + switch (type) { + case 'source': { + params.append('logo', 'github') + params.append('color', labelColor || DEFAULT_LABEL_COLOR) + return { + badgeUrl: `${BADGE_URL}/badge/source-a?${params.toString()}`, + link: githubLink, + alt: 'github source', + } + } + case 'stars': + case 'forks': { + params.append('style', theme || 'social') + return { + badgeUrl: `${BADGE_URL}/github/${type}/${repo}?${params.toString()}`, + link: githubLink, + alt: `github ${type}`, + } + } + case 'license': + return { + badgeUrl: `${BADGE_URL}/github/license/${repo}?${params.toString()}`, + link: githubLink, + alt: 'license', + } + case 'version': { + params.append('label', label || name || 'npm') + return { + badgeUrl: `${BADGE_URL}/npm/v/${normalizeName}?${params.toString()}`, + link: npmLink, + alt: 'npm version', + } + } + case 'dt': + case 'd18m': { + params.append('label', label || 'downloads') + return { + badgeUrl: `${BADGE_URL}/npm/d18m/${normalizeName}?${params.toString()}`, + link: npmLink, + alt: 'npm downloads', + } + } + case 'dm': + case 'dy': + case 'dw': { + params.append('label', label || 'downloads') + return { + badgeUrl: `${BADGE_URL}/npm/${type}/${normalizeName}?${params.toString()}`, + link: npmLink, + alt: 'npm downloads', + } + } + default: + return { + badgeUrl: `${BADGE_URL}/badge/unknown?${params.toString()}`, + alt: 'unknown', + } + } +} diff --git a/theme/src/node/autoFrontmatter/resolveOptions.ts b/theme/src/node/autoFrontmatter/resolveOptions.ts index c417240b..35947d59 100644 --- a/theme/src/node/autoFrontmatter/resolveOptions.ts +++ b/theme/src/node/autoFrontmatter/resolveOptions.ts @@ -194,34 +194,36 @@ export function resolveOptions( include: '**/{readme,README,index}.md', frontmatter: {}, }, - { - include: localeOptions.blog?.include ?? ['**/*.md'], - frontmatter: { - ...options.title !== false - ? { - title(title: string, { relativePath }) { - if (title) - return title - const basename = path.basename(relativePath || '', '.md') - return basename - }, - } as AutoFrontmatterObject - : undefined, - ...baseFrontmatter, - ...options.permalink !== false - ? { - permalink(permalink: string, { relativePath }) { - if (permalink) - return permalink - const locale = resolveLocale(relativePath) - const prefix = withBase(articlePrefix, locale) + localeOptions.blog !== false + ? { + include: localeOptions.blog?.include ?? ['**/*.md'], + frontmatter: { + ...options.title !== false + ? { + title(title: string, { relativePath }) { + if (title) + return title + const basename = path.basename(relativePath || '', '.md') + return basename + }, + } as AutoFrontmatterObject + : undefined, + ...baseFrontmatter, + ...options.permalink !== false + ? { + permalink(permalink: string, { relativePath }) { + if (permalink) + return permalink + const locale = resolveLocale(relativePath) + const prefix = withBase(articlePrefix, locale) - return normalizePath(`${prefix}/${nanoid()}/`) - }, - } as AutoFrontmatterObject - : undefined, - }, - }, + return normalizePath(`${prefix}/${nanoid()}/`) + }, + } as AutoFrontmatterObject + : undefined, + }, + } + : '', { include: '*', diff --git a/theme/src/node/config/resolveThemeData.ts b/theme/src/node/config/resolveThemeData.ts index 1484be1a..a8f025e4 100644 --- a/theme/src/node/config/resolveThemeData.ts +++ b/theme/src/node/config/resolveThemeData.ts @@ -35,8 +35,6 @@ export function resolveThemeData(app: App, options: PlumeThemeLocaleOptions): Pl } }) - const blog = options.blog || {} - const blogLink = blog.link || '/blog/' entries(options.locales || {}).forEach(([locale, opt]) => { // 注入预设 导航栏 // home | blog | tags | archives @@ -47,21 +45,25 @@ export function resolveThemeData(app: App, options: PlumeThemeLocaleOptions): Pl text: PRESET_LOCALES[localePath].home, link: locale, }] - navbar.push({ - text: PRESET_LOCALES[localePath].blog, - link: withBase(blogLink, locale), - }) - if (blog.tags !== false) { + if (options.blog !== false) { + const blog = options.blog || {} + const blogLink = blog.link || '/blog/' navbar.push({ - text: PRESET_LOCALES[localePath].tag, - link: withBase(blog.tagsLink || `${blogLink}/tags/`, locale), - }) - } - if (blog.archives !== false) { - navbar.push({ - text: PRESET_LOCALES[localePath].archive, - link: withBase(blog.archivesLink || `${blogLink}/archives/`, locale), + text: PRESET_LOCALES[localePath].blog, + link: withBase(blogLink, locale), }) + if (blog.tags !== false) { + navbar.push({ + text: PRESET_LOCALES[localePath].tag, + link: withBase(blog.tagsLink || `${blogLink}/tags/`, locale), + }) + } + if (blog.archives !== false) { + navbar.push({ + text: PRESET_LOCALES[localePath].archive, + link: withBase(blog.archivesLink || `${blogLink}/archives/`, locale), + }) + } } themeData.locales![locale].navbar = navbar diff --git a/theme/src/node/prepare/prepareBlogData.ts b/theme/src/node/prepare/prepareBlogData.ts index c563a048..ee8531ac 100644 --- a/theme/src/node/prepare/prepareBlogData.ts +++ b/theme/src/node/prepare/prepareBlogData.ts @@ -25,6 +25,12 @@ export async function preparedBlogData( localeOptions: PlumeThemeLocaleOptions, encrypt?: PlumeThemeEncrypt, ): Promise { + if (localeOptions.blog === false) { + const content = resolveContent(app, { name: 'blogPostData', content: [] }) + await writeTemp(app, 'internal/blogData.js', content) + return + } + const start = performance.now() const blog = localeOptions.blog || {} diff --git a/theme/src/node/prepare/prepareIcons.ts b/theme/src/node/prepare/prepareIcons.ts index 44dd6120..bc085bf7 100644 --- a/theme/src/node/prepare/prepareIcons.ts +++ b/theme/src/node/prepare/prepareIcons.ts @@ -16,8 +16,8 @@ interface IconData { type CollectMap = Record type IconDataMap = Record -const ICON_REGEXP = /<(?:VP)?Icon(?:ify)?([^>]*)>/g -const ICON_NAME_REGEXP = /name="([^"]+)"/ +const ICON_REGEXP = /<(?:VP)?(Icon|Card|LinkCard)([^>]*)>/g +const ICON_NAME_REGEXP = /(?:name|icon)="([^"]+)"/ const URL_CONTENT_REGEXP = /(url\([\s\S]+\))/ const JS_FILENAME = 'internal/iconify.js' const CSS_FILENAME = 'internal/iconify.css' diff --git a/theme/src/node/setupPages.ts b/theme/src/node/setupPages.ts index 3beb8c93..7892cff4 100644 --- a/theme/src/node/setupPages.ts +++ b/theme/src/node/setupPages.ts @@ -18,6 +18,9 @@ export async function setupPage( app: App, localeOption: PlumeThemeLocaleOptions, ) { + if (localeOption.blog === false) + return + const pageList: Promise[] = [] const locales = localeOption.locales || {} const rootPath = getRootLangPath(app) diff --git a/theme/src/shared/options/locale.ts b/theme/src/shared/options/locale.ts index 47af52a4..97f09d65 100644 --- a/theme/src/shared/options/locale.ts +++ b/theme/src/shared/options/locale.ts @@ -64,7 +64,7 @@ export interface PlumeThemeLocaleData extends LocaleData { /** * 博客配置 */ - blog?: PlumeThemeBlog + blog?: false | PlumeThemeBlog /** * 文章链接前缀 @@ -274,7 +274,7 @@ export interface PlumeThemeLocaleData extends LocaleData { encryptPlaceholder?: string } -/** =========================== Avatar ================================ */ +/** =========================== Profile ================================ */ /** * 个人资料 diff --git a/theme/tsup.config.ts b/theme/tsup.config.ts index 56142148..4a6f6da7 100644 --- a/theme/tsup.config.ts +++ b/theme/tsup.config.ts @@ -1,3 +1,6 @@ +import process from 'node:process' +import fs from 'node:fs' +import path from 'node:path' import { type Options, defineConfig } from 'tsup' const sharedExternal: (string | RegExp)[] = [ @@ -12,6 +15,11 @@ const clientExternal: (string | RegExp)[] = [ /.*\.css$/, ] +const featuresComposables = fs.readdirSync( + path.join(process.cwd(), 'src/client/features/composables'), + { recursive: true, encoding: 'utf-8' }, +) + export default defineConfig((cli) => { const DEFAULT_OPTIONS: Options = { dts: !cli.watch, @@ -35,6 +43,7 @@ export default defineConfig((cli) => { outDir: './lib/node', external: sharedExternal, target: 'node18', + watch: false, }, // client/utils/index.js { @@ -77,5 +86,16 @@ export default defineConfig((cli) => { './config.js', ], }, + ...featuresComposables.map(file => ({ + ...DEFAULT_OPTIONS, + entry: [`./src/client/features/composables/${file}`], + outDir: `./lib/client/features/composables/`, + external: [ + ...clientExternal, + '../../composables/index.js', + '../../utils/index.js', + ...featuresComposables.map(file => `./${file.replace('.ts', '.js')}`), + ], + })), ] })