parent
f7bc044147
commit
6e601f9f0e
@ -229,6 +229,96 @@ permalink: /guide/a1b2c3d4/
|
||||
---
|
||||
```
|
||||
|
||||
In the collection, the `meta` option allows you to set the display method of article metadata,
|
||||
This setting will directly affect the display of metadata on both the **article list page** and the **article content page**:
|
||||
|
||||
::: code-tabs#config
|
||||
|
||||
@tab .vuepress/config.ts
|
||||
|
||||
```ts
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
collections: [
|
||||
{
|
||||
type: 'doc',
|
||||
dir: 'guide',
|
||||
title: 'Guide',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // Whether to display labels
|
||||
/**
|
||||
* Whether to display the creation time, or set the time format
|
||||
* - 'short': Display as `2022-01-01`, default
|
||||
* - 'long': Display as `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // Whether to display the reading time estimate
|
||||
wordCount: true, // Whether to display the word count
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@tab .vuepress/plume.config.ts
|
||||
|
||||
``` ts
|
||||
import { defineThemeConfig } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineThemeConfig({
|
||||
collections: [
|
||||
{
|
||||
type: 'doc',
|
||||
dir: 'guide',
|
||||
title: 'Guide',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // Whether to display labels
|
||||
/**
|
||||
* Whether to display the creation time, or set the time format
|
||||
* - 'short': Display as `2022-01-01`, default
|
||||
* - 'long': Display as `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // Whether to display the reading time estimate
|
||||
wordCount: true, // Whether to display the word count
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
In markdown, configure article metadata through frontmatter:
|
||||
|
||||
```md
|
||||
---
|
||||
title: Article Title
|
||||
createTime: 2024/01/01 00:00:00
|
||||
tags:
|
||||
- tag1
|
||||
- tag2
|
||||
---
|
||||
```
|
||||
|
||||
`title` and `createTime` are automatically generated when files are created and support manual modification.
|
||||
|
||||
### Available Properties
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
| ---------- | ---------- | ------------ | ------------- |
|
||||
| title | `string` | File name | Article title |
|
||||
| createTime | `string` | Current time | Creation time |
|
||||
| tags | `string[]` | `[]` | Article tags |
|
||||
|
||||
Also supports all fields from [common frontmatter configuration](../../config/frontmatter/basic.md).
|
||||
|
||||
## Sidebar Configuration
|
||||
|
||||
Provides flexible sidebar navigation configuration options:
|
||||
|
||||
@ -744,7 +744,75 @@ Automatically switches to `top` layout on narrow-screen devices to ensure displa
|
||||
|
||||
## Article Metadata
|
||||
|
||||
Configure article metadata through frontmatter:
|
||||
## 文章元数据
|
||||
|
||||
In the collection, the `meta` option allows you to set the display method of article metadata,
|
||||
This setting will directly affect the display of metadata on both the **article list page** and the **article content page**:
|
||||
|
||||
::: code-tabs#config
|
||||
|
||||
@tab .vuepress/config.ts
|
||||
|
||||
```ts
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
collections: [
|
||||
{
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // Whether to display labels
|
||||
/**
|
||||
* Whether to display the creation time, or set the time format
|
||||
* - 'short': Display as `2022-01-01`, default
|
||||
* - 'long': Display as `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // Whether to display the reading time estimate
|
||||
wordCount: true, // Whether to display the word count
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@tab .vuepress/plume.config.ts
|
||||
|
||||
``` ts
|
||||
import { defineThemeConfig } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineThemeConfig({
|
||||
collections: [
|
||||
{
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // Whether to display labels
|
||||
/**
|
||||
* Whether to display the creation time, or set the time format
|
||||
* - 'short': Display as `2022-01-01`, default
|
||||
* - 'long': Display as `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // Whether to display the reading time estimate
|
||||
wordCount: true, // Whether to display the word count
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
In markdown, configure article metadata through frontmatter:
|
||||
|
||||
```md
|
||||
---
|
||||
@ -761,7 +829,7 @@ tags:
|
||||
### Available Properties
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
| ---------- | ------------------- | ------- | ----------------------------------------- |
|
||||
| ---------- | ------------------- | ------------ | ----------------------------------------- |
|
||||
| title | `string` | File name | Article title |
|
||||
| createTime | `string` | Current time | Creation time |
|
||||
| tags | `string[]` | `[]` | Article tags |
|
||||
|
||||
@ -228,6 +228,97 @@ permalink: /guide/a1b2c3d4/
|
||||
---
|
||||
```
|
||||
|
||||
## 文章元数据
|
||||
|
||||
在集合中通过 `meta` 选项,可以设置文章元数据的显示方式:
|
||||
|
||||
::: code-tabs#config
|
||||
|
||||
@tab .vuepress/config.ts
|
||||
|
||||
```ts
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
collections: [
|
||||
{
|
||||
type: 'doc',
|
||||
dir: 'guide',
|
||||
title: '指南',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // 是否显示标签
|
||||
/**
|
||||
* 是否显示创建时间,或设置时间格式
|
||||
* - 'short': 显示为 `2022-01-01`,默认
|
||||
* - 'long': 显示为 `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // 是否显示阅读时间估算
|
||||
wordCount: true, // 是否显示字数统计
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@tab .vuepress/plume.config.ts
|
||||
|
||||
``` ts
|
||||
import { defineThemeConfig } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineThemeConfig({
|
||||
collections: [
|
||||
{
|
||||
type: 'doc',
|
||||
dir: 'guide',
|
||||
title: '指南',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // 是否显示标签
|
||||
/**
|
||||
* 是否显示创建时间,或设置时间格式
|
||||
* - 'short': 显示为 `2022-01-01`,默认
|
||||
* - 'long': 显示为 `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // 是否显示阅读时间估算
|
||||
wordCount: true, // 是否显示字数统计
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
在 markdown 中,通过 frontmatter 配置文章元数据:
|
||||
|
||||
```md
|
||||
---
|
||||
title: 文章标题
|
||||
createTime: 2024/01/01 00:00:00
|
||||
tags:
|
||||
- tag1
|
||||
- tag2
|
||||
---
|
||||
```
|
||||
|
||||
`title` 和 `createTime` 在文件创建时自动生成,支持手动修改。
|
||||
|
||||
### 可用属性
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
| ---------- | ------------------- | -------- | -------------------------- |
|
||||
| title | `string` | 文件名 | 文章标题 |
|
||||
| createTime | `string` | 当前时间 | 创建时间 |
|
||||
| tags | `string[]` | `[]` | 文章标签 |
|
||||
|
||||
同时支持[通用 frontmatter 配置](../../config/frontmatter/basic.md)中的所有字段。
|
||||
|
||||
## 侧边栏配置
|
||||
|
||||
提供灵活的侧边栏导航配置选项:
|
||||
|
||||
@ -738,7 +738,73 @@ interface PostCoverStyle {
|
||||
|
||||
## 文章元数据
|
||||
|
||||
通过 frontmatter 配置文章元数据:
|
||||
在集合中通过 `meta` 选项,可以设置文章元数据的显示方式,
|
||||
该设置将直接影响 **文章列表页** 和 **文章内容页** 的元数据显示:
|
||||
|
||||
::: code-tabs#config
|
||||
|
||||
@tab .vuepress/config.ts
|
||||
|
||||
```ts
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineUserConfig({
|
||||
theme: plumeTheme({
|
||||
collections: [
|
||||
{
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // 是否显示标签
|
||||
/**
|
||||
* 是否显示创建时间,或设置时间格式
|
||||
* - 'short': 显示为 `2022-01-01`,默认
|
||||
* - 'long': 显示为 `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // 是否显示阅读时间估算
|
||||
wordCount: true, // 是否显示字数统计
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
@tab .vuepress/plume.config.ts
|
||||
|
||||
``` ts
|
||||
import { defineThemeConfig } from 'vuepress-theme-plume'
|
||||
|
||||
export default defineThemeConfig({
|
||||
collections: [
|
||||
{
|
||||
type: 'post',
|
||||
dir: 'blog',
|
||||
title: '博客',
|
||||
// [!code hl:11]
|
||||
meta: {
|
||||
tags: true, // 是否显示标签
|
||||
/**
|
||||
* 是否显示创建时间,或设置时间格式
|
||||
* - 'short': 显示为 `2022-01-01`,默认
|
||||
* - 'long': 显示为 `2022-01-01 00:00:00`
|
||||
*/
|
||||
createTime: true, // boolean | 'short' | 'long'
|
||||
readingTime: true, // 是否显示阅读时间估算
|
||||
wordCount: true, // 是否显示字数统计
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
在 markdown 中,通过 frontmatter 配置文章元数据:
|
||||
|
||||
```md
|
||||
---
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import type { PostsCoverStyle, ThemePostsItem } from '../../../shared/index.js'
|
||||
import VPLink from '@theme/VPLink.vue'
|
||||
import { isMobile as _isMobile } from '@vuepress/helper/client'
|
||||
import { getReadingTimeLocale, useReadingTimeLocaleConfig } from '@vuepress/plugin-reading-time/client'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { withBase } from 'vuepress/client'
|
||||
import { useData, useInternalLink, useTagColors } from '../../composables/index.js'
|
||||
@ -24,9 +25,26 @@ const { collection } = useData<'page', 'post'>()
|
||||
const colors = useTagColors()
|
||||
const { categories: categoriesLink, tags: tagsLink } = useInternalLink()
|
||||
|
||||
const createTime = computed(() => post.createTime?.split(/\s|T/)[0].replace(/\//g, '-'))
|
||||
const metaConfig = computed(() => collection.value?.meta ?? {})
|
||||
const createTime = computed(() => {
|
||||
if (!post.createTime || metaConfig.value.createTime === false)
|
||||
return ''
|
||||
|
||||
const format = metaConfig.value.createTime === true ? 'short' : metaConfig.value.createTime ?? 'short'
|
||||
return (format !== 'short' ? post.createTime : post.createTime?.split(/\s|T/)[0]).replace(/\//g, '-')
|
||||
})
|
||||
const categoryList = computed(() => post.categoryList ?? [])
|
||||
|
||||
const readingTimeLocale = useReadingTimeLocaleConfig()
|
||||
const readingTime = computed(() => {
|
||||
const fallback = { time: '', words: '' }
|
||||
if (!post.readingTime)
|
||||
return fallback
|
||||
const res = readingTimeLocale.value ? getReadingTimeLocale(post.readingTime, readingTimeLocale.value) : fallback
|
||||
res.time = res.time.replace(/^\D+/, '')
|
||||
return res
|
||||
})
|
||||
|
||||
const sticky = computed(() => {
|
||||
if (typeof post.sticky === 'boolean') {
|
||||
return post.sticky
|
||||
@ -122,6 +140,11 @@ const coverStyles = computed(() => {
|
||||
<span v-if="i !== categoryList.length - 1">/</span>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="readingTime.time && (metaConfig.readingTime !== false || metaConfig.wordCount !== false)" class="reading-time">
|
||||
<span class="vpi-books icon" />
|
||||
<span v-if="metaConfig.wordCount !== false">{{ readingTime.words }}</span>
|
||||
<span v-if="metaConfig.readingTime !== false">{{ readingTime.time }}</span>
|
||||
</div>
|
||||
<div v-if="tags.length" class="tag-list">
|
||||
<span class="icon vpi-tag" />
|
||||
<template v-for="tag in tags" :key="tag.name">
|
||||
@ -316,7 +339,7 @@ const coverStyles = computed(() => {
|
||||
.post-item-content .post-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
gap: 0 16px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 14px;
|
||||
@ -327,19 +350,14 @@ const coverStyles = computed(() => {
|
||||
|
||||
.post-item-content .post-meta > div {
|
||||
display: flex;
|
||||
gap: 0 6px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.post-item-content .post-meta .tag-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.post-item-content .post-meta .tag-list .tag {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
margin-right: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
color: var(--vp-tag-color);
|
||||
@ -355,7 +373,6 @@ const coverStyles = computed(() => {
|
||||
.post-item-content .post-meta .icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 0.3rem;
|
||||
color: var(--vp-c-text-3);
|
||||
transition: color var(--vp-t-color);
|
||||
}
|
||||
@ -370,11 +387,11 @@ const coverStyles = computed(() => {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.excerpt.vp-doc :deep(p:first-of-type) {
|
||||
.excerpt.vp-doc :deep(:first-of-type) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.excerpt.vp-doc :deep(p:last-of-type) {
|
||||
.excerpt.vp-doc :deep(:last-of-type) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@ -392,4 +409,10 @@ const coverStyles = computed(() => {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 419px) {
|
||||
.excerpt.vp-doc :deep(.hint-container) {
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -12,17 +12,26 @@ const readingTime = useReadingTimeLocale()
|
||||
const { tags: tagsLink } = useInternalLink()
|
||||
const { isPosts } = usePostsPageData()
|
||||
|
||||
const metaConfig = computed(() => collection.value?.meta ?? {})
|
||||
|
||||
const createTime = computed(() => {
|
||||
if (matter.value.createTime === false || metaConfig.value.createTime === false)
|
||||
return ''
|
||||
|
||||
const format = metaConfig.value.createTime === true ? 'short' : metaConfig.value.createTime ?? 'short'
|
||||
const show = theme.value.createTime ?? true
|
||||
if (!show || (show === 'only-posts' && !isPosts.value))
|
||||
return ''
|
||||
if (matter.value.createTime)
|
||||
return matter.value.createTime.split(/\s|T/)[0].replace(/\//g, '-')
|
||||
const createTime = matter.value.createTime
|
||||
if (createTime)
|
||||
return (format !== 'short' ? createTime : createTime.split(/\s|T/)[0]).replace(/\//g, '-')
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
const tags = computed(() => {
|
||||
if (metaConfig.value.tags === false)
|
||||
return []
|
||||
const tagTheme = collection.value?.tagsTheme ?? 'colored'
|
||||
if (matter.value.tags) {
|
||||
return matter.value.tags.slice(0, 4).map(tag => ({
|
||||
@ -45,7 +54,7 @@ const badge = computed(() => {
|
||||
const hasDocMetaSlot = inject<Ref<boolean>>('doc-meta-slot-exists', ref(false))
|
||||
|
||||
const hasMeta = computed(() =>
|
||||
readingTime.value.time
|
||||
(readingTime.value.time && (metaConfig.value.readingTime !== false || metaConfig.value.wordCount !== false))
|
||||
|| tags.value.length
|
||||
|| createTime.value
|
||||
|| hasDocMetaSlot.value,
|
||||
@ -66,10 +75,10 @@ const hasMeta = computed(() =>
|
||||
<div v-if="hasMeta" class="vp-doc-meta">
|
||||
<slot name="doc-meta-before" />
|
||||
|
||||
<p v-if="readingTime.time && matter.readingTime !== false" class="reading-time">
|
||||
<p v-if="readingTime.time && matter.readingTime !== false && (metaConfig.readingTime !== false || metaConfig.wordCount !== false)" class="reading-time">
|
||||
<span class="vpi-books icon" />
|
||||
<span>{{ readingTime.words }}</span>
|
||||
<span>{{ readingTime.time }}</span>
|
||||
<span v-if="metaConfig.wordCount !== false">{{ readingTime.words }}</span>
|
||||
<span v-if="metaConfig.readingTime !== false">{{ readingTime.time }}</span>
|
||||
</p>
|
||||
|
||||
<p v-if="tags.length > 0">
|
||||
|
||||
@ -48,6 +48,7 @@ function processPostData(
|
||||
excerpt: '',
|
||||
cover: page.frontmatter.cover,
|
||||
coverStyle: page.frontmatter.coverStyle,
|
||||
readingTime: page.data.readingTime,
|
||||
}
|
||||
|
||||
if (typeof data.cover === 'object') {
|
||||
|
||||
@ -50,6 +50,36 @@ export interface ThemeBaseCollection {
|
||||
* 自动生成文章的 frontmatter
|
||||
*/
|
||||
autoFrontmatter?: AutoFrontmatterOptions | false
|
||||
|
||||
/**
|
||||
* 文章元数据配置
|
||||
* - 设置文章列表中的文章元信息 显示方式
|
||||
* - 设置文章内容页元信息显示方式
|
||||
*/
|
||||
meta?: {
|
||||
/**
|
||||
* 元数据中是否显示标签
|
||||
* @default true
|
||||
*/
|
||||
tags?: boolean
|
||||
/**
|
||||
* 元数据中是否显示阅读时间
|
||||
* @default true
|
||||
*/
|
||||
readingTime?: boolean
|
||||
/**
|
||||
* 元数据中是否显示字数
|
||||
* @default true
|
||||
*/
|
||||
wordCount?: boolean
|
||||
/**
|
||||
* 元数据中是否显示创建时间,或者创建时间的显示格式
|
||||
* - `short`: 2022-01-01
|
||||
* - `long`: 2022-01-01 00:00:00
|
||||
* @default 'short'
|
||||
*/
|
||||
createTime?: 'short' | 'long' | boolean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import type { ReadingTime } from '@vuepress/plugin-reading-time'
|
||||
|
||||
export interface PostsCategoryItem {
|
||||
/**
|
||||
* 分类 ID
|
||||
@ -100,6 +102,11 @@ export interface ThemePostsItem {
|
||||
* 文章是否为草稿
|
||||
*/
|
||||
draft?: boolean
|
||||
|
||||
/**
|
||||
* 阅读统计
|
||||
*/
|
||||
readingTime?: ReadingTime
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,7 +5,7 @@ export interface ThemePostFrontmatter extends ThemePageFrontmatter {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string
|
||||
createTime?: string | false
|
||||
|
||||
/**
|
||||
* 文章标签
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user