diff --git a/docs/.vuepress/notes/zh/theme-guide.ts b/docs/.vuepress/notes/zh/theme-guide.ts
index 7e2494b91..d01f56126 100644
--- a/docs/.vuepress/notes/zh/theme-guide.ts
+++ b/docs/.vuepress/notes/zh/theme-guide.ts
@@ -113,6 +113,7 @@ export const themeGuide = defineNoteConfig({
'加密',
'文章贡献者',
'文章变更历史',
+ '文章版权所有',
'文章水印',
'友情链接页',
'seo',
diff --git a/docs/notes/theme/config/frontmatter/basic.md b/docs/notes/theme/config/frontmatter/basic.md
index 7c6e6821e..878de339a 100644
--- a/docs/notes/theme/config/frontmatter/basic.md
+++ b/docs/notes/theme/config/frontmatter/basic.md
@@ -199,6 +199,16 @@ permalink: /config/frontmatter/basic/
当前页面是否显示页面变更历史。
+### copyright
+
+- 类型: `boolean | CopyrightLicense | CopyrightFrontmatter`
+- 默认值: `false`
+- 详情:
+
+ 当前文章是否 显示 版权信息。
+
+ 完整信息请查看 [copyright](../../guide/功能/文章版权所有.md)
+
### editLink
- 类型: `boolean`
diff --git "a/docs/notes/theme/config/\344\270\273\351\242\230\351\205\215\347\275\256.md" "b/docs/notes/theme/config/\344\270\273\351\242\230\351\205\215\347\275\256.md"
index e054349ed..358ddb2e8 100644
--- "a/docs/notes/theme/config/\344\270\273\351\242\230\351\205\215\347\275\256.md"
+++ "b/docs/notes/theme/config/\344\270\273\351\242\230\351\205\215\347\275\256.md"
@@ -838,6 +838,50 @@ interface SidebarItem {
- 默认值: `'View All Changelog'`
- 详情: 变更记录的按钮文本
+### copyright
+
+- 类型: `boolean | CopyrightLicense | CopyrightOptions`
+- 默认值: `false`
+- 详情: 版权配置
+
+ 详情请参考 [版权所有](../guide/功能/文章版权所有.md)
+
+### copyrightText
+
+- 类型: `string`
+- 默认值: `'Copyright'`
+- 详情: 版权所有的文本
+
+### copyrightAuthorText
+
+- 类型: `string`
+- 默认值: `'Copyright Ownership:'`
+- 详情: 版权所有者的文本
+
+### copyrightCreationOriginalText
+
+- 类型: `string`
+- 默认值: `'This article link:'`
+- 详情: 本文链接的文本
+
+### copyrightCreationTranslateText
+
+- 类型: `string`
+- 默认值: `'This article translated from:'`
+- 详情: 本文翻译的文本
+
+### copyrightCreationReprintText
+
+- 类型: `string`
+- 默认值: `'This article reprint from:'`
+- 详情: 本文转载的文本
+
+### copyrightLicenseText
+
+- 类型: `string`
+- 默认值: `'License under:'`
+- 详情: 版权许可证的文本
+
### prevPage
- 类型: `boolean`
diff --git "a/docs/notes/theme/guide/\345\212\237\350\203\275/\346\226\207\347\253\240\347\211\210\346\235\203\346\211\200\346\234\211.md" "b/docs/notes/theme/guide/\345\212\237\350\203\275/\346\226\207\347\253\240\347\211\210\346\235\203\346\211\200\346\234\211.md"
new file mode 100644
index 000000000..3f192bb35
--- /dev/null
+++ "b/docs/notes/theme/guide/\345\212\237\350\203\275/\346\226\207\347\253\240\347\211\210\346\235\203\346\211\200\346\234\211.md"
@@ -0,0 +1,254 @@
+---
+title: 文章版权所有
+icon: lucide:creative-commons
+badge:
+ type: tip
+ text: v1.0.0-rc.118 +
+createTime: 2024/11/20 10:52:49
+permalink: /guide/features/copyright/
+---
+
+
+
+## 概述
+
+主题支持为文章添加 文章 **版权所有** 声明。
+
+文章通常来源于 原创、转载、翻译等。针对于不同的来源,添加版权声明信息能够更好地保护知识产权,
+以及避免产生版权纠纷。
+
+### Creative Commons
+
+主题默认支持 [Creative Commons](https://creativecommons.org/) 许可协议的版权声明,包括:
+
+
+
+
+
+- [CC0 1.0 通用 (CC0)](https://creativecommons.org/publicdomain/zero/1.0/)
+
+- [署名 4.0 国际 (CC-BY-4.0)](https://creativecommons.org/licenses/by/4.0/)
+
+- [署名-相同方式共享 4.0 国际 (CC-BY-SA-4.0)](https://creativecommons.org/licenses/by-sa/4.0/)
+
+- [署名-非商业性 4.0 国际 (CC-BY-NC-4.0)](https://creativecommons.org/licenses/by-nc/4.0/)
+
+- [署名-禁止演绎 4.0 国际 (CC-BY-ND-4.0)](https://creativecommons.org/licenses/by-nd/4.0/)
+
+- [署名-非商业性-相同方式共享 4.0 国际 (CC-BY-NC-SA-4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/)
+
+- [署名-非商业性-禁止演绎 4.0 国际 (CC-BY-NC-ND-4.0)](https://creativecommons.org/licenses/by-nc-nd/4.0/)
+
+
+
+
+您可以根据需要选择不同的许可协议,或者自定义许可协议。
+
+### 版权信息
+
+版权信息包括:
+
+- 版权所有者,版权所有者链接
+- 版权许可证,版权许可证链接
+- 作品原文链接
+
+这些信息将显示在文章的底部。
+
+::: tip 使用此功能建议同时启用 [贡献者](./文章贡献者.md) 功能。对于原创文章,主题会自动将文章的第一位贡献者作为版权所有者。你也可以在文章 frontmatter 中手动指定版权所有者。
+:::
+
+## 全局配置
+
+您可以通过以下配置为您的站点的所有文章,声明版权许可证为 `CC-BY-4.0`:
+
+::: code-tabs
+@tab .vuepress/config.ts
+
+```ts
+import { defineUserConfig } from 'vuepress'
+import { plumeTheme } from 'vuepress-theme-plume'
+
+export default defineUserConfig({
+ theme: plumeTheme({
+ copyright: 'CC-BY-4.0' // [!code hl]
+ })
+})
+```
+
+:::
+
+您可以通过以下配置为您的站点的所有文章 声明自定义的版权许可证:
+
+::: code-tabs
+@tab .vuepress/config.ts
+
+```ts :no-line-numbers
+import { defineUserConfig } from 'vuepress'
+import { plumeTheme } from 'vuepress-theme-plume'
+
+export default defineUserConfig({
+ theme: plumeTheme({
+ copyright: { // [!code hl:6]
+ license: {
+ name: 'MIT', // 许可证名称
+ url: 'https://your-license-url' // 许可证地址
+ }
+ }
+ })
+})
+```
+
+:::
+
+**配置类型:**
+
+```ts
+export type CopyrightLicense =
+ | 'CC-BY-4.0'
+ | 'CC-BY-SA-4.0'
+ | 'CC-BY-NC-4.0'
+ | 'CC-BY-NC-SA-4.0'
+ | 'CC-BY-ND-4.0'
+ | 'CC-BY-NC-ND-4.0'
+ | 'CC0'
+ | string
+
+/**
+ * - 配置为 `true` 时,默认为 `CC-BY-4.0`
+ * - 配置为 `false` 时,不显示版权,但可以在文章 frontmatter.copyright 中覆盖配置
+ */
+type CopyrightOptions = boolean | string | CopyrightLicense | {
+ /**
+ * 许可证
+ */
+ license: CopyrightLicense | {
+ name: CopyrightLicense | string
+ url: string
+ }
+}
+```
+
+::: warning 全局配置只适用于 原创文章,对于非原创文章,您应该在文章 frontmatter 中配置版权信息。
+:::
+
+## 文章 frontmatter 配置
+
+您可以在文章 frontmatter 中为单个文章配置版权信息,以覆盖全局配置:
+
+```md
+---
+title: 我的文章
+copyright: CC-BY-4.0
+---
+```
+
+**配置类型:**
+
+```ts
+/**
+ * 配置为 `false` 时,不显示版权
+ * 配置为 `true` 时,则默认为 全局配置的 copyright
+ */
+export type CopyrightFrontmatter = boolean | string | CopyrightLicense | {
+ /**
+ * 版权许可
+ */
+ license?: CopyrightLicense | { name: string, url: string }
+
+ /**
+ * 版权所有者
+ * - 原创文章时默认为文章的第一位贡献者
+ * - 非原创文章时需要声明版权所有者
+ */
+ author?: string | { name: string, url?: string }
+
+ /**
+ * 作品的创作方式, 原创、翻译、转载
+ * @default 'original'
+ */
+ creation?: 'original' | 'translate' | 'reprint'
+
+ /**
+ * 原文地址,非原创作品时需要声明原文地址
+ * @default ''
+ */
+ source?: string
+}
+```
+
+## 文章配置示例
+
+### 原创文章
+
+```md
+---
+title: 我的文章
+copyright: CC-BY-4.0
+---
+```
+
+
+
+### 转载文章
+
+```md
+---
+title: 转载的文章
+copyright:
+ creation: reprint
+ license: CC-BY-4.0
+ source: https://example.com/origin
+ author:
+ name: 转载者
+ url: https://example.com/author
+---
+```
+
+
+
+### 翻译文章
+
+```md
+---
+title: 翻译的文章
+copyright:
+ creation: translate
+ license: CC-BY-4.0
+ source: https://example.com/origin
+ author:
+ name: 原文作者
+ url: https://example.com/author
+---
+```
+
+
+
+### 自定义许可证
+
+```md
+---
+title: 我的文章
+copyright:
+ license:
+ name: MIT
+ url: https://example.com/mit
+---
+```
+
+
diff --git a/theme/src/client/components/VPCopyright.vue b/theme/src/client/components/VPCopyright.vue
new file mode 100644
index 000000000..1f7da15a6
--- /dev/null
+++ b/theme/src/client/components/VPCopyright.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+ {{ theme.copyrightAuthorText || 'Copyright Ownership:' }}
+
+ {{ author.name }}
+
+
+
+ {{ creationText }}
+
+ {{ sourceUrl }}
+
+
+
+ {{ theme.copyrightLicenseText || 'License under' }}
+
+ {{ license.name }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme/src/client/components/VPDoc.vue b/theme/src/client/components/VPDoc.vue
index 070b82cd7..a6a3f147b 100644
--- a/theme/src/client/components/VPDoc.vue
+++ b/theme/src/client/components/VPDoc.vue
@@ -3,6 +3,7 @@ import VPDocAside from '@theme/VPDocAside.vue'
import VPDocBreadcrumbs from '@theme/VPDocBreadcrumbs.vue'
import VPDocChangelog from '@theme/VPDocChangelog.vue'
import VPDocContributor from '@theme/VPDocContributor.vue'
+import VPDocCopyright from '@theme/VPDocCopyright.vue'
import VPDocFooter from '@theme/VPDocFooter.vue'
import VPDocMeta from '@theme/VPDocMeta.vue'
import VPEncryptPage from '@theme/VPEncryptPage.vue'
@@ -129,6 +130,7 @@ watch(
+
diff --git a/theme/src/client/components/VPDocBreadcrumbs.vue b/theme/src/client/components/VPDocBreadcrumbs.vue
index ea322670f..a20a70891 100644
--- a/theme/src/client/components/VPDocBreadcrumbs.vue
+++ b/theme/src/client/components/VPDocBreadcrumbs.vue
@@ -101,6 +101,12 @@ function resolveSidebar(
transition: border-left var(--vp-t-color);
}
+@media print {
+ .vp-breadcrumb {
+ display: none;
+ }
+}
+
.vp-breadcrumb ol {
display: flex;
flex-wrap: wrap;
diff --git a/theme/src/client/components/VPDocChangelog.vue b/theme/src/client/components/VPDocChangelog.vue
index d840e7cbc..9fdb28b72 100644
--- a/theme/src/client/components/VPDocChangelog.vue
+++ b/theme/src/client/components/VPDocChangelog.vue
@@ -69,6 +69,12 @@ const hasChangelog = computed(() =>
display: block;
}
+@media print {
+ .vp-doc-changelog {
+ display: none;
+ }
+}
+
.vp-doc-changelog .changelog-header > span {
display: block;
}
diff --git a/theme/src/client/components/VPDocCopyright.vue b/theme/src/client/components/VPDocCopyright.vue
new file mode 100644
index 000000000..fac9be791
--- /dev/null
+++ b/theme/src/client/components/VPDocCopyright.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+ {{ theme.copyrightText || 'Copyright' }}
+
+
+
+
+
diff --git a/theme/src/client/composables/copyright.ts b/theme/src/client/composables/copyright.ts
new file mode 100644
index 000000000..5baec74fa
--- /dev/null
+++ b/theme/src/client/composables/copyright.ts
@@ -0,0 +1,113 @@
+import type { CopyrightFrontmatter, CopyrightLicense, CopyrightOptions, GitContributor, KnownCopyrightLicense } from '../../shared/index.js'
+import { computed, type ComputedRef } from 'vue'
+import { useRoute, useRouteLocale } from 'vuepress/client'
+import { useContributors } from './contributors.js'
+import { useData } from './data.js'
+import { getPresetLocaleData } from './preset-locales.js'
+
+const LICENSE_URL: Record = {
+ 'CC0': {
+ url: 'https://creativecommons.org/publicdomain/zero/1.0/',
+ icons: ['zero'],
+ },
+ 'CC-BY-4.0': {
+ url: 'https://creativecommons.org/licenses/by/4.0/',
+ icons: ['cc', 'by'],
+ },
+ 'CC-BY-NC-4.0': {
+ url: 'https://creativecommons.org/licenses/by-nc/4.0/',
+ icons: ['cc', 'by', 'nc'],
+ },
+ 'CC-BY-NC-SA-4.0': {
+ url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
+ icons: ['cc', 'by', 'nc', 'sa'],
+ },
+ 'CC-BY-NC-ND-4.0': {
+ url: 'https://creativecommons.org/licenses/by-nc-nd/4.0/',
+ icons: ['cc', 'by', 'nc', 'nd'],
+ },
+ 'CC-BY-ND-4.0': {
+ url: 'https://creativecommons.org/licenses/by-nd/4.0/',
+ icons: ['cc', 'by', 'nd'],
+ },
+ 'CC-BY-SA-4.0': {
+ url: 'https://creativecommons.org/licenses/by-sa/4.0/',
+ icons: ['cc', 'by', 'sa'],
+ },
+}
+
+export function useCopyright(copyright: ComputedRef) {
+ const { theme } = useData<'post'>()
+ const route = useRoute()
+ const routeLocale = useRouteLocale()
+ const { contributors } = useContributors()
+
+ const hasCopyright = computed(() => Boolean(copyright.value))
+
+ const creation = computed(() => copyright.value.creation || 'original')
+
+ const license = computed(() => resolveLicense(copyright.value.license, routeLocale.value))
+
+ const author = computed(() => resolveAuthor(copyright.value.author, creation.value, contributors.value))
+
+ const sourceUrl = computed(() => {
+ if (creation.value === 'original')
+ return __VUEPRESS_SSR__ ? route.fullPath : location.href.split('#')[0]
+
+ return copyright.value.source
+ })
+
+ const creationText = computed(() => {
+ const creation = copyright.value.creation
+ if (creation === 'translate') {
+ return theme.value.copyrightCreationTranslateText || 'This article is translated from'
+ }
+ else if (creation === 'reprint') {
+ return theme.value.copyrightCreationReprintText || 'This article is reprint from'
+ }
+ return theme.value.copyrightCreationOriginalText || 'This article link: '
+ })
+
+ return { license, author, hasCopyright, creation, creationText, sourceUrl }
+}
+
+interface License {
+ name: string
+ url?: string
+ icons?: string[]
+}
+
+function resolveLicense(
+ license: CopyrightOptions['license'] = 'CC-BY-4.0',
+ locale: string,
+): License {
+ const result: License = typeof license === 'string' ? { name: license } : { ...license }
+ const fallback = LICENSE_URL[result.name]
+ const name = getPresetLocaleData(locale, result.name as CopyrightLicense)
+ if (name) {
+ result.name = `${name} (${result.name})`
+ }
+ result.url ||= fallback?.url
+ result.icons = fallback?.icons
+ return result
+}
+
+function resolveAuthor(
+ author: CopyrightFrontmatter['author'],
+ creation: CopyrightFrontmatter['creation'],
+ contributors: GitContributor[],
+): { name: string, url?: string } | undefined {
+ const contributor = contributors[0]
+
+ const options = typeof author === 'string' ? { name: author } : author
+
+ if (options && !options.url) {
+ const contributor = contributors.find(c => c.name === options.name)
+ if (contributor)
+ options.url = contributor.url
+ }
+ if (creation === 'original' && contributor)
+ return contributor
+
+ return options
+}
diff --git a/theme/src/client/composables/index.ts b/theme/src/client/composables/index.ts
index 90c41a3eb..cdc1fa0f7 100644
--- a/theme/src/client/composables/index.ts
+++ b/theme/src/client/composables/index.ts
@@ -7,6 +7,7 @@ export * from './blog-post-list.js'
export * from './blog-tags.js'
export * from './bulletin.js'
export * from './contributors.js'
+export * from './copyright.js'
export * from './dark-mode.js'
export * from './data.js'
export * from './edit-link.js'
diff --git a/theme/src/node/locales/en.ts b/theme/src/node/locales/en.ts
index 8366333a9..fdeaacd4a 100644
--- a/theme/src/node/locales/en.ts
+++ b/theme/src/node/locales/en.ts
@@ -12,11 +12,17 @@ export const enLocale: PlumeThemeLocaleData = {
editLinkText: 'Edit this page',
contributorsText: 'Contributors',
lastUpdatedText: 'Last Updated',
-
changelogText: 'Changelog',
changelogOnText: 'On',
changelogButtonText: 'View All Changelog',
+ copyrightText: 'Copyright',
+ copyrightAuthorText: 'Copyright Ownership:',
+ copyrightCreationOriginalText: 'This article link:',
+ copyrightCreationTranslateText: 'This article is translated from:',
+ copyrightCreationReprintText: 'This article is reprint from:',
+ copyrightLicenseText: 'License under:',
+
encryptButtonText: 'Confirm',
encryptPlaceholder: 'Enter password',
encryptGlobalText: 'Only password can access this site',
@@ -29,12 +35,21 @@ export const enLocale: PlumeThemeLocaleData = {
}
export const enPresetLocale: PresetLocale = {
- home: 'Home',
- blog: 'Blog',
- tag: 'Tags',
- archive: 'Archives',
- category: 'Categories',
- archiveTotal: '{count} articles',
+ 'home': 'Home',
+ 'blog': 'Blog',
+ 'tag': 'Tags',
+ 'archive': 'Archives',
+ 'category': 'Categories',
+ 'archiveTotal': '{count} articles',
+
+ // ------ copyright license ------
+ 'CC0': 'CC0 1.0 Universal',
+ 'CC-BY-4.0': 'Attribution 4.0 International',
+ 'CC-BY-NC-4.0': 'Attribution-NonCommercial 4.0 International',
+ 'CC-BY-NC-SA-4.0': 'Attribution-NonCommercial-ShareAlike 4.0 International',
+ 'CC-BY-NC-ND-4.0': 'Attribution-NonCommercial-NoDerivatives 4.0 International',
+ 'CC-BY-ND-4.0': 'Attribution-NoDerivatives 4.0 International',
+ 'CC-BY-SA-4.0': 'Attribution-ShareAlike 4.0 International',
}
export const enSearchLocale: Partial = {
diff --git a/theme/src/node/locales/zh.ts b/theme/src/node/locales/zh.ts
index d18ec88d2..4443937ac 100644
--- a/theme/src/node/locales/zh.ts
+++ b/theme/src/node/locales/zh.ts
@@ -22,6 +22,13 @@ export const zhLocale: PlumeThemeLocaleData = {
changelogOnText: '于',
changelogButtonText: '查看全部变更历史',
+ copyrightText: '版权所有',
+ copyrightAuthorText: '版权归属于:',
+ copyrightCreationOriginalText: '本文链接:',
+ copyrightCreationTranslateText: '本文翻译自:',
+ copyrightCreationReprintText: '本文转载自:',
+ copyrightLicenseText: '许可证:',
+
notFound: {
code: '404',
title: '页面未找到',
@@ -41,12 +48,21 @@ export const zhLocale: PlumeThemeLocaleData = {
}
export const zhPresetLocale: PresetLocale = {
- home: '首页',
- blog: '博客',
- tag: '标签',
- archive: '归档',
- category: '分类',
- archiveTotal: '{count} 篇',
+ 'home': '首页',
+ 'blog': '博客',
+ 'tag': '标签',
+ 'archive': '归档',
+ 'category': '分类',
+ 'archiveTotal': '{count} 篇',
+
+ // ------ copyright license ------
+ 'CC0': 'CC0 1.0 通用',
+ 'CC-BY-4.0': '署名 4.0 国际',
+ 'CC-BY-NC-4.0': '署名-非商业性 4.0 国际',
+ 'CC-BY-NC-SA-4.0': '署名-非商业性-相同方式共享 4.0 国际',
+ 'CC-BY-NC-ND-4.0': '署名-非商业性-禁止演绎 4.0 国际',
+ 'CC-BY-ND-4.0': '署名-禁止演绎 4.0 国际',
+ 'CC-BY-SA-4.0': '署名-相同方式共享 4.0 国际',
}
export const zhDocsearchLocale: DocSearchLocaleOptions = {
diff --git a/theme/src/shared/base.ts b/theme/src/shared/base.ts
index b244e25ef..b3033d5fc 100644
--- a/theme/src/shared/base.ts
+++ b/theme/src/shared/base.ts
@@ -1,3 +1,12 @@
+/**
+ * A literal type that supports custom further strings but preserves autocompletion in IDEs.
+ *
+ * @see [copied from issue](https://github.com/microsoft/TypeScript/issues/29729#issuecomment-471566609)
+ */
+export type LiteralUnion =
+ | Union
+ | (Base & { zz_IGNORE_ME?: never })
+
export type ThemeImage =
| string
| { src: string, alt?: string }
@@ -41,7 +50,7 @@ export type SocialLinkIconUnion =
export type SocialLinkIcon = SocialLinkIconUnion | { svg: string, name?: string }
-export interface PresetLocale {
+export interface PresetLocale extends Record {
home: string
blog: string
tag: string
@@ -67,3 +76,45 @@ export interface ThemeTransition {
*/
appearance?: boolean | 'fade' | 'circle-clip' | 'horizontal-clip' | 'vertical-clip' | 'skew-clip'
}
+
+export type KnownCopyrightLicense =
+ | 'CC-BY-4.0'
+ | 'CC-BY-SA-4.0'
+ | 'CC-BY-NC-4.0'
+ | 'CC-BY-NC-SA-4.0'
+ | 'CC-BY-ND-4.0'
+ | 'CC-BY-NC-ND-4.0'
+ | 'CC0'
+
+export type CopyrightLicense = LiteralUnion
+
+export interface CopyrightOptions {
+ /**
+ * 版权信息
+ * @see https://creativecommons.org/share-your-work/cclicenses/
+ * @default 'CC-BY-4.0'
+ */
+ license?: CopyrightLicense | { name: string, url: string }
+}
+
+export interface CopyrightFrontmatter extends CopyrightOptions {
+ /**
+ * 作品的作者
+ *
+ * 如果是 原创,则默认为 contributors 中的第一个,否则需要手动指定
+ * @default ''
+ */
+ author?: string | { name: string, url?: string }
+
+ /**
+ * 作品的创作方式
+ * @default 'original'
+ */
+ creation?: 'original' | 'translate' | 'reprint'
+
+ /**
+ * 原文地址,非 原创 作品时需要声明原文地址
+ * @default ''
+ */
+ source?: string
+}
diff --git a/theme/src/shared/frontmatter/post.ts b/theme/src/shared/frontmatter/post.ts
index c53c51399..4183c8872 100644
--- a/theme/src/shared/frontmatter/post.ts
+++ b/theme/src/shared/frontmatter/post.ts
@@ -1,3 +1,4 @@
+import type { CopyrightFrontmatter, CopyrightLicense } from '../base.js'
import type { BlogPostCover } from '../blog.js'
import type { PlumeThemePageFrontmatter } from './page.js'
@@ -38,4 +39,9 @@ export interface PlumeThemePostFrontmatter extends PlumeThemePageFrontmatter {
* 是否展示文章摘要,传入 string 时为自定义摘要,此时 `` 无效
*/
excerpt?: boolean | string
+
+ /**
+ * 版权信息
+ */
+ copyright?: boolean | CopyrightLicense | CopyrightFrontmatter
}
diff --git a/theme/src/shared/options/locale.ts b/theme/src/shared/options/locale.ts
index 7dce11545..ac9205418 100644
--- a/theme/src/shared/options/locale.ts
+++ b/theme/src/shared/options/locale.ts
@@ -1,5 +1,5 @@
import type { LocaleData } from 'vuepress/core'
-import type { SocialLink, SocialLinkIconUnion, ThemeOutline, ThemeTransition } from '../base.js'
+import type { CopyrightLicense, CopyrightOptions, SocialLink, SocialLinkIconUnion, ThemeOutline, ThemeTransition } from '../base.js'
import type { PlumeThemeBlog } from '../blog.js'
import type { NavItem } from '../navbar.js'
import type { NotesOptions } from '../notes.js'
@@ -115,6 +115,48 @@ export interface PlumeThemeLocaleData extends LocaleData {
*/
bulletin?: true | BulletinOptions
+ /**
+ * 配置版权信息
+ * @default false
+ */
+ copyright?: boolean | CopyrightLicense | CopyrightOptions
+
+ /**
+ * 版权所有的文本
+ * @default 'Copyright'
+ */
+ copyrightText?: string
+
+ /**
+ * 版权归属者的文本
+ * @default 'Copyright Ownership:'
+ */
+ copyrightAuthorText?: string
+
+ /**
+ * 本文链接的文本
+ * @default 'This article link:'
+ */
+ copyrightCreationOriginalText?: string
+
+ /**
+ * 本文翻译链接的文本
+ * @default 'This article is translated from:'
+ */
+ copyrightCreationTranslateText?: string
+
+ /**
+ * 转载链接的文本
+ * @default 'This article is reprint from:'
+ */
+ copyrightCreationReprintText?: string
+
+ /**
+ * 许可证的文本
+ * @default 'License under:'
+ */
+ copyrightLicenseText?: string
+
/**
* 是否启用过渡动画效果
*