fix: switch blog pagination to client-side
Astro 6 getStaticPaths+paginate has issues with non-dynamic pages. Client-side pagination works fine for small blog volumes.
This commit is contained in:
@@ -2,18 +2,14 @@
|
||||
import PageShell from '../components/PageShell.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
export async function getStaticPaths({ paginate }) {
|
||||
const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
);
|
||||
const POSTS_PER_PAGE = 12;
|
||||
|
||||
return paginate(posts, { pageSize: 12 });
|
||||
}
|
||||
|
||||
const { page } = Astro.props;
|
||||
const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
);
|
||||
|
||||
// Collect all unique categories
|
||||
const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort();
|
||||
const allCategories = [...new Set(posts.map((p) => p.data.category))].sort();
|
||||
---
|
||||
|
||||
<PageShell
|
||||
@@ -38,7 +34,7 @@ const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort()
|
||||
</div>
|
||||
|
||||
<div class="blog-grid" id="blog-grid">
|
||||
{page.data.map((post) => {
|
||||
{posts.map((post) => {
|
||||
const fmt = new Intl.DateTimeFormat('th-TH', { day: '2-digit', month: 'short', year: '2-digit' }).format(post.data.pubDate);
|
||||
return (
|
||||
<a class="blog-card liquid-glass liquidGlass-wrapper" href={`/blog/${post.id}/`} data-cat={post.data.category}>
|
||||
@@ -59,32 +55,83 @@ const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort()
|
||||
<p class="blog-empty" id="blog-empty" hidden>ไม่พบบทความที่ตรงกับหมวดหมู่นี้</p>
|
||||
|
||||
<!-- Pagination -->
|
||||
{page.lastPage > 1 && (
|
||||
<nav class="blog-pagination" aria-label="หน้าบทความ">
|
||||
{page.url.prev ? (
|
||||
<a class="pagination-btn" href={page.url.prev} aria-label="หน้าก่อนหน้า">
|
||||
← ก่อนหน้า
|
||||
</a>
|
||||
) : (
|
||||
<span class="pagination-btn pagination-btn--disabled">← ก่อนหน้า</span>
|
||||
)}
|
||||
|
||||
<span class="pagination-info">
|
||||
หน้า {page.currentPage} จาก {page.lastPage}
|
||||
</span>
|
||||
|
||||
{page.url.next ? (
|
||||
<a class="pagination-btn" href={page.url.next} aria-label="หน้าถัดไป">
|
||||
ถัดไป →
|
||||
</a>
|
||||
) : (
|
||||
<span class="pagination-btn pagination-btn--disabled">ถัดไป →</span>
|
||||
)}
|
||||
</nav>
|
||||
)}
|
||||
<nav class="blog-pagination" id="blog-pagination" aria-label="หน้าบทความ" hidden>
|
||||
<button class="pagination-btn" id="prev-btn" disabled>← ก่อนหน้า</button>
|
||||
<span class="pagination-info" id="page-info"></span>
|
||||
<button class="pagination-btn" id="next-btn">ถัดไป →</button>
|
||||
</nav>
|
||||
</section>
|
||||
</PageShell>
|
||||
|
||||
<script is:inline define:vars={{ POSTS_PER_PAGE }}>
|
||||
const grid = document.getElementById('blog-grid');
|
||||
const tagsEl = document.getElementById('blog-tags');
|
||||
const empty = document.getElementById('blog-empty');
|
||||
const pagination = document.getElementById('blog-pagination');
|
||||
const prevBtn = document.getElementById('prev-btn');
|
||||
const nextBtn = document.getElementById('next-btn');
|
||||
const pageInfo = document.getElementById('page-info');
|
||||
|
||||
const allCards = Array.from(grid?.querySelectorAll('.blog-card') || []);
|
||||
const tagBtns = tagsEl?.querySelectorAll('.blog-tag');
|
||||
|
||||
let currentPage = 1;
|
||||
let activeCategory = 'all';
|
||||
|
||||
function getVisibleCards() {
|
||||
return allCards.filter(card =>
|
||||
activeCategory === 'all' || card.dataset.cat === activeCategory
|
||||
);
|
||||
}
|
||||
|
||||
function updateDisplay() {
|
||||
const visible = getVisibleCards();
|
||||
const totalPages = Math.ceil(visible.length / POSTS_PER_PAGE);
|
||||
const start = (currentPage - 1) * POSTS_PER_PAGE;
|
||||
const end = start + POSTS_PER_PAGE;
|
||||
|
||||
// Hide all cards
|
||||
allCards.forEach(card => card.style.display = 'none');
|
||||
|
||||
// Show current page cards
|
||||
visible.slice(start, end).forEach(card => card.style.display = '');
|
||||
|
||||
// Update pagination
|
||||
empty.hidden = visible.length > 0;
|
||||
pagination.hidden = totalPages <= 1;
|
||||
prevBtn.disabled = currentPage <= 1;
|
||||
nextBtn.disabled = currentPage >= totalPages;
|
||||
pageInfo.textContent = totalPages > 0
|
||||
? `หน้า ${currentPage} จาก ${totalPages}`
|
||||
: '';
|
||||
}
|
||||
|
||||
// Category filter
|
||||
if (tagBtns) {
|
||||
tagBtns.forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
activeCategory = btn.dataset.cat;
|
||||
currentPage = 1;
|
||||
tagBtns.forEach((b) => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
updateDisplay();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Pagination buttons
|
||||
prevBtn?.addEventListener('click', () => {
|
||||
if (currentPage > 1) { currentPage--; updateDisplay(); }
|
||||
});
|
||||
nextBtn?.addEventListener('click', () => {
|
||||
const totalPages = Math.ceil(getVisibleCards().length / POSTS_PER_PAGE);
|
||||
if (currentPage < totalPages) { currentPage++; updateDisplay(); }
|
||||
});
|
||||
|
||||
// Initial render
|
||||
updateDisplay();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.blog-section::before { display: none; }
|
||||
|
||||
@@ -194,17 +241,16 @@ const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort()
|
||||
color: var(--ink);
|
||||
font-size: 0.88rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all .2s var(--ease);
|
||||
}
|
||||
.pagination-btn:hover {
|
||||
.pagination-btn:hover:not(:disabled) {
|
||||
background: var(--yellow);
|
||||
border-color: var(--yellow);
|
||||
}
|
||||
.pagination-btn--disabled {
|
||||
.pagination-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pagination-info {
|
||||
color: var(--muted);
|
||||
@@ -233,31 +279,3 @@ const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort()
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const tagsEl = document.getElementById('blog-tags');
|
||||
const grid = document.getElementById('blog-grid');
|
||||
const empty = document.getElementById('blog-empty');
|
||||
const cards = grid?.querySelectorAll('.blog-card');
|
||||
const tagBtns = tagsEl?.querySelectorAll('.blog-tag');
|
||||
|
||||
if (tagBtns && cards) {
|
||||
tagBtns.forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
const cat = btn.dataset.cat;
|
||||
tagBtns.forEach((b) => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
let visible = 0;
|
||||
cards.forEach((card) => {
|
||||
if (cat === 'all' || card.dataset.cat === cat) {
|
||||
card.style.display = '';
|
||||
visible++;
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
empty.hidden = visible > 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user