feat: refactor taxonomy data handling for categories, destinations, and tags

This commit is contained in:
Thuan Bui
2026-03-19 17:27:05 +07:00
parent beac1efd7f
commit 2c1d3b2f7f
9 changed files with 33 additions and 36 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
--- ---
import { categoryMap, getCategoryPath } from "@/utils/taxonomy"; import { getTaxonomyMap, getTaxonomyPath } from "@/utils/taxonomy";
export interface Props { export interface Props {
categories: string[]; categories: string[];
@@ -15,10 +15,10 @@ const { categories, class: className = "text-sm" } = Astro.props;
{categories.map((category) => ( {categories.map((category) => (
<li class="inline-block relative"> <li class="inline-block relative">
<a <a
href={`/category/${getCategoryPath(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"
> >
{categoryMap.get(category)?.name ?? category} {getTaxonomyMap("category").get(category)?.name ?? category}
</a> </a>
</li> </li>
))} ))}
+4 -3
View File
@@ -1,5 +1,5 @@
--- ---
import { destinationMap, getDestinationPath } from "@/utils/taxonomy"; import { getTaxonomyMap, getTaxonomyPath } from "@/utils/taxonomy";
export interface Props { export interface Props {
destinations: string[]; destinations: string[];
@@ -15,7 +15,7 @@ const { destinations, class: className = "text-sm" } = Astro.props;
{destinations.map((destination) => ( {destinations.map((destination) => (
<li class="inline-block relative"> <li class="inline-block relative">
<a <a
href={`/destination/${getDestinationPath(destination)}`} href={`/destination/${getTaxonomyPath("destination", destination)}`}
class="inline-flex items-center gap-1 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 hover:text-emerald-800 dark:hover:text-emerald-300 px-3 py-1 rounded-full border border-emerald-500/20 transition-colors duration-200" class="inline-flex items-center gap-1 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 hover:text-emerald-800 dark:hover:text-emerald-300 px-3 py-1 rounded-full border border-emerald-500/20 transition-colors duration-200"
> >
<svg <svg
@@ -32,7 +32,8 @@ 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>
{destinationMap.get(destination)?.name ?? destination} {getTaxonomyMap("destination").get(destination)?.name ??
destination}
</a> </a>
</li> </li>
))} ))}
+7 -3
View File
@@ -1,10 +1,14 @@
--- ---
import type { Page } from "astro";
import type { CollectionEntry } from "astro:content";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
export interface SimplePage {
currentPage: number;
lastPage: number;
url: { prev?: string; next?: string };
}
export interface Props { export interface Props {
page: Page<CollectionEntry<"blog">>; page: SimplePage;
class?: string; class?: string;
} }
+2 -2
View File
@@ -1,5 +1,5 @@
--- ---
import { tagMap } from "@/utils/taxonomy"; import { getTaxonomyMap } from "@/utils/taxonomy";
export interface Props { export interface Props {
tags: string[]; tags: string[];
@@ -18,7 +18,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"
> >
#{tagMap.get(tag)?.name ?? tag} #{getTaxonomyMap("tag").get(tag)?.name ?? tag}
</a> </a>
</li> </li>
))} ))}
+7 -5
View File
@@ -7,8 +7,8 @@ import Pagination from "@/components/ui/Pagination.astro";
import type { Page } from "astro"; import type { Page } from "astro";
import type { CollectionEntry } from "astro:content"; import type { CollectionEntry } from "astro:content";
import { import {
categoryMap, getTaxonomyMap,
getCategoryPath, getTaxonomyPath,
type TaxonomyItem, type TaxonomyItem,
} from "@/utils/taxonomy"; } from "@/utils/taxonomy";
@@ -27,8 +27,10 @@ export async function getStaticPaths() {
.filter((post) => post.data.categories?.includes(slug)) .filter((post) => post.data.categories?.includes(slug))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()); .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
const fullPath = getCategoryPath(slug); const fullPath = getTaxonomyPath("category", slug);
const cat = categoryMap.get(slug) ?? ({ slug, name: slug } as TaxonomyItem); const cat =
getTaxonomyMap("category").get(slug) ??
({ slug, name: slug } as TaxonomyItem);
const totalPages = Math.max(1, Math.ceil(catPosts.length / PAGE_SIZE)); const totalPages = Math.max(1, Math.ceil(catPosts.length / PAGE_SIZE));
return Array.from({ length: totalPages }, (_, i) => { return Array.from({ length: totalPages }, (_, i) => {
@@ -65,7 +67,7 @@ const page = {
currentPage, currentPage,
lastPage, lastPage,
url: { prev: prevUrl, next: nextUrl }, url: { prev: prevUrl, next: nextUrl },
} as unknown as Page<CollectionEntry<"blog">>; };
const metadata = { const metadata = {
title: cat.name, title: cat.name,
@@ -5,7 +5,7 @@ import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro"; import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro"; import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro"; import type { GetStaticPathsOptions } from "astro";
import { categoryMap } from "@/utils/taxonomy"; import { getTaxonomyMap } from "@/utils/taxonomy";
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) { export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const allPosts = await getCollection("blog"); const allPosts = await getCollection("blog");
@@ -31,7 +31,7 @@ export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const { page } = Astro.props; const { page } = Astro.props;
const { category } = Astro.params; const { category } = Astro.params;
const categoryInfo = categoryMap.get(category!); const categoryInfo = getTaxonomyMap("category").get(category!);
const displayName = categoryInfo?.name ?? category!; const displayName = categoryInfo?.name ?? category!;
const description = categoryInfo?.description; const description = categoryInfo?.description;
+6 -5
View File
@@ -7,8 +7,8 @@ import Pagination from "@/components/ui/Pagination.astro";
import type { Page } from "astro"; import type { Page } from "astro";
import type { CollectionEntry } from "astro:content"; import type { CollectionEntry } from "astro:content";
import { import {
destinationMap, getTaxonomyMap,
getDestinationPath, getTaxonomyPath,
type TaxonomyItem, type TaxonomyItem,
} from "@/utils/taxonomy"; } from "@/utils/taxonomy";
@@ -27,9 +27,10 @@ export async function getStaticPaths() {
.filter((post) => post.data.destination?.includes(slug)) .filter((post) => post.data.destination?.includes(slug))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()); .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
const fullPath = getDestinationPath(slug); const fullPath = getTaxonomyPath("destination", slug);
const dest = const dest =
destinationMap.get(slug) ?? ({ slug, name: slug } as TaxonomyItem); getTaxonomyMap("destination").get(slug) ??
({ slug, name: slug } as TaxonomyItem);
const totalPages = Math.max(1, Math.ceil(destPosts.length / PAGE_SIZE)); const totalPages = Math.max(1, Math.ceil(destPosts.length / PAGE_SIZE));
return Array.from({ length: totalPages }, (_, i) => { return Array.from({ length: totalPages }, (_, i) => {
@@ -66,7 +67,7 @@ const page = {
currentPage, currentPage,
lastPage, lastPage,
url: { prev: prevUrl, next: nextUrl }, url: { prev: prevUrl, next: nextUrl },
} as unknown as Page<CollectionEntry<"blog">>; };
const metadata = { const metadata = {
title: dest.name, title: dest.name,
+2 -2
View File
@@ -5,7 +5,7 @@ import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro"; import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro"; import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro"; import type { GetStaticPathsOptions } from "astro";
import { tagMap } from "@/utils/taxonomy"; import { getTaxonomyMap } from "@/utils/taxonomy";
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) { export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const allPosts = await getCollection("blog"); const allPosts = await getCollection("blog");
@@ -31,7 +31,7 @@ export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const { page } = Astro.props; const { page } = Astro.props;
const { tag } = Astro.params; const { tag } = Astro.params;
const tagInfo = tagMap.get(tag!); const tagInfo = getTaxonomyMap("tag").get(tag!);
const displayName = tagInfo?.name ?? tag!; const displayName = tagInfo?.name ?? tag!;
const description = tagInfo?.description; const description = tagInfo?.description;
-11
View File
@@ -51,14 +51,3 @@ export function getTaxonomyItem(
): TaxonomyItem | undefined { ): TaxonomyItem | undefined {
return getTaxonomyMap(type).get(slug); return getTaxonomyMap(type).get(slug);
} }
// Convenience aliases kept for backward compatibility
export const categoryMap = getTaxonomyMap("category");
export const destinationMap = getTaxonomyMap("destination");
export const tagMap = getTaxonomyMap("tag");
export const getCategoryPath = (slug: string) =>
getTaxonomyPath("category", slug);
export const getDestinationPath = (slug: string) =>
getTaxonomyPath("destination", slug);
export const getTagPath = (slug: string) => getTaxonomyPath("tag", slug);