nomadweb/frontend/src/components/BlogSection.tsx
eric bf654f76e6 Add visa wizard, coworking, packing, season guide, and UX polish
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 23:05:48 -05:00

67 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useMemo, useState } from "react";
import Link from "next/link";
import type { BlogPost } from "@/lib/types";
export default function BlogSection({ posts }: { posts: BlogPost[] }) {
const allTags = useMemo(() => {
const tags = new Set<string>();
posts.forEach((p) => p.tags.forEach((t) => tags.add(t)));
return Array.from(tags);
}, [posts]);
const [activeTag, setActiveTag] = useState("all");
const filtered = useMemo(() => {
if (activeTag === "all") return posts;
return posts.filter((p) => p.tags.includes(activeTag));
}, [posts, activeTag]);
return (
<section className="section blog-section" id="blog">
<div className="container">
<div className="section-header reveal">
<span className="section-tag">📝 BLOG</span>
<h2>游民博客</h2>
<p>深度攻略、签证指南与旅居经验分享</p>
</div>
{allTags.length > 0 && (
<div className="blog-filters reveal">
<button className={`filter-btn${activeTag === "all" ? " active" : ""}`} onClick={() => setActiveTag("all")}>
📚 全部
</button>
{allTags.map((t) => (
<button key={t} className={`filter-btn${activeTag === t ? " active" : ""}`} onClick={() => setActiveTag(t)}>
{t}
</button>
))}
</div>
)}
<div className="blog-grid">
{filtered.map((post) => (
<Link key={post.slug} href={`/blog/${post.slug}`} className="blog-card reveal">
<div className="blog-emoji">{post.emoji}</div>
<div className="blog-meta">
<span>📅 {post.published_at}</span>
<span>⏱️ {post.read_time} 分钟阅读</span>
</div>
<h3>{post.title}</h3>
<p>{post.excerpt}</p>
<div className="blog-tags">
{post.tags.map((t) => <span key={t} className="blog-tag">{t}</span>)}
</div>
<span className="blog-read-more">阅读全文 →</span>
</Link>
))}
</div>
{filtered.length === 0 && (
<p className="dest-empty reveal">该分类暂无文章</p>
)}
</div>
</section>
);
}