feat(theme): add support for tags color themes (#284)

This commit is contained in:
pengzhanbo 2024-10-14 13:12:31 +08:00 committed by GitHub
parent aa638a864f
commit a7595025b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 81 additions and 19 deletions

View File

@ -104,6 +104,17 @@ interface BlogOptions {
*/
tagsLink?: string
/**
* 标签颜色主题
*
* - `colored` 彩色标签,不同标签颜色不同
* - `brand`: 使用主题颜色作为标签颜色
* - `gray`: 使用 灰色 作为标签颜色
*
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'
/**
* 是否启用归档页
* @default true

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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}`,
}))
})

View File

@ -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
* -------------------------------------------------------------------------- */

View File

@ -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),

View File

@ -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) {

View File

@ -74,6 +74,13 @@ export interface PlumeThemeBlog {
* @default '/blog/tags/'
*/
tagsLink?: string
/**
*
*
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'
/**
*
* @default true