Give tags index a hero summary and card grid
This commit is contained in:
@@ -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">
|
||||||
</h1>
|
<div className="inline-flex items-center gap-2 text-accent">
|
||||||
<p className="type-small text-slate-500 dark:text-slate-400">
|
<FontAwesomeIcon icon={faTags} className="h-5 w-5" />
|
||||||
目前共有 {tags.length} 個標籤。
|
<span className="type-small uppercase tracking-[0.4em] text-slate-500 dark:text-slate-400">
|
||||||
</p>
|
標籤索引
|
||||||
<div className="flex flex-wrap gap-3 text-xs">
|
</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) => {
|
{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>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user