mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
feat(theme): add support for tags color themes (#284)
This commit is contained in:
parent
aa638a864f
commit
a7595025b7
@ -104,6 +104,17 @@ interface BlogOptions {
|
||||
*/
|
||||
tagsLink?: string
|
||||
|
||||
/**
|
||||
* 标签颜色主题
|
||||
*
|
||||
* - `colored`: 彩色标签,不同标签颜色不同
|
||||
* - `brand`: 使用主题颜色作为标签颜色
|
||||
* - `gray`: 使用 灰色 作为标签颜色
|
||||
*
|
||||
* @default 'colored'
|
||||
*/
|
||||
tagsTheme?: 'colored' | 'gray' | 'brand'
|
||||
|
||||
/**
|
||||
* 是否启用归档页
|
||||
* @default true
|
||||
|
||||
@ -94,11 +94,11 @@ const { tags, currentTag, postList, handleTagClick } = useTags()
|
||||
padding: 6px 10px 6px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
color: var(--vp-c-bg);
|
||||
color: var(--vp-tag-color);
|
||||
word-wrap: break-word;
|
||||
cursor: pointer;
|
||||
background-color: var(--vp-tag-color);
|
||||
border: solid 1px var(--vp-tag-color);
|
||||
background-color: var(--vp-tag-bg);
|
||||
border: 1px solid var(--vp-tag-bg);
|
||||
border-radius: 6px;
|
||||
transition: all var(--vp-t-color);
|
||||
}
|
||||
@ -117,8 +117,8 @@ const { tags, currentTag, postList, handleTagClick } = useTags()
|
||||
display: inline-block;
|
||||
padding-left: 6px;
|
||||
margin-left: 4px;
|
||||
color: var(--vp-c-bg);
|
||||
border-left: 1px solid var(--vp-c-bg);
|
||||
color: var(--vp-tag-color);
|
||||
border-left: 1px solid var(--vp-tag-color);
|
||||
transition: color var(--vp-t-color), border-left var(--vp-t-color);
|
||||
}
|
||||
|
||||
|
||||
@ -27,14 +27,18 @@ const sticky = computed(() => {
|
||||
return false
|
||||
})
|
||||
|
||||
const tags = computed(() =>
|
||||
(props.post.tags ?? [])
|
||||
const tags = computed(() => {
|
||||
const blog = theme.value.blog || {}
|
||||
const tagTheme = blog.tagsTheme ?? 'colored'
|
||||
|
||||
return (props.post.tags ?? [])
|
||||
.slice(0, 4)
|
||||
.map(tag => ({
|
||||
name: tag,
|
||||
className: `vp-tag-${colors.value[tag]}`,
|
||||
})),
|
||||
)
|
||||
className: colors.value[tag] ? `vp-tag-${colors.value[tag]}` : `tag-${tagTheme}`,
|
||||
}))
|
||||
})
|
||||
|
||||
const cover = computed<BlogPostCover | null>(() => {
|
||||
if (!props.post.cover)
|
||||
return null
|
||||
|
||||
@ -22,10 +22,12 @@ const createTime = computed(() => {
|
||||
})
|
||||
|
||||
const tags = computed(() => {
|
||||
const blog = theme.value.blog || {}
|
||||
const tagTheme = blog.tagsTheme ?? 'colored'
|
||||
if (matter.value.tags) {
|
||||
return matter.value.tags.slice(0, 4).map(tag => ({
|
||||
name: tag,
|
||||
className: `vp-tag-${colors.value[tag]}`,
|
||||
className: colors.value[tag] ? `vp-tag-${colors.value[tag]}` : `tag-${tagTheme}`,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -122,8 +124,8 @@ const hasMeta = computed(() => readingTime.value.time || tags.value.length || cr
|
||||
margin-right: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
color: var(--vp-tag-color, var(--vp-c-text-3));
|
||||
background-color: var(--vp-tag-bg, var(--vp-c-default-soft));
|
||||
color: var(--vp-tag-color);
|
||||
background-color: var(--vp-tag-bg);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
@ -2,17 +2,22 @@ import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
|
||||
import { computed } from 'vue'
|
||||
import { toArray } from '../utils/index.js'
|
||||
import { useLocalePostList } from './blog-data.js'
|
||||
import { useData } from './data.js'
|
||||
import { useRouteQuery } from './route-query.js'
|
||||
import { useTagColors } from './tag-colors.js'
|
||||
|
||||
type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
|
||||
|
||||
export function useTags() {
|
||||
const { theme } = useData()
|
||||
const list = useLocalePostList()
|
||||
|
||||
const colors = useTagColors()
|
||||
|
||||
const tags = computed(() => {
|
||||
const blog = theme.value.blog || {}
|
||||
const tagTheme = blog.tagsTheme ?? 'colored'
|
||||
|
||||
const tagMap: Record<string, number> = {}
|
||||
list.value.forEach((item) => {
|
||||
if (item.tags) {
|
||||
@ -27,7 +32,7 @@ export function useTags() {
|
||||
return Object.keys(tagMap).map(tag => ({
|
||||
name: tag,
|
||||
count: tagMap[tag] > 99 ? '99+' : tagMap[tag],
|
||||
className: `vp-tag-${colors.value[tag]}`,
|
||||
className: colors.value[tag] ? `vp-tag-${colors.value[tag]}` : `tag-${tagTheme}`,
|
||||
}))
|
||||
})
|
||||
|
||||
|
||||
@ -689,6 +689,22 @@
|
||||
--vp-mark-color-soft: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
/**
|
||||
* post tag
|
||||
* -------------------------------------------------------------------------- */
|
||||
.tag:not([class*="vp-tag-"]),
|
||||
.tag.tag-gray {
|
||||
--vp-tag-color: var(--vp-c-text-3);
|
||||
--vp-tag-bg: var(--vp-c-default-soft);
|
||||
--vp-tag-hover-color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.tag.tag-brand {
|
||||
--vp-tag-color: var(--vp-c-brand-1);
|
||||
--vp-tag-bg: var(--vp-c-brand-soft);
|
||||
--vp-tag-hover-color: var(--vp-c-brand-2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatible with `vuepress` guidelines
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -14,7 +14,7 @@ export async function prepareData(
|
||||
const start = performance.now()
|
||||
const { localeOptions, encrypt } = getThemeConfig()
|
||||
await Promise.all([
|
||||
prepareArticleTagColors(app),
|
||||
prepareArticleTagColors(app, localeOptions),
|
||||
preparedBlogData(app, localeOptions, encrypt),
|
||||
prepareSidebar(app, localeOptions),
|
||||
prepareEncrypt(app, encrypt),
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import type { App } from 'vuepress'
|
||||
import type { PlumeThemeLocaleOptions } from '../../shared/index.js'
|
||||
import { toArray } from '@pengzhanbo/utils'
|
||||
import { isPlainObject } from 'vuepress/shared'
|
||||
import { logger, nanoid, resolveContent, writeTemp } from '../utils/index.js'
|
||||
|
||||
export type TagsColorsItem = readonly [
|
||||
@ -32,11 +34,16 @@ export const PRESET: TagsColorsItem[] = [
|
||||
// { index: className }
|
||||
const cache: Record<number, string> = {}
|
||||
|
||||
export async function prepareArticleTagColors(app: App): Promise<void> {
|
||||
export async function prepareArticleTagColors(app: App, localeOptions: PlumeThemeLocaleOptions): Promise<void> {
|
||||
const start = performance.now()
|
||||
const { js, css } = genCode(app)
|
||||
await writeTemp(app, 'internal/articleTagColors.css', css)
|
||||
const blog = isPlainObject(localeOptions.blog) ? localeOptions.blog : {}
|
||||
|
||||
const { js, css } = genCode(app, blog.tagsTheme ?? 'colored')
|
||||
if (css)
|
||||
await writeTemp(app, 'internal/articleTagColors.css', css)
|
||||
|
||||
await writeTemp(app, 'internal/articleTagColors.js', js)
|
||||
|
||||
if (app.env.isDebug) {
|
||||
logger.info(
|
||||
`Generate article tag colors: ${(performance.now() - start).toFixed(2)}ms`,
|
||||
@ -44,10 +51,20 @@ export async function prepareArticleTagColors(app: App): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export function genCode(app: App): { js: string, css: string } {
|
||||
export function genCode(app: App, theme: 'colored' | 'brand' | 'gray'): { js: string, css: string } {
|
||||
const articleTagColors: Record<string, string> = {}
|
||||
const tagList = new Set<string>()
|
||||
|
||||
if (theme !== 'colored') {
|
||||
return {
|
||||
js: resolveContent(app, {
|
||||
name: 'articleTagColors',
|
||||
content: articleTagColors,
|
||||
}),
|
||||
css: '',
|
||||
}
|
||||
}
|
||||
|
||||
app.pages.forEach((page) => {
|
||||
const { frontmatter: { tags } } = page
|
||||
if (tags) {
|
||||
|
||||
@ -74,6 +74,13 @@ export interface PlumeThemeBlog {
|
||||
* @default '/blog/tags/'
|
||||
*/
|
||||
tagsLink?: string
|
||||
|
||||
/**
|
||||
* 标签颜色主题
|
||||
*
|
||||
* @default 'colored'
|
||||
*/
|
||||
tagsTheme?: 'colored' | 'gray' | 'brand'
|
||||
/**
|
||||
* 是否启用归档页
|
||||
* @default true
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user