190 lines
5.2 KiB
TypeScript

import { usePageLang } from '@vuepress/client'
import { useBlogPostData } from '@vuepress-plume/plugin-blog-data/client'
import { computed, ref } from 'vue'
import type { Ref } from 'vue'
import type { PlumeThemeBlogPostItem } from '../../shared/index.js'
import { useLocaleLink, useThemeLocaleData } from '../composables/index.js'
import { toArray } from '../utils/index.js'
export const usePostListControl = () => {
const locale = usePageLang()
const themeData = useThemeLocaleData()
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
const blog = computed(() => themeData.value.blog || {})
const pagination = computed(() => blog.value.pagination || {})
const postList = computed(() => {
const stickyList = list.value.filter((item) =>
typeof item.sticky === 'boolean' ? item.sticky : item.sticky >= 0
)
const otherList = list.value.filter(
(item) => item.sticky === undefined || item.sticky === false
)
return [
...stickyList.sort((prev, next) => {
if (next.sticky === true && prev.sticky === true) return 0
return next.sticky > prev.sticky ? 1 : -1
}),
...otherList,
].filter((item) => item.lang === locale.value)
})
const page = ref(1)
const totalPage = computed(() => {
if (blog.value.pagination === false) return 0
const perPage = blog.value.pagination?.perPage || 20
return Math.ceil(postList.value.length / perPage)
})
const isLastPage = computed(() => page.value >= totalPage.value)
const isFirstPage = computed(() => page.value <= 1)
const isPaginationEnabled = computed(() => blog.value.pagination !== false && totalPage.value > 1)
const finalList = computed(() => {
if (blog.value.pagination === false) return postList.value
const perPage = blog.value.pagination?.perPage || 20
if (postList.value.length <= perPage) return postList.value
return postList.value.slice(
(page.value - 1) * perPage,
page.value * perPage
)
})
const changePage = (offset: number) => {
page.value += offset
window.scrollTo({ top: 0, left: 0, behavior: 'instant' })
}
return {
pagination,
postList: finalList,
page,
totalPage,
isLastPage,
isFirstPage,
isPaginationEnabled,
changePage,
}
}
const extractLocales: Record<string, { tags: string; archives: string }> = {
'zh-CN': { tags: '标签', archives: '归档' },
en: { tags: 'Tags', archives: 'Archives' },
'zh-TW': { tags: '標籤', archives: '歸檔' },
}
export const useBlogExtract = () => {
const theme = useThemeLocaleData()
const locale = usePageLang()
const hasBlogExtract = computed(() => theme.value.blog?.archives !== false || theme.value.blog?.tags !== false)
const tagsLink = useLocaleLink('blog/tags/')
const archiveLink = useLocaleLink('blog/archives/')
const tags = computed(() => ({
link: tagsLink.value,
text: extractLocales[locale.value]?.tags || extractLocales.en.tags,
}))
const archives = computed(() => ({
link: archiveLink.value,
text: extractLocales[locale.value]?.archives || extractLocales.en.archives,
}))
return {
hasBlogExtract,
tags,
archives,
}
}
export type ShortPostItem = Pick<PlumeThemeBlogPostItem, 'title' | 'path' | 'createTime'>
export const useTags = () => {
const locale = usePageLang()
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
const filteredList = computed(() =>
list.value.filter((item) => item.lang === locale.value)
)
const tags = computed(() => {
const tagMap: Record<string, number> = {}
filteredList.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],
}))
})
const postList = ref<ShortPostItem[]>([])
const currentTag = ref<string>()
const handleTagClick = (tag: string) => {
currentTag.value = tag
postList.value = filteredList.value.filter((item) => {
if (item.tags) {
return toArray(item.tags).includes(tag)
}
return false
}).map((item) => ({
title: item.title,
path: item.path,
createTime: item.createTime.split(' ')[0],
}))
}
return {
tags,
currentTag,
postList,
handleTagClick
}
}
export const useArchives = () => {
const locale = usePageLang()
const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]>
const filteredList = computed(() =>
list.value.filter((item) => item.lang === locale.value)
)
const archives = computed(() => {
const archives: { label: string, list: ShortPostItem[] }[] = []
filteredList.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),
})
})
return archives
})
return {
archives
}
}