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 type { Metadata } from 'next';
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 { SectionDivider } from '@/components/section-divider';
import { ScrollReveal } from '@/components/scroll-reveal';
export const metadata: Metadata = {
title: '標籤索引'
@@ -10,35 +12,60 @@ export const metadata: Metadata = {
export default function TagIndexPage() {
const tags = getAllTagsWithCount();
const topTags = tags.slice(0, 3);
const colorClasses = [
'bg-rose-100 text-rose-700 dark:bg-rose-900/60 dark:text-rose-200',
'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/60 dark:text-emerald-200',
'bg-sky-100 text-sky-700 dark:bg-sky-900/60 dark:text-sky-200',
'bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-200',
'bg-violet-100 text-violet-700 dark:bg-violet-900/60 dark:text-violet-200'
'from-rose-400/70 to-rose-200/40',
'from-emerald-400/70 to-emerald-200/40',
'from-sky-400/70 to-sky-200/40',
'from-amber-400/70 to-amber-200/40',
'from-violet-400/70 to-violet-200/40'
];
return (
<section className="space-y-4">
<h1 className="type-title flex items-center gap-2 font-semibold text-slate-900 dark:text-slate-50">
<FontAwesomeIcon icon={faTags} className="h-5 w-5 text-slate-400" />
</h1>
<p className="type-small text-slate-500 dark:text-slate-400">
{tags.length}
</p>
<div className="flex flex-wrap gap-3 text-xs">
<section className="space-y-6">
<SectionDivider>
<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>
<p className="type-small mt-2 text-slate-600 dark:text-slate-300">
{topTags.map((t) => t.tag).join('、')}
</p>
</div>
</ScrollReveal>
</SectionDivider>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{tags.map(({ tag, slug, count }, index) => {
const color = colorClasses[index % colorClasses.length];
return (
<Link
key={tag}
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="opacity-70">({count})</span>
<span className={`mb-3 block h-1.5 w-16 rounded-full bg-gradient-to-r ${color}`} aria-hidden="true" />
<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>
);
})}