mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
162 lines
4.3 KiB
TypeScript
162 lines
4.3 KiB
TypeScript
import type { ComputedRef, Ref } from 'vue'
|
|
import type { ThemePostsItem } from '../../shared/index.js'
|
|
import { computed } from 'vue'
|
|
import { useData } from './data.js'
|
|
import { useLayout } from './layout.js'
|
|
import { useLocalePostList } from './posts-data.js'
|
|
import { useRouteQuery } from './route-query.js'
|
|
|
|
const DEFAULT_PER_PAGE = 15
|
|
|
|
interface UsePostListControlResult {
|
|
postList: ComputedRef<ThemePostsItem[]>
|
|
page: Ref<number>
|
|
totalPage: ComputedRef<number>
|
|
pageRange: ComputedRef<{
|
|
value: number | string
|
|
more?: true
|
|
}[]>
|
|
isLastPage: ComputedRef<boolean>
|
|
isFirstPage: ComputedRef<boolean>
|
|
isPaginationEnabled: ComputedRef<boolean>
|
|
changePage: (page: number) => void
|
|
}
|
|
|
|
export function usePostListControl(homePage: Ref<boolean>): UsePostListControlResult {
|
|
const { collection } = useData<'page', 'post'>()
|
|
|
|
const list = useLocalePostList()
|
|
const { is960 } = useLayout()
|
|
|
|
const postCollection = computed(() => {
|
|
if (collection.value?.type === 'post')
|
|
return collection.value
|
|
return undefined
|
|
})
|
|
|
|
const postList = computed(() => {
|
|
const stickyList = list.value.filter(item =>
|
|
item.sticky === true || typeof item.sticky === 'number',
|
|
)
|
|
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,
|
|
] as ThemePostsItem[]
|
|
})
|
|
|
|
const page = useRouteQuery('p', 1, {
|
|
mode: 'push',
|
|
transform(val) {
|
|
const page = Number(val)
|
|
if (!Number.isNaN(page) && page > 0)
|
|
return page
|
|
return 1
|
|
},
|
|
})
|
|
|
|
const perPage = computed(() => {
|
|
if (postCollection.value?.pagination === false)
|
|
return 0
|
|
if (typeof postCollection.value?.pagination === 'number')
|
|
return postCollection.value.pagination
|
|
return postCollection.value?.pagination?.perPage || DEFAULT_PER_PAGE
|
|
})
|
|
|
|
const totalPage = computed(() => {
|
|
if (postCollection.value?.pagination === false)
|
|
return 0
|
|
return Math.ceil(postList.value.length / perPage.value)
|
|
})
|
|
const isLastPage = computed(() => page.value >= totalPage.value)
|
|
const isFirstPage = computed(() => page.value <= 1)
|
|
const isPaginationEnabled = computed(() => postCollection.value?.pagination !== false && totalPage.value > 1)
|
|
|
|
const finalList = computed(() => {
|
|
if (postCollection.value?.pagination === false)
|
|
return postList.value
|
|
|
|
if (postList.value.length <= perPage.value)
|
|
return postList.value
|
|
|
|
return postList.value.slice(
|
|
(page.value - 1) * perPage.value,
|
|
page.value * perPage.value,
|
|
)
|
|
})
|
|
|
|
const pageRange = computed(() => {
|
|
let range: { value: number | string, more?: true }[] = []
|
|
const total = totalPage.value
|
|
const _page = page.value
|
|
const per = is960.value ? 4 : 5
|
|
|
|
if (total <= 0)
|
|
return range
|
|
if (total <= 10) {
|
|
range = Array.from({ length: total }, (_, i) => ({ value: i + 1 }))
|
|
}
|
|
else {
|
|
let i = 1
|
|
let hasMore = false
|
|
while (i <= total) {
|
|
if ((_page <= per && i <= per) || (_page >= total - (per - 1) && i >= total - (per - 1))) {
|
|
hasMore = false
|
|
range.push({ value: i })
|
|
}
|
|
else if (i <= 2 || i >= total - 1) {
|
|
hasMore = false
|
|
range.push({ value: i })
|
|
}
|
|
else if (
|
|
(_page > per + 1 || _page < total - (per + 1))
|
|
&& _page - i < per - 2
|
|
&& i - _page < per - 2
|
|
) {
|
|
hasMore = false
|
|
range.push({ value: i })
|
|
}
|
|
else if (!hasMore) {
|
|
hasMore = true
|
|
range.push({ value: i, more: true })
|
|
}
|
|
i++
|
|
}
|
|
}
|
|
return range
|
|
})
|
|
|
|
const changePage = (current: number): void => {
|
|
if (page.value === current)
|
|
return
|
|
page.value = current
|
|
setTimeout(() => {
|
|
let top = 0
|
|
if (homePage.value) {
|
|
top = document.querySelector('.vp-posts')?.getBoundingClientRect().top || 0
|
|
top += window.scrollY - 64
|
|
}
|
|
|
|
window.scrollTo({ top, behavior: 'instant' })
|
|
}, 0)
|
|
}
|
|
|
|
return {
|
|
postList: finalList,
|
|
page,
|
|
totalPage,
|
|
pageRange,
|
|
isLastPage,
|
|
isFirstPage,
|
|
isPaginationEnabled,
|
|
changePage,
|
|
}
|
|
}
|