@@ -109,7 +119,7 @@ export default function DatingPage() {

@@ -119,7 +129,7 @@ export default function DatingPage() {
📍 {currentProfile.location}
-
匹配标签:
+
{t("matchTags")}:
{currentProfile.tags.map((tag) => (
{tag}
@@ -129,16 +139,16 @@ export default function DatingPage() {
{currentProfile.bio}
-
-
+
💚
- 喜欢
+ {t("like")}
@@ -147,6 +157,7 @@ export default function DatingPage() {
+
);
}
diff --git a/app/[locale]/gigs/page.tsx b/app/[locale]/gigs/page.tsx
new file mode 100644
index 0000000..69bbb2e
--- /dev/null
+++ b/app/[locale]/gigs/page.tsx
@@ -0,0 +1,63 @@
+"use client";
+
+import { useTranslation } from "@/i18n/navigation";
+import Footer from "@/app/components/Footer";
+
+const MOCK_GIGS = [
+ { id: "1", title: "帮我 P 图", city: "大理", reward: "¥50", author: "林**" },
+ { id: "2", title: "找惠州 loft 民宿", city: "深圳", reward: "¥100", author: "陈**" },
+ { id: "3", title: "代收快递", city: "成都", reward: "¥30", author: "王**" },
+ { id: "4", title: "一起 citywalk 拍 neo2 航拍", city: "杭州", reward: "面议", author: "张**" },
+ { id: "5", title: "翻译英文文档", city: "上海", reward: "¥200", author: "李**" },
+];
+
+export default function GigsPage() {
+ const { t } = useTranslation("gigs");
+
+ return (
+
+
+
+
+
+ {t("title")}
+
+
+ {t("subtitle")} · {t("platformFee")}
+
+
+
+ {t("publish")}
+
+
+
+
+ {MOCK_GIGS.map((gig) => (
+
+
+
+ {gig.title}
+
+
+ 📍 {gig.city} · {gig.author}
+
+
+
+
+ {gig.reward}
+
+
+ {t("browse")}
+
+
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
index fee0b87..41fe0b5 100644
--- a/app/[locale]/layout.tsx
+++ b/app/[locale]/layout.tsx
@@ -8,9 +8,9 @@ import Navbar from "../components/Navbar";
const LOCALES: Locale[] = ["zh", "en"];
export const metadata: Metadata = {
- title: "游牧中国 - 数字游民的理想目的地",
+ title: "游牧中国 NomadCNA - 数字游民生活操作系统",
description:
- "发现全球最适合远程工作和生活的城市,加入中国数字游民社区,探索远程办公新方式",
+ "数字游民的一站式生活操作系统:城市决策、税务签证、智能匹配、赏金任务。从 Free 到 Pro,开启你的游牧人生",
};
export function generateStaticParams() {
diff --git a/app/[locale]/pricing/page.tsx b/app/[locale]/pricing/page.tsx
new file mode 100644
index 0000000..170efc5
--- /dev/null
+++ b/app/[locale]/pricing/page.tsx
@@ -0,0 +1,109 @@
+"use client";
+
+import { useState } from "react";
+import { useTranslation } from "@/i18n/navigation";
+import { Link } from "@/i18n/navigation";
+import Footer from "@/app/components/Footer";
+
+const PLANS = [
+ { id: "free", key: "free", price: 0, priceYear: 0, features: ["browse"], highlight: false },
+ { id: "basic", key: "basic", price: 39, priceYear: 390, features: ["browse", "noAds", "advancedFilter", "unlimitedSwipe", "priorityEvent"], highlight: true },
+ { id: "pro", key: "pro", price: 149, priceYear: 1490, features: ["browse", "noAds", "advancedFilter", "unlimitedSwipe", "priorityEvent", "crmRoster", "oneOnOne", "gigAccess", "dashboard"], highlight: false },
+] as const;
+
+export default function PricingPage() {
+ const { t } = useTranslation("pricing");
+ const [yearly, setYearly] = useState(false);
+
+ return (
+
+
+
+
+ {t("title")}
+
+
+ {t("subtitle")}
+
+
+
+ {t("monthly")}
+
+ setYearly(!yearly)}
+ className={`relative w-12 h-6 rounded-full transition-colors ${yearly ? "bg-[#ff4d4f]" : "bg-gray-200 dark:bg-gray-700"}`}
+ >
+
+
+
+ {t("yearly")}
+
+
+
+
+
+ {PLANS.map((plan) => {
+ const displayPrice = yearly ? plan.priceYear : plan.price;
+ const priceKey = yearly ? "perYear" : "perMonth";
+ return (
+
+
+ {t(plan.key)}
+
+
+
+ {displayPrice === 0 ? "¥0" : `¥${displayPrice.toLocaleString()}`}
+
+ {displayPrice > 0 && (
+
+ {t(priceKey)}
+
+ )}
+
+ {yearly && plan.priceYear > 0 && (
+
+ 省 ¥{(plan.price * 12 - plan.priceYear).toLocaleString()}
+
+ )}
+
+ {plan.features.map((f) => (
+ -
+ ✓
+ {t(`features.${f}`)}
+
+ ))}
+
+
+ {plan.id === "free" ? t("getStarted") : t("upgrade")}
+
+
+ );
+ })}
+
+
+
+ {t("features.experienceCamp")}
+
+
+
+
+ );
+}
diff --git a/app/[locale]/report/page.tsx b/app/[locale]/report/page.tsx
new file mode 100644
index 0000000..23d9dcf
--- /dev/null
+++ b/app/[locale]/report/page.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import { useState } from "react";
+import { useTranslation } from "@/i18n/navigation";
+import Footer from "@/app/components/Footer";
+
+export default function ReportPage() {
+ const { t } = useTranslation("report");
+ const [generated, setGenerated] = useState(false);
+
+ return (
+
+
+
+
+ {t("title")}
+
+
+ {t("subtitle")}
+
+
+
+ {!generated ? (
+
+
+ 📊
+
+
+ {t("desc")}
+
+
setGenerated(true)}
+ className="px-6 py-3 rounded-xl bg-[#ff4d4f] text-white font-medium hover:bg-[#ff3333] transition-colors"
+ >
+ {t("generate")}
+
+
+ ) : (
+
+
+
+
+ {t("yearTitle")}
+
+
+
+
+
¥5,200
+
{t("avgCost")}
+
+
+
12
+
{t("coworkingCheckins")}
+
+
+
+
+ {t("watermark")}
+
+
setGenerated(false)}
+ className="mt-4 w-full py-2 rounded-lg border border-gray-200 dark:border-gray-700 text-sm text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800"
+ >
+ {t("regenerate")}
+
+
+
+ )}
+
+
+
+ );
+}
diff --git a/app/[locale]/tools/page.tsx b/app/[locale]/tools/page.tsx
new file mode 100644
index 0000000..4ccb766
--- /dev/null
+++ b/app/[locale]/tools/page.tsx
@@ -0,0 +1,131 @@
+"use client";
+
+import { useState } from "react";
+import { useTranslation } from "@/i18n/navigation";
+import Footer from "@/app/components/Footer";
+
+const RATES = [
+ { from: "CNY", to: "USD", rate: 0.14 },
+ { from: "CNY", to: "EUR", rate: 0.13 },
+ { from: "CNY", to: "THB", rate: 5.2 },
+ { from: "USD", to: "CNY", rate: 7.2 },
+];
+
+export default function ToolsPage() {
+ const { t } = useTranslation("tools");
+ const [income, setIncome] = useState(100000);
+ const [cnyAmount, setCnyAmount] = useState(10000);
+ const [visaDate, setVisaDate] = useState("2025-06-15");
+
+ const taxEstimate = Math.round(income * 0.15);
+ const cnyToUsd = (v: number) => (v * 0.14).toFixed(2);
+ const daysLeft = Math.ceil(
+ (new Date(visaDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24)
+ );
+
+ return (
+
+
+
+
+ {t("title")}
+
+
+ {t("subtitle")}
+
+
+
+
+
+
+ 💱 {t("exchange")}
+
+
+ {RATES.map((r) => (
+
+
+ {r.from} → {r.to}
+
+
+ {r.rate}
+
+
+ ))}
+
+
+
+
+ setCnyAmount(Number(e.target.value) || 0)}
+ className="flex-1 rounded-lg border border-gray-200 dark:border-gray-700 px-3 py-2 text-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"
+ />
+ ≈
+ ${cnyToUsd(cnyAmount)}
+
+
+
+ {t("disclaimer")}
+
+
+
+
+
+ 📊 {t("tax")}
+
+
+
+
+ setIncome(Number(e.target.value))}
+ className="w-full rounded-lg border border-gray-200 dark:border-gray-700 px-4 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
+ />
+
+
+
+ {t("estimate")}: 约 ¥{taxEstimate.toLocaleString()}/年
+
+
+ {t("taxDisclaimer")}
+
+
+
+
+
+
+
+ 🛂 {t("visa")}
+
+
+
+
+ setVisaDate(e.target.value)}
+ className="w-full rounded-lg border border-gray-200 dark:border-gray-700 px-4 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
+ />
+
+
+
+ {daysLeft > 0 ? `${daysLeft} ${t("daysLeft")}` : t("expired")}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx
index 0ccbb53..ceda1e7 100644
--- a/app/components/Footer.tsx
+++ b/app/components/Footer.tsx
@@ -15,8 +15,9 @@ const footerSections = [
{
titleKey: "tools" as const,
links: [
- { labelKey: "climate" as const, href: "#" },
- { labelKey: "cost" as const, href: "#" },
+ { labelKey: "dashboard" as const, href: "/dashboard" },
+ { labelKey: "cost" as const, href: "/tools" },
+ { labelKey: "ai" as const, href: "/ai" },
{ labelKey: "coworking" as const, href: "#" },
{ labelKey: "compare" as const, href: "#" },
],
@@ -27,6 +28,7 @@ const footerSections = [
{ labelKey: "guide" as const, href: "#" },
{ labelKey: "cityGuide" as const, href: "#" },
{ labelKey: "stories" as const, href: "#" },
+ { labelKey: "report" as const, href: "/report" },
{ labelKey: "faq" as const, href: "#" },
],
},
@@ -34,6 +36,8 @@ const footerSections = [
titleKey: "about" as const,
links: [
{ labelKey: "aboutUs" as const, href: "/about" },
+ { labelKey: "pricing" as const, href: "/pricing" },
+ { labelKey: "gigs" as const, href: "/gigs" },
{ labelKey: "recruit" as const, href: "/jobs" },
{ labelKey: "terms" as const, href: "#" },
{ labelKey: "privacy" as const, href: "#" },
diff --git a/app/components/HeroSection.tsx b/app/components/HeroSection.tsx
index cb7beab..7920093 100644
--- a/app/components/HeroSection.tsx
+++ b/app/components/HeroSection.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { Link } from "@/i18n/navigation";
+import { useTranslation } from "@/i18n/navigation";
const avatarPhotos = [
"https://i.pravatar.cc/150?img=32",
@@ -18,14 +19,16 @@ const avatarPhotos = [
];
const features = [
- { icon: "🍹", text: "每年在 30+ 城市参加线下聚会" },
- { icon: "❤️", text: "结识新朋友,约会交友" },
- { icon: "🧪", text: "研究目的地,找到最适合居住和工作的地方" },
- { icon: "🌎", text: "追踪你的旅行,记录你去过的地方" },
- { icon: "💬", text: "加入社群聊天,在旅途中找到你的归属" },
+ { icon: "📍", key: "feature1" as const },
+ { icon: "📊", key: "feature2" as const },
+ { icon: "👥", key: "feature3" as const },
+ { icon: "💰", key: "feature4" as const },
+ { icon: "📈", key: "feature5" as const },
];
export default function HeroSection() {
+ const { t } = useTranslation("common");
+ const { t: tHero } = useTranslation("hero");
const [email, setEmail] = useState("");
const handleJoin = (e: React.FormEvent) => {
@@ -57,29 +60,28 @@ export default function HeroSection() {
{/* Left Column */}
-
- 🏆 中国数字游民社区 · 始于 2024
+
+ 🏆 {tHero("badge")}
- 探索中国
+ {tHero("title")}
- 远程工作,自由生活
+ {tHero("titleSuffix")}
-
- 加入全球华人数字游民社区,发现中国最适合远程工作和生活的城市,
- 从大理到成都,从深圳到杭州,开启你的游牧人生
+
+ {tHero("subtitle")}
{features.map((f) => (
-
+
{f.icon}
-
- {f.text}
+
+ {tHero(f.key)}
))}
@@ -92,26 +94,26 @@ export default function HeroSection() {
key={i}
src={src}
alt=""
- className="w-8 h-8 rounded-full border-2 border-white shadow-sm object-cover"
+ className="w-8 h-8 rounded-full border-2 border-white dark:border-gray-800 shadow-sm object-cover"
/>
))}
-
- 5,000+ 成员已加入
+
+ 5,000+ 成员已加入
-
-
+
+
媒体报道
{["36氪", "少数派", "极客公园", "虎嗅", "创业邦", "澎湃新闻"].map(
(name) => (
-
+
{name}
),
@@ -122,7 +124,7 @@ export default function HeroSection() {
{/* Right Column: Video + Email */}
-
+
@@ -147,7 +149,7 @@ export default function HeroSection() {
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="输入你的邮箱..."
- className="w-full border border-gray-200 rounded-lg px-4 py-3 text-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#ff4d4f]/20 focus:border-[#ff4d4f] transition-colors mb-3"
+ className="w-full border border-gray-200 dark:border-gray-700 rounded-lg px-4 py-3 text-sm placeholder-gray-400 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-[#ff4d4f]/20 focus:border-[#ff4d4f] transition-colors mb-3"
/>
加入游牧中国 →
-
+
已有账号?输入邮箱即可自动登录
-
+
+ 📍 下一站
+
+
🍹 线下聚会
-
- ❤️ 交友约会
+
+ ❤️ 智能匹配
-
+
+ 📊 工具箱
+
+
+ 🤖 AI 助理
+
+
+ 💰 赏金墙
+
+
+ 📊 年报
+
+
💬 加入社群
diff --git a/app/components/Navbar.tsx b/app/components/Navbar.tsx
index 50eef48..50b48b3 100644
--- a/app/components/Navbar.tsx
+++ b/app/components/Navbar.tsx
@@ -8,8 +8,13 @@ import ThemeToggle from "./ThemeToggle";
const navLinks = [
{ labelKey: "cities" as const, icon: "🏙️", href: "/" },
+ { labelKey: "dashboard" as const, icon: "📍", href: "/dashboard" },
{ labelKey: "travel" as const, icon: "✈️", href: "/meetups" },
{ labelKey: "community" as const, icon: "💬", href: "/dating" },
+ { labelKey: "tools" as const, icon: "📊", href: "/tools" },
+ { labelKey: "ai" as const, icon: "🤖", href: "/ai" },
+ { labelKey: "gigs" as const, icon: "💰", href: "/gigs" },
+ { labelKey: "pricing" as const, icon: "👑", href: "/pricing" },
{ labelKey: "explore" as const, icon: "🎒", href: "/#community" },
];
@@ -48,7 +53,7 @@ export default function Navbar() {
-
+
{navLinks.map((link) => (