blog / src /components /common /Pagination.astro
cacode's picture
Upload 434 files
96dd062 verified
---
import type { Page } from "astro";
import { Icon } from "astro-icon/components";
import I18nKey from "@/i18n/i18nKey";
import { i18n } from "@/i18n/translation";
import { url } from "@/utils/url-utils";
interface Props {
page: Page;
class?: string;
style?: string;
}
const { page, style } = Astro.props;
const HIDDEN = -1;
const className = Astro.props.class;
const ADJ_DIST = 2;
const VISIBLE = ADJ_DIST * 2 + 1;
// for test
let count = 1;
let l = page.currentPage;
let r = page.currentPage;
while (0 < l - 1 && r + 1 <= page.lastPage && count + 2 <= VISIBLE) {
count += 2;
l--;
r++;
}
while (0 < l - 1 && count < VISIBLE) {
count++;
l--;
}
while (r + 1 <= page.lastPage && count < VISIBLE) {
count++;
r++;
}
let pages: number[] = [];
if (l > 1) pages.push(1);
if (l === 3) pages.push(2);
if (l > 3) pages.push(HIDDEN);
for (let i = l; i <= r; i++) pages.push(i);
if (r < page.lastPage - 2) pages.push(HIDDEN);
if (r === page.lastPage - 2) pages.push(page.lastPage - 1);
if (r < page.lastPage) pages.push(page.lastPage);
const getPageUrl = (p: number) => {
if (p === 1) return "/";
return `/${p}/`;
};
---
<div class:list={[className, "flex flex-col gap-4 items-center"]} style={style}>
<!-- 分页信息 - 已禁用 -->
<!--
{
page.lastPage > 1 && (
<div class="text-sm text-(--text-secondary) text-center">
第 {page.currentPage} 页,共 {page.lastPage} 页
</div>
)
}
-->
<!-- 分页控件 -->
<div class="flex flex-row gap-3 justify-center" role="navigation" aria-label={i18n(I18nKey.postList)}>
<a
href={page.url.prev || "#"}
aria-label={i18n(I18nKey.paginationPrev)}
aria-disabled={page.url.prev === undefined ? "true" : "false"}
tabindex={page.url.prev === undefined ? "-1" : "0"}
class:list={[
"btn-card overflow-hidden rounded-lg text-(--primary) w-11 h-11",
{ disabled: page.url.prev == undefined },
]}
>
<Icon
name="material-symbols:chevron-left-rounded"
class="text-[1.75rem]"
aria-hidden="true"
/>
</a>
<div
class="bg-(--card-bg) flex flex-row rounded-lg items-center text-neutral-700 dark:text-neutral-300 font-bold"
>
{
pages.map((p) => {
if (p == HIDDEN)
return <Icon name="material-symbols:more-horiz" class="mx-1" aria-hidden="true" />;
if (p == page.currentPage)
return (
<div
class="h-11 w-11 rounded-lg bg-(--primary) flex items-center justify-center
font-bold text-white dark:text-black/70"
aria-current="page"
>
{p}
</div>
);
return (
<a
href={url(getPageUrl(p))}
aria-label={`${i18n(I18nKey.paginationPage)} ${p}`}
class="btn-card w-11 h-11 rounded-lg overflow-hidden active:scale-[0.85]"
>
{p}
</a>
);
})
}
</div>
<a
href={page.url.next || "#"}
aria-label={i18n(I18nKey.paginationNext)}
aria-disabled={page.url.next === undefined ? "true" : "false"}
tabindex={page.url.next === undefined ? "-1" : "0"}
class:list={[
"btn-card overflow-hidden rounded-lg text-(--primary) w-11 h-11",
{ disabled: page.url.next == undefined },
]}
>
<Icon
name="material-symbols:chevron-right-rounded"
class="text-[1.75rem]"
aria-hidden="true"
/>
</a>
</div>
</div>