commit
8ac657b828
@ -100,8 +100,8 @@ H~2~O
|
||||
**图标:**
|
||||
|
||||
- home - <Icon name="material-symbols:home" color="currentColor" size="1em" />
|
||||
- vscode - <Iconify name="skill-icons:vscode-dark" size="2em" />
|
||||
- twitter - <Iconify name="skill-icons:twitter" size="2em" />
|
||||
- vscode - <Icon name="skill-icons:vscode-dark" size="2em" />
|
||||
- twitter - <Icon name="skill-icons:twitter" size="2em" />
|
||||
|
||||
**demo wrapper:**
|
||||
|
||||
|
||||
@ -56,16 +56,6 @@ permalink: /config/frontmatter/basic/
|
||||
|
||||
主题会在文件创建时,自动填充 当前文件名作为 文章标题。
|
||||
|
||||
### author
|
||||
|
||||
- 类型: `string`
|
||||
- 默认值: `''`
|
||||
- 详情:
|
||||
|
||||
文章作者。
|
||||
|
||||
主题会在文件创建时,自动填充 `avatar.name || packageJson.author` 作为 文章作者。
|
||||
|
||||
### createTime
|
||||
|
||||
- 类型: `string`
|
||||
@ -186,11 +176,13 @@ permalink: /config/frontmatter/basic/
|
||||
### contributors
|
||||
|
||||
- 类型: `boolean`
|
||||
- 默认值: `true`
|
||||
- 默认值: `true | string | string[]`
|
||||
- 详情:
|
||||
|
||||
当前文章是否 显示 贡献者。 贡献者 根据 git 提交者自动填充。
|
||||
|
||||
如果您的文章来源于第三方, git 提交不能完整列出所有的作者,您可以在此处补充贡献者。
|
||||
|
||||
### editLink
|
||||
|
||||
- 类型: `boolean`
|
||||
|
||||
@ -11,7 +11,7 @@ tags:
|
||||
|
||||
## 介绍
|
||||
|
||||
**vuepress-theme-plume** 是一个基于 VuePress 的主题,适用于 博客、文档 和 知识笔记 。
|
||||
==vuepress-theme-plume== 是一个基于 VuePress 的主题,适用于 博客、文档 和 知识笔记 。
|
||||
|
||||
VuePress 是一个 [静态站点生成器](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) 。
|
||||
专为构建快速、以内容为中心的站点而设计。
|
||||
@ -40,7 +40,7 @@ VuePress 是一个 [静态站点生成器](https://en.wikipedia.org/wiki/Static_
|
||||
- 支持使用单独的主题配置文件,避免修改配置导致频繁重启 VuePress 服务。
|
||||
- 大幅度简化了配置,更易于使用,同时还保留了丰富灵活的配置项,满足个性化的需求。
|
||||
|
||||
`plume` 主题尽可能的内置你可能需要的功能,以及搭建站点所需要的一般性配置,您无需关注这些细节。
|
||||
==plume 主题== 尽可能的内置你可能需要的功能,以及搭建站点所需要的一般性配置,您无需关注这些细节。
|
||||
目的是,让您更专注于 内容的创作,更好的表达你的想法,享受 Markdown 增强语法带来的便利。
|
||||
|
||||
## 功能
|
||||
|
||||
@ -69,14 +69,13 @@ export default defineUserConfig({
|
||||
---
|
||||
title: 文章标题
|
||||
createTime: 2024/01/01 00:00:00
|
||||
author: your name
|
||||
tags:
|
||||
- tag1
|
||||
- tag2
|
||||
---
|
||||
```
|
||||
|
||||
其中,`title` / `createTime` / `author` 会在新建 md 文件时由主题自动填充,你可以随意修改它们。
|
||||
其中,`title` / `createTime` 会在新建 md 文件时由主题自动填充,你可以随意修改它们。
|
||||
|
||||
以下是在 博客文章中可用的 `frontmatter` 属性。
|
||||
|
||||
@ -84,7 +83,6 @@ tags:
|
||||
| ---------- | ------------------- | --------------------------- | -------------------------------------------- |
|
||||
| title | `string` | 默认自动填入文件名 | 文章标题 |
|
||||
| createTime | `string` | 当前时间 | 文章创建时间 |
|
||||
| author | `string` | 默认自动填入 `profile.name` | 文章作者 |
|
||||
| tags | `string[]` | `[]` | 文章标签 |
|
||||
| sticky | `boolean \| number` | false | 是否置顶, 如果为数字,则数字越大,置顶越靠前 |
|
||||
| draft | `boolean` | false | 是否为草稿,草稿文章不会被展示 |
|
||||
|
||||
@ -29,11 +29,11 @@ const option = {
|
||||
return (
|
||||
`${date.getDate()
|
||||
}/${
|
||||
date.getMonth() + 1
|
||||
date.getMonth() + 1
|
||||
}/${
|
||||
date.getFullYear()
|
||||
date.getFullYear()
|
||||
} : ${
|
||||
params.value[1]}`
|
||||
params.value[1]}`
|
||||
)
|
||||
},
|
||||
axisPointer: {
|
||||
|
||||
@ -12,10 +12,10 @@
|
||||
"vuepress": "2.0.0-rc.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/json": "^2.2.238",
|
||||
"@iconify/json": "^2.2.239",
|
||||
"@simonwep/pickr": "^1.9.1",
|
||||
"@vuepress/bundler-vite": "2.0.0-rc.14",
|
||||
"chart.js": "^4.4.3",
|
||||
"chart.js": "^4.4.4",
|
||||
"echarts": "^5.5.1",
|
||||
"flowchart.ts": "^3.0.0",
|
||||
"http-server": "^14.1.1",
|
||||
|
||||
@ -39,8 +39,8 @@
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.4.0",
|
||||
"@commitlint/config-conventional": "^19.2.2",
|
||||
"@pengzhanbo/eslint-config-vue": "^1.12.0",
|
||||
"@pengzhanbo/stylelint-config": "^1.12.0",
|
||||
"@pengzhanbo/eslint-config-vue": "^1.13.0",
|
||||
"@pengzhanbo/stylelint-config": "^1.13.0",
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/node": "20.12.10",
|
||||
"@types/webpack-env": "^1.18.5",
|
||||
@ -50,14 +50,14 @@
|
||||
"cpx2": "^7.0.1",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^9.9.0",
|
||||
"husky": "^9.1.4",
|
||||
"husky": "^9.1.5",
|
||||
"lint-staged": "^15.2.9",
|
||||
"rimraf": "^6.0.1",
|
||||
"stylelint": "^16.8.2",
|
||||
"tsconfig-vuepress": "^5.0.0",
|
||||
"tsup": "^8.2.4",
|
||||
"typescript": "^5.5.4",
|
||||
"wait-on": "^7.2.0"
|
||||
"wait-on": "^8.0.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint --fix"
|
||||
|
||||
@ -41,12 +41,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vuepress/helper": "2.0.0-rc.40",
|
||||
"@vueuse/core": "^11.0.0",
|
||||
"@vueuse/core": "^11.0.1",
|
||||
"markdown-it-container": "^4.0.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"shiki": "^1.14.1",
|
||||
"tm-grammars": "^1.17.2",
|
||||
"tm-themes": "^1.7.1",
|
||||
"tm-grammars": "^1.17.3",
|
||||
"tm-themes": "^1.8.0",
|
||||
"vue": "^3.4.38"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -63,8 +63,8 @@ ${Array.from(imports.values()).join('\n')}
|
||||
export default defineClientConfig({
|
||||
enhance({ router, app }) {
|
||||
${Array.from(enhances.values())
|
||||
.map(item => ` ${item}`)
|
||||
.join('\n')}
|
||||
.map(item => ` ${item}`)
|
||||
.join('\n')}
|
||||
}
|
||||
})
|
||||
`,
|
||||
|
||||
@ -41,8 +41,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vuepress/helper": "2.0.0-rc.40",
|
||||
"@vueuse/core": "^11.0.0",
|
||||
"@vueuse/integrations": "^11.0.0",
|
||||
"@vueuse/core": "^11.0.1",
|
||||
"@vueuse/integrations": "^11.0.1",
|
||||
"chokidar": "^3.6.0",
|
||||
"focus-trap": "^7.5.4",
|
||||
"mark.js": "^8.11.1",
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
"@shikijs/twoslash": "^1.14.1",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@vuepress/helper": "2.0.0-rc.40",
|
||||
"@vueuse/core": "^11.0.0",
|
||||
"@vueuse/core": "^11.0.1",
|
||||
"floating-vue": "^5.2.2",
|
||||
"mdast-util-from-markdown": "^2.0.1",
|
||||
"mdast-util-gfm": "^3.0.0",
|
||||
|
||||
@ -14,8 +14,8 @@ export function getLanguage(
|
||||
if (!langLoaded && !isPlainLang(lang) && !isSpecialLang(lang)) {
|
||||
logger.warn(
|
||||
c.yellow(
|
||||
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang || 'txt'
|
||||
}' for syntax highlighting.`,
|
||||
`\nThe language '${lang}' is not loaded, falling back to '${defaultLang || 'txt'
|
||||
}' for syntax highlighting.`,
|
||||
),
|
||||
)
|
||||
lang = defaultLang
|
||||
|
||||
@ -21,19 +21,19 @@ import { useCollapsedLines } from '${CLIENT_FOLDER}composables/collapsed-lines.j
|
||||
|
||||
export default {
|
||||
${twoslash
|
||||
? `enhance({ app }) {
|
||||
? `enhance({ app }) {
|
||||
enhanceTwoslash(app)
|
||||
},`
|
||||
: ''}
|
||||
: ''}
|
||||
${copyCode
|
||||
? `setup() {
|
||||
? `setup() {
|
||||
useCopyCode({
|
||||
selector: __CC_SELECTOR__,
|
||||
duration: __CC_DURATION__,
|
||||
})
|
||||
useCollapsedLines()
|
||||
},`
|
||||
: ''}
|
||||
: ''}
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
804
pnpm-lock.yaml
generated
804
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -71,7 +71,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/utils": "^2.1.30",
|
||||
"@iconify/utils": "^2.1.31",
|
||||
"@iconify/vue": "^4.1.2",
|
||||
"@pengzhanbo/utils": "^1.1.2",
|
||||
"@vuepress-plume/plugin-content-update": "workspace:*",
|
||||
@ -91,7 +91,7 @@
|
||||
"@vuepress/plugin-seo": "2.0.0-rc.40",
|
||||
"@vuepress/plugin-sitemap": "2.0.0-rc.40",
|
||||
"@vuepress/plugin-watermark": "2.0.0-rc.40",
|
||||
"@vueuse/core": "^11.0.0",
|
||||
"@vueuse/core": "^11.0.1",
|
||||
"bcrypt-ts": "^5.0.2",
|
||||
"chokidar": "^3.6.0",
|
||||
"create-filter": "^1.1.0",
|
||||
@ -109,6 +109,6 @@
|
||||
"vuepress-plugin-md-power": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.238"
|
||||
"@iconify/json": "^2.2.239"
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,7 @@ const hasEditLink = computed(() =>
|
||||
const hasLastUpdated = computed(() =>
|
||||
Boolean(theme.value.lastUpdated && frontmatter.value.lastUpdated !== false && lastUpdated.value),
|
||||
)
|
||||
const hasContributors = computed(() =>
|
||||
Boolean(theme.value.contributors && frontmatter.value.contributors !== false && contributors.value?.length),
|
||||
)
|
||||
const hasContributors = computed(() => Boolean(contributors.value.length))
|
||||
|
||||
const showFooter = computed(() => {
|
||||
return hasEditLink.value
|
||||
@ -62,8 +60,8 @@ const showFooter = computed(() => {
|
||||
</span>
|
||||
<span class="contributors-info">
|
||||
<template v-for="(contributor, index) in contributors" :key="contributor">
|
||||
<span class="contributor" :title="`email: ${contributor.email}`">
|
||||
{{ contributor.name }}
|
||||
<span class="contributor">
|
||||
{{ contributor }}
|
||||
</span>
|
||||
<template v-if="index !== contributors.length - 1">, </template>
|
||||
</template>
|
||||
|
||||
@ -59,10 +59,10 @@ const hasMeta = computed(() => readingTime.value.time || tags.value.length || cr
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
<div v-if="hasMeta" class="vp-doc-meta">
|
||||
<p v-if="matter.author" class="author">
|
||||
<!-- <p v-if="matter.author" class="author">
|
||||
<span class="icon vpi-user" />
|
||||
<span>{{ matter.author }}</span>
|
||||
</p>
|
||||
</p> -->
|
||||
<p v-if="readingTime.time && matter.readingTime !== false" class="reading-time">
|
||||
<span class="vpi-books icon" />
|
||||
<span>{{ readingTime.words }}</span>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { onMounted, ref, toValue, watch } from 'vue'
|
||||
import { useMediaQuery } from '@vueuse/core'
|
||||
|
||||
const props = defineProps<{
|
||||
@ -8,8 +8,9 @@ const props = defineProps<{
|
||||
|
||||
const md = useMediaQuery('(min-width: 768px)')
|
||||
const lg = useMediaQuery('(min-width: 960px)')
|
||||
const repeat = ref(1)
|
||||
|
||||
const cols = computed(() => {
|
||||
function resolveCols() {
|
||||
const reset = { sm: 1, md: 2, lg: 2 }
|
||||
if (!props.cols)
|
||||
return reset
|
||||
@ -17,25 +18,29 @@ const cols = computed(() => {
|
||||
const cols = Number(props.cols)
|
||||
return { sm: cols, md: cols, lg: cols }
|
||||
}
|
||||
return { ...reset, ...props.cols }
|
||||
return { ...reset, ...toValue(props.cols) }
|
||||
}
|
||||
|
||||
function getRepeat() {
|
||||
const cols = resolveCols()
|
||||
if (lg.value)
|
||||
return cols.lg
|
||||
if (md.value)
|
||||
return cols.md
|
||||
return cols.sm
|
||||
}
|
||||
|
||||
watch(() => [md.value, lg.value, props.cols], () => {
|
||||
repeat.value = getRepeat()
|
||||
})
|
||||
|
||||
const repeat = computed(() => {
|
||||
if (lg.value)
|
||||
return cols.value.lg
|
||||
else if (md.value)
|
||||
return cols.value.md
|
||||
else
|
||||
return cols.value.sm
|
||||
onMounted(() => {
|
||||
repeat.value = getRepeat()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="vp-card-grid" :class="[`cols-${repeat}`]" :style="{
|
||||
gridTemplateColumns: `repeat(${repeat}, 1fr)`,
|
||||
}"
|
||||
>
|
||||
<div class="vp-card-grid" :class="[`cols-${repeat}`]" :style="{ gridTemplateColumns: `repeat(${repeat}, 1fr)` }">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -118,6 +118,7 @@ const date = computed(() => {
|
||||
margin: 0 0 16px;
|
||||
overflow: hidden;
|
||||
font-size: 18px;
|
||||
color: var(--vp-c-white);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { computed } from 'vue'
|
||||
import type { ComputedRef } from 'vue'
|
||||
import type { PlumeThemePageData } from '../../shared/index.js'
|
||||
import { useData } from '../composables/data.js'
|
||||
import { toArray } from '../utils/index.js'
|
||||
|
||||
export function useContributors(): ComputedRef<
|
||||
null | Required<PlumeThemePageData['git']>['contributors']
|
||||
> {
|
||||
export function useContributors(): ComputedRef<string[]> {
|
||||
const { theme, page, frontmatter } = useData()
|
||||
|
||||
return computed(() => {
|
||||
const showContributors
|
||||
= frontmatter.value.contributors ?? theme.value.contributors ?? true
|
||||
const config = frontmatter.value.contributors ?? theme.value.contributors ?? true
|
||||
|
||||
if (!showContributors)
|
||||
return null
|
||||
if (config === false)
|
||||
return []
|
||||
|
||||
return page.value.git?.contributors ?? null
|
||||
const contributors = config === true ? [] : toArray(config)
|
||||
const gitContributors = (page.value.git?.contributors ?? []).map(({ name }) => name)
|
||||
|
||||
return Array.from(new Set([...gitContributors, ...contributors]))
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
.vp-doc h6 {
|
||||
position: relative;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
overflow-wrap: break-word;
|
||||
outline: none;
|
||||
transition: color var(--t-color);
|
||||
}
|
||||
|
||||
.vp-doc h1 {
|
||||
@ -62,7 +62,7 @@
|
||||
|
||||
.vp-doc .header-anchor {
|
||||
position: relative;
|
||||
color: inherit;
|
||||
color: currentcolor;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@ -277,6 +277,41 @@
|
||||
color: var(--vp-code-link-hover-color);
|
||||
}
|
||||
|
||||
.vp-doc mark {
|
||||
padding: 2px;
|
||||
color: currentcolor;
|
||||
background-color: transparent;
|
||||
background-image:
|
||||
linear-gradient(
|
||||
to bottom,
|
||||
transparent 25%,
|
||||
var(--vp-mark-color-soft) 30%,
|
||||
var(--vp-mark-color-soft) 50%,
|
||||
var(--vp-mark-color) 75%,
|
||||
var(--vp-mark-color) 90%,
|
||||
var(--vp-mark-color-soft) 100%
|
||||
);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 1em;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
animation: mark-highlight 1.5s 0.5s forwards;
|
||||
}
|
||||
|
||||
.vp-doc :not(h1,h2,h3,h4,h5,h6) mark {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@keyframes mark-highlight {
|
||||
0% {
|
||||
background-position: 0 1em;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* External links
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -632,3 +632,16 @@ html.dark {
|
||||
--photo-swipe-bullet: var(--vp-c-bg);
|
||||
--photo-swipe-bullet-active: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* mark
|
||||
* -------------------------------------------------------------------------- */
|
||||
:root {
|
||||
--vp-mark-color: var(--vp-c-brand-3);
|
||||
--vp-mark-color-soft: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-mark-color: var(--vp-c-brand-3);
|
||||
--vp-mark-color-soft: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import type {
|
||||
} from '../../shared/index.js'
|
||||
import {
|
||||
getCurrentDirname,
|
||||
getPackage,
|
||||
nanoid,
|
||||
normalizePath,
|
||||
pathJoin,
|
||||
@ -24,8 +23,7 @@ export function resolveOptions(
|
||||
localeOptions: PlumeThemeLocaleOptions,
|
||||
options: AutoFrontmatter,
|
||||
): AutoFrontmatter {
|
||||
const pkg = getPackage()
|
||||
const { locales = {}, article: articlePrefix = '/article/' } = localeOptions
|
||||
const { article: articlePrefix = '/article/' } = localeOptions
|
||||
|
||||
const resolveLocale = (relativeFilepath: string) => {
|
||||
const file = ensureLeadingSlash(relativeFilepath)
|
||||
@ -33,11 +31,6 @@ export function resolveOptions(
|
||||
return resolveLocalePath(localeOptions.locales!, file)
|
||||
}
|
||||
|
||||
const resolveOptions = (relativeFilepath: string) => {
|
||||
const locale = resolveLocale(relativeFilepath)
|
||||
return locales[locale] || localeOptions
|
||||
}
|
||||
|
||||
const notesList = resolveNotesOptions(localeOptions)
|
||||
const localesNotesDirs = uniq(notesList
|
||||
.flatMap(({ notes, dir }) =>
|
||||
@ -46,18 +39,6 @@ export function resolveOptions(
|
||||
|
||||
const baseFrontmatter: AutoFrontmatterObject = {}
|
||||
|
||||
if (options.author !== false) {
|
||||
baseFrontmatter.author = (author: string, { relativePath }, data) => {
|
||||
if (author)
|
||||
return author
|
||||
if (data.friends || data.pageLayout === 'friends')
|
||||
return
|
||||
const profile = resolveOptions(relativePath).profile ?? resolveOptions(relativePath).avatar
|
||||
|
||||
return profile?.name || pkg.author || ''
|
||||
}
|
||||
}
|
||||
|
||||
if (options.createTime !== false) {
|
||||
baseFrontmatter.createTime = (formatTime: string, { createTime }, data) => {
|
||||
if (formatTime)
|
||||
|
||||
@ -71,7 +71,7 @@ export function getPlugins({
|
||||
|
||||
if (pluginOptions.git ?? isProd) {
|
||||
plugins.push(gitPlugin({
|
||||
createdTime: false,
|
||||
createdTime: true,
|
||||
updatedTime: true,
|
||||
contributors: true,
|
||||
}))
|
||||
|
||||
@ -51,6 +51,8 @@ export interface AutoFrontmatter {
|
||||
* 是否自动生成 author
|
||||
*
|
||||
* 默认读取 `profile.name` 或 `package.json` 的 `author`
|
||||
*
|
||||
* @deprecated 不再默认生成 `author`, 该配置已废弃
|
||||
*/
|
||||
author?: boolean
|
||||
/**
|
||||
|
||||
@ -25,7 +25,7 @@ export interface PlumeThemePageFrontmatter extends PlumeNormalFrontmatter {
|
||||
/**
|
||||
* 是否显示贡献者
|
||||
*/
|
||||
contributors?: boolean
|
||||
contributors?: boolean | string | string[]
|
||||
/**
|
||||
* 上一篇
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user