97 lines
3.3 KiB
TypeScript
97 lines
3.3 KiB
TypeScript
"use client";
|
||
|
||
import { useMemo, useState } from "react";
|
||
import Link from "next/link";
|
||
import { TOOL_CATEGORIES, TOOL_LINKS } from "@/lib/tools";
|
||
import SiteShell from "@/components/SiteShell";
|
||
|
||
const FEATURED = ["weekend", "day-plan", "bill-split", "mood", "scam-alerts", "deposit-return", "airport-transfer", "invoice-fx", "hydration", "sleep", "coliving-qa", "rainy-day"];
|
||
|
||
export default function ToolsHubPage() {
|
||
const [filter, setFilter] = useState("all");
|
||
const [q, setQ] = useState("");
|
||
|
||
const featured = useMemo(
|
||
() => FEATURED.map((id) => TOOL_LINKS.find((t) => t.id === id)).filter((t): t is NonNullable<typeof t> => !!t),
|
||
[]
|
||
);
|
||
|
||
const filtered = useMemo(() => {
|
||
let list = filter === "all" ? TOOL_LINKS : TOOL_LINKS.filter((t) => t.category === filter);
|
||
if (q.trim()) {
|
||
const s = q.toLowerCase();
|
||
list = list.filter((t) => t.title.toLowerCase().includes(s) || t.desc.toLowerCase().includes(s));
|
||
}
|
||
return list;
|
||
}, [filter, q]);
|
||
|
||
return (
|
||
<SiteShell showFooter>
|
||
<div className="tools-hub-page">
|
||
<div className="container">
|
||
<nav className="detail-nav">
|
||
<Link href="/">← 返回首页</Link>
|
||
</nav>
|
||
<div className="section-header">
|
||
<span className="section-tag">🛠️ TOOLKIT</span>
|
||
<h1>nomadro 工具箱</h1>
|
||
<p>规划、金钱、工作、生活与安全——一站直达所有旅居工具</p>
|
||
</div>
|
||
|
||
<div className="tools-featured">
|
||
<div className="tools-featured-head">
|
||
<strong>✨ 本周推荐</strong>
|
||
<span>一次上新 12+ 工具 · 周末/分账/防坑…</span>
|
||
</div>
|
||
<div className="tools-featured-grid">
|
||
{featured.map((t) => (
|
||
<Link key={t.id} href={t.href} className="tools-featured-card">
|
||
<span>{t.emoji}</span>
|
||
<div>
|
||
<h3>{t.title}</h3>
|
||
<p>{t.desc}</p>
|
||
</div>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="tools-hub-toolbar">
|
||
<input
|
||
className="tools-hub-search"
|
||
placeholder="搜索工具,如「签证」「机票」「笔记」…"
|
||
value={q}
|
||
onChange={(e) => setQ(e.target.value)}
|
||
/>
|
||
<div className="tools-hub-filters">
|
||
{TOOL_CATEGORIES.map((c) => (
|
||
<button
|
||
key={c.key}
|
||
className={`filter-btn${filter === c.key ? " active" : ""}`}
|
||
onClick={() => setFilter(c.key)}
|
||
>
|
||
{c.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="tools-hub-grid">
|
||
{filtered.map((t) => (
|
||
<Link key={t.id} href={t.href} className="tools-hub-card">
|
||
<span className="tools-hub-emoji">{t.emoji}</span>
|
||
<h3>{t.title}</h3>
|
||
<p>{t.desc}</p>
|
||
<span className="tools-hub-go">打开 →</span>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
{filtered.length === 0 && (
|
||
<p className="dest-empty">没有匹配的工具,试试其他关键词</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</SiteShell>
|
||
);
|
||
}
|