- 语言路由:localeDetection 关闭,/ 固定英文、/zh 固定中文,URL 决定语言 (不再按 cookie/Accept-Language 自动跳转;语言切换器显式切换不受影响) - 五站独立视觉语言(data-theme 驱动的设计系统层): · AI Stack:深蓝渐变 Hero + 统计条 + 卡片左色条 hover(专业 SaaS) · LaunchAI:橙色渐变 Banner + 斜切底边 + 暖白底(活力社区) · The AI Ledger:黑色报头日期条 + 衬线字体 + 直角 + 双细线 + 报纸排版(媒体) · DevAI.tools:全站深色 + 等宽字体 + 终端 Hero + 扫描线纹理 + 系统状态条(终端) · findai:纯白极简 + 紫色聚焦光圈 + 无界卡片(搜索引擎) - 修复 :first-of-type 误伤(hero 样式收敛到专用 class)
202 lines
7.7 KiB
TypeScript
202 lines
7.7 KiB
TypeScript
// 自动生成:站点首页组件(源自底座 niche 形态,品牌来自 @/site/brand)
|
||
import { siteConfig } from "@/site/brand";
|
||
import { Code2, Terminal, Workflow, Layers } from "lucide-react";
|
||
import { getTranslations } from "next-intl/server";
|
||
import { ToolCard } from "@/components/tool-card";
|
||
import { LocaleLink } from "@/components/locale-link";
|
||
import { SectionHeader } from "@/kit/section";
|
||
import { getHomeDataSafe } from "@/kit/home-data";
|
||
|
||
/** Niche:垂直行业目录(AI for Developers) */
|
||
|
||
|
||
const navItems = [
|
||
{ label: "Tools", href: "/tools" },
|
||
{ label: "Workflows", href: "/best" },
|
||
{ label: "Use Cases", href: "/ai-tools-for" },
|
||
{ label: "Rankings", href: "/rankings" },
|
||
{ label: "Submit", href: "/submit" },
|
||
];
|
||
|
||
const footerGroups = [
|
||
{
|
||
title: "Directory",
|
||
links: [
|
||
{ label: "All Tools", href: "/tools" },
|
||
{ label: "Rankings", href: "/rankings" },
|
||
{ label: "Use Cases", href: "/ai-tools-for" },
|
||
],
|
||
},
|
||
{
|
||
title: "Build",
|
||
links: [
|
||
{ label: "Workflows", href: "/best" },
|
||
{ label: "Submit a Tool", href: "/submit" },
|
||
{ label: "Blog", href: "/blog" },
|
||
],
|
||
},
|
||
{
|
||
title: "Legal",
|
||
links: [
|
||
{ label: "Terms", href: "/terms" },
|
||
{ label: "Privacy", href: "/privacy" },
|
||
],
|
||
},
|
||
];
|
||
|
||
async function SiteHome({ locale }: { locale: string }) {
|
||
const t = await getTranslations("siteHome");
|
||
const th = await getTranslations("hero");
|
||
const data = await getHomeDataSafe(6);
|
||
|
||
return (
|
||
<div className="min-h-screen bg-background">
|
||
{/* Terminal 风格 Hero + 绿色系统状态条 */}
|
||
<div className="border-b border-border bg-background">
|
||
<div className="mx-auto flex max-w-5xl items-center gap-2 px-4 py-2 font-mono text-[11px] text-muted-foreground sm:px-6">
|
||
<span className="inline-block h-2 w-2 animate-pulse rounded-full bg-emerald-500" />
|
||
system: online · 1,000+ tools indexed · updated hourly
|
||
</div>
|
||
</div>
|
||
<section className="border-b border-border bg-[hsl(var(--secondary))]/40">
|
||
<div className="mx-auto max-w-5xl px-4 py-14 sm:px-6 md:py-20">
|
||
<div className="mx-auto max-w-2xl overflow-hidden rounded-xl border border-border bg-background shadow-sm">
|
||
<div className="flex items-center gap-1.5 border-b border-border bg-secondary/50 px-4 py-2.5">
|
||
<span className="h-2.5 w-2.5 rounded-full bg-red-400" />
|
||
<span className="h-2.5 w-2.5 rounded-full bg-amber-400" />
|
||
<span className="h-2.5 w-2.5 rounded-full bg-emerald-400" />
|
||
<span className="ml-2 text-xs text-muted-foreground">devai — zsh</span>
|
||
</div>
|
||
<div className="space-y-1.5 p-5 font-mono text-sm">
|
||
<p className="text-muted-foreground">
|
||
<span className="text-emerald-600 dark:text-emerald-400">$</span>{" "}
|
||
find-ai-tools --for developer
|
||
</p>
|
||
<p className="flex items-center gap-2 text-foreground">
|
||
<Terminal className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400" />
|
||
{th("title")}
|
||
</p>
|
||
<p className="text-xs leading-relaxed text-muted-foreground">
|
||
{th("description")}
|
||
</p>
|
||
<p className="pt-2">
|
||
<LocaleLink
|
||
href="/tools"
|
||
className="inline-block rounded-md bg-primary px-4 py-1.5 font-sans text-xs font-semibold text-primary-foreground hover:opacity-90"
|
||
>
|
||
Browse tools
|
||
</LocaleLink>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div className="mx-auto max-w-5xl space-y-12 px-4 py-12 sm:px-6">
|
||
{/* Use Cases as workflows */}
|
||
{data.useCases.length > 0 && (
|
||
<section>
|
||
<SectionHeader
|
||
title={t("shipTitle")}
|
||
subtitle={t("shipSubtitle")}
|
||
viewAllHref="/ai-tools-for"
|
||
viewAllLabel={t("useCasesViewAll")}
|
||
/>
|
||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||
{data.useCases.slice(0, 6).map((uc) => (
|
||
<LocaleLink
|
||
key={uc.id}
|
||
href={`/ai-tools-for/${uc.slug}`}
|
||
className="group rounded-xl border border-border p-4 transition-all hover:border-primary/40 hover:bg-primary/5"
|
||
>
|
||
<div className="flex items-center justify-between">
|
||
<Workflow className="h-4 w-4 text-primary" />
|
||
<span className="text-xs text-muted-foreground tabular-nums">
|
||
{uc.toolCount} tools
|
||
</span>
|
||
</div>
|
||
<h3 className="mt-2 text-sm font-semibold text-foreground group-hover:text-primary">
|
||
{locale === "zh" && uc.nameZh ? uc.nameZh : uc.nameEn}
|
||
</h3>
|
||
</LocaleLink>
|
||
))}
|
||
</div>
|
||
</section>
|
||
)}
|
||
|
||
{/* Trending tools */}
|
||
{data.trending.length > 0 && (
|
||
<section>
|
||
<SectionHeader
|
||
title={t("upvotedTitle")}
|
||
viewAllHref="/rankings?board=trending"
|
||
/>
|
||
<div className="grid gap-3 md:grid-cols-2">
|
||
{data.trending.slice(0, 6).map((tool, i) => (
|
||
<ToolCard
|
||
key={tool.id}
|
||
tool={tool}
|
||
locale={locale}
|
||
rank={i + 1}
|
||
/>
|
||
))}
|
||
</div>
|
||
</section>
|
||
)}
|
||
|
||
{/* Workflows(collections) */}
|
||
{data.collections.length > 0 && (
|
||
<section>
|
||
<SectionHeader
|
||
title={t("workflowsTitle")}
|
||
subtitle={t("workflowsSubtitle")}
|
||
viewAllHref="/best"
|
||
viewAllLabel={t("workflowsViewAll")}
|
||
/>
|
||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||
{data.collections.slice(0, 3).map((col) => (
|
||
<LocaleLink
|
||
key={col.id}
|
||
href={`/best/${col.slug}`}
|
||
className="group rounded-xl border border-border p-4 transition-all hover:border-primary/40"
|
||
>
|
||
<Layers className="h-4 w-4 text-primary" />
|
||
<h3 className="mt-2 text-sm font-semibold text-foreground group-hover:text-primary">
|
||
{locale === "zh" && col.nameZh ? col.nameZh : col.nameEn}
|
||
</h3>
|
||
<p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
||
{locale === "zh" && col.introZh ? col.introZh : col.introEn}
|
||
</p>
|
||
</LocaleLink>
|
||
))}
|
||
</div>
|
||
</section>
|
||
)}
|
||
|
||
{/* Categories */}
|
||
{data.categories.length > 0 && (
|
||
<section>
|
||
<SectionHeader title={t("categoriesTitle")} viewAllHref="/tools" />
|
||
<div className="flex flex-wrap gap-2">
|
||
{data.categories.slice(0, 14).map((cat) => (
|
||
<LocaleLink
|
||
key={cat.id}
|
||
href={`/category/${cat.slug}`}
|
||
className="rounded-lg border border-border px-3 py-1.5 font-mono text-xs text-foreground transition-colors hover:border-primary/40 hover:bg-primary/5"
|
||
>
|
||
{locale === "zh" && cat.nameZh ? cat.nameZh : cat.nameEn}
|
||
<span className="ml-1.5 text-muted-foreground">
|
||
{cat.toolCount}
|
||
</span>
|
||
</LocaleLink>
|
||
))}
|
||
</div>
|
||
</section>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export { SiteHome };
|