Give tags index a hero summary and card grid

This commit is contained in:
2025-11-19 00:51:00 +08:00
parent 82a459bede
commit 10e4e7e21e

View File

@@ -1,8 +1,10 @@
import Link from 'next/link'; import Link from 'next/link';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faTags } from '@fortawesome/free-solid-svg-icons'; import { faTags, faFire } from '@fortawesome/free-solid-svg-icons';
import { getAllTagsWithCount } from '@/lib/posts'; import { getAllTagsWithCount } from '@/lib/posts';
import { SectionDivider } from '@/components/section-divider';
import { ScrollReveal } from '@/components/scroll-reveal';
export const metadata: Metadata = { export const metadata: Metadata = {
title: '標籤索引' title: '標籤索引'
@@ -10,35 +12,60 @@ export const metadata: Metadata = {
export default function TagIndexPage() { export default function TagIndexPage() {
const tags = getAllTagsWithCount(); const tags = getAllTagsWithCount();
const topTags = tags.slice(0, 3);
const colorClasses = [ const colorClasses = [
'bg-rose-100 text-rose-700 dark:bg-rose-900/60 dark:text-rose-200', 'from-rose-400/70 to-rose-200/40',
'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/60 dark:text-emerald-200', 'from-emerald-400/70 to-emerald-200/40',
'bg-sky-100 text-sky-700 dark:bg-sky-900/60 dark:text-sky-200', 'from-sky-400/70 to-sky-200/40',
'bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-200', 'from-amber-400/70 to-amber-200/40',
'bg-violet-100 text-violet-700 dark:bg-violet-900/60 dark:text-violet-200' 'from-violet-400/70 to-violet-200/40'
]; ];
return ( return (
<section className="space-y-4"> <section className="space-y-6">
<h1 className="type-title flex items-center gap-2 font-semibold text-slate-900 dark:text-slate-50"> <SectionDivider>
<FontAwesomeIcon icon={faTags} className="h-5 w-5 text-slate-400" /> <ScrollReveal>
<div className="motion-card rounded-2xl border bg-white/90 p-6 text-center shadow-sm dark:border-slate-800 dark:bg-slate-900">
<div className="inline-flex items-center gap-2 text-accent">
<FontAwesomeIcon icon={faTags} className="h-5 w-5" />
<span className="type-small uppercase tracking-[0.4em] text-slate-500 dark:text-slate-400">
</span>
</div>
<h1 className="type-title mt-2 font-semibold text-slate-900 dark:text-slate-50">
{tags.length}
</h1> </h1>
<p className="type-small text-slate-500 dark:text-slate-400"> <p className="type-small mt-2 text-slate-600 dark:text-slate-300">
{tags.length}
{topTags.map((t) => t.tag).join('、')}
</p> </p>
<div className="flex flex-wrap gap-3 text-xs"> </div>
</ScrollReveal>
</SectionDivider>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{tags.map(({ tag, slug, count }, index) => { {tags.map(({ tag, slug, count }, index) => {
const color = colorClasses[index % colorClasses.length]; const color = colorClasses[index % colorClasses.length];
return ( return (
<Link <Link
key={tag} key={tag}
href={`/tags/${slug}`} href={`/tags/${slug}`}
className={`tag-chip rounded-full px-3 py-1 shadow-sm transition-transform transition-shadow duration-200 ease-out hover:-translate-y-0.5 hover:shadow-md ${color}`} className="motion-card flex flex-col rounded-xl border bg-white/90 p-4 shadow-sm transition hover:-translate-y-1 dark:border-slate-800 dark:bg-slate-900"
> >
<span className="mr-1">{tag}</span> <span className={`mb-3 block h-1.5 w-16 rounded-full bg-gradient-to-r ${color}`} aria-hidden="true" />
<span className="opacity-70">({count})</span> <div className="flex items-center justify-between">
<h2 className="type-subtitle font-semibold text-slate-900 dark:text-slate-50">
{tag}
</h2>
<span className="type-small text-slate-600 dark:text-slate-300">
{count}
</span>
</div>
<span className="mt-1 inline-flex items-center gap-1 text-xs text-slate-500 dark:text-slate-400">
<FontAwesomeIcon icon={faFire} className="h-3 w-3" />
#{index + 1}
</span>
</Link> </Link>
); );
})} })}