feat: 深度设计五站视觉语言 + 语言路由修复

- 语言路由: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)
This commit is contained in:
AI Directory Platform
2026-09-09 19:22:58 +00:00
parent 5cc4195d68
commit 6baf0246d2
20 changed files with 360 additions and 15 deletions
+5
View File
@@ -23,6 +23,7 @@ const SITES_ROOT = path.join(REPO_ROOT, "sites");
// ====================================================================
const SITES = {
"ai-stack": {
themeClass: "site-ai-stack",
brandZh: {
name: "AI Stack",
tagline: "由真实用户排名的专业 AI 工具目录。",
@@ -91,6 +92,7 @@ const SITES = {
},
},
launchai: {
themeClass: "site-launchai",
brandZh: {
name: "LaunchAI",
tagline: "发现并投票今日的 AI 新品。",
@@ -157,6 +159,7 @@ const SITES = {
},
},
"the-ai-ledger": {
themeClass: "site-the-ai-ledger",
brandZh: {
name: "The AI Ledger",
tagline: "独立 AI 报道,附社区排名目录。",
@@ -224,6 +227,7 @@ const SITES = {
},
},
"devai-tools": {
themeClass: "site-devai-tools",
brandZh: {
name: "DevAI.tools",
tagline: "面向开发者的 AI 工具——精选、实测、社区排名。",
@@ -289,6 +293,7 @@ const SITES = {
},
},
findai: {
themeClass: "site-findai",
brandZh: {
name: "findai",
tagline: "极简 AI 工具搜索引擎。",
+4 -1
View File
@@ -4,7 +4,10 @@ import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
locales: ['en', 'zh'],
defaultLocale: 'en',
localePrefix: 'as-needed'
localePrefix: 'as-needed',
// 品牌站根路径固定默认语言(英文):不按 cookie/Accept-Language 自动跳转。
// 中文用户通过导航语言切换器显式进入 /zh。
localeDetection: false
});
export type Locale = (typeof routing.locales)[number];
+5 -1
View File
@@ -48,7 +48,11 @@ export async function SiteChrome({
const footerGroups = footerGroupsRaw ?? config.footerGroups;
return (
<div style={config.cssVars as React.CSSProperties}>
<div
data-theme={config.id}
className={config.themeClass}
style={config.cssVars as React.CSSProperties}
>
<ThemeHeader
brand={brand}
navItems={navItems}
@@ -63,7 +63,7 @@ async function ClassicHome({ locale }: { locale: string }) {
return (
<div className="bg-background">
{/* Hero */}
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
<section className="hero-dark border-b border-border">
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
{th("title")}
@@ -88,13 +88,28 @@ async function ClassicHome({ locale }: { locale: string }) {
</button>
</div>
</form>
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
<span>{t("popularLabel")}</span>
{/* 统计条(深色 Hero 内的白色数字) */}
<div className="mx-auto mt-10 flex max-w-lg items-center justify-center gap-10 border-t border-white/15 pt-6">
{[
{ v: "1,000+", l: "AI tools" },
{ v: "14", l: "Categories" },
{ v: "7", l: "Rankings" },
].map((s) => (
<div key={s.l} className="text-center">
<div className="text-2xl font-bold text-white">{s.v}</div>
<div className="text-xs text-white/60">{s.l}</div>
</div>
))}
</div>
<div className="mt-8 flex flex-wrap items-center justify-center gap-2 text-xs">
<span className="text-white/60">{t("popularLabel")}</span>
{t.raw("popularSearches").map((q: string) => (
<LocaleLink
key={q}
href={`/tools?search=${q}`}
className="rounded-full bg-secondary px-2.5 py-1 transition-colors hover:bg-hover"
className="rounded-full bg-white/10 px-2.5 py-1 text-white/80 transition-colors hover:bg-white/20"
>
{q}
</LocaleLink>
@@ -59,8 +59,17 @@ async function EditorialHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Masthead:黑色报头条(当日日期 + 期号),报纸头版签名 */}
<div className="bg-foreground text-background">
<div className="mx-auto flex max-w-4xl items-center justify-between px-4 py-2 text-[11px] uppercase tracking-[0.25em] sm:px-6">
<span>{new Date().toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}</span>
<span className="hidden sm:inline">Est. 2026</span>
<span>Daily</span>
</div>
</div>
{/* Masthead */}
<section className="border-b border-border">
<section className="hero-mast border-b border-border">
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
{t("mastheadLabel")}
@@ -77,6 +77,7 @@ async function MinimalHome({ locale }: { locale: string }) {
</div>
</form>
<div className="mx-auto mt-10 max-w-md border-t border-border/60 pt-5" />
<div className="mt-6 flex flex-wrap items-center justify-center gap-2">
{popularSearches.map((q) => (
<LocaleLink
@@ -56,7 +56,13 @@ async function NicheHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Terminal 风格 Hero */}
{/* 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">
@@ -115,7 +115,7 @@ async function ProductHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Hero:今日发布 */}
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
<section className="hero-launch border-b border-border bg-gradient-to-b from-primary/5 to-background">
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
{th("title")}
+2
View File
@@ -32,6 +32,8 @@ export interface SiteConfig {
seo?: Record<string, { title: string; description: string }>;
/** 品牌强调色 HSL 三元组(登录页分栏模板) */
accent?: string;
/** 站点视觉签名 class(挂载在站点外壳根元素,驱动全站差异化样式) */
themeClass?: string;
/** 中文品牌文案(导航/页脚/hero/搜索占位) */
brandZh?: {
name?: string;
+264
View File
@@ -119,3 +119,267 @@ html {
.animate-drawer-in {
animation: bu-drawer-in 0.18s ease-out;
}
/* ============================================================
五站视觉签名(Site Identity Layers)
每个网站一套独立设计语言:字体 / 底色 / 圆角 / 边框 / 按钮形态
由 SiteChrome 的 data-theme 驱动,仅作用于主题表现层
============================================================ */
/* ---------- 1. AI Stack(classic):深蓝专业 SaaS ----------
密度较高、细边框、轻阴影、蓝色主色 */
[data-theme="ai-stack"] {
--primary: 224 64% 33%;
--primary-foreground: 0 0% 100%;
--ring: 224 64% 33%;
}
[data-theme="ai-stack"] .rounded-xl,
[data-theme="ai-stack"] .rounded-2xl {
border-radius: 0.625rem;
}
[data-theme="ai-stack"] .group.relative.rounded-xl {
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
/* ---------- 2. LaunchAI(product):暖橙活力社区 ----------
暖白底、胶囊按钮、大圆角卡片、橙色主色 */
[data-theme="launchai"] {
--primary: 16 85% 53%;
--primary-foreground: 0 0% 100%;
--background: 30 55% 97%;
--secondary: 28 50% 92%;
--ring: 16 85% 53%;
}
[data-theme="launchai"] .bg-background {
background-color: hsl(var(--background));
}
[data-theme="launchai"] .rounded-xl { border-radius: 1.1rem; }
[data-theme="launchai"] .rounded-2xl { border-radius: 1.4rem; }
[data-theme="launchai"] h1, [data-theme="launchai"] h2 {
letter-spacing: -0.02em;
}
/* ---------- 3. The AI Ledger(editorial):报纸编辑风 ----------
纸白底、衬线字体、直角、黑主色、无阴影、粗黑分隔 */
[data-theme="the-ai-ledger"] {
--primary: 24 10% 12%;
--primary-foreground: 40 40% 98%;
--background: 42 45% 97%;
--border: 30 10% 82%;
--radius: 0px;
}
[data-theme="the-ai-ledger"] {
font-family: Georgia, "Times New Roman", "Noto Serif SC", serif;
}
[data-theme="the-ai-ledger"] h1,
[data-theme="the-ai-ledger"] h2,
[data-theme="the-ai-ledger"] h3 {
font-family: Georgia, "Times New Roman", "Noto Serif SC", serif;
letter-spacing: -0.005em;
}
[data-theme="the-ai-ledger"] .rounded-full,
[data-theme="the-ai-ledger"] .rounded-xl,
[data-theme="the-ai-ledger"] .rounded-2xl,
[data-theme="the-ai-ledger"] .rounded-lg {
border-radius: 1px;
}
[data-theme="the-ai-ledger"] .shadow,
[data-theme="the-ai-ledger"] .shadow-sm,
[data-theme="the-ai-ledger"] .shadow-lg {
box-shadow: none;
}
[data-theme="the-ai-ledger"] .bg-primary,
[data-theme="the-ai-ledger"] .hover\:bg-primary {
background-color: hsl(24 10% 12%);
}
[data-theme="the-ai-ledger"] header .rounded-lg {
border-radius: 1px;
}
/* ---------- 4. DevAI.tools(niche):深色终端 ----------
深色底、等宽字体、绿色主色、代码面板感 */
[data-theme="devai-tools"] {
--background: 220 25% 7%;
--foreground: 210 20% 92%;
--primary: 150 60% 45%;
--primary-foreground: 220 25% 7%;
--secondary: 220 20% 13%;
--muted: 220 20% 13%;
--muted-foreground: 215 15% 62%;
--border: 218 18% 17%;
--ring: 150 60% 45%;
--card: 220 25% 9%;
--popover: 220 25% 9%;
--accent: 220 20% 15%;
}
[data-theme="devai-tools"] {
font-family: ui-sans-serif, system-ui, sans-serif;
}
[data-theme="devai-tools"] h1,
[data-theme="devai-tools"] h2,
[data-theme="devai-tools"] h3,
[data-theme="devai-tools"] header .font-bold {
font-family: ui-monospace, "SF Mono", Menlo, monospace;
letter-spacing: -0.01em;
}
[data-theme="devai-tools"] .bg-background,
[data-theme="devai-tools"] .group.relative {
background-color: hsl(220 25% 9%);
}
[data-theme="devai-tools"] .rounded-xl { border-radius: 0.5rem; }
[data-theme="devai-tools"] .text-primary { color: hsl(150 60% 45%); }
/* ---------- 5. findai(minimal):极简紫 ----------
纯白、无边框卡片、细分隔、紫罗兰、大留白 */
[data-theme="findai"] {
--primary: 262 65% 52%;
--primary-foreground: 0 0% 100%;
--ring: 262 65% 52%;
}
[data-theme="findai"] .group.relative {
border-color: transparent;
box-shadow: none;
transition: background-color 0.15s ease;
}
[data-theme="findai"] .group.relative:hover {
background-color: hsl(262 40% 97%);
}
[data-theme="findai"] .shadow-lg {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
}
[data-theme="findai"] .rounded-full { border-radius: 999px; }
/* ============================================================
深度设计层 v2 —— 每站完整的视觉语言(不只是换色)
============================================================ */
/* ---------- 1. AI Stack:深蓝渐变 Hero + 统计条(专业 SaaS) ---------- */
[data-theme="ai-stack"] .hero-dark {
background: linear-gradient(180deg, hsl(224 60% 14%) 0%, hsl(224 55% 22%) 75%, hsl(var(--background)) 100%);
}
[data-theme="ai-stack"] .hero-dark h1 {
color: white;
}
[data-theme="ai-stack"] .hero-dark p,
[data-theme="ai-stack"] .hero-dark span {
color: rgba(255, 255, 255, 0.65);
}
[data-theme="ai-stack"] .hero-dark input {
background: white;
border-color: transparent;
}
[data-theme="ai-stack"] .hero-dark .bg-secondary {
background-color: rgba(255, 255, 255, 0.12);
color: rgba(255, 255, 255, 0.85);
}
[data-theme="ai-stack"] .hero-dark .bg-secondary:hover {
background-color: rgba(255, 255, 255, 0.2);
}
[data-theme="ai-stack"] .group.relative {
border-left: 3px solid transparent;
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
[data-theme="ai-stack"] .group.relative:hover {
border-left-color: hsl(224 64% 40%);
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
}
/* ---------- 2. LaunchAI:橙色渐变 Banner + 活力大字 ---------- */
[data-theme="launchai"] .hero-launch {
background: linear-gradient(135deg, hsl(16 90% 50%) 0%, hsl(24 90% 55%) 100%);
}
[data-theme="launchai"] .hero-launch h1,
[data-theme="launchai"] .hero-launch p {
color: white;
}
[data-theme="launchai"] .hero-launch .text-muted-foreground {
color: rgba(255, 255, 255, 0.85);
}
[data-theme="launchai"] .hero-launch a.bg-primary,
[data-theme="launchai"] .hero-launch button.bg-primary {
background: white;
color: hsl(16 90% 50%);
}
[data-theme="launchai"] .border-l-4 { border-left-width: 4px; }
[data-theme="launchai"] .group.relative:hover {
transform: translateY(-1px);
}
/* ---------- 3. The AI Ledger:黑色报头 + 报纸排版 ---------- */
[data-theme="the-ai-ledger"] header {
border-bottom: 3px double hsl(24 10% 12%);
}
[data-theme="the-ai-ledger"] section:first-of-type {
border-bottom: 1px solid hsl(24 10% 12%);
background: transparent;
}
[data-theme="the-ai-ledger"] section:first-of-type h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 900;
}
[data-theme="the-ai-ledger"] .hero-mast p:first-of-type {
text-transform: uppercase;
letter-spacing: 0.35em;
font-size: 11px;
}
[data-theme="the-ai-ledger"] .group.relative:hover h3 {
text-decoration: underline;
text-underline-offset: 3px;
}
[data-theme="the-ai-ledger"] .rounded-full.bg-primary,
[data-theme="the-ai-ledger"] a.bg-primary {
border-radius: 1px;
}
/* 首页大标题区域居中双细线(报纸报头风格) */
[data-theme="the-ai-ledger"] .border-b.border-border {
border-bottom-style: double;
border-bottom-width: 3px;
}
/* ---------- 4. DevAI.tools:扫描线 + 终端霓虹 ---------- */
[data-theme="devai-tools"] {
background-image: repeating-linear-gradient(
0deg,
rgba(150, 60% 45% / 0.015) 0px,
rgba(150, 60% 45% / 0.015) 1px,
transparent 1px,
transparent 3px
);
}
[data-theme="devai-tools"] .group.relative {
border: 1px solid hsl(218 18% 17%);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
[data-theme="devai-tools"] .group.relative:hover {
border-color: hsl(150 60% 45% / 0.5);
box-shadow: 0 0 0 1px hsl(150 60% 45% / 0.15), 0 0 24px hsl(150 60% 45% / 0.06);
}
[data-theme="devai-tools"] .rounded-xl.bg-primary {
background-color: hsl(150 60% 45%);
color: hsl(220 25% 7%);
}
[data-theme="devai-tools"] header .bg-secondary {
background-color: hsl(220 20% 13%);
}
/* ---------- 5. findai:聚焦光圈 + 无界卡片 ---------- */
[data-theme="findai"] input:focus {
box-shadow: 0 0 0 6px hsl(262 65% 52% / 0.08), 0 8px 30px hsl(262 65% 52% / 0.1);
border-color: hsl(262 65% 52% / 0.4);
}
[data-theme="findai"] .group.relative:hover h3 {
color: hsl(262 65% 52%);
}
[data-theme="findai"] .rounded-full.border {
border-color: hsl(0 0% 90%);
}
/* LaunchAI hero 斜切签名条 */
[data-theme="launchai"] section:first-of-type::after {
content: "";
display: block;
height: 18px;
margin-top: -18px;
background: hsl(var(--background));
clip-path: polygon(0 100%, 100% 0, 100% 100%, 0 100%);
}
+1
View File
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@/kit/types";
// AI Stack —— 独立站点的全部品牌/导航/页脚配置
export const siteConfig: SiteConfig = {
"themeClass": "site-ai-stack",
"brandZh": {
"name": "AI Stack",
"tagline": "由真实用户排名的专业 AI 工具目录。",
+19 -4
View File
@@ -58,7 +58,7 @@ async function SiteHome({ locale }: { locale: string }) {
return (
<div className="bg-background">
{/* Hero */}
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
<section className="hero-dark border-b border-border">
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
{th("title")}
@@ -83,13 +83,28 @@ async function SiteHome({ locale }: { locale: string }) {
</button>
</div>
</form>
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
<span>{t("popularLabel")}</span>
{/* 统计条(深色 Hero 内的白色数字) */}
<div className="mx-auto mt-10 flex max-w-lg items-center justify-center gap-10 border-t border-white/15 pt-6">
{[
{ v: "1,000+", l: "AI tools" },
{ v: "14", l: "Categories" },
{ v: "7", l: "Rankings" },
].map((s) => (
<div key={s.l} className="text-center">
<div className="text-2xl font-bold text-white">{s.v}</div>
<div className="text-xs text-white/60">{s.l}</div>
</div>
))}
</div>
<div className="mt-8 flex flex-wrap items-center justify-center gap-2 text-xs">
<span className="text-white/60">{t("popularLabel")}</span>
{t.raw("popularSearches").map((q: string) => (
<LocaleLink
key={q}
href={`/tools?search=${q}`}
className="rounded-full bg-secondary px-2.5 py-1 transition-colors hover:bg-hover"
className="rounded-full bg-white/10 px-2.5 py-1 text-white/80 transition-colors hover:bg-white/20"
>
{q}
</LocaleLink>
+1
View File
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@/kit/types";
// DevAI.tools —— 独立站点的全部品牌/导航/页脚配置
export const siteConfig: SiteConfig = {
"themeClass": "site-devai-tools",
"brandZh": {
"name": "DevAI.tools",
"tagline": "面向开发者的 AI 工具——精选、实测、社区排名。",
+7 -1
View File
@@ -51,7 +51,13 @@ async function SiteHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Terminal 风格 Hero */}
{/* 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">
+1
View File
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@/kit/types";
// findai —— 独立站点的全部品牌/导航/页脚配置
export const siteConfig: SiteConfig = {
"themeClass": "site-findai",
"brandZh": {
"name": "findai",
"tagline": "极简 AI 工具搜索引擎。",
+1
View File
@@ -73,6 +73,7 @@ async function SiteHome({ locale }: { locale: string }) {
</div>
</form>
<div className="mx-auto mt-10 max-w-md border-t border-border/60 pt-5" />
<div className="mt-6 flex flex-wrap items-center justify-center gap-2">
{popularSearches.map((q) => (
<LocaleLink
+1
View File
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@/kit/types";
// LaunchAI —— 独立站点的全部品牌/导航/页脚配置
export const siteConfig: SiteConfig = {
"themeClass": "site-launchai",
"brandZh": {
"name": "LaunchAI",
"tagline": "发现并投票今日的 AI 新品。",
+1 -1
View File
@@ -111,7 +111,7 @@ async function SiteHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Hero:今日发布 */}
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
<section className="hero-launch border-b border-border bg-gradient-to-b from-primary/5 to-background">
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
{th("title")}
+1
View File
@@ -2,6 +2,7 @@ import type { SiteConfig } from "@/kit/types";
// The AI Ledger —— 独立站点的全部品牌/导航/页脚配置
export const siteConfig: SiteConfig = {
"themeClass": "site-the-ai-ledger",
"brandZh": {
"name": "The AI Ledger",
"tagline": "独立 AI 报道,附社区排名目录。",
+9
View File
@@ -54,6 +54,15 @@ async function SiteHome({ locale }: { locale: string }) {
return (
<div className="min-h-screen bg-background">
{/* Masthead:黑色报头条(当日日期 + 期号),报纸头版签名 */}
<div className="bg-foreground text-background">
<div className="mx-auto flex max-w-4xl items-center justify-between px-4 py-2 text-[11px] uppercase tracking-[0.25em] sm:px-6">
<span>{new Date().toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}</span>
<span className="hidden sm:inline">Est. 2026</span>
<span>Daily</span>
</div>
</div>
{/* Masthead */}
<section className="border-b border-border">
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">