diff --git a/docs/.vuepress/configs/navbar/en.ts b/docs/.vuepress/configs/navbar/en.ts
index 95136945f6..245a503c5e 100644
--- a/docs/.vuepress/configs/navbar/en.ts
+++ b/docs/.vuepress/configs/navbar/en.ts
@@ -20,6 +20,7 @@ export const navbarEn: NavbarConfig = [
{
text: 'Common Features',
children: [
+ '/plugins/append-date',
'/plugins/back-to-top',
'/plugins/catalog',
'/plugins/copy-code',
diff --git a/docs/.vuepress/configs/navbar/zh.ts b/docs/.vuepress/configs/navbar/zh.ts
index e0e565ae17..ebe3482770 100644
--- a/docs/.vuepress/configs/navbar/zh.ts
+++ b/docs/.vuepress/configs/navbar/zh.ts
@@ -20,6 +20,7 @@ export const navbarZh: NavbarConfig = [
{
text: '常用功能',
children: [
+ '/zh/plugins/append-date',
'/zh/plugins/back-to-top',
'/zh/plugins/catalog',
'/zh/plugins/copy-code',
diff --git a/docs/.vuepress/configs/sidebar/en.ts b/docs/.vuepress/configs/sidebar/en.ts
index 925f91d4b4..44e58f7b75 100644
--- a/docs/.vuepress/configs/sidebar/en.ts
+++ b/docs/.vuepress/configs/sidebar/en.ts
@@ -5,6 +5,7 @@ export const sidebarEn: SidebarConfig = {
{
text: 'Common Features',
children: [
+ '/plugins/append-date',
'/plugins/back-to-top',
'/plugins/catalog',
'/plugins/copy-code',
diff --git a/docs/.vuepress/configs/sidebar/zh.ts b/docs/.vuepress/configs/sidebar/zh.ts
index c65311ebeb..7df99c8007 100644
--- a/docs/.vuepress/configs/sidebar/zh.ts
+++ b/docs/.vuepress/configs/sidebar/zh.ts
@@ -5,6 +5,7 @@ export const sidebarZh: SidebarConfig = {
{
text: '常用功能',
children: [
+ '/zh/plugins/append-date',
'/zh/plugins/back-to-top',
'/zh/plugins/catalog',
'/zh/plugins/copy-code',
diff --git a/docs/plugins/append-date.md b/docs/plugins/append-date.md
new file mode 100644
index 0000000000..85961e878a
--- /dev/null
+++ b/docs/plugins/append-date.md
@@ -0,0 +1,37 @@
+# back-to-top
+
+
+
+This plugin will append writing date to frontmatter with [@vuepress/plugin-git](git.md).
+
+## Usage
+
+```bash
+npm i -D @vuepress/plugin-append-date@next
+```
+
+```ts
+import { appendDatePlugin } from '@vuepress/plugin-append-date'
+
+export default {
+ plugins: [appendDatePlugin()],
+}
+```
+
+## Options
+
+### key
+
+- Type: `string`
+- Default: `"date"`
+- Details:
+
+ Frontmatter key to use when appending date.
+
+### format
+
+- Type: `"date" | "time" | "full"`
+- Default: `"date"`
+- Details:
+
+ Format of the date value when appending date.
diff --git a/docs/zh/plugins/append-date.md b/docs/zh/plugins/append-date.md
new file mode 100644
index 0000000000..10f730af54
--- /dev/null
+++ b/docs/zh/plugins/append-date.md
@@ -0,0 +1,33 @@
+# back-to-top
+
+
+
+该插件会基于 [@vuepress/plugin-git](git.md) 为 frontmatter 追加写作日期。
+
+## 使用方法
+
+```bash
+npm i -D @vuepress/plugin-append-date@next
+```
+
+```ts
+import { appendDatePlugin } from '@vuepress/plugin-append-date'
+
+export default {
+ plugins: [appendDatePlugin()],
+}
+```
+
+## 选项
+
+### key
+
+- 类型: `string`
+- 默认值: `"date"`
+- 详情:追加时间时使用的 frontmatter 键名。
+
+### format
+
+- 类型: `"date" | "time" | "full"`
+- 默认值: `"date"`
+- 详情:追加时间时使用的日期格式。
diff --git a/plugins/plugin-append-date/package.json b/plugins/plugin-append-date/package.json
new file mode 100644
index 0000000000..332b2c7bbb
--- /dev/null
+++ b/plugins/plugin-append-date/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "@vuepress/plugin-append-date",
+ "version": "2.0.0-rc.19",
+ "description": "VuePress plugin - append date",
+ "keywords": [
+ "vuepress-plugin",
+ "vuepress",
+ "plugin",
+ "append-date"
+ ],
+ "homepage": "https://ecosystem.vuejs.press/plugins/append-date.html",
+ "bugs": {
+ "url": "https://github.com/vuepress/ecosystem/issues"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vuepress/ecosystem.git",
+ "directory": "plugins/plugin-append-date"
+ },
+ "license": "MIT",
+ "author": {
+ "name": "Mr.Hope",
+ "email": "mister-hope@outlook.com",
+ "url": "https://mister-hope.com"
+ },
+ "type": "module",
+ "exports": {
+ ".": "./lib/node/index.js",
+ "./package.json": "./package.json"
+ },
+ "main": "lib/node/index.js",
+ "types": "lib/node/index.d.ts",
+ "files": [
+ "lib"
+ ],
+ "scripts": {
+ "build": "tsc -b tsconfig.build.json",
+ "clean": "rimraf --glob ./lib ./*.tsbuildinfo"
+ },
+ "dependencies": {
+ "@vuepress/helper": "workspace:~"
+ },
+ "peerDependencies": {
+ "@vuepress/plugin-git": "workspace:~",
+ "vuepress": "2.0.0-rc.8"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/plugins/plugin-append-date/src/node/appendDate.ts b/plugins/plugin-append-date/src/node/appendDate.ts
new file mode 100644
index 0000000000..691d0c74b5
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/appendDate.ts
@@ -0,0 +1,42 @@
+import { startsWith } from '@vuepress/helper'
+import type { GitPluginPageData } from '@vuepress/plugin-git'
+import type { Page } from 'vuepress/core'
+import { fs } from 'vuepress/utils'
+import {
+ getDateString,
+ getFullDateString,
+ getTimeString,
+} from './formatDate.js'
+import type { AppendDatePluginOptions } from './options.js'
+
+export const appendDateToPage = async (
+ { key = 'date', format = 'date' }: AppendDatePluginOptions,
+ { data, filePath, frontmatter }: Page,
+): Promise => {
+ if (frontmatter[key] || !filePath) return
+
+ const { createdTime } = data.git
+
+ if (!createdTime) return
+
+ const date = new Date(createdTime)
+
+ const text =
+ format === 'time'
+ ? getTimeString(date)
+ : format === 'full'
+ ? getFullDateString(date)
+ : getDateString(date)
+
+ frontmatter[key] = new Date(createdTime)
+
+ const markdownContent = await fs.readFile(filePath, 'utf-8')
+
+ await fs.writeFile(
+ filePath,
+ startsWith(markdownContent, '---\n')
+ ? `---\n${key}: ${text}\n${markdownContent.substring(4)}`
+ : `---\n${key}: ${text}\n---\n\n${markdownContent}`,
+ 'utf-8',
+ )
+}
diff --git a/plugins/plugin-append-date/src/node/appendDatePlugin.ts b/plugins/plugin-append-date/src/node/appendDatePlugin.ts
new file mode 100644
index 0000000000..378dc66f34
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/appendDatePlugin.ts
@@ -0,0 +1,21 @@
+import type { GitPluginPageData } from '@vuepress/plugin-git'
+import type { Page, PluginObject } from 'vuepress/core'
+import { appendDateToPage } from './appendDate.js'
+import { isGitPluginEnabled } from './checkGitPlugin.js'
+import { PLUGIN_NAME } from './logger.js'
+import type { AppendDatePluginOptions } from './options.js'
+
+export const appendDatePlugin = (
+ options: AppendDatePluginOptions = {},
+): PluginObject => ({
+ name: PLUGIN_NAME,
+
+ onInitialized: async (app): Promise => {
+ if (isGitPluginEnabled(app))
+ await Promise.all(
+ (app.pages as Page[]).map((page) =>
+ appendDateToPage(options, page),
+ ),
+ )
+ },
+})
diff --git a/plugins/plugin-append-date/src/node/checkGitPlugin.ts b/plugins/plugin-append-date/src/node/checkGitPlugin.ts
new file mode 100644
index 0000000000..5d3c0b3d0a
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/checkGitPlugin.ts
@@ -0,0 +1,32 @@
+import { createRequire } from 'node:module'
+import type { App } from 'vuepress/core'
+import { colors } from 'vuepress/utils'
+import { logger } from './logger.js'
+
+const require = createRequire(import.meta.url)
+
+const GIT_PLUGIN_NAME = '@vuepress/plugin-git'
+
+export const isGitPluginEnabled = (app: App): boolean => {
+ if (
+ app.pluginApi.plugins.every((plugin) => plugin.name !== GIT_PLUGIN_NAME)
+ ) {
+ try {
+ require.resolve(GIT_PLUGIN_NAME)
+
+ logger.info(`${colors.magenta(GIT_PLUGIN_NAME)} is not enabled.`)
+
+ return false
+ } catch (err) {
+ logger.error(
+ `${colors.magenta(
+ GIT_PLUGIN_NAME,
+ )} is required for this plugin, please install it.`,
+ )
+ }
+
+ return false
+ }
+
+ return true
+}
diff --git a/plugins/plugin-append-date/src/node/formatDate.ts b/plugins/plugin-append-date/src/node/formatDate.ts
new file mode 100644
index 0000000000..16b8f7a833
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/formatDate.ts
@@ -0,0 +1,23 @@
+const padZero = (num: number, length = 2): string =>
+ num.toString().padStart(length, '0')
+
+const getFullYear = (date: Date): string => padZero(date.getFullYear(), 4)
+
+const getMonth = (date: Date): string => padZero(date.getMonth() + 1)
+
+const getDate = (date: Date): string => padZero(date.getDate())
+
+const getHours = (date: Date): string => padZero(date.getHours())
+
+const getMinutes = (date: Date): string => padZero(date.getMinutes())
+
+const getSeconds = (date: Date): string => padZero(date.getSeconds())
+
+export const getDateString = (date: Date): string =>
+ `${getFullYear(date)}-${getMonth(date)}-${getDate(date)}`
+
+export const getTimeString = (date: Date): string =>
+ `${getHours(date)}:${getMinutes(date)}:${getSeconds(date)}`
+
+export const getFullDateString = (date: Date): string =>
+ `${getDateString(date)} ${getTimeString(date)}`
diff --git a/plugins/plugin-append-date/src/node/index.ts b/plugins/plugin-append-date/src/node/index.ts
new file mode 100644
index 0000000000..7011377e74
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/index.ts
@@ -0,0 +1,2 @@
+export * from './appendDatePlugin.js'
+export * from './options.js'
diff --git a/plugins/plugin-append-date/src/node/logger.ts b/plugins/plugin-append-date/src/node/logger.ts
new file mode 100644
index 0000000000..865ace8f35
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/logger.ts
@@ -0,0 +1,5 @@
+import { Logger } from '@vuepress/helper'
+
+export const PLUGIN_NAME = 'vuepress-plugin-append-date'
+
+export const logger = new Logger(PLUGIN_NAME)
diff --git a/plugins/plugin-append-date/src/node/options.ts b/plugins/plugin-append-date/src/node/options.ts
new file mode 100644
index 0000000000..d2aea7e016
--- /dev/null
+++ b/plugins/plugin-append-date/src/node/options.ts
@@ -0,0 +1,19 @@
+export interface AppendDatePluginOptions {
+ /**
+ * Frontmatter key to use when appending date.
+ *
+ * 追加时间时使用的 frontmatter 键名。
+ *
+ * @default 'date'
+ */
+ key?: string
+
+ /**
+ * Format of the date value when appending date.
+ *
+ * 追加时间时使用的日期格式。
+ *
+ * @default 'date'
+ */
+ format?: 'date' | 'time' | 'full'
+}
diff --git a/plugins/plugin-append-date/tests/node/formatDate.spec.ts b/plugins/plugin-append-date/tests/node/formatDate.spec.ts
new file mode 100644
index 0000000000..1fee1a90a3
--- /dev/null
+++ b/plugins/plugin-append-date/tests/node/formatDate.spec.ts
@@ -0,0 +1,40 @@
+import { describe, expect, it } from 'vitest'
+import {
+ getDateString,
+ getFullDateString,
+ getTimeString,
+} from '../../src/node/formatDate.js'
+
+describe('getDateString', () => {
+ it('should return date string', () => {
+ expect(getDateString(new Date('2021-01-01'))).toBe('2021-01-01')
+ })
+
+ it('should return date string with full date', () => {
+ expect(getDateString(new Date('2021-01-11 10:11:12'))).toBe('2021-01-11')
+ })
+})
+
+describe('getTimeString', () => {
+ it('should return time string with date', () => {
+ expect(getTimeString(new Date('2021-01-01'))).toBe('00:00:00')
+ })
+
+ it('should return time string with full date', () => {
+ expect(getTimeString(new Date('2021-01-11 10:11:12'))).toBe('10:11:12')
+ })
+})
+
+describe('getFullDateString', () => {
+ it('should return full date string', () => {
+ expect(getFullDateString(new Date('2021-01-01'))).toBe(
+ '2021-01-01 00:00:00',
+ )
+ })
+
+ it('should return full date string with full date', () => {
+ expect(getFullDateString(new Date('2021-01-11 10:11:12'))).toBe(
+ '2021-01-11 10:11:12',
+ )
+ })
+})
diff --git a/plugins/plugin-append-date/tsconfig.build.json b/plugins/plugin-append-date/tsconfig.build.json
new file mode 100644
index 0000000000..9b984d7cd2
--- /dev/null
+++ b/plugins/plugin-append-date/tsconfig.build.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.build.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./lib"
+ },
+ "include": ["./src"],
+ "references": [
+ { "path": "../plugin-git/tsconfig.build.json" },
+ { "path": "../../tools/helper/tsconfig.build.json" }
+ ]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b2fcdd73a6..c77b043d29 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -223,6 +223,18 @@ importers:
specifier: 2.0.0-rc.8
version: 2.0.0-rc.8(@vuepress/bundler-vite@2.0.0-rc.8)(@vuepress/bundler-webpack@2.0.0-rc.8)(typescript@5.4.2)(vue@3.4.21)
+ plugins/plugin-append-date:
+ dependencies:
+ '@vuepress/helper':
+ specifier: workspace:~
+ version: link:../../tools/helper
+ '@vuepress/plugin-git':
+ specifier: workspace:~
+ version: link:../plugin-git
+ vuepress:
+ specifier: 2.0.0-rc.8
+ version: 2.0.0-rc.8(@vuepress/bundler-vite@2.0.0-rc.8)(@vuepress/bundler-webpack@2.0.0-rc.8)(typescript@5.4.2)(vue@3.4.21)
+
plugins/plugin-back-to-top:
dependencies:
'@vuepress/helper':
diff --git a/tsconfig.build.json b/tsconfig.build.json
index a0716fa33b..44e2d38062 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -7,6 +7,7 @@
{
"path": "./plugins/plugin-active-header-links/tsconfig.build.json"
},
+ { "path": "./plugins/plugin-append-date/tsconfig.build.json" },
{ "path": "./plugins/plugin-back-to-top/tsconfig.build.json" },
{ "path": "./plugins/plugin-baidu-analytics/tsconfig.build.json" },
{ "path": "./plugins/plugin-blog/tsconfig.build.json" },