mirror of
https://github.com/10h30/blog-balodeplao.git
synced 2026-05-12 15:21:15 +09:00
feat: optimize taxonomy data retrieval and streamline pagination handling
This commit is contained in:
@@ -7,6 +7,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { categories, class: className = "text-sm" } = Astro.props;
|
const { categories, class: className = "text-sm" } = Astro.props;
|
||||||
|
const categoryMap = getTaxonomyMap("category");
|
||||||
---
|
---
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -18,7 +19,7 @@ const { categories, class: className = "text-sm" } = Astro.props;
|
|||||||
href={`/category/${getTaxonomyPath("category", category)}`}
|
href={`/category/${getTaxonomyPath("category", category)}`}
|
||||||
class="inline-block bg-primary/10 hover:bg-primary/20 text-primary hover:text-primary px-3 py-1 rounded-full border border-primary/20 transition-colors duration-200"
|
class="inline-block bg-primary/10 hover:bg-primary/20 text-primary hover:text-primary px-3 py-1 rounded-full border border-primary/20 transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{getTaxonomyMap("category").get(category)?.name ?? category}
|
{categoryMap.get(category)?.name ?? category}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { destinations, class: className = "text-sm" } = Astro.props;
|
const { destinations, class: className = "text-sm" } = Astro.props;
|
||||||
|
const destinationMap = getTaxonomyMap("destination");
|
||||||
---
|
---
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -32,8 +33,7 @@ const { destinations, class: className = "text-sm" } = Astro.props;
|
|||||||
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z" />
|
||||||
<circle cx="12" cy="10" r="3" />
|
<circle cx="12" cy="10" r="3" />
|
||||||
</svg>
|
</svg>
|
||||||
{getTaxonomyMap("destination").get(destination)?.name ??
|
{destinationMap.get(destination)?.name ?? destination}
|
||||||
destination}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { tags, class: className = "text-sm" } = Astro.props;
|
const { tags, class: className = "text-sm" } = Astro.props;
|
||||||
|
const tagMap = getTaxonomyMap("tag");
|
||||||
---
|
---
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -18,7 +19,7 @@ const { tags, class: className = "text-sm" } = Astro.props;
|
|||||||
href={`/tag/${tag}`}
|
href={`/tag/${tag}`}
|
||||||
class="inline-block bg-muted/50 hover:bg-muted text-muted-foreground hover:text-foreground px-3 py-1 rounded-full border border-border transition-colors duration-200"
|
class="inline-block bg-muted/50 hover:bg-muted text-muted-foreground hover:text-foreground px-3 py-1 rounded-full border border-border transition-colors duration-200"
|
||||||
>
|
>
|
||||||
#{getTaxonomyMap("tag").get(tag)?.name ?? tag}
|
#{tagMap.get(tag)?.name ?? tag}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ export async function getStaticPaths() {
|
|||||||
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
|
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
|
||||||
props: {
|
props: {
|
||||||
cat,
|
cat,
|
||||||
fullPath,
|
|
||||||
posts: page.data,
|
posts: page.data,
|
||||||
currentPage: page.currentPage,
|
currentPage: page.currentPage,
|
||||||
lastPage: page.lastPage,
|
lastPage: page.lastPage,
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
---
|
|
||||||
import BaseLayout from "@/layouts/BaseLayout.astro";
|
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import Headline from "@/components/ui/Headline.astro";
|
|
||||||
import PostItem from "@/components/blog/PostItem.astro";
|
|
||||||
import Pagination from "@/components/ui/Pagination.astro";
|
|
||||||
import { getTaxonomyMap } from "@/utils/taxonomy";
|
|
||||||
import { buildPaginatedPaths } from "@/utils/paginate";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const allPosts = await getCollection("blog");
|
|
||||||
const posts = allPosts.filter((post) => post.data && post.data.pubDate);
|
|
||||||
|
|
||||||
const categories = new Set<string>();
|
|
||||||
posts.forEach((post) => {
|
|
||||||
post.data.categories?.forEach((cat) => categories.add(cat));
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(categories).flatMap((category) => {
|
|
||||||
const categoryPosts = posts
|
|
||||||
.filter((post) => post.data.categories?.includes(category))
|
|
||||||
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
|
|
||||||
|
|
||||||
return buildPaginatedPaths(categoryPosts, `/category/${category}`).map(
|
|
||||||
({ pageParam, page }) => ({
|
|
||||||
params: { category, page: pageParam },
|
|
||||||
props: { page },
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { page } = Astro.props;
|
|
||||||
const { category } = Astro.params;
|
|
||||||
|
|
||||||
const categoryInfo = getTaxonomyMap("category").get(category!);
|
|
||||||
const displayName = categoryInfo?.name ?? category!;
|
|
||||||
const description = categoryInfo?.description;
|
|
||||||
|
|
||||||
const metadata = {
|
|
||||||
title: displayName,
|
|
||||||
description: description ?? `Các bài viết trong danh mục ${displayName}.`,
|
|
||||||
};
|
|
||||||
---
|
|
||||||
|
|
||||||
<BaseLayout metadata={metadata}>
|
|
||||||
<section class="relative px-4 py-8 sm:px-6 lg:px-8 md:py-12">
|
|
||||||
<div class="relative mx-auto max-w-5xl">
|
|
||||||
<Headline
|
|
||||||
tagline="Category"
|
|
||||||
title={displayName}
|
|
||||||
subtitle={description ?? `Hiển thị ${page.total} bài viết.`}
|
|
||||||
classes={{
|
|
||||||
container: "mb-12 text-center",
|
|
||||||
title:
|
|
||||||
"font-heading mb-4 text-4xl font-bold tracking-tight text-foreground md:text-6xl capitalized",
|
|
||||||
subtitle: "mx-auto max-w-3xl text-xl text-muted-foreground",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="mb-8 text-center">
|
|
||||||
<a href="/blog" class="text-primary hover:underline">← Quay lại blog</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
|
|
||||||
{page.data.map((post) => <PostItem post={post} />)}
|
|
||||||
</div>
|
|
||||||
<Pagination page={page} />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</BaseLayout>
|
|
||||||
@@ -35,7 +35,6 @@ export async function getStaticPaths() {
|
|||||||
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
|
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
|
||||||
props: {
|
props: {
|
||||||
dest,
|
dest,
|
||||||
fullPath,
|
|
||||||
posts: page.data,
|
posts: page.data,
|
||||||
currentPage: page.currentPage,
|
currentPage: page.currentPage,
|
||||||
lastPage: page.lastPage,
|
lastPage: page.lastPage,
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export interface PageMeta {
|
|||||||
* @param items Full sorted list of items to paginate.
|
* @param items Full sorted list of items to paginate.
|
||||||
* @param basePath Base URL without trailing slash, e.g. "/blog" or "/category/travel".
|
* @param basePath Base URL without trailing slash, e.g. "/blog" or "/category/travel".
|
||||||
* @param pageSize Number of items per page (default: DEFAULT_PAGE_SIZE).
|
* @param pageSize Number of items per page (default: DEFAULT_PAGE_SIZE).
|
||||||
* @returns Array of { params: { page }, props: { page: PageMeta } }.
|
* @returns Array of { pageParam, page } objects where pageParam is the route segment
|
||||||
|
* (undefined for page 1, "page/N" for N≥2) and page is a PageMeta object.
|
||||||
|
* Callers should map these into Astro's { params, props } format.
|
||||||
*/
|
*/
|
||||||
export function buildPaginatedPaths<T>(
|
export function buildPaginatedPaths<T>(
|
||||||
items: T[],
|
items: T[],
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function buildHierarchicalPath(
|
|||||||
visited.add(slug);
|
visited.add(slug);
|
||||||
const item = map.get(slug);
|
const item = map.get(slug);
|
||||||
if (!item?.parent) return slug;
|
if (!item?.parent) return slug;
|
||||||
return `${buildHierarchicalPath(item.parent, map, new Set(visited))}/${slug}`;
|
return `${buildHierarchicalPath(item.parent, map, visited)}/${slug}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTaxonomyPath(type: string, slug: string): string {
|
export function getTaxonomyPath(type: string, slug: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user