refactor(theme): improve blog structure
This commit is contained in:
parent
a941d90712
commit
155667234d
@ -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()
|
||||
|
||||
@ -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'
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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,
|
||||
|
||||
31
theme/src/client/composables/blog-archives.ts
Normal file
31
theme/src/client/composables/blog-archives.ts
Normal 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 }
|
||||
}
|
||||
41
theme/src/client/composables/blog-extract.ts
Normal file
41
theme/src/client/composables/blog-extract.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
@ -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 }
|
||||
}
|
||||
62
theme/src/client/composables/blog-tags.ts
Normal file
62
theme/src/client/composables/blog-tags.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
@ -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'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user