Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/notes/theme/config/主题配置.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ interface BlogOptions {
*/
tagsLink?: string

/**
* 标签颜色主题
*
* - `colored`: 彩色标签,不同标签颜色不同
* - `brand`: 使用主题颜色作为标签颜色
* - `gray`: 使用 灰色 作为标签颜色
*
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'

/**
* 是否启用归档页
* @default true
Expand Down
10 changes: 5 additions & 5 deletions theme/src/client/components/Blog/VPBlogTags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}

Expand Down
14 changes: 9 additions & 5 deletions theme/src/client/components/Blog/VPPostItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions theme/src/client/components/VPDocMeta.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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}`,
}))
}

Expand Down Expand Up @@ -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;
}

Expand Down
7 changes: 6 additions & 1 deletion theme/src/client/composables/blog-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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}`,
}))
})

Expand Down
16 changes: 16 additions & 0 deletions theme/src/client/styles/vars.css
Original file line number Diff line number Diff line change
Expand Up @@ -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
* -------------------------------------------------------------------------- */
Expand Down
2 changes: 1 addition & 1 deletion theme/src/node/prepare/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
25 changes: 21 additions & 4 deletions theme/src/node/prepare/prepareArticleTagColor.ts
Original file line number Diff line number Diff line change
@@ -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 [
Expand Down Expand Up @@ -32,22 +34,37 @@ 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`,
)
}
}

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) {
Expand Down
7 changes: 7 additions & 0 deletions theme/src/shared/blog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ export interface PlumeThemeBlog {
* @default '/blog/tags/'
*/
tagsLink?: string

/**
* 标签颜色主题
*
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'
/**
* 是否启用归档页
* @default true
Expand Down