refactor(theme): improve blog structure

This commit is contained in:
pengzhanbo 2024-06-18 14:35:24 +08:00
parent a941d90712
commit 155667234d
10 changed files with 148 additions and 127 deletions

View File

@ -1,6 +1,7 @@
<script lang="ts" setup>
import VPShortPostList from '@theme/Blog/VPShortPostList.vue'
import { useArchives, useBlogExtract } from '../../composables/blog.js'
import { useBlogExtract } from '../../composables/blog-extract.js'
import { useArchives } from '../../composables/blog-archives.js'
const { archives: archivesLink } = useBlogExtract()
const { archives } = useArchives()

View File

@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue'
import { useRoute, withBase } from 'vuepress/client'
import { isLinkHttp } from 'vuepress/shared'
import VPLink from '@theme/VPLink.vue'
import { useBlogExtract } from '../../composables/blog.js'
import { useBlogExtract } from '../../composables/blog-extract.js'
import { useData } from '../../composables/data.js'
import { inBrowser } from '../../utils/index.js'

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { useRoute } from 'vuepress/client'
import VPLink from '@theme/VPLink.vue'
import { useBlogExtract } from '../../composables/blog.js'
import { useBlogExtract } from '../../composables/blog-extract.js'
const props = defineProps<{
isLocal?: boolean

View File

@ -1,6 +1,7 @@
<script lang="ts" setup>
import VPShortPostList from '@theme/Blog/VPShortPostList.vue'
import { useBlogExtract, useTags } from '../../composables/blog.js'
import { useBlogExtract } from '../../composables/blog-extract.js'
import { useTags } from '../../composables/blog-tags.js'
const { tags, currentTag, postList, handleTagClick } = useTags()
const { tags: tagsLink } = useBlogExtract()

View File

@ -2,7 +2,7 @@
import VPTransitionDrop from '@theme/VPTransitionDrop.vue'
import VPPostItem from '@theme/Blog/VPPostItem.vue'
import VPPagination from '@theme/Blog/VPPagination.vue'
import { usePostListControl } from '../../composables/blog.js'
import { usePostListControl } from '../../composables/blog-post-list.js'
const {
postList,

View File

@ -0,0 +1,31 @@
import { computed } from 'vue'
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
import { useLocalePostList } from './blog-post-list.js'
export type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
export function useArchives() {
const list = useLocalePostList()
const archives = computed(() => {
const archives: { label: string, list: ShortPostItem[] }[] = []
list.value.forEach((item) => {
const createTime = item.createTime.split(' ')[0]
const year = createTime.split('/')[0]
let current = archives.find(archive => archive.label === year)
if (!current) {
current = { label: year, list: [] }
archives.push(current)
}
current.list.push({
title: item.title,
path: item.path,
createTime: createTime.slice(year.length + 1).replace(/\//g, '-'),
})
})
return archives
})
return { archives }
}

View File

@ -0,0 +1,41 @@
import { useRouteLocale } from 'vuepress/client'
import { computed } from 'vue'
import type { PresetLocale } from '../../shared/index.js'
import { useLocalePostList } from './blog-post-list.js'
import { useTags } from './blog-tags.js'
import { useData } from './data.js'
import { useLocaleLink } from './locale.js'
declare const __PLUME_PRESET_LOCALE__: Record<string, PresetLocale>
const presetLocales = __PLUME_PRESET_LOCALE__
export function useBlogExtract() {
const { theme } = useData()
const locale = useRouteLocale()
const postList = useLocalePostList()
const { tags: tagsList } = useTags()
const blog = computed(() => theme.value.blog || {})
const hasBlogExtract = computed(() => blog.value.archives !== false || blog.value.tags !== false)
const tagsLink = useLocaleLink(blog.value.tagsLink || 'blog/tags/')
const archiveLink = useLocaleLink(blog.value.archivesLink || 'blog/archives/')
const tags = computed(() => ({
link: tagsLink.value,
text: presetLocales[locale.value]?.tag || presetLocales['/'].tag,
total: tagsList.value.length,
}))
const archives = computed(() => ({
link: archiveLink.value,
text: presetLocales[locale.value]?.archive || presetLocales['/'].archive,
total: postList.value.length,
}))
return {
hasBlogExtract,
tags,
archives,
}
}

View File

@ -3,9 +3,8 @@ import { useBlogPostData } from '@vuepress-plume/plugin-blog-data/client'
import { computed } from 'vue'
import { useMediaQuery } from '@vueuse/core'
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
import { useData, useLocaleLink, useRouteQuery } from '../composables/index.js'
import { toArray } from '../utils/index.js'
import { useTagColors } from './tag-colors.js'
import { useData } from './data.js'
import { useRouteQuery } from './route-query.js'
const DEFAULT_PER_PAGE = 10
@ -133,121 +132,3 @@ export function usePostListControl() {
changePage,
}
}
const extractLocales: Record<string, { tags: string, archives: string }> = {
'zh-CN': { tags: '标签', archives: '归档' },
'en': { tags: 'Tags', archives: 'Archives' },
'zh-TW': { tags: '標籤', archives: '歸檔' },
}
export function useBlogExtract() {
const { theme } = useData()
const locale = usePageLang()
const postList = useLocalePostList()
const { tags: tagsList } = useTags()
const blog = computed(() => theme.value.blog || {})
const hasBlogExtract = computed(() => blog.value.archives !== false || blog.value.tags !== false)
const tagsLink = useLocaleLink(blog.value.tagsLink || 'blog/tags/')
const archiveLink = useLocaleLink(blog.value.archivesLink || 'blog/archives/')
const tags = computed(() => ({
link: tagsLink.value,
text: extractLocales[locale.value]?.tags || extractLocales.en.tags,
total: tagsList.value.length,
}))
const archives = computed(() => ({
link: archiveLink.value,
text: extractLocales[locale.value]?.archives || extractLocales.en.archives,
total: postList.value.length,
}))
return {
hasBlogExtract,
tags,
archives,
}
}
export type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
export function useTags() {
const list = useLocalePostList()
const colors = useTagColors()
const tags = computed(() => {
const tagMap: Record<string, number> = {}
list.value.forEach((item) => {
if (item.tags) {
toArray(item.tags).forEach((tag) => {
if (tagMap[tag])
tagMap[tag] += 1
else
tagMap[tag] = 1
})
}
})
return Object.keys(tagMap).map(tag => ({
name: tag,
count: tagMap[tag] > 99 ? '99+' : tagMap[tag],
className: `vp-tag-${colors.value[tag]}`,
}))
})
const currentTag = useRouteQuery<string>('tag')
const postList = computed<ShortPostItem[]>(() => {
if (!currentTag.value)
return []
return list.value.filter((item) => {
if (item.tags)
return toArray(item.tags).includes(currentTag.value)
return false
}).map(item => ({
title: item.title,
path: item.path,
createTime: item.createTime.split(' ')[0].replace(/\//g, '-'),
}))
})
const handleTagClick = (tag: string) => {
currentTag.value = tag
}
return {
tags,
currentTag,
postList,
handleTagClick,
}
}
export function useArchives() {
const list = useLocalePostList()
const archives = computed(() => {
const archives: { label: string, list: ShortPostItem[] }[] = []
list.value.forEach((item) => {
const createTime = item.createTime.split(' ')[0]
const year = createTime.split('/')[0]
let current = archives.find(archive => archive.label === year)
if (!current) {
current = { label: year, list: [] }
archives.push(current)
}
current.list.push({
title: item.title,
path: item.path,
createTime: createTime.slice(year.length + 1).replace(/\//g, '-'),
})
})
return archives
})
return { archives }
}

View File

@ -0,0 +1,62 @@
import { computed } from 'vue'
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
import { toArray } from '../utils/index.js'
import { useTagColors } from './tag-colors.js'
import { useLocalePostList } from './blog-post-list.js'
import { useRouteQuery } from './route-query.js'
type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
export function useTags() {
const list = useLocalePostList()
const colors = useTagColors()
const tags = computed(() => {
const tagMap: Record<string, number> = {}
list.value.forEach((item) => {
if (item.tags) {
toArray(item.tags).forEach((tag) => {
if (tagMap[tag])
tagMap[tag] += 1
else
tagMap[tag] = 1
})
}
})
return Object.keys(tagMap).map(tag => ({
name: tag,
count: tagMap[tag] > 99 ? '99+' : tagMap[tag],
className: `vp-tag-${colors.value[tag]}`,
}))
})
const currentTag = useRouteQuery<string>('tag')
const postList = computed<ShortPostItem[]>(() => {
if (!currentTag.value)
return []
return list.value.filter((item) => {
if (item.tags)
return toArray(item.tags).includes(currentTag.value)
return false
}).map(item => ({
title: item.title,
path: item.path,
createTime: item.createTime.split(' ')[0].replace(/\//g, '-'),
}))
})
const handleTagClick = (tag: string) => {
currentTag.value = tag
}
return {
tags,
currentTag,
postList,
handleTagClick,
}
}

View File

@ -2,6 +2,7 @@ export * from './theme-data.js'
export * from './dark-mode.js'
export * from './data.js'
export * from './scroll-promise.js'
export * from './scroll-behavior.js'
export * from './sidebar.js'
export * from './aside.js'
@ -12,7 +13,10 @@ export * from './edit-link.js'
export * from './latest-updated.js'
export * from './contributors.js'
export * from './blog.js'
export * from './blog-post-list.js'
export * from './blog-extract.js'
export * from './blog-tags.js'
export * from './blog-archives.js'
export * from './tag-colors.js'
export * from './locale.js'