'多语言'
This commit is contained in:
@@ -1,144 +1,94 @@
|
||||
const links = [
|
||||
{
|
||||
icon: "📖",
|
||||
title: "入门指南",
|
||||
desc: "完整的数字游民入门教程",
|
||||
label: "开始学习 ↗",
|
||||
},
|
||||
{
|
||||
icon: "💬",
|
||||
title: "Discord 社区",
|
||||
desc: "与全球数字游民实时交流",
|
||||
label: "加入社区 ↗",
|
||||
},
|
||||
{
|
||||
icon: "🛒",
|
||||
title: "工具集市",
|
||||
desc: "发现、评测和分享远程工具",
|
||||
label: "浏览工具 ↗",
|
||||
},
|
||||
{
|
||||
icon: "📦",
|
||||
title: "GitHub",
|
||||
desc: "开源项目,欢迎 Star 和 PR",
|
||||
label: "访问仓库 ↗",
|
||||
},
|
||||
{
|
||||
icon: "📝",
|
||||
title: "飞书知识库",
|
||||
desc: "7天入门指南 · 中文图文教程",
|
||||
label: "查看文档 ↗",
|
||||
},
|
||||
{
|
||||
icon: "🗺️",
|
||||
title: "目的地数据库",
|
||||
desc: "全球数字游民城市信息",
|
||||
label: "探索城市 ↗",
|
||||
},
|
||||
];
|
||||
"use client";
|
||||
|
||||
import { Link, useTranslation } from "@/i18n/navigation";
|
||||
|
||||
const linkKeys = ["guide", "discord", "tools", "github", "feishu", "destinations"] as const;
|
||||
const linkIcons: Record<(typeof linkKeys)[number], string> = {
|
||||
guide: "📖",
|
||||
discord: "💬",
|
||||
tools: "🛒",
|
||||
github: "📦",
|
||||
feishu: "📝",
|
||||
destinations: "🗺️",
|
||||
};
|
||||
|
||||
export default function Community() {
|
||||
const { t } = useTranslation("community");
|
||||
return (
|
||||
<section id="community" className="py-20 sm:py-28">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
{/* Community cards */}
|
||||
<div className="mb-20 grid gap-6 md:grid-cols-2">
|
||||
<a
|
||||
{/* 数字游民社区 - 优化布局 */}
|
||||
<div className="mb-20">
|
||||
<Link
|
||||
href="/join"
|
||||
className="block rounded-2xl border border-sky-200 bg-gradient-to-br from-sky-50 to-cyan-50 p-8 transition-all hover:shadow-lg"
|
||||
className="group block overflow-hidden rounded-2xl border border-sky-200/80 bg-gradient-to-br from-sky-50 via-white to-cyan-50/60 p-8 shadow-sm transition-all duration-300 hover:border-sky-300 hover:shadow-xl hover:shadow-sky-100/50 sm:p-10"
|
||||
>
|
||||
<div className="mb-2 text-sm font-semibold text-sky-600">
|
||||
👥 数字游民社区
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900">
|
||||
加入全球华人数字游民网络
|
||||
</h3>
|
||||
<p className="mb-6 text-sm leading-relaxed text-slate-600">
|
||||
填写申请表加入社区
|
||||
<br />
|
||||
1000+ 数字游民 · 每周线上分享 · 城市攻略
|
||||
</p>
|
||||
<div className="flex items-center justify-center rounded-xl bg-white/80 p-6 shadow-sm backdrop-blur-sm">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-14 w-14 items-center justify-center rounded-full bg-sky-100 text-3xl">
|
||||
<div className="flex flex-col gap-6 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="mb-3 inline-flex items-center gap-2 rounded-full bg-sky-100 px-4 py-1.5 text-sm font-semibold text-sky-700">
|
||||
<span className="text-lg">👥</span>
|
||||
{t("nomadCommunity")}
|
||||
</div>
|
||||
<h3 className="mb-3 text-2xl font-bold tracking-tight text-slate-900 sm:text-3xl">
|
||||
{t("joinTitle")}
|
||||
</h3>
|
||||
<p className="mb-4 max-w-xl text-base leading-relaxed text-slate-600">
|
||||
{t("joinDesc")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<span className="rounded-lg bg-white/90 px-3 py-1.5 text-sm font-medium text-slate-600 shadow-sm">
|
||||
{t("applyForm")}
|
||||
</span>
|
||||
<span className="rounded-lg bg-white/90 px-3 py-1.5 text-sm font-medium text-slate-600 shadow-sm">
|
||||
{t("approveJoin")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-4 rounded-2xl bg-white/90 p-6 shadow-md backdrop-blur-sm transition-transform group-hover:scale-[1.02] sm:p-8">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-400 to-cyan-500 text-3xl shadow-lg shadow-sky-200/50">
|
||||
📝
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="font-bold text-slate-800">
|
||||
立即申请加入 →
|
||||
{t("applyNow")}
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-slate-400">
|
||||
填写简单表单,审核通过即可入群
|
||||
<div className="mt-1 text-sm text-slate-500">
|
||||
{t("applyHint")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/course"
|
||||
className="block rounded-2xl border border-amber-200 bg-gradient-to-br from-amber-50 to-orange-50 p-8 transition-all hover:shadow-lg"
|
||||
>
|
||||
<div className="mb-2 text-sm font-semibold text-amber-600">
|
||||
🎬 数字游民实战课
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900">
|
||||
打造 7×24 小时自动化收入系统
|
||||
</h3>
|
||||
<div className="mb-4 flex flex-wrap gap-3">
|
||||
<span className="rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-slate-600">
|
||||
🔥 实战训练营
|
||||
</span>
|
||||
<span className="rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-slate-600">
|
||||
📹 视频教程
|
||||
</span>
|
||||
<span className="rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-slate-600">
|
||||
¥199
|
||||
</span>
|
||||
</div>
|
||||
<p className="mb-6 text-sm leading-relaxed text-slate-600">
|
||||
7 天打造你的远程工作体系 · 从入门到精通
|
||||
</p>
|
||||
<div className="flex items-center justify-center rounded-xl bg-white/80 p-6 shadow-sm backdrop-blur-sm">
|
||||
<div className="text-center">
|
||||
<div className="text-5xl">🎓</div>
|
||||
<div className="mt-3 text-sm font-medium text-slate-600">
|
||||
点击查看课程详情 →
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Open source contribution */}
|
||||
<div className="text-center">
|
||||
<div className="mb-2 text-sm font-semibold text-slate-400">
|
||||
🤝 开源共建
|
||||
{t("openSource")}
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
社区与<span className="gradient-text">贡献</span>
|
||||
{t("contributeTitle")} <span className="gradient-text">{t("contributeHighlight")}</span>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民指南是开源项目,致力于做最好的中文数字游民资源聚合站。
|
||||
{t("contributeSubtitle")}
|
||||
<br />
|
||||
欢迎补充资源、改进内容、分享经验。
|
||||
{t("contributeSubtitle2")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{links.map((l) => (
|
||||
{linkKeys.map((key) => (
|
||||
<div
|
||||
key={l.title}
|
||||
key={key}
|
||||
className="card-hover flex items-start gap-4 rounded-xl border border-slate-100 bg-white p-5 shadow-sm"
|
||||
>
|
||||
<span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-slate-50 text-xl">
|
||||
{l.icon}
|
||||
{linkIcons[key]}
|
||||
</span>
|
||||
<div>
|
||||
<h4 className="font-bold text-slate-900">{l.title}</h4>
|
||||
<p className="mt-1 text-sm text-slate-500">{l.desc}</p>
|
||||
<h4 className="font-bold text-slate-900">{t(`links.${key}.title`)}</h4>
|
||||
<p className="mt-1 text-sm text-slate-500">{t(`links.${key}.desc`)}</p>
|
||||
<span className="mt-2 inline-block text-sm font-medium text-sky-600">
|
||||
{l.label}
|
||||
{t(`links.${key}.label`)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,15 +97,15 @@ export default function Community() {
|
||||
|
||||
<div className="mt-12 text-center">
|
||||
<div className="mb-4 text-lg font-bold text-slate-900">
|
||||
🌟 一起让数字游民指南变得更好
|
||||
{t("betterTitle")}
|
||||
</div>
|
||||
<p className="mb-6 text-slate-600">
|
||||
发现了好资源?写了旅居心得?有工具推荐?
|
||||
{t("betterDesc")}
|
||||
<br />
|
||||
提一个 PR,你的贡献将帮助更多人。
|
||||
{t("betterDesc2")}
|
||||
</p>
|
||||
<button className="inline-flex items-center gap-2 rounded-full bg-slate-900 px-8 py-3 font-semibold text-white transition-colors hover:bg-slate-800">
|
||||
⭐ Star & Fork on GitHub
|
||||
{t("starFork")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,49 +1,42 @@
|
||||
const features = [
|
||||
{
|
||||
icon: "🌏",
|
||||
title: "地点自由",
|
||||
desc: "在世界任何角落工作——咖啡馆、海滩、共享空间,你的办公室就是整个地球。告别固定工位,拥抱无限可能。",
|
||||
},
|
||||
{
|
||||
icon: "⚡",
|
||||
title: "技能变现",
|
||||
desc: "编程、设计、写作、营销、咨询……用你的专业技能换取全球收入,构建多元化的收入体系。",
|
||||
},
|
||||
{
|
||||
icon: "🔄",
|
||||
title: "工作生活平衡",
|
||||
desc: "自主安排时间,工作与旅行完美融合。按照自己的节奏生活,找到真正属于你的生活方式。",
|
||||
},
|
||||
];
|
||||
"use client";
|
||||
|
||||
import { useTranslation } from "@/i18n/navigation";
|
||||
|
||||
const featureKeys = ["location", "skill", "balance"] as const;
|
||||
|
||||
export default function Features() {
|
||||
const { t } = useTranslation("features");
|
||||
const features = featureKeys.map((key) => ({
|
||||
icon: key === "location" ? "🌏" : key === "skill" ? "⚡" : "🔄",
|
||||
key,
|
||||
}));
|
||||
return (
|
||||
<section id="features" className="py-20 sm:py-28">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
什么是<span className="gradient-text">数字游民</span>?
|
||||
{t("title")} <span className="gradient-text">{t("titleHighlight")}</span>{t("titleSuffix")}
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民是一种利用互联网技术远程工作、不受地理位置限制的生活方式。
|
||||
{t("subtitle")}
|
||||
<br className="hidden sm:block" />
|
||||
它让你在探索世界的同时,持续创造价值。
|
||||
{t("subtitle2")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{features.map((f) => (
|
||||
<div
|
||||
key={f.title}
|
||||
key={f.key}
|
||||
className="card-hover rounded-2xl border border-slate-100 bg-white p-8 shadow-sm"
|
||||
>
|
||||
<div className="mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-sky-50 text-3xl">
|
||||
{f.icon}
|
||||
</div>
|
||||
<h3 className="mb-3 text-xl font-bold text-slate-900">
|
||||
{f.title}
|
||||
{t(`items.${f.key}.title`)}
|
||||
</h3>
|
||||
<p className="leading-relaxed text-slate-600">{f.desc}</p>
|
||||
<p className="leading-relaxed text-slate-600">{t(`items.${f.key}.desc`)}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -51,7 +44,7 @@ export default function Features() {
|
||||
<div className="mt-12 text-center">
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-amber-200 bg-amber-50 px-5 py-2 text-sm font-medium text-amber-700">
|
||||
<span>🔥</span>
|
||||
全球已有超过 <span className="font-bold">3500 万</span> 数字游民
|
||||
{t("stat")} <span className="font-bold">{t("statCount")}</span> {t("statSuffix")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,72 +1,76 @@
|
||||
"use client";
|
||||
|
||||
import { Link, useTranslation } from "@/i18n/navigation";
|
||||
|
||||
const footerSections = [
|
||||
{
|
||||
title: "指南",
|
||||
titleKey: "guide" as const,
|
||||
links: [
|
||||
{ label: "7天学习路径", href: "#roadmap" },
|
||||
{ label: "全部资源", href: "#resources" },
|
||||
{ label: "工具推荐", href: "#tools" },
|
||||
{ label: "目的地数据库", href: "#" },
|
||||
{ labelKey: "roadmap" as const, href: "#roadmap" },
|
||||
{ labelKey: "tools" as const, href: "#tools" },
|
||||
{ labelKey: "destinations" as const, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "资源",
|
||||
titleKey: "resources" as const,
|
||||
links: [
|
||||
{ label: "远程工作平台", href: "#" },
|
||||
{ label: "签证政策汇总", href: "#" },
|
||||
{ label: "共居空间推荐", href: "#" },
|
||||
{ label: "数字游民保险", href: "#" },
|
||||
{ labelKey: "remoteJobs" as const, href: "#" },
|
||||
{ labelKey: "visa" as const, href: "#" },
|
||||
{ labelKey: "coliving" as const, href: "#" },
|
||||
{ labelKey: "insurance" as const, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "社区",
|
||||
titleKey: "community" as const,
|
||||
links: [
|
||||
{ label: "Discord", href: "#" },
|
||||
{ label: "微信群", href: "#community" },
|
||||
{ label: "即刻", href: "#" },
|
||||
{ label: "GitHub", href: "#" },
|
||||
{ labelKey: "discord" as const, href: "#" },
|
||||
{ labelKey: "wechat" as const, href: "#community" },
|
||||
{ labelKey: "jike" as const, href: "#" },
|
||||
{ labelKey: "github" as const, href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "关于",
|
||||
titleKey: "about" as const,
|
||||
links: [
|
||||
{ label: "关于我们", href: "#" },
|
||||
{ label: "贡献指南", href: "#" },
|
||||
{ label: "隐私政策", href: "#" },
|
||||
{ label: "联系我们", href: "#" },
|
||||
{ labelKey: "aboutUs" as const, href: "#" },
|
||||
{ labelKey: "contribute" as const, href: "#" },
|
||||
{ labelKey: "privacy" as const, href: "#" },
|
||||
{ labelKey: "contact" as const, href: "#" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function Footer() {
|
||||
const { t } = useTranslation("footer");
|
||||
return (
|
||||
<footer className="border-t border-slate-100 bg-white">
|
||||
<div className="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:px-8 lg:py-16">
|
||||
<div className="grid gap-8 sm:grid-cols-2 lg:grid-cols-5">
|
||||
<div className="lg:col-span-1">
|
||||
<a href="#" className="flex items-center gap-2 text-lg font-bold">
|
||||
<Link href="/" className="flex items-center gap-2 text-lg font-bold">
|
||||
<span className="text-2xl">🌍</span>
|
||||
<span>数字游民指南</span>
|
||||
</a>
|
||||
<span>{t("siteName")}</span>
|
||||
</Link>
|
||||
<p className="mt-3 text-sm leading-relaxed text-slate-500">
|
||||
开源免费的数字游民资源平台
|
||||
{t("tagline")}
|
||||
<br />
|
||||
助你开启自由工作与旅行的生活方式
|
||||
{t("tagline2")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{footerSections.map((section) => (
|
||||
<div key={section.title}>
|
||||
<div key={section.titleKey}>
|
||||
<h4 className="mb-4 text-sm font-bold text-slate-900">
|
||||
{section.title}
|
||||
{t(`sections.${section.titleKey}`)}
|
||||
</h4>
|
||||
<ul className="space-y-2.5">
|
||||
{section.links.map((link) => (
|
||||
<li key={link.label}>
|
||||
<li key={link.labelKey}>
|
||||
<a
|
||||
href={link.href}
|
||||
className="text-sm text-slate-500 transition-colors hover:text-slate-700"
|
||||
>
|
||||
{link.label}
|
||||
{t(`links.${link.labelKey}`)}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
@@ -77,9 +81,9 @@ export default function Footer() {
|
||||
|
||||
<div className="mt-12 flex flex-col items-center justify-between gap-4 border-t border-slate-100 pt-8 sm:flex-row">
|
||||
<p className="text-sm text-slate-400">
|
||||
Made with 🌍 by 数字游民社区 | Digital Nomad Guide
|
||||
{t("madeBy")}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400">开源共享 · 社区驱动</p>
|
||||
<p className="text-sm text-slate-400">{t("openSource")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { Link, useLocale, usePathname, useRouter, useTranslation } from "@/i18n/navigation";
|
||||
import AuthModal from "./AuthModal";
|
||||
|
||||
const navLinks = [
|
||||
{ label: "学习路径", href: "#roadmap" },
|
||||
{ label: "工具推荐", href: "#tools" },
|
||||
{ label: "精选资源", href: "#resources" },
|
||||
{ label: "社区", href: "#community" },
|
||||
{ labelKey: "roadmap" as const, href: "#roadmap" },
|
||||
{ labelKey: "tools" as const, href: "#tools" },
|
||||
{ labelKey: "community" as const, href: "#community" },
|
||||
];
|
||||
|
||||
function getStoredUser(): string | null {
|
||||
@@ -23,6 +23,11 @@ function getStoredUser(): string | null {
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
const { t } = useTranslation("common");
|
||||
const { t: tNav } = useTranslation("nav");
|
||||
const locale = useLocale();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const [authOpen, setAuthOpen] = useState(false);
|
||||
@@ -48,11 +53,11 @@ export default function Header() {
|
||||
>
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex h-16 items-center justify-between">
|
||||
<a href="#" className="flex items-center gap-2 text-lg font-bold">
|
||||
<Link href="/" className="flex items-center gap-2 text-lg font-bold">
|
||||
<span className="text-2xl">🌍</span>
|
||||
<span className="hidden sm:inline">数字游民指南</span>
|
||||
<span className="sm:hidden">DN Guide</span>
|
||||
</a>
|
||||
<span className="hidden sm:inline">{t("siteName")}</span>
|
||||
<span className="sm:hidden">{t("siteNameShort")}</span>
|
||||
</Link>
|
||||
|
||||
<nav className="hidden items-center gap-1 md:flex">
|
||||
{navLinks.map((link) => (
|
||||
@@ -61,9 +66,16 @@ export default function Header() {
|
||||
href={link.href}
|
||||
className="rounded-lg px-3 py-2 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
|
||||
>
|
||||
{link.label}
|
||||
{tNav(link.labelKey)}
|
||||
</a>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.replace(pathname, { locale: locale === "zh" ? "en" : "zh" })}
|
||||
className="rounded-lg px-3 py-2 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
|
||||
>
|
||||
{locale === "zh" ? "EN" : "中文"}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -76,7 +88,7 @@ export default function Header() {
|
||||
onClick={handleLogout}
|
||||
className="rounded-full border border-slate-200 px-4 py-2 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-50"
|
||||
>
|
||||
退出
|
||||
{t("logout")}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -84,20 +96,20 @@ export default function Header() {
|
||||
onClick={() => setAuthOpen(true)}
|
||||
className="hidden rounded-full border border-slate-200 px-4 py-2 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-50 sm:inline-flex"
|
||||
>
|
||||
登录 / 注册
|
||||
{t("loginRegister")}
|
||||
</button>
|
||||
)}
|
||||
<a
|
||||
href="#roadmap"
|
||||
className="hidden rounded-full bg-sky-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-sky-600 sm:inline-flex"
|
||||
>
|
||||
开始探索 →
|
||||
{t("explore")}
|
||||
</a>
|
||||
|
||||
<button
|
||||
onClick={() => setMobileOpen(!mobileOpen)}
|
||||
className="inline-flex items-center justify-center rounded-lg p-2 text-slate-600 transition-colors hover:bg-slate-100 md:hidden"
|
||||
aria-label="切换菜单"
|
||||
aria-label={t("toggleMenu")}
|
||||
>
|
||||
{mobileOpen ? (
|
||||
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -123,9 +135,19 @@ export default function Header() {
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className="block rounded-lg px-3 py-2.5 text-base font-medium text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
|
||||
>
|
||||
{link.label}
|
||||
{tNav(link.labelKey)}
|
||||
</a>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setMobileOpen(false);
|
||||
router.replace(pathname, { locale: locale === "zh" ? "en" : "zh" });
|
||||
}}
|
||||
className="block w-full rounded-lg px-3 py-2.5 text-left text-base font-medium text-slate-600 transition-colors hover:bg-slate-100 hover:text-slate-900"
|
||||
>
|
||||
{locale === "zh" ? "EN" : "中文"}
|
||||
</button>
|
||||
{userEmail ? (
|
||||
<div className="mt-2 flex items-center justify-between rounded-lg border border-slate-100 bg-slate-50 px-4 py-2.5">
|
||||
<span className="truncate text-sm text-slate-600">{userEmail}</span>
|
||||
@@ -136,7 +158,7 @@ export default function Header() {
|
||||
}}
|
||||
className="text-sm font-medium text-sky-500"
|
||||
>
|
||||
退出
|
||||
{t("logout")}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -147,7 +169,7 @@ export default function Header() {
|
||||
}}
|
||||
className="mt-2 block w-full rounded-full border border-slate-200 px-4 py-2.5 text-center text-base font-medium text-slate-600"
|
||||
>
|
||||
登录 / 注册
|
||||
{t("loginRegister")}
|
||||
</button>
|
||||
)}
|
||||
<a
|
||||
@@ -155,7 +177,7 @@ export default function Header() {
|
||||
onClick={() => setMobileOpen(false)}
|
||||
className="mt-2 block rounded-full bg-sky-500 px-4 py-2.5 text-center text-base font-medium text-white transition-colors hover:bg-sky-600"
|
||||
>
|
||||
开始探索 →
|
||||
{t("explore")}
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
const stats = [
|
||||
{ value: "200+", label: "精选资源" },
|
||||
{ value: "7 天", label: "入门路径" },
|
||||
{ value: "50+", label: "远程工具" },
|
||||
{ value: "30+", label: "目的地" },
|
||||
{ value: "100%", label: "免费开源" },
|
||||
];
|
||||
"use client";
|
||||
|
||||
import { useTranslation } from "@/i18n/navigation";
|
||||
|
||||
export default function Hero() {
|
||||
const { t } = useTranslation("hero");
|
||||
const stats = [
|
||||
{ value: "200+", labelKey: "resources" as const },
|
||||
{ value: "7 天", labelKey: "path" as const },
|
||||
{ value: "50+", labelKey: "tools" as const },
|
||||
{ value: "30+", labelKey: "destinations" as const },
|
||||
{ value: "100%", labelKey: "free" as const },
|
||||
];
|
||||
return (
|
||||
<section className="relative overflow-hidden pt-24 pb-16 sm:pt-32 sm:pb-20">
|
||||
<div className="pointer-events-none absolute inset-0 bg-gradient-to-b from-sky-50/80 via-white to-white" />
|
||||
@@ -16,20 +20,20 @@ export default function Hero() {
|
||||
<div className="text-center">
|
||||
<div className="mb-6 inline-flex items-center gap-2 rounded-full border border-sky-200 bg-sky-50 px-4 py-1.5 text-sm font-medium text-sky-700">
|
||||
<span>🎒</span>
|
||||
<span>开源免费 · 收录 200+ 篇实用资源</span>
|
||||
<span>{t("badge")}</span>
|
||||
</div>
|
||||
|
||||
<h1 className="mx-auto max-w-4xl text-4xl font-extrabold tracking-tight sm:text-5xl lg:text-7xl">
|
||||
<span className="gradient-text">数字游民</span>
|
||||
<span className="gradient-text">{t("title")}</span>
|
||||
<br className="sm:hidden" />
|
||||
生活指南
|
||||
{t("titleSuffix")}
|
||||
</h1>
|
||||
|
||||
<p className="mx-auto mt-6 max-w-2xl text-lg leading-relaxed text-slate-600 sm:text-xl">
|
||||
从零开始,7天开启你的数字游民生活
|
||||
{t("subtitle")}
|
||||
<br className="hidden sm:block" />
|
||||
<span className="text-slate-400 sm:text-slate-600">
|
||||
The open-source guide to becoming a digital nomad
|
||||
{t("subtitleEn")}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
@@ -38,14 +42,14 @@ export default function Hero() {
|
||||
href="#roadmap"
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-sky-500 px-8 py-3.5 text-base font-semibold text-white shadow-lg shadow-sky-500/25 transition-all hover:bg-sky-600 hover:shadow-xl hover:shadow-sky-500/30 sm:w-auto"
|
||||
>
|
||||
🚀 开始学习
|
||||
{t("ctaStart")}
|
||||
<span>→</span>
|
||||
</a>
|
||||
<a
|
||||
href="#resources"
|
||||
href="#community"
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-full border border-slate-200 bg-white px-8 py-3.5 text-base font-semibold text-slate-700 shadow-sm transition-all hover:border-slate-300 hover:bg-slate-50 sm:w-auto"
|
||||
>
|
||||
📚 浏览资源
|
||||
{t("ctaResources")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,7 +66,7 @@ export default function Hero() {
|
||||
{s.value}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-500">
|
||||
{s.label}
|
||||
{t(`stats.${s.labelKey}`)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -80,7 +84,7 @@ export default function Hero() {
|
||||
{s.value}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-500">
|
||||
{s.label}
|
||||
{t(`stats.${s.labelKey}`)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,72 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { Link, useTranslation } from "@/i18n/navigation";
|
||||
|
||||
const days = [
|
||||
{
|
||||
day: 1,
|
||||
icon: "👋",
|
||||
title: "认识数字游民",
|
||||
desc: "了解数字游民的真正含义,评估这种生活方式是否适合你,破除常见误解。",
|
||||
color: "bg-sky-500",
|
||||
},
|
||||
{
|
||||
day: 2,
|
||||
icon: "💡",
|
||||
title: "发现远程技能",
|
||||
desc: "掌握最受欢迎的远程工作技能,从编程、设计到内容创作,找到你的方向。",
|
||||
color: "bg-cyan-500",
|
||||
},
|
||||
{
|
||||
day: 3,
|
||||
icon: "💰",
|
||||
title: "构建收入体系",
|
||||
desc: "自由职业、远程全职、被动收入、在线课程,构建可持续的多元收入来源。",
|
||||
color: "bg-teal-500",
|
||||
},
|
||||
{
|
||||
day: 4,
|
||||
icon: "🛠️",
|
||||
title: "工具武装",
|
||||
desc: "生产力工具、通讯协作、项目管理、云服务,打造你的移动办公装备库。",
|
||||
color: "bg-emerald-500",
|
||||
},
|
||||
{
|
||||
day: 5,
|
||||
icon: "📋",
|
||||
title: "签证与法律",
|
||||
desc: "数字游民签证政策、税务规划、海外保险、银行账户,搞定法律合规问题。",
|
||||
color: "bg-amber-500",
|
||||
},
|
||||
{
|
||||
day: 6,
|
||||
icon: "🗺️",
|
||||
title: "目的地指南",
|
||||
desc: "热门数字游民城市推荐,生活成本对比、网速测评、社区活跃度一目了然。",
|
||||
color: "bg-orange-500",
|
||||
},
|
||||
{
|
||||
day: 7,
|
||||
icon: "🚀",
|
||||
title: "启程出发",
|
||||
desc: "打包清单、过渡计划、第一站选择建议,从规划到行动的最后一步。",
|
||||
color: "bg-rose-500",
|
||||
},
|
||||
{ day: 1, icon: "👋", color: "bg-sky-500" },
|
||||
{ day: 2, icon: "💡", color: "bg-cyan-500" },
|
||||
{ day: 3, icon: "💰", color: "bg-teal-500" },
|
||||
{ day: 4, icon: "🛠️", color: "bg-emerald-500" },
|
||||
{ day: 5, icon: "📋", color: "bg-amber-500" },
|
||||
{ day: 6, icon: "🗺️", color: "bg-orange-500" },
|
||||
{ day: 7, icon: "🚀", color: "bg-rose-500" },
|
||||
];
|
||||
|
||||
export default function Roadmap() {
|
||||
const { t } = useTranslation("roadmap");
|
||||
return (
|
||||
<section id="roadmap" className="bg-slate-50 py-20 sm:py-28">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
7天<span className="gradient-text">学习路径</span>
|
||||
{t("title")} <span className="gradient-text">{t("titleHighlight")}</span>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
从入门到出发,每天一个主题,循序渐进开启你的数字游民之旅。
|
||||
{t("subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 参考 openclaw101.dev:卡片网格,非时间轴 */}
|
||||
<div className="mt-14 grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
{days.map((d) => (
|
||||
<a
|
||||
<Link
|
||||
key={d.day}
|
||||
href={`/day/${d.day}`}
|
||||
className="card-hover group flex flex-col rounded-2xl border border-slate-100 bg-white p-5 shadow-sm transition-all hover:border-sky-200 hover:shadow-md"
|
||||
@@ -79,36 +41,54 @@ export default function Roadmap() {
|
||||
</div>
|
||||
<span className="text-xl">{d.icon}</span>
|
||||
<h3 className="text-base font-bold text-slate-900 group-hover:text-sky-600">
|
||||
{d.title}
|
||||
{t(`days.${d.day}.title`)}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="mt-3 flex-1 text-sm leading-relaxed text-slate-600">
|
||||
{d.desc}
|
||||
{t(`days.${d.day}.desc`)}
|
||||
</p>
|
||||
<span className="mt-3 inline-flex items-center text-sm font-medium text-sky-600">
|
||||
查看详情 →
|
||||
{t("viewDetails")}
|
||||
</span>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
<Link
|
||||
href="/ebook"
|
||||
className="card-hover group flex flex-col rounded-2xl border border-slate-100 bg-white p-5 shadow-sm transition-all hover:border-sky-200 hover:shadow-md"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-gradient-to-r from-sky-500 to-cyan-500 text-xs font-bold text-white">
|
||||
📖
|
||||
</div>
|
||||
<h3 className="text-base font-bold text-slate-900 group-hover:text-sky-600">
|
||||
{t("ebook.title")}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="mt-3 flex-1 text-sm leading-relaxed text-slate-600">
|
||||
{t("ebook.desc")}
|
||||
</p>
|
||||
<span className="mt-3 inline-flex items-center text-sm font-medium text-sky-600">
|
||||
{t("ebook.cta")}
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Training camp CTA */}
|
||||
<div className="mt-16 overflow-hidden rounded-2xl border border-amber-200 bg-gradient-to-r from-amber-50 to-orange-50 p-8 text-center sm:p-10">
|
||||
<div className="mb-2 text-sm font-semibold text-amber-600">
|
||||
🎓 实战训练营
|
||||
{t("course.tag")}
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-slate-900">
|
||||
数字游民实战课
|
||||
{t("course.title")}
|
||||
</h3>
|
||||
<p className="mx-auto mt-3 max-w-xl text-slate-600">
|
||||
21节视频课程,手把手带你从零规划专属数字游民路线,打通远程工作全流程
|
||||
{t("course.desc")}
|
||||
</p>
|
||||
<a
|
||||
<Link
|
||||
href="/course"
|
||||
className="mt-6 inline-flex items-center gap-2 rounded-full bg-amber-500 px-8 py-3 font-semibold text-white transition-colors hover:bg-amber-600"
|
||||
>
|
||||
了解详情 →
|
||||
</a>
|
||||
{t("course.cta")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslation } from "@/i18n/navigation";
|
||||
import toolsData from "../data/tools.json";
|
||||
|
||||
const categories = toolsData.categories as Array<{
|
||||
@@ -14,29 +17,27 @@ function truncateDesc(desc: string, maxLen = 5) {
|
||||
return desc.slice(0, maxLen) + "...";
|
||||
}
|
||||
|
||||
const toolStats = (() => {
|
||||
const total = categories.reduce((s, c) => s + c.tools.length, 0);
|
||||
return [
|
||||
{ value: `${total}+`, label: "精选工具" },
|
||||
{ value: String(categories.length), label: "分类" },
|
||||
{ value: "数字游民", label: "出海" },
|
||||
{ value: "佣金", label: "推荐" },
|
||||
];
|
||||
})();
|
||||
|
||||
export default function Tools() {
|
||||
const { t } = useTranslation("tools");
|
||||
const total = categories.reduce((s, c) => s + c.tools.length, 0);
|
||||
const toolStats = [
|
||||
{ value: `${total}+`, key: "tools" as const },
|
||||
{ value: String(categories.length), key: "categories" as const },
|
||||
{ value: "数字游民", key: "nomad" as const },
|
||||
{ value: "佣金", key: "affiliate" as const },
|
||||
];
|
||||
return (
|
||||
<section id="tools" className="py-20 sm:py-28">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-sky-200 bg-sky-50 px-4 py-1.5 text-sm font-medium text-sky-700">
|
||||
🚀 50+ 精选工具
|
||||
{t("badge")}
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
<span className="gradient-text">工具推荐</span>
|
||||
<span className="gradient-text">{t("title")}</span>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民出海必备工具精选,含游民社区、VPS、金融收款、出海掘金等,每个链接可点击跳转。
|
||||
{t("subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -83,17 +84,16 @@ export default function Tools() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Stats bar */}
|
||||
<div className="mt-14 grid grid-cols-2 gap-4 sm:grid-cols-4">
|
||||
{toolStats.map((s) => (
|
||||
<div
|
||||
key={s.label}
|
||||
key={s.key}
|
||||
className="rounded-2xl border border-slate-100 bg-white p-5 text-center shadow-sm"
|
||||
>
|
||||
<div className="text-3xl font-extrabold text-sky-600">
|
||||
{s.value}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-500">{s.label}</div>
|
||||
<div className="mt-1 text-sm text-slate-500">{t(`stats.${s.key}`)}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user