's'
This commit is contained in:
164
app/components/Community.tsx
Normal file
164
app/components/Community.tsx
Normal file
@@ -0,0 +1,164 @@
|
||||
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: "探索城市 ↗",
|
||||
},
|
||||
];
|
||||
|
||||
export default function 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
|
||||
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"
|
||||
>
|
||||
<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>
|
||||
<div className="text-left">
|
||||
<div className="font-bold text-slate-800">
|
||||
立即申请加入 →
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-slate-400">
|
||||
填写简单表单,审核通过即可入群
|
||||
</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>
|
||||
</div>
|
||||
|
||||
{/* Open source contribution */}
|
||||
<div className="text-center">
|
||||
<div className="mb-2 text-sm font-semibold text-slate-400">
|
||||
🤝 开源共建
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
社区与<span className="gradient-text">贡献</span>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民指南是开源项目,致力于做最好的中文数字游民资源聚合站。
|
||||
<br />
|
||||
欢迎补充资源、改进内容、分享经验。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{links.map((l) => (
|
||||
<div
|
||||
key={l.title}
|
||||
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}
|
||||
</span>
|
||||
<div>
|
||||
<h4 className="font-bold text-slate-900">{l.title}</h4>
|
||||
<p className="mt-1 text-sm text-slate-500">{l.desc}</p>
|
||||
<span className="mt-2 inline-block text-sm font-medium text-sky-600">
|
||||
{l.label}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center">
|
||||
<div className="mb-4 text-lg font-bold text-slate-900">
|
||||
🌟 一起让数字游民指南变得更好
|
||||
</div>
|
||||
<p className="mb-6 text-slate-600">
|
||||
发现了好资源?写了旅居心得?有工具推荐?
|
||||
<br />
|
||||
提一个 PR,你的贡献将帮助更多人。
|
||||
</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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
12
app/components/DayContent.tsx
Normal file
12
app/components/DayContent.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
export default function DayContent({ content }: { content: string }) {
|
||||
return (
|
||||
<div className="prose-custom">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>{content}</ReactMarkdown>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
60
app/components/Features.tsx
Normal file
60
app/components/Features.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
const features = [
|
||||
{
|
||||
icon: "🌏",
|
||||
title: "地点自由",
|
||||
desc: "在世界任何角落工作——咖啡馆、海滩、共享空间,你的办公室就是整个地球。告别固定工位,拥抱无限可能。",
|
||||
},
|
||||
{
|
||||
icon: "⚡",
|
||||
title: "技能变现",
|
||||
desc: "编程、设计、写作、营销、咨询……用你的专业技能换取全球收入,构建多元化的收入体系。",
|
||||
},
|
||||
{
|
||||
icon: "🔄",
|
||||
title: "工作生活平衡",
|
||||
desc: "自主安排时间,工作与旅行完美融合。按照自己的节奏生活,找到真正属于你的生活方式。",
|
||||
},
|
||||
];
|
||||
|
||||
export default function Features() {
|
||||
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>?
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民是一种利用互联网技术远程工作、不受地理位置限制的生活方式。
|
||||
<br className="hidden sm:block" />
|
||||
它让你在探索世界的同时,持续创造价值。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{features.map((f) => (
|
||||
<div
|
||||
key={f.title}
|
||||
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}
|
||||
</h3>
|
||||
<p className="leading-relaxed text-slate-600">{f.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<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> 数字游民
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
87
app/components/Footer.tsx
Normal file
87
app/components/Footer.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
const footerSections = [
|
||||
{
|
||||
title: "指南",
|
||||
links: [
|
||||
{ label: "7天学习路径", href: "#roadmap" },
|
||||
{ label: "全部资源", href: "#resources" },
|
||||
{ label: "工具推荐", href: "#tools" },
|
||||
{ label: "目的地数据库", href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "资源",
|
||||
links: [
|
||||
{ label: "远程工作平台", href: "#" },
|
||||
{ label: "签证政策汇总", href: "#" },
|
||||
{ label: "共居空间推荐", href: "#" },
|
||||
{ label: "数字游民保险", href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "社区",
|
||||
links: [
|
||||
{ label: "Discord", href: "#" },
|
||||
{ label: "微信群", href: "#community" },
|
||||
{ label: "即刻", href: "#" },
|
||||
{ label: "GitHub", href: "#" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "关于",
|
||||
links: [
|
||||
{ label: "关于我们", href: "#" },
|
||||
{ label: "贡献指南", href: "#" },
|
||||
{ label: "隐私政策", href: "#" },
|
||||
{ label: "联系我们", href: "#" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function 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">
|
||||
<span className="text-2xl">🌍</span>
|
||||
<span>数字游民指南</span>
|
||||
</a>
|
||||
<p className="mt-3 text-sm leading-relaxed text-slate-500">
|
||||
开源免费的数字游民资源平台
|
||||
<br />
|
||||
助你开启自由工作与旅行的生活方式
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{footerSections.map((section) => (
|
||||
<div key={section.title}>
|
||||
<h4 className="mb-4 text-sm font-bold text-slate-900">
|
||||
{section.title}
|
||||
</h4>
|
||||
<ul className="space-y-2.5">
|
||||
{section.links.map((link) => (
|
||||
<li key={link.label}>
|
||||
<a
|
||||
href={link.href}
|
||||
className="text-sm text-slate-500 transition-colors hover:text-slate-700"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<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
|
||||
</p>
|
||||
<p className="text-sm text-slate-400">开源共享 · 社区驱动</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
102
app/components/Header.tsx
Normal file
102
app/components/Header.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const navLinks = [
|
||||
{ label: "学习路径", href: "#roadmap" },
|
||||
{ label: "工具推荐", href: "#tools" },
|
||||
{ label: "精选资源", href: "#resources" },
|
||||
{ label: "社区", href: "#community" },
|
||||
];
|
||||
|
||||
export default function Header() {
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const onScroll = () => setScrolled(window.scrollY > 20);
|
||||
window.addEventListener("scroll", onScroll);
|
||||
return () => window.removeEventListener("scroll", onScroll);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header
|
||||
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
||||
scrolled
|
||||
? "bg-white/80 backdrop-blur-lg shadow-sm"
|
||||
: "bg-transparent"
|
||||
}`}
|
||||
>
|
||||
<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">
|
||||
<span className="text-2xl">🌍</span>
|
||||
<span className="hidden sm:inline">数字游民指南</span>
|
||||
<span className="sm:hidden">DN Guide</span>
|
||||
</a>
|
||||
|
||||
<nav className="hidden items-center gap-1 md:flex">
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
key={link.href}
|
||||
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}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<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"
|
||||
>
|
||||
开始探索 →
|
||||
</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="切换菜单"
|
||||
>
|
||||
{mobileOpen ? (
|
||||
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{mobileOpen && (
|
||||
<div className="border-t border-slate-100 bg-white/95 backdrop-blur-lg md:hidden">
|
||||
<nav className="mx-auto max-w-7xl space-y-1 px-4 py-3">
|
||||
{navLinks.map((link) => (
|
||||
<a
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
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}
|
||||
</a>
|
||||
))}
|
||||
<a
|
||||
href="#roadmap"
|
||||
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"
|
||||
>
|
||||
开始探索 →
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
92
app/components/Hero.tsx
Normal file
92
app/components/Hero.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
const stats = [
|
||||
{ value: "200+", label: "精选资源" },
|
||||
{ value: "7 天", label: "入门路径" },
|
||||
{ value: "50+", label: "远程工具" },
|
||||
{ value: "30+", label: "目的地" },
|
||||
{ value: "100%", label: "免费开源" },
|
||||
];
|
||||
|
||||
export default function Hero() {
|
||||
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" />
|
||||
<div className="pointer-events-none absolute top-0 left-1/2 h-[600px] w-[800px] -translate-x-1/2 rounded-full bg-gradient-to-br from-sky-100/60 via-cyan-50/40 to-amber-50/30 blur-3xl" />
|
||||
|
||||
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<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>
|
||||
</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>
|
||||
<br className="sm:hidden" />
|
||||
生活指南
|
||||
</h1>
|
||||
|
||||
<p className="mx-auto mt-6 max-w-2xl text-lg leading-relaxed text-slate-600 sm:text-xl">
|
||||
从零开始,7天开启你的数字游民生活
|
||||
<br className="hidden sm:block" />
|
||||
<span className="text-slate-400 sm:text-slate-600">
|
||||
The open-source guide to becoming a digital nomad
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row sm:gap-4">
|
||||
<a
|
||||
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"
|
||||
>
|
||||
🚀 开始学习
|
||||
<span>→</span>
|
||||
</a>
|
||||
<a
|
||||
href="#resources"
|
||||
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"
|
||||
>
|
||||
📚 浏览资源
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats marquee */}
|
||||
<div className="marquee-container mt-16 overflow-hidden">
|
||||
<div className="flex animate-scroll w-max gap-6">
|
||||
{[...stats, ...stats].map((s, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex shrink-0 items-center gap-3 rounded-2xl border border-slate-100 bg-white/80 px-6 py-4 shadow-sm backdrop-blur-sm"
|
||||
>
|
||||
<span className="text-2xl font-bold text-sky-600 sm:text-3xl">
|
||||
{s.value}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-500">
|
||||
{s.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="marquee-container mt-4 overflow-hidden">
|
||||
<div className="flex animate-scroll-reverse w-max gap-6">
|
||||
{[...stats, ...stats].map((s, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="flex shrink-0 items-center gap-3 rounded-2xl border border-slate-100 bg-white/80 px-6 py-4 shadow-sm backdrop-blur-sm"
|
||||
>
|
||||
<span className="text-2xl font-bold text-amber-500 sm:text-3xl">
|
||||
{s.value}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-500">
|
||||
{s.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
175
app/components/Resources.tsx
Normal file
175
app/components/Resources.tsx
Normal file
@@ -0,0 +1,175 @@
|
||||
const resources = [
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "📖 入门指南",
|
||||
title: "数字游民完全入门手册",
|
||||
desc: "从概念到实践,系统化的数字游民入门指南,含远程工作、签证、财务全攻略",
|
||||
source: "少数派",
|
||||
color: "bg-sky-50 text-sky-700 border-sky-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "📖 经典书籍",
|
||||
title: "The 4-Hour Workweek — Tim Ferriss",
|
||||
desc: "数字游民圣经,重新定义工作与生活的关系,构建「新富族」生活方式",
|
||||
source: "Amazon",
|
||||
color: "bg-amber-50 text-amber-700 border-amber-200",
|
||||
},
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "☁️ 远程求职",
|
||||
title: "国内远程工作机会汇总 — 电鸭社区",
|
||||
desc: "最大的中文远程工作社区,收录数千个远程岗位,涵盖开发、设计、运营等领域",
|
||||
source: "电鸭社区",
|
||||
color: "bg-emerald-50 text-emerald-700 border-emerald-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "🗺️ 目的地",
|
||||
title: "Nomad List — Best Cities for Digital Nomads",
|
||||
desc: "全球数字游民城市数据库,含生活成本、网速、安全指数、社区活跃度等指标",
|
||||
source: "Nomad List",
|
||||
color: "bg-violet-50 text-violet-700 border-violet-200",
|
||||
},
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "📹 视频教程",
|
||||
title: "从程序员到数字游民 — 我的转型之路",
|
||||
desc: "真实经历分享:如何从 996 转型为自由的数字游民,含收入、签证、生活细节",
|
||||
source: "Bilibili",
|
||||
color: "bg-rose-50 text-rose-700 border-rose-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "💰 财务规划",
|
||||
title: "Tax Planning for Digital Nomads — Complete Guide",
|
||||
desc: "数字游民税务规划权威指南:税务居民身份、双重征税协定、合规架构搭建",
|
||||
source: "SafetyWing",
|
||||
color: "bg-teal-50 text-teal-700 border-teal-200",
|
||||
},
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "🛠️ 工具评测",
|
||||
title: "远程工作者必备工具清单 2026",
|
||||
desc: "50+ 工具横评:协作、会议、设计、开发、生产力工具深度体验与推荐",
|
||||
source: "即刻",
|
||||
color: "bg-orange-50 text-orange-700 border-orange-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "🔬 深度文章",
|
||||
title: "State of Digital Nomads 2026 — Annual Report",
|
||||
desc: "2026年度数字游民状态报告:3500万全球数字游民的收入、工作、生活数据洞察",
|
||||
source: "A Brother Abroad",
|
||||
color: "bg-indigo-50 text-indigo-700 border-indigo-200",
|
||||
},
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "📱 社区",
|
||||
title: "数字游民部落 — 中文社区指南",
|
||||
desc: "连接全球华人数字游民:经验分享、城市攻略、合租搭伴、线下 Meetup",
|
||||
source: "微信公众号",
|
||||
color: "bg-cyan-50 text-cyan-700 border-cyan-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "📋 签证",
|
||||
title: "Digital Nomad Visa Guide — 50+ Countries",
|
||||
desc: "全球 50+ 国家数字游民签证政策汇总,含申请条件、费用、停留期限对比",
|
||||
source: "VisaGuide.World",
|
||||
color: "bg-lime-50 text-lime-700 border-lime-200",
|
||||
},
|
||||
{
|
||||
lang: "中文",
|
||||
tag: "🏠 共居空间",
|
||||
title: "全球最佳 Coliving 空间推荐",
|
||||
desc: "精选 30+ 数字游民共居空间:巴厘岛、清迈、里斯本、麦德林……含价格与评测",
|
||||
source: "数字游民部落",
|
||||
color: "bg-pink-50 text-pink-700 border-pink-200",
|
||||
},
|
||||
{
|
||||
lang: "EN",
|
||||
tag: "💼 自由职业",
|
||||
title: "Freelancing 101 — From Zero to First Client",
|
||||
desc: "从零开始接单指南:Upwork/Fiverr/Toptal 平台对比、定价策略、客户沟通技巧",
|
||||
source: "freeCodeCamp",
|
||||
color: "bg-sky-50 text-sky-700 border-sky-200",
|
||||
},
|
||||
];
|
||||
|
||||
const sourceStats = [
|
||||
{ value: "200+", label: "篇资源" },
|
||||
{ value: "80", label: "中文资源" },
|
||||
{ value: "120+", label: "英文资源" },
|
||||
{ value: "12", label: "大分类" },
|
||||
];
|
||||
|
||||
export default function Resources() {
|
||||
return (
|
||||
<section id="resources" 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">
|
||||
<div className="mb-2 text-sm font-semibold text-slate-400">
|
||||
📚 精选收录
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
全网<span className="gradient-text">优质资源</span>聚合
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
从少数派到 Nomad List,从 B站 到 freeCodeCamp
|
||||
—— 一站式获取数字游民最佳资源。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="mt-10 flex flex-wrap items-center justify-center gap-4 text-sm">
|
||||
{sourceStats.map((s) => (
|
||||
<div key={s.label} className="flex items-center gap-1.5">
|
||||
<span className="font-bold text-sky-600">{s.value}</span>
|
||||
<span className="text-slate-500">{s.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Resource grid */}
|
||||
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{resources.map((r, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="resource-card flex flex-col rounded-xl border border-slate-100 bg-white p-5 shadow-sm"
|
||||
>
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<span
|
||||
className={`rounded-md border px-2 py-0.5 text-xs font-semibold ${r.color}`}
|
||||
>
|
||||
{r.lang}
|
||||
</span>
|
||||
<span className="text-xs text-slate-400">{r.tag}</span>
|
||||
</div>
|
||||
<h3 className="mb-2 text-sm font-bold leading-snug text-slate-900">
|
||||
{r.title}
|
||||
</h3>
|
||||
<p className="mb-4 flex-1 text-xs leading-relaxed text-slate-500">
|
||||
{r.desc}
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-medium text-slate-400">
|
||||
{r.source}
|
||||
</span>
|
||||
<span className="cursor-pointer text-xs font-medium text-sky-600 transition-colors hover:text-sky-700">
|
||||
访问 ↗
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-10 text-center">
|
||||
<button className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-6 py-3 text-sm font-semibold text-slate-700 shadow-sm transition-all hover:border-slate-300 hover:bg-slate-50">
|
||||
查看全部 200+ 篇资源 →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
138
app/components/Roadmap.tsx
Normal file
138
app/components/Roadmap.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
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",
|
||||
},
|
||||
];
|
||||
|
||||
export default function 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>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
从入门到出发,每天一个主题,循序渐进开启你的数字游民之旅。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-16">
|
||||
{/* Desktop: vertical timeline line */}
|
||||
<div className="absolute top-0 bottom-0 left-[27px] hidden w-0.5 bg-gradient-to-b from-sky-200 via-amber-200 to-rose-200 lg:left-1/2 lg:block lg:-translate-x-px" />
|
||||
|
||||
<div className="space-y-6 lg:space-y-8">
|
||||
{days.map((d, i) => (
|
||||
<div
|
||||
key={d.day}
|
||||
className={`relative lg:flex lg:items-center lg:gap-8 ${
|
||||
i % 2 === 0 ? "lg:flex-row" : "lg:flex-row-reverse"
|
||||
}`}
|
||||
>
|
||||
{/* Timeline dot (desktop) */}
|
||||
<div className="absolute left-1/2 top-8 z-10 hidden h-4 w-4 -translate-x-1/2 rounded-full border-4 border-white shadow-sm lg:block"
|
||||
style={{ background: `var(--tw-shadow-color, #0ea5e9)` }}
|
||||
>
|
||||
<div className={`h-full w-full rounded-full ${d.color}`} />
|
||||
</div>
|
||||
<div className="hidden lg:block lg:w-1/2" />
|
||||
|
||||
<div className="card-hover w-full rounded-2xl border border-slate-100 bg-white p-6 shadow-sm lg:w-1/2">
|
||||
<div className="flex items-start gap-4">
|
||||
<div
|
||||
className={`flex h-12 w-12 shrink-0 items-center justify-center rounded-xl text-white text-sm font-bold ${d.color}`}
|
||||
>
|
||||
DAY {d.day}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="mb-1 flex items-center gap-2">
|
||||
<span className="text-xl">{d.icon}</span>
|
||||
<h3 className="text-lg font-bold text-slate-900">
|
||||
{d.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="text-sm leading-relaxed text-slate-600">
|
||||
{d.desc}
|
||||
</p>
|
||||
<a
|
||||
href={`/day/${d.day}`}
|
||||
className="mt-3 inline-block text-sm font-medium text-sky-600 transition-colors hover:text-sky-700"
|
||||
>
|
||||
查看详情 →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</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">
|
||||
🎓 实战训练营
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-slate-900">
|
||||
数字游民实战课
|
||||
</h3>
|
||||
<p className="mx-auto mt-3 max-w-xl text-slate-600">
|
||||
21节视频课程,手把手带你从零规划专属数字游民路线,打通远程工作全流程
|
||||
</p>
|
||||
<a
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
191
app/components/Tools.tsx
Normal file
191
app/components/Tools.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
const categories = [
|
||||
{
|
||||
icon: "💬",
|
||||
title: "远程协作",
|
||||
count: 12,
|
||||
tools: [
|
||||
{ name: "Slack", desc: "团队沟通" },
|
||||
{ name: "Notion", desc: "知识管理" },
|
||||
{ name: "Linear", desc: "项目追踪" },
|
||||
{ name: "Figma", desc: "协同设计" },
|
||||
],
|
||||
color: "from-sky-500 to-cyan-500",
|
||||
bg: "bg-sky-50",
|
||||
text: "text-sky-700",
|
||||
},
|
||||
{
|
||||
icon: "🎥",
|
||||
title: "视频会议",
|
||||
count: 8,
|
||||
tools: [
|
||||
{ name: "Zoom", desc: "视频会议" },
|
||||
{ name: "Google Meet", desc: "在线会议" },
|
||||
{ name: "Around", desc: "轻量会议" },
|
||||
{ name: "Loom", desc: "异步视频" },
|
||||
],
|
||||
color: "from-violet-500 to-purple-500",
|
||||
bg: "bg-violet-50",
|
||||
text: "text-violet-700",
|
||||
},
|
||||
{
|
||||
icon: "📋",
|
||||
title: "项目管理",
|
||||
count: 10,
|
||||
tools: [
|
||||
{ name: "Trello", desc: "看板管理" },
|
||||
{ name: "Asana", desc: "任务管理" },
|
||||
{ name: "Monday", desc: "工作流" },
|
||||
{ name: "ClickUp", desc: "全能协作" },
|
||||
],
|
||||
color: "from-emerald-500 to-teal-500",
|
||||
bg: "bg-emerald-50",
|
||||
text: "text-emerald-700",
|
||||
},
|
||||
{
|
||||
icon: "💻",
|
||||
title: "开发工具",
|
||||
count: 15,
|
||||
tools: [
|
||||
{ name: "VS Code", desc: "代码编辑" },
|
||||
{ name: "GitHub", desc: "代码托管" },
|
||||
{ name: "Vercel", desc: "部署平台" },
|
||||
{ name: "Cursor", desc: "AI 编程" },
|
||||
],
|
||||
color: "from-blue-500 to-indigo-500",
|
||||
bg: "bg-blue-50",
|
||||
text: "text-blue-700",
|
||||
},
|
||||
{
|
||||
icon: "🎨",
|
||||
title: "设计工具",
|
||||
count: 9,
|
||||
tools: [
|
||||
{ name: "Figma", desc: "UI 设计" },
|
||||
{ name: "Canva", desc: "图形设计" },
|
||||
{ name: "Framer", desc: "网页设计" },
|
||||
{ name: "Midjourney", desc: "AI 作图" },
|
||||
],
|
||||
color: "from-pink-500 to-rose-500",
|
||||
bg: "bg-pink-50",
|
||||
text: "text-pink-700",
|
||||
},
|
||||
{
|
||||
icon: "💳",
|
||||
title: "财务工具",
|
||||
count: 7,
|
||||
tools: [
|
||||
{ name: "Wise", desc: "跨境转账" },
|
||||
{ name: "PayPal", desc: "在线支付" },
|
||||
{ name: "Stripe", desc: "收款平台" },
|
||||
{ name: "Deel", desc: "薪酬合规" },
|
||||
],
|
||||
color: "from-amber-500 to-orange-500",
|
||||
bg: "bg-amber-50",
|
||||
text: "text-amber-700",
|
||||
},
|
||||
{
|
||||
icon: "🔒",
|
||||
title: "安全与 VPN",
|
||||
count: 6,
|
||||
tools: [
|
||||
{ name: "NordVPN", desc: "网络安全" },
|
||||
{ name: "1Password", desc: "密码管理" },
|
||||
{ name: "Authy", desc: "双因素认证" },
|
||||
{ name: "ProtonMail", desc: "加密邮件" },
|
||||
],
|
||||
color: "from-slate-500 to-gray-600",
|
||||
bg: "bg-slate-50",
|
||||
text: "text-slate-700",
|
||||
},
|
||||
{
|
||||
icon: "📝",
|
||||
title: "生产力",
|
||||
count: 11,
|
||||
tools: [
|
||||
{ name: "Obsidian", desc: "笔记系统" },
|
||||
{ name: "Todoist", desc: "待办清单" },
|
||||
{ name: "RescueTime", desc: "时间追踪" },
|
||||
{ name: "Arc", desc: "浏览器" },
|
||||
],
|
||||
color: "from-teal-500 to-cyan-500",
|
||||
bg: "bg-teal-50",
|
||||
text: "text-teal-700",
|
||||
},
|
||||
];
|
||||
|
||||
const toolStats = [
|
||||
{ value: "50+", label: "精选工具" },
|
||||
{ value: "8", label: "分类" },
|
||||
{ value: "15", label: "开发工具" },
|
||||
{ value: "12", label: "协作工具" },
|
||||
];
|
||||
|
||||
export default function Tools() {
|
||||
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+ 精选工具
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
<span className="gradient-text">工具推荐</span>
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600">
|
||||
数字游民必备工具精选,覆盖远程协作、开发、设计、财务等 8 大分类。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-14 grid gap-5 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{categories.map((cat) => (
|
||||
<div
|
||||
key={cat.title}
|
||||
className="card-hover group overflow-hidden rounded-2xl border border-slate-100 bg-white shadow-sm"
|
||||
>
|
||||
<div className={`h-1.5 bg-gradient-to-r ${cat.color}`} />
|
||||
<div className="p-5">
|
||||
<div className="mb-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-2xl">{cat.icon}</span>
|
||||
<h3 className="font-bold text-slate-900">{cat.title}</h3>
|
||||
</div>
|
||||
<span className={`rounded-full px-2 py-0.5 text-xs font-semibold ${cat.bg} ${cat.text}`}>
|
||||
{cat.count}
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{cat.tools.map((tool) => (
|
||||
<div
|
||||
key={tool.name}
|
||||
className="flex items-center justify-between rounded-lg bg-slate-50 px-3 py-2 text-sm transition-colors group-hover:bg-slate-100/80"
|
||||
>
|
||||
<span className="font-medium text-slate-700">
|
||||
{tool.name}
|
||||
</span>
|
||||
<span className="text-slate-400">{tool.desc}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Stats bar */}
|
||||
<div className="mt-14 grid grid-cols-2 gap-4 sm:grid-cols-4">
|
||||
{toolStats.map((s) => (
|
||||
<div
|
||||
key={s.label}
|
||||
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>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
445
app/course/page.tsx
Normal file
445
app/course/page.tsx
Normal file
@@ -0,0 +1,445 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
/* ─── data ─── */
|
||||
|
||||
const stats = [
|
||||
{ value: "21", label: "节实战课程" },
|
||||
{ value: "150+", label: "分钟视频" },
|
||||
{ value: "3", label: "位实战讲师" },
|
||||
];
|
||||
|
||||
const audiences = [
|
||||
{
|
||||
icon: "💼",
|
||||
title: "职场人想转型",
|
||||
desc: "受够了 996?学会远程工作技能,平滑过渡到自由生活方式",
|
||||
},
|
||||
{
|
||||
icon: "👨💻",
|
||||
title: "开发者 / 设计师",
|
||||
desc: "你的技能天然适合远程,学会如何接全球客户、拿美金报酬",
|
||||
},
|
||||
{
|
||||
icon: "📱",
|
||||
title: "自媒体 / 内容创作者",
|
||||
desc: "边旅行边创作,掌握数字游民内容变现的全套方法论",
|
||||
},
|
||||
{
|
||||
icon: "🌍",
|
||||
title: "想出国旅居的人",
|
||||
desc: "签证、税务、保险、目的地一站搞定,少走弯路直接出发",
|
||||
},
|
||||
];
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
num: 1,
|
||||
title: "完整的远程工作体系",
|
||||
desc: "从技能评估到客户获取,建立可持续的远程收入系统",
|
||||
},
|
||||
{
|
||||
num: 2,
|
||||
title: "打通 3+ 收入渠道",
|
||||
desc: "远程全职、自由职业、数字产品、内容创作多管齐下",
|
||||
},
|
||||
{
|
||||
num: 3,
|
||||
title: "掌握 50+ 远程工具",
|
||||
desc: "协作、会议、项目管理、财务,一个背包装下整个办公室",
|
||||
},
|
||||
{
|
||||
num: 4,
|
||||
title: "签证 + 税务 + 保险全通关",
|
||||
desc: "55 国数字游民签证政策、合规税务方案、保险选购指南",
|
||||
},
|
||||
{
|
||||
num: 5,
|
||||
title: "跑通第一次数字游民旅程",
|
||||
desc: "从选目的地到打包出发,手把手带你完成首次数字游民体验",
|
||||
},
|
||||
];
|
||||
|
||||
const curriculum = [
|
||||
{
|
||||
emoji: "🚀",
|
||||
chapter: "基础篇 · 认识数字游民",
|
||||
lessons: [
|
||||
{ id: "01", title: "什么是数字游民?破除 5 个常见误解", duration: "12:30" },
|
||||
{ id: "02", title: "数字游民三种模式:蜜蜂、乌龟、候鸟", duration: "08:45" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "💡",
|
||||
chapter: "技能篇 · 远程工作能力",
|
||||
lessons: [
|
||||
{ id: "03", title: "远程高薪技能全景图:找到你的方向", duration: "14:20" },
|
||||
{ id: "04", title: "30天技能升级路线:从评估到接单", duration: "11:15" },
|
||||
{ id: "05", title: "建立个人品牌:让客户主动找你", duration: "09:40" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "💰",
|
||||
chapter: "收入篇 · 构建收入体系",
|
||||
lessons: [
|
||||
{ id: "06", title: "远程全职 vs 自由职业:选哪条路?", duration: "10:05" },
|
||||
{ id: "07", title: "自由职业平台实操:Upwork / Toptal / 电鸭", duration: "13:50" },
|
||||
{ id: "08", title: "被动收入搭建:数字产品 & 在线课程", duration: "12:20" },
|
||||
{ id: "09", title: "定价的艺术:如何报价不心虚", duration: "07:30" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "🛠️",
|
||||
chapter: "工具篇 · 移动办公装备",
|
||||
lessons: [
|
||||
{ id: "10", title: "硬件极简主义:一个背包装下办公室", duration: "06:45" },
|
||||
{ id: "11", title: "远程协作工具栈:Slack / Notion / Linear", duration: "08:30" },
|
||||
{ id: "12", title: "安全必修课:VPN / 密码管理 / 2FA", duration: "05:55" },
|
||||
{ id: "13", title: "跨境财务工具:Wise / Stripe / Revolut", duration: "07:10" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "📋",
|
||||
chapter: "合规篇 · 签证税务保险",
|
||||
lessons: [
|
||||
{ id: "14", title: "55 国数字游民签证政策全解读", duration: "15:30" },
|
||||
{ id: "15", title: "税务居民身份与合规规划", duration: "11:40" },
|
||||
{ id: "16", title: "数字游民保险选购指南", duration: "06:20" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "🗺️",
|
||||
chapter: "目的地篇 · 选择你的城市",
|
||||
lessons: [
|
||||
{ id: "17", title: "亚洲三城:清迈 / 巴厘岛 / 首尔深度对比", duration: "10:50" },
|
||||
{ id: "18", title: "欧洲双雄:里斯本 / 巴塞罗那生活实录", duration: "09:25" },
|
||||
{ id: "19", title: "美洲探索:墨西哥城 / 麦德林旅居指南", duration: "08:15" },
|
||||
],
|
||||
},
|
||||
{
|
||||
emoji: "🏆",
|
||||
chapter: "实战篇 · 启程出发",
|
||||
lessons: [
|
||||
{ id: "20", title: "出发前检查清单 & 打包哲学", duration: "07:40" },
|
||||
{ id: "21", title: "第一个月生存指南 & 长期可持续策略", duration: "13:10" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const instructors = [
|
||||
{
|
||||
name: "Alex",
|
||||
avatar: "🧑💻",
|
||||
role: "全栈开发者 / 5年数字游民",
|
||||
tag: "技术导师",
|
||||
desc: "前字节跳动高级工程师,2021年开始数字游民生活,足迹遍布 20+ 国家,远程服务硅谷客户",
|
||||
},
|
||||
{
|
||||
name: "Lisa",
|
||||
avatar: "👩🎨",
|
||||
role: "品牌设计师 / 自由职业教练",
|
||||
tag: "变现专家",
|
||||
desc: "Toptal 认证设计师,年收入 $120K+,帮助 500+ 人成功转型远程自由职业",
|
||||
},
|
||||
{
|
||||
name: "Marco",
|
||||
avatar: "🧳",
|
||||
role: "旅居作家 / 签证顾问",
|
||||
tag: "旅居达人",
|
||||
desc: "常驻里斯本,持有 3 国数字游民签证,《数字游民签证手册》作者,深谙各国政策",
|
||||
},
|
||||
];
|
||||
|
||||
/* ─── component ─── */
|
||||
|
||||
export default function CoursePage() {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white text-slate-900">
|
||||
{/* ── Nav ── */}
|
||||
<header className="sticky top-0 z-50 border-b border-slate-100 bg-white/80 backdrop-blur-lg">
|
||||
<div className="mx-auto flex h-14 max-w-5xl items-center justify-between px-4 sm:px-6">
|
||||
<a href="/" className="flex items-center gap-2 text-sm font-bold">
|
||||
<span className="text-lg">🌍</span>
|
||||
数字游民指南
|
||||
</a>
|
||||
<button
|
||||
onClick={() => setModalOpen(true)}
|
||||
className="rounded-full bg-sky-500 px-4 py-1.5 text-sm font-semibold text-white transition-colors hover:bg-sky-600"
|
||||
>
|
||||
立即报名
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* ── Hero ── */}
|
||||
<section className="relative overflow-hidden bg-gradient-to-b from-slate-50 to-white py-20 sm:py-28">
|
||||
<div className="pointer-events-none absolute top-0 left-1/2 h-[500px] w-[700px] -translate-x-1/2 rounded-full bg-gradient-to-br from-sky-100/50 via-cyan-50/30 to-amber-50/20 blur-3xl" />
|
||||
<div className="relative mx-auto max-w-3xl px-4 text-center sm:px-6">
|
||||
<h1 className="text-4xl font-extrabold tracking-tight sm:text-5xl lg:text-6xl">
|
||||
<span className="gradient-text">数字游民</span>实战课
|
||||
</h1>
|
||||
<p className="mx-auto mt-5 max-w-xl text-lg leading-relaxed text-slate-600 sm:text-xl">
|
||||
7天打造你的远程工作体系与自由生活方式
|
||||
</p>
|
||||
|
||||
<div className="mt-10 flex items-center justify-center gap-6 sm:gap-10">
|
||||
{stats.map((s) => (
|
||||
<div key={s.label} className="text-center">
|
||||
<div className="text-3xl font-extrabold text-sky-600 sm:text-4xl">
|
||||
{s.value}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-500">{s.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setModalOpen(true)}
|
||||
className="mt-10 inline-flex items-center gap-2 rounded-full bg-sky-500 px-10 py-4 text-lg font-semibold text-white shadow-lg shadow-sky-500/25 transition-all hover:bg-sky-600 hover:shadow-xl hover:shadow-sky-500/30"
|
||||
>
|
||||
立即报名
|
||||
<span>→</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Audience ── */}
|
||||
<section className="py-20 sm:py-24">
|
||||
<div className="mx-auto max-w-5xl px-4 sm:px-6">
|
||||
<h2 className="text-center text-2xl font-bold sm:text-3xl">
|
||||
这门课适合谁?
|
||||
</h2>
|
||||
<p className="mx-auto mt-3 max-w-xl text-center text-slate-500">
|
||||
不管你是什么背景,只要想拥有地点自由的生活
|
||||
</p>
|
||||
|
||||
<div className="mt-14 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{audiences.map((a) => (
|
||||
<div
|
||||
key={a.title}
|
||||
className="card-hover rounded-2xl border border-slate-100 bg-white p-6 text-center shadow-sm"
|
||||
>
|
||||
<div className="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-2xl bg-sky-50 text-3xl">
|
||||
{a.icon}
|
||||
</div>
|
||||
<h3 className="mb-2 font-bold">{a.title}</h3>
|
||||
<p className="text-sm leading-relaxed text-slate-500">
|
||||
{a.desc}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Benefits ── */}
|
||||
<section className="bg-slate-50 py-20 sm:py-24">
|
||||
<div className="mx-auto max-w-5xl px-4 sm:px-6">
|
||||
<h2 className="text-center text-2xl font-bold sm:text-3xl">
|
||||
学完你将获得
|
||||
</h2>
|
||||
<p className="mx-auto mt-3 max-w-xl text-center text-slate-500">
|
||||
5 大核心收益,助你顺利开启数字游民生活
|
||||
</p>
|
||||
|
||||
<div className="mt-14 space-y-5">
|
||||
{benefits.map((b) => (
|
||||
<div
|
||||
key={b.num}
|
||||
className="card-hover flex items-start gap-5 rounded-2xl border border-slate-100 bg-white p-6 shadow-sm sm:items-center"
|
||||
>
|
||||
<div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-sky-500 to-cyan-500 text-xl font-extrabold text-white shadow-md shadow-sky-500/20">
|
||||
{b.num}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-bold text-slate-900">{b.title}</h3>
|
||||
<p className="mt-1 text-sm text-slate-500">{b.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Curriculum ── */}
|
||||
<section className="py-20 sm:py-24">
|
||||
<div className="mx-auto max-w-5xl px-4 sm:px-6">
|
||||
<h2 className="text-center text-2xl font-bold sm:text-3xl">
|
||||
21 节实战课程
|
||||
</h2>
|
||||
<p className="mx-auto mt-3 max-w-xl text-center text-slate-500">
|
||||
从入门到启程,完整的学习路径
|
||||
</p>
|
||||
|
||||
<div className="mt-14 space-y-6">
|
||||
{curriculum.map((ch) => (
|
||||
<div
|
||||
key={ch.chapter}
|
||||
className="overflow-hidden rounded-2xl border border-slate-100 bg-white shadow-sm"
|
||||
>
|
||||
{/* Chapter header */}
|
||||
<div className="flex items-center gap-3 border-b border-slate-100 bg-slate-50/80 px-6 py-4">
|
||||
<span className="text-xl">{ch.emoji}</span>
|
||||
<h3 className="font-bold text-slate-800">{ch.chapter}</h3>
|
||||
</div>
|
||||
|
||||
{/* Lessons */}
|
||||
<ul>
|
||||
{ch.lessons.map((lesson, i) => (
|
||||
<li
|
||||
key={lesson.id}
|
||||
className={`flex items-center justify-between px-6 py-3.5 transition-colors hover:bg-sky-50/40 ${
|
||||
i < ch.lessons.length - 1
|
||||
? "border-b border-slate-50"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-slate-100 text-xs font-bold text-slate-500">
|
||||
{lesson.id}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-slate-700 sm:text-base">
|
||||
{lesson.title}
|
||||
</span>
|
||||
</div>
|
||||
<span className="ml-4 shrink-0 text-xs tabular-nums text-slate-400">
|
||||
{lesson.duration}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Instructors ── */}
|
||||
<section className="bg-slate-50 py-20 sm:py-24">
|
||||
<div className="mx-auto max-w-5xl px-4 sm:px-6">
|
||||
<h2 className="text-center text-2xl font-bold sm:text-3xl">
|
||||
三位实战讲师联合授课
|
||||
</h2>
|
||||
<p className="mx-auto mt-3 max-w-xl text-center text-slate-500">
|
||||
真正的数字游民亲自带你上手
|
||||
</p>
|
||||
|
||||
<div className="mt-14 grid gap-6 sm:grid-cols-3">
|
||||
{instructors.map((ins) => (
|
||||
<div
|
||||
key={ins.name}
|
||||
className="card-hover rounded-2xl border border-slate-100 bg-white p-6 text-center shadow-sm"
|
||||
>
|
||||
<div className="mx-auto mb-4 flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-sky-100 to-cyan-50 text-5xl">
|
||||
{ins.avatar}
|
||||
</div>
|
||||
<h3 className="text-lg font-bold">{ins.name}</h3>
|
||||
<p className="mt-1 text-sm text-slate-500">{ins.role}</p>
|
||||
<span className="mt-3 inline-block rounded-full bg-sky-50 px-3 py-1 text-xs font-semibold text-sky-600">
|
||||
{ins.tag}
|
||||
</span>
|
||||
<p className="mt-4 text-sm leading-relaxed text-slate-500">
|
||||
{ins.desc}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Final CTA ── */}
|
||||
<section className="py-20 sm:py-28">
|
||||
<div className="mx-auto max-w-3xl px-4 text-center sm:px-6">
|
||||
<h2 className="text-2xl font-bold sm:text-3xl">
|
||||
准备好开启你的数字游民生活了吗?
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-lg text-slate-500">
|
||||
加入我们,跟着实战讲师一起,从零开始规划属于你的自由生活
|
||||
</p>
|
||||
|
||||
<div className="mt-8 flex flex-wrap items-center justify-center gap-4 text-sm text-slate-500">
|
||||
<span className="rounded-full border border-slate-200 bg-white px-4 py-1.5">
|
||||
21节实战视频
|
||||
</span>
|
||||
<span className="rounded-full border border-slate-200 bg-white px-4 py-1.5">
|
||||
永久回看
|
||||
</span>
|
||||
<span className="rounded-full border border-slate-200 bg-white px-4 py-1.5">
|
||||
社群答疑
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setModalOpen(true)}
|
||||
className="mt-10 inline-flex items-center gap-2 rounded-full bg-sky-500 px-10 py-4 text-lg font-semibold text-white shadow-lg shadow-sky-500/25 transition-all hover:bg-sky-600 hover:shadow-xl hover:shadow-sky-500/30"
|
||||
>
|
||||
立即加入
|
||||
<span>→</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Footer ── */}
|
||||
<footer className="border-t border-slate-100 bg-white py-8 text-center text-sm text-slate-400">
|
||||
<a href="/" className="font-medium text-slate-600 transition-colors hover:text-sky-600">
|
||||
🌍 数字游民指南
|
||||
</a>
|
||||
<span className="mx-2">·</span>
|
||||
开源免费 · 社区驱动
|
||||
</footer>
|
||||
|
||||
{/* ── Modal ── */}
|
||||
{modalOpen && (
|
||||
<div
|
||||
className="fixed inset-0 z-[100] flex items-center justify-center bg-black/50 p-4 backdrop-blur-sm"
|
||||
onClick={() => setModalOpen(false)}
|
||||
>
|
||||
<div
|
||||
className="relative w-full max-w-sm animate-fade-in rounded-2xl bg-white p-8 shadow-2xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
onClick={() => setModalOpen(false)}
|
||||
className="absolute top-4 right-4 flex h-8 w-8 items-center justify-center rounded-full text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-600"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h3 className="text-center text-lg font-bold">
|
||||
数字游民实战课
|
||||
</h3>
|
||||
<p className="mt-1 text-center text-sm text-slate-500">
|
||||
7天打造你的远程工作体系
|
||||
</p>
|
||||
|
||||
<div className="mt-6 rounded-xl border border-slate-100 bg-slate-50 p-6 text-center">
|
||||
<div className="text-6xl">🌍</div>
|
||||
<p className="mt-3 text-sm font-medium text-slate-600">
|
||||
扫码报名
|
||||
</p>
|
||||
<p className="mt-4 text-3xl font-extrabold text-sky-600">¥199</p>
|
||||
<p className="mt-1 text-xs text-slate-400">
|
||||
微信扫码 · 小程序购买
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 rounded-xl border border-slate-100 bg-slate-50 p-4 text-center">
|
||||
<div className="text-4xl">💬</div>
|
||||
<p className="mt-2 text-sm font-medium text-slate-600">
|
||||
添加微信进群
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-slate-400">
|
||||
交流答疑 · 文档资料 · 权益通知
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
993
app/data/days.ts
Normal file
993
app/data/days.ts
Normal file
@@ -0,0 +1,993 @@
|
||||
export interface DayData {
|
||||
day: number;
|
||||
icon: string;
|
||||
title: string;
|
||||
readingTime: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export const daysData: DayData[] = [
|
||||
{
|
||||
day: 1,
|
||||
icon: "👋",
|
||||
title: "认识数字游民",
|
||||
readingTime: "约 12 分钟",
|
||||
content: `
|
||||
# 认识数字游民
|
||||
|
||||
数字游民 7天指南 - Day 1: 认识数字游民
|
||||
|
||||
> *"我不再需要一张固定的办公桌,也不再需要每天挤地铁。我的办公室是整个地球,而我的同事分布在六个时区。这不是假期,这是我的日常。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 什么是数字游民,以及它**不是**什么
|
||||
* 数字游民和远程工作的**本质区别**
|
||||
* 全球数字游民生态的**现状与趋势**
|
||||
* 为什么**现在**是最好的开始时机
|
||||
|
||||
---
|
||||
|
||||
## 先聊聊你的困惑
|
||||
|
||||
你可能在社交媒体上看过这样的场景——
|
||||
|
||||
一个人在巴厘岛的海边咖啡馆,面前是一台 MacBook 和一杯椰子水。蓝天白云,海风轻拂,背景是无尽的稻田。配文写着:"今天的办公室 🌴"
|
||||
|
||||
然后你想:"这也太爽了吧,但这真的可行吗?"
|
||||
|
||||
**可行。** 而且比你想象的更接近现实。
|
||||
|
||||
但首先,让我们把一些误解清理掉。
|
||||
|
||||
---
|
||||
|
||||
## 数字游民 ≠ 旅游博主
|
||||
|
||||
让我猜猜你对"数字游民"的第一印象——
|
||||
|
||||
一群有钱有闲的年轻人,整天在海滩上拍照,偶尔打开电脑假装工作?
|
||||
|
||||
**大错特错。**
|
||||
|
||||
一个真正的数字游民是什么样的?
|
||||
|
||||
| 维度 | 常见误解 | 真实情况 |
|
||||
| --- | --- | --- |
|
||||
| **工作** | 不用工作 / 轻松赚钱 | 有稳定的远程收入来源,工作量不比上班少 |
|
||||
| **地点** | 永远在度假胜地 | 会选择性价比高、基础设施好的城市 |
|
||||
| **收入** | 需要很多钱 | 很多目的地生活成本远低于一线城市 |
|
||||
| **社交** | 孤独流浪 | 全球数字游民社区非常活跃 |
|
||||
| **签证** | 灰色地带 | 50+ 国家已推出官方数字游民签证 |
|
||||
| **稳定性** | 不稳定 | 可以长期持续的生活方式 |
|
||||
|
||||
> 💡 **关键认知**:数字游民的核心不是"旅行",而是"自由"——选择在哪里生活、如何安排时间、为谁工作的自由。旅行只是这种自由的一个副产品。
|
||||
|
||||
---
|
||||
|
||||
## 2026年的数字游民生态
|
||||
|
||||
数字游民不是一个小众概念——它是一场正在发生的全球性变革。
|
||||
|
||||
### 关键数据
|
||||
|
||||
* **全球数字游民人数**:超过 3500 万(2024年数据,每年增长 15-20%)
|
||||
* **平均收入**:$85,000/年(高于很多发达国家的平均工资)
|
||||
* **最热门目的地**:葡萄牙、泰国、墨西哥、哥伦比亚、印尼
|
||||
* **最常见职业**:软件开发、设计、营销、写作、咨询
|
||||
* **提供数字游民签证的国家**:55+(且在持续增加)
|
||||
|
||||
### 为什么突然火了?
|
||||
|
||||
三个因素在同时发生:
|
||||
|
||||
**1. 远程工作成为主流**
|
||||
|
||||
疫情后,远程工作从"例外"变成了"标配"。全球超过 60% 的知识工作者现在可以选择远程工作。公司不再问"你为什么不来办公室",而是问"你需要什么才能高效工作"。
|
||||
|
||||
**2. 基础设施全球化**
|
||||
|
||||
高速互联网覆盖了越来越多的地方。共享办公空间(Coworking Space)在全球遍地开花。数字游民社区在各大城市扎根。
|
||||
|
||||
**3. 签证政策松绑**
|
||||
|
||||
从爱沙尼亚(全球首个数字游民签证)开始,越来越多国家推出了专门面向远程工作者的签证。这意味着你可以完全合法地在另一个国家生活和工作。
|
||||
|
||||
> 🌍 **趋势观察**:2024年,西班牙、日本、韩国都推出或升级了数字游民签证政策。这不是昙花一现——各国正在竞争吸引高收入远程工作者。
|
||||
|
||||
---
|
||||
|
||||
## 数字游民的三种模式
|
||||
|
||||
不是所有数字游民都一样。根据移动频率和工作方式,大致可以分为三类:
|
||||
|
||||
### 🐝 蜜蜂型 — 频繁移动
|
||||
|
||||
* 每 1-3 个月换一个城市
|
||||
* 追求新鲜感和多元体验
|
||||
* 适合:单身、喜欢冒险、工作时间灵活
|
||||
* 挑战:需要频繁适应新环境
|
||||
|
||||
### 🐢 乌龟型 — 慢旅行
|
||||
|
||||
* 在一个地方待 3-12 个月
|
||||
* 深度融入当地生活
|
||||
* 适合:需要稳定工作环境、有伴侣/宠物
|
||||
* 优势:能建立深度人际关系
|
||||
|
||||
### 🦅 候鸟型 — 季节迁移
|
||||
|
||||
* 有几个固定的"基地"城市
|
||||
* 随季节或心情在基地间切换
|
||||
* 适合:有一定经济基础、追求舒适
|
||||
* 优势:每个基地都有熟悉的社交圈
|
||||
|
||||
> 💡 **选择建议**:如果你是第一次尝试数字游民生活,建议从"乌龟型"开始——选一个目的地,待 1-3 个月。频繁移动会消耗大量精力,不利于保持工作效率。
|
||||
|
||||
---
|
||||
|
||||
## 你适合成为数字游民吗?
|
||||
|
||||
不是每个人都适合这种生活方式。在你兴奋地订机票之前,先诚实地回答以下问题:
|
||||
|
||||
### ✅ 你可能适合,如果:
|
||||
|
||||
* 你有一技之长可以远程交付(编程、设计、写作、营销等)
|
||||
* 你对新环境适应力强
|
||||
* 你能自我管理,不需要别人监督才能工作
|
||||
* 你对物质生活的需求不高(不需要大房子和固定资产)
|
||||
* 你享受独处,同时也善于建立新的社交关系
|
||||
|
||||
### ❌ 你可能不适合,如果:
|
||||
|
||||
* 你需要固定的社交圈和稳定感
|
||||
* 你的工作必须线下完成
|
||||
* 你无法忍受网络不稳定
|
||||
* 你有很多不能移动的责任(房贷、年幼的孩子、需要照顾的家人)
|
||||
* 你把数字游民等同于"永久度假"
|
||||
|
||||
**关键不是"你想不想",而是"你能不能"。** 想清楚这个问题,剩下的都是技术细节。
|
||||
|
||||
---
|
||||
|
||||
## 接下来的 7 天,你将获得什么?
|
||||
|
||||
让我帮你预览一下这趟旅程:
|
||||
|
||||
| 天数 | 你会做什么 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| Day 1(今天) | 了解数字游民的真正形态 | ✅ 你在这里 |
|
||||
| Day 2 | 评估远程技能与市场需求 | 🎯 找到你的方向 |
|
||||
| Day 3 | 构建多元收入体系 | 💰 收入有保障 |
|
||||
| Day 4 | 配置远程工作工具链 | 🛠️ 效率最大化 |
|
||||
| Day 5 | 搞定签证、税务、保险 | 📋 合规无忧 |
|
||||
| Day 6 | 选择你的第一个目的地 | 🗺️ 目标明确 |
|
||||
| Day 7 | 制定行动计划并启程 | 🚀 准备出发 |
|
||||
|
||||
**7 天后,你将拥有一份完整的数字游民启动方案——从技能到工具,从签证到目的地,一切就绪。**
|
||||
|
||||
这不需要辞职,不需要卖房,不需要一笔巨大的存款。你只需要一台电脑、一个可远程的技能、和开始行动的勇气。
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **数字游民 ≠ 旅游博主**:核心是"远程工作+地点自由",不是"不工作"
|
||||
* **全球 3500 万+**:这是一场正在发生的全球性变革
|
||||
* **三种模式**:蜜蜂型(频繁移动)、乌龟型(慢旅行)、候鸟型(季节迁移)
|
||||
* **不适合所有人**:需要可远程的技能、自我管理能力、对不确定性的容忍度
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
Day 1 没有需要动手的步骤——今天你只需要做两件事:
|
||||
|
||||
**1. 评估你的远程工作能力**
|
||||
|
||||
拿出一张纸,写下:
|
||||
* 你现在的技能中,哪些可以远程交付?
|
||||
* 如果离开当前公司,你能独立获得收入吗?
|
||||
* 你的工作需要什么——只需要一台电脑和网络?还是需要特殊设备或面对面沟通?
|
||||
|
||||
**2. 想象你的理想一天**
|
||||
|
||||
如果没有任何限制,你理想中的一天是什么样的?几点起床?在哪里工作?工作多久?下午做什么?
|
||||
|
||||
把这些写下来。这就是你的"北极星"——接下来 6 天的一切规划,都是为了让这个理想变成现实。
|
||||
|
||||
---
|
||||
|
||||
## 预告:Day 2 — 发现你的远程技能
|
||||
|
||||
> 明天我们要认真审视你的技能库。哪些技能最容易远程变现?市场需求如何?怎样在 30 天内让你的技能准备好远程工作?
|
||||
>
|
||||
> 准备好你的简历和作品集,我们明天见。
|
||||
|
||||
---
|
||||
|
||||
> 🌍 **数字游民小贴士**:如果你正在阅读这篇文章的时候还坐在办公室的格子间里——别急。改变不是一天发生的,但它从今天开始。每一个成功的数字游民,都是从"我想试试"这个念头开始的。
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 2,
|
||||
icon: "💡",
|
||||
title: "发现远程技能",
|
||||
readingTime: "约 15 分钟",
|
||||
content: `
|
||||
# 发现远程技能
|
||||
|
||||
数字游民 7天指南 - Day 2: 发现你的远程技能
|
||||
|
||||
> *"不是所有技能都适合远程工作,但几乎所有人都有至少一项可以远程变现的能力。关键是发现它、打磨它、定价它。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 最受欢迎的**10大远程工作技能**及其市场需求
|
||||
* 如何**评估你现有技能**的远程变现潜力
|
||||
* **30天技能升级计划**——快速让你的技能达到远程工作标准
|
||||
* 建立**个人品牌**的核心方法
|
||||
|
||||
---
|
||||
|
||||
## 远程工作技能全景图
|
||||
|
||||
并非所有工作都能远程完成。以下是 2026 年最受欢迎的远程工作领域:
|
||||
|
||||
### 🔥 高需求 · 高薪资
|
||||
|
||||
| 技能领域 | 平均年收入 | 入门难度 | 市场需求 |
|
||||
| --- | --- | --- | --- |
|
||||
| 软件开发 | $95,000 | ⭐⭐⭐⭐ | 🔥🔥🔥🔥🔥 |
|
||||
| 产品设计 (UI/UX) | $85,000 | ⭐⭐⭐ | 🔥🔥🔥🔥 |
|
||||
| 数据科学 / AI | $110,000 | ⭐⭐⭐⭐⭐ | 🔥🔥🔥🔥🔥 |
|
||||
| DevOps / 云架构 | $105,000 | ⭐⭐⭐⭐ | 🔥🔥🔥🔥 |
|
||||
| 网络安全 | $100,000 | ⭐⭐⭐⭐ | 🔥🔥🔥🔥 |
|
||||
|
||||
### 📈 中等门槛 · 灵活自由
|
||||
|
||||
| 技能领域 | 平均年收入 | 入门难度 | 市场需求 |
|
||||
| --- | --- | --- | --- |
|
||||
| 数字营销 / SEO | $65,000 | ⭐⭐ | 🔥🔥🔥🔥 |
|
||||
| 内容创作 / 写作 | $55,000 | ⭐⭐ | 🔥🔥🔥 |
|
||||
| 项目管理 | $75,000 | ⭐⭐⭐ | 🔥🔥🔥 |
|
||||
| 翻译 / 本地化 | $50,000 | ⭐⭐ | 🔥🔥🔥 |
|
||||
| 在线教育 / 咨询 | $70,000 | ⭐⭐ | 🔥🔥🔥🔥 |
|
||||
|
||||
> 💡 **重要提醒**:以上数据基于全球市场。如果你主要服务国内客户,收入水平可能不同,但远程工作的可行性是一样的。
|
||||
|
||||
---
|
||||
|
||||
## 评估你的技能
|
||||
|
||||
回答以下 5 个问题,给自己打分(1-5分):
|
||||
|
||||
1. **可远程性**:你的工作是否只需要电脑和网络就能完成?
|
||||
2. **市场需求**:有多少公司/个人需要你的技能?
|
||||
3. **可量化交付**:你的工作成果是否容易衡量?(代码、设计稿、文章等)
|
||||
4. **时区灵活性**:你的工作是否允许异步协作?
|
||||
5. **可替代性**:你的技能是否容易被替代?(越难替代越好)
|
||||
|
||||
**总分解读**:
|
||||
* **20-25分**:你已经具备远程工作的条件,可以直接开始
|
||||
* **15-19分**:稍加调整就能远程工作
|
||||
* **10-14分**:需要学习新技能或转型
|
||||
* **5-9分**:建议先在现有领域积累,同时学习可远程的副技能
|
||||
|
||||
---
|
||||
|
||||
## 30天技能升级路线
|
||||
|
||||
无论你处于什么阶段,以下路线都能帮你提升远程竞争力:
|
||||
|
||||
### 第 1 周:评估与定位
|
||||
* 完成技能自评(上面的 5 个问题)
|
||||
* 研究 3-5 个感兴趣的远程工作领域
|
||||
* 在 LinkedIn、Remote OK、电鸭社区浏览远程岗位需求
|
||||
* 确定你的目标方向
|
||||
|
||||
### 第 2 周:快速学习
|
||||
* 选择 1-2 门在线课程(Udemy、Coursera、极客时间)
|
||||
* 每天投入 2 小时学习
|
||||
* 加入相关的社区和论坛
|
||||
|
||||
### 第 3 周:项目实战
|
||||
* 完成 2-3 个练习项目
|
||||
* 建立你的作品集 / Portfolio
|
||||
* 开始写技术博客或发社交媒体
|
||||
|
||||
### 第 4 周:市场验证
|
||||
* 在自由职业平台注册(Upwork、Fiverr、猪八戒)
|
||||
* 投递 10 个远程工作申请
|
||||
* 接第一个小项目(哪怕低价)
|
||||
|
||||
> 🌍 **数字游民小贴士**:不要等到"完全准备好"才开始。完美主义是数字游民最大的敌人。先开始,边做边学,这就是最好的策略。
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **高薪远程技能**:开发、设计、数据、安全是最热门的领域
|
||||
* **自我评估**:诚实评估你的技能远程化潜力
|
||||
* **30天行动**:评估→学习→实战→验证,一个月内完成转型准备
|
||||
* **立即开始**:不要等到完美,先迈出第一步
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
1. 完成技能自评打分
|
||||
2. 在远程工作平台浏览 20 个职位,了解市场需求
|
||||
3. 确定你的 1-2 个目标技能方向
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 3,
|
||||
icon: "💰",
|
||||
title: "构建收入体系",
|
||||
readingTime: "约 14 分钟",
|
||||
content: `
|
||||
# 构建收入体系
|
||||
|
||||
数字游民 7天指南 - Day 3: 构建可持续的收入体系
|
||||
|
||||
> *"数字游民的自由不是来自不工作,而是来自多元化的收入来源。当你不再依赖单一雇主,你就真正自由了。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 数字游民的**四大收入模式**及其优劣
|
||||
* 如何从**零开始构建**你的第一个远程收入来源
|
||||
* **被动收入**的真相——它真的被动吗?
|
||||
* 定价策略与**收入最大化**技巧
|
||||
|
||||
---
|
||||
|
||||
## 四大收入模式
|
||||
|
||||
### 1. 🏢 远程全职
|
||||
|
||||
为一家公司全职远程工作,拿固定工资。
|
||||
|
||||
* **优势**:收入稳定、有社保/福利、风险低
|
||||
* **劣势**:时间不完全自由、受限于公司政策
|
||||
* **适合**:刚开始尝试数字游民的人
|
||||
* **平台推荐**:Remote OK、We Work Remotely、电鸭社区
|
||||
|
||||
### 2. 💼 自由职业
|
||||
|
||||
按项目或小时收费,为多个客户提供服务。
|
||||
|
||||
* **优势**:时间高度灵活、可选择客户、收入上限高
|
||||
* **劣势**:收入不稳定、需自己找客户、无福利
|
||||
* **适合**:有专业技能且善于沟通的人
|
||||
* **平台推荐**:Upwork、Toptal、Fiverr、猪八戒
|
||||
|
||||
### 3. 📦 产品化收入
|
||||
|
||||
创建数字产品(课程、模板、SaaS、电子书等)进行销售。
|
||||
|
||||
* **优势**:做一次卖多次、可规模化、真正的被动收入
|
||||
* **劣势**:前期投入大、需要营销、成功率不高
|
||||
* **适合**:有创业精神、愿意长期投入的人
|
||||
* **代表案例**:Gumroad 创作者、独立开发者、在线教育
|
||||
|
||||
### 4. 🎨 内容创作
|
||||
|
||||
通过写作、视频、播客等内容获取广告、赞助、付费订阅收入。
|
||||
|
||||
* **优势**:表达自我、建立影响力、收入形式多样
|
||||
* **劣势**:见效慢、竞争激烈、需持续产出
|
||||
* **适合**:善于表达、有独特视角的人
|
||||
* **平台推荐**:YouTube、B站、公众号、Substack、小红书
|
||||
|
||||
---
|
||||
|
||||
## 收入组合策略
|
||||
|
||||
**最健康的数字游民收入结构是「三角形」**:
|
||||
|
||||
\`\`\`
|
||||
稳定收入(基座)
|
||||
/ \\
|
||||
自由职业 产品收入
|
||||
(灵活) (增长)
|
||||
\`\`\`
|
||||
|
||||
* **基座**:一个稳定的收入来源(远程全职或长期客户),覆盖基本生活开支
|
||||
* **左翼**:自由职业项目,提供额外收入和灵活性
|
||||
* **右翼**:数字产品或内容创作,提供长期增长潜力
|
||||
|
||||
> 💡 **新手建议**:先搞定"基座",确保生活无忧,然后逐步发展另外两个收入来源。不要一开始就辞职去做自由职业——除非你已经有了 6 个月的生活储备金。
|
||||
|
||||
---
|
||||
|
||||
## 定价的艺术
|
||||
|
||||
定价是自由职业者最头疼的问题。以下是几个原则:
|
||||
|
||||
1. **按价值定价,不按时间定价**:客户买的是结果,不是你的时间
|
||||
2. **起步价可以低,但要有涨价计划**:前 3 个项目可以低于市场价,积累作品和评价后立即提价
|
||||
3. **永远报你觉得"有点贵"的价格**:如果客户从不还价,说明你定价太低了
|
||||
4. **打包服务**:比如不卖"一个 Logo",卖"品牌视觉包"(Logo + 名片 + 社交媒体头图)
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **四大模式**:远程全职、自由职业、产品化、内容创作
|
||||
* **三角形结构**:稳定收入为基座,灵活收入和增长收入为两翼
|
||||
* **先稳后闯**:确保基本收入后再冒险
|
||||
* **按价值定价**:不要贱卖你的时间
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
1. 确定你当前最适合的收入模式(四选一作为起点)
|
||||
2. 在对应平台创建账号并完善个人资料
|
||||
3. 计算你的"数字游民最低月收入"——覆盖目标城市的基本开支需要多少钱?
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 4,
|
||||
icon: "🛠️",
|
||||
title: "工具武装",
|
||||
readingTime: "约 13 分钟",
|
||||
content: `
|
||||
# 工具武装
|
||||
|
||||
数字游民 7天指南 - Day 4: 打造你的移动办公装备库
|
||||
|
||||
> *"一个优秀的数字游民,装备精简但效率惊人。你的整个办公室,应该能装进一个背包里。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 数字游民的**硬件装备清单**——什么该带,什么不该带
|
||||
* **软件工具栈**——协作、通讯、生产力全覆盖
|
||||
* 如何在**任何地方**高效工作
|
||||
* **网络安全**必备措施
|
||||
|
||||
---
|
||||
|
||||
## 硬件装备清单
|
||||
|
||||
### 🎒 核心三件套
|
||||
|
||||
| 装备 | 推荐 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 笔记本电脑 | MacBook Air M3 / ThinkPad X1 | 轻薄、续航长、性能够用 |
|
||||
| 降噪耳机 | AirPods Pro / Sony WH-1000XM5 | 嘈杂环境必备 |
|
||||
| 手机 | 任意智能手机 | 热点备份、双因素认证 |
|
||||
|
||||
### 📦 可选装备
|
||||
|
||||
* **便携显示器**:15.6寸 USB-C 便携屏,双屏效率翻倍
|
||||
* **折叠键盘**:如果你经常用手机/平板工作
|
||||
* **移动电源**:20000mAh,支持 PD 快充笔记本
|
||||
* **万能转换插头**:全球通用
|
||||
* **便携路由器**:GL.iNet 旅行路由器,VPN 直连
|
||||
|
||||
> 💡 **极简原则**:能不带就不带。你需要的东西远比你想象的少。记住:每多一件行李,就多一份牵挂。
|
||||
|
||||
---
|
||||
|
||||
## 软件工具栈
|
||||
|
||||
### 💬 沟通协作
|
||||
* **Slack** — 团队即时通讯,频道管理清晰
|
||||
* **Discord** — 社区交流,很多数字游民社区都在这里
|
||||
* **Zoom / Google Meet** — 视频会议
|
||||
* **Loom** — 录制异步视频消息,跨时区神器
|
||||
|
||||
### 📋 项目管理
|
||||
* **Notion** — 笔记、知识库、项目管理一体化
|
||||
* **Linear** — 开发团队的项目追踪
|
||||
* **Todoist** — 个人任务管理
|
||||
|
||||
### 💻 开发工具
|
||||
* **VS Code / Cursor** — 代码编辑器
|
||||
* **GitHub** — 代码托管和协作
|
||||
* **Vercel / Netlify** — 一键部署
|
||||
|
||||
### 🔒 安全工具
|
||||
* **NordVPN / Mullvad** — 公共 WiFi 必开
|
||||
* **1Password** — 密码管理
|
||||
* **Authy** — 双因素认证
|
||||
|
||||
### 💳 财务工具
|
||||
* **Wise** — 多币种账户,跨境转账手续费最低
|
||||
* **Revolut** — 旅行消费卡,汇率好
|
||||
* **Stripe / PayPal** — 收款
|
||||
|
||||
---
|
||||
|
||||
## 在任何地方高效工作的秘诀
|
||||
|
||||
### 🏠 住宿选择优先级
|
||||
1. **WiFi 速度** > 50 Mbps(必须!预订前问清楚)
|
||||
2. **安静的工作空间**(独立桌子和椅子)
|
||||
3. **位置便利**(离 Coworking Space 近)
|
||||
4. **价格合理**
|
||||
|
||||
### ☕ 咖啡馆工作守则
|
||||
* 先买东西再开电脑(尊重店家)
|
||||
* 自带充电线和转换插头
|
||||
* 戴耳机
|
||||
* 不要占位超过 3 小时
|
||||
* 找好备选地点
|
||||
|
||||
### 🏢 Coworking Space 推荐
|
||||
* **WeWork** — 全球连锁,稳定可靠
|
||||
* **Hubud (巴厘岛)** — 数字游民圣地
|
||||
* **Punspace (清迈)** — 性价比之王
|
||||
* **Second Home (里斯本)** — 设计感十足
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **轻装上阵**:核心三件套 + 精选可选装备
|
||||
* **工具为效率服务**:不要为了工具而工具
|
||||
* **安全第一**:VPN + 密码管理 + 双因素认证
|
||||
* **适应环境**:学会在任何地方保持高效
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
1. 检查你的硬件装备,列出需要补充的清单
|
||||
2. 安装并配置核心软件工具(至少 5 个)
|
||||
3. 测试你当前的网络速度,并准备一个备用方案
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 5,
|
||||
icon: "📋",
|
||||
title: "签证与法律",
|
||||
readingTime: "约 11 分钟",
|
||||
content: `
|
||||
# 签证与法律
|
||||
|
||||
数字游民 7天指南 - Day 5: 搞定签证、税务、保险
|
||||
|
||||
> *"自由的前提是合规。搞定法律问题,你才能真正安心地享受数字游民生活。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* **数字游民签证**全球政策概览
|
||||
* **税务规划**基础知识——如何合法优化税务
|
||||
* 必备的**保险方案**
|
||||
* 海外**银行与支付**方案
|
||||
|
||||
---
|
||||
|
||||
## 数字游民签证一览
|
||||
|
||||
越来越多的国家推出了专门面向远程工作者的签证。以下是 2026 年最受欢迎的选项:
|
||||
|
||||
### 🌟 热门签证
|
||||
|
||||
| 国家 | 签证名称 | 停留期 | 收入要求 | 费用 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 🇵🇹 葡萄牙 | D8 签证 | 1年(可续) | €3,500/月 | €75 |
|
||||
| 🇪🇸 西班牙 | 数字游民签证 | 1年(可续至5年) | €2,520/月 | €80 |
|
||||
| 🇹🇭 泰国 | DTV 签证 | 5年(每次180天) | $500,000资产 或 收入证明 | $230 |
|
||||
| 🇮🇩 印尼 | B211A | 6个月 | $2,000/月 | $300 |
|
||||
| 🇲🇽 墨西哥 | 临时居留 | 1年(可续至4年) | $2,500/月 | $400 |
|
||||
| 🇭🇷 克罗地亚 | 数字游民签证 | 1年 | €2,540/月 | 免费 |
|
||||
| 🇯🇵 日本 | 数字游民签证 | 6个月 | ¥10,000,000/年 | 免费 |
|
||||
| 🇰🇷 韩国 | Workation 签证 | 1-2年 | 变化中 | ₩40,000 |
|
||||
|
||||
> 💡 **注意**:签证政策经常变化,申请前务必查看最新的官方信息。以上数据截至 2026 年初。
|
||||
|
||||
---
|
||||
|
||||
## 税务规划基础
|
||||
|
||||
数字游民的税务问题比较复杂,但核心是搞清楚一个问题:**你的税务居民身份在哪里?**
|
||||
|
||||
### 关键概念
|
||||
|
||||
* **税务居民**:你在哪个国家有纳税义务
|
||||
* **183天规则**:很多国家规定,一年内居住超过 183 天就成为税务居民
|
||||
* **双重征税协定**:两国之间的协议,避免你被两边收税
|
||||
* **源泉税**:某些收入在产生地就被征税
|
||||
|
||||
### 基本策略
|
||||
|
||||
1. **确定你的税务居民身份**
|
||||
2. **了解你的纳税义务**
|
||||
3. **利用双重征税协定避免重复纳税**
|
||||
4. **考虑专业税务顾问**(强烈推荐!)
|
||||
|
||||
> ⚠️ **重要提醒**:税务问题非常个人化,以上信息仅供参考。强烈建议咨询专业的国际税务顾问。错误的税务规划可能导致严重的法律后果。
|
||||
|
||||
---
|
||||
|
||||
## 保险方案
|
||||
|
||||
数字游民需要的保险和普通旅行保险不同。你需要:
|
||||
|
||||
### 推荐方案
|
||||
|
||||
* **SafetyWing Nomad Insurance** — 专为数字游民设计,$45/月起
|
||||
* **World Nomads** — 覆盖范围广,含极限运动
|
||||
* **Genki World Explorer** — 欧洲公司,含心理健康覆盖
|
||||
|
||||
### 保险应覆盖
|
||||
|
||||
* ✅ 医疗(含住院)
|
||||
* ✅ 紧急撤离
|
||||
* ✅ 电子设备(笔记本电脑等)
|
||||
* ✅ 个人责任
|
||||
* ✅ 旅行中断
|
||||
* ❌ 普通旅行险通常不覆盖"工作"相关场景
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **签证合规**:选择合适的数字游民签证,合法居留和工作
|
||||
* **税务规划**:明确税务居民身份,必要时咨询专业顾问
|
||||
* **保险保障**:选择专为数字游民设计的保险方案
|
||||
* **提前准备**:签证申请需要时间,尽早开始
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
1. 根据你的目标目的地,研究对应的签证政策
|
||||
2. 评估你当前的税务居民身份
|
||||
3. 获取 1-2 家数字游民保险的报价
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 6,
|
||||
icon: "🗺️",
|
||||
title: "目的地指南",
|
||||
readingTime: "约 14 分钟",
|
||||
content: `
|
||||
# 目的地指南
|
||||
|
||||
数字游民 7天指南 - Day 6: 选择你的第一个目的地
|
||||
|
||||
> *"世界那么大,选第一站反而是最难的。别想太多——你的第一个目的地不需要完美,它只需要'足够好'。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 选择目的地的**核心评估维度**
|
||||
* **10大热门数字游民城市**深度对比
|
||||
* **亚洲、欧洲、美洲**各区域推荐
|
||||
* 如何做出你的**第一站选择**
|
||||
|
||||
---
|
||||
|
||||
## 选择目的地的 6 个维度
|
||||
|
||||
### 评估框架
|
||||
|
||||
| 维度 | 权重 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 🌐 网速 | ⭐⭐⭐⭐⭐ | 最核心!低于 30Mbps 不考虑 |
|
||||
| 💰 生活成本 | ⭐⭐⭐⭐ | 决定你的财务可持续性 |
|
||||
| 🌡️ 气候 | ⭐⭐⭐ | 影响你的工作状态和心情 |
|
||||
| 🔒 安全 | ⭐⭐⭐⭐ | 人身和财产安全 |
|
||||
| 👥 社区 | ⭐⭐⭐⭐ | 数字游民社区的活跃度 |
|
||||
| 📋 签证 | ⭐⭐⭐ | 入境和停留的便利程度 |
|
||||
|
||||
---
|
||||
|
||||
## 🌏 亚洲推荐
|
||||
|
||||
### 🇹🇭 清迈,泰国
|
||||
|
||||
数字游民的"入门款"目的地,没有之一。
|
||||
|
||||
* **月均生活成本**:$800 - $1,200
|
||||
* **网速**:50-100 Mbps
|
||||
* **优势**:物价极低、美食天堂、社区超活跃、Coworking 多
|
||||
* **劣势**:空气质量(烧季)、语言障碍
|
||||
* **适合**:预算有限的初次数字游民
|
||||
|
||||
### 🇮🇩 巴厘岛(Canggu),印尼
|
||||
|
||||
Instagram 上出镜率最高的数字游民圣地。
|
||||
|
||||
* **月均生活成本**:$1,200 - $1,800
|
||||
* **网速**:30-80 Mbps
|
||||
* **优势**:社区氛围最佳、冲浪+瑜伽、创业者聚集
|
||||
* **劣势**:网速不稳定、交通混乱、签证限制
|
||||
* **适合**:喜欢社交和生活方式的人
|
||||
|
||||
### 🇰🇷 首尔,韩国
|
||||
|
||||
亚洲最被低估的数字游民城市。
|
||||
|
||||
* **月均生活成本**:$1,500 - $2,200
|
||||
* **网速**:200+ Mbps(全球最快之一)
|
||||
* **优势**:网速逆天、公共交通完美、美食、安全
|
||||
* **劣势**:生活成本较高、语言障碍
|
||||
* **适合**:重视网速和基础设施的开发者
|
||||
|
||||
---
|
||||
|
||||
## 🇪🇺 欧洲推荐
|
||||
|
||||
### 🇵🇹 里斯本,葡萄牙
|
||||
|
||||
欧洲数字游民的首选之城。
|
||||
|
||||
* **月均生活成本**:$1,800 - $2,500
|
||||
* **网速**:100+ Mbps
|
||||
* **优势**:气候宜人、英语普及、签证友好、创业生态好
|
||||
* **劣势**:房价上涨快、旅游旺季拥挤
|
||||
* **适合**:想在欧洲长期定居的人
|
||||
|
||||
### 🇪🇸 巴塞罗那,西班牙
|
||||
|
||||
文化、美食、海滩、建筑——应有尽有。
|
||||
|
||||
* **月均生活成本**:$2,000 - $2,800
|
||||
* **网速**:100+ Mbps
|
||||
* **优势**:生活品质极高、文化丰富、社区活跃
|
||||
* **劣势**:生活成本较高、小偷多
|
||||
* **适合**:追求生活品质的人
|
||||
|
||||
---
|
||||
|
||||
## 🌎 美洲推荐
|
||||
|
||||
### 🇲🇽 墨西哥城,墨西哥
|
||||
|
||||
北美数字游民的后花园。
|
||||
|
||||
* **月均生活成本**:$1,200 - $1,800
|
||||
* **网速**:50-100 Mbps
|
||||
* **优势**:美食(!!)、文化底蕴、性价比高、时区好(对美国客户)
|
||||
* **劣势**:空气质量、部分区域安全
|
||||
* **适合**:服务北美客户的自由职业者
|
||||
|
||||
### 🇨🇴 麦德林,哥伦比亚
|
||||
|
||||
从"最危险城市"到"数字游民天堂"的逆袭。
|
||||
|
||||
* **月均生活成本**:$1,000 - $1,500
|
||||
* **网速**:50-100 Mbps
|
||||
* **优势**:四季如春、物价低、人民友好、社区爆发式增长
|
||||
* **劣势**:语言(西班牙语为主)、刻板印象
|
||||
* **适合**:喜欢户外运动和社交的人
|
||||
|
||||
---
|
||||
|
||||
## 如何做出第一站选择?
|
||||
|
||||
**不要纠结。** 根据以下三个条件快速决定:
|
||||
|
||||
1. **预算**:月预算 < $1,500 → 东南亚;$1,500-2,500 → 拉美/南欧;> $2,500 → 随便选
|
||||
2. **时区**:你的客户/团队在哪个时区?选时差小于 6 小时的目的地
|
||||
3. **直觉**:以上条件筛完后还剩 2-3 个?选你最"想去"的那个
|
||||
|
||||
> 🌍 **数字游民小贴士**:你的第一站不是终点。大多数数字游民在第一年会换 2-3 个城市。别把第一次选择想得太重——去了不喜欢,换就是了。
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **六维评估**:网速、成本、气候、安全、社区、签证
|
||||
* **亚洲入门**:清迈(最便宜)、巴厘岛(最社交)、首尔(最快网速)
|
||||
* **欧洲进阶**:里斯本(最全面)、巴塞罗那(最有文化)
|
||||
* **美洲选择**:墨西哥城(最佳时区)、麦德林(最佳气候)
|
||||
* **快速决策**:预算→时区→直觉
|
||||
|
||||
---
|
||||
|
||||
## 今日任务 ✅
|
||||
|
||||
1. 使用六维评估框架,对 3 个感兴趣的城市打分
|
||||
2. 在 Nomad List 上查看这些城市的详细数据
|
||||
3. 做出你的第一站选择!
|
||||
`,
|
||||
},
|
||||
{
|
||||
day: 7,
|
||||
icon: "🚀",
|
||||
title: "启程出发",
|
||||
readingTime: "约 10 分钟",
|
||||
content: `
|
||||
# 启程出发
|
||||
|
||||
数字游民 7天指南 - Day 7: 从规划到行动
|
||||
|
||||
> *"知道和做到之间,隔着一张机票的距离。今天,我们把这个距离归零。"*
|
||||
|
||||
---
|
||||
|
||||
## 📖 本章导读
|
||||
|
||||
今天你将了解:
|
||||
|
||||
* 出发前的**完整检查清单**
|
||||
* **过渡期规划**——如何优雅地从当前生活切换
|
||||
* **第一个月生存指南**
|
||||
* **长期可持续**的数字游民生活策略
|
||||
|
||||
---
|
||||
|
||||
## 出发前检查清单
|
||||
|
||||
### 📋 必须完成
|
||||
|
||||
- [ ] 收入来源已确认(远程工作 / 自由职业 / 产品收入)
|
||||
- [ ] 至少 3-6 个月的储蓄金(安全网)
|
||||
- [ ] 护照有效期 > 6 个月
|
||||
- [ ] 签证/入境要求已研究清楚
|
||||
- [ ] 保险已购买
|
||||
- [ ] 银行已通知(避免海外刷卡被冻结)
|
||||
- [ ] 重要文件已数字化备份(护照、保险单、学历证明等)
|
||||
- [ ] 住宿已预订(至少前 2 周)
|
||||
|
||||
### 📦 打包原则
|
||||
|
||||
**核心规则:一个背包 + 一个随身包**
|
||||
|
||||
* 衣物:7天的量(到了再买/洗)
|
||||
* 电子设备:笔记本 + 手机 + 充电器 + 转换插头
|
||||
* 文件:护照 + 1张实体信用卡 + 少量现金
|
||||
* 其他:降噪耳机 + 眼罩 + 旅行锁
|
||||
|
||||
> 💡 **打包哲学**:打完包后,把一半的衣服拿出来。你永远会带太多东西。
|
||||
|
||||
---
|
||||
|
||||
## 过渡期规划
|
||||
|
||||
### 如果你还有全职工作
|
||||
|
||||
1. **提前 1-3 个月** 和公司沟通远程工作的可能性
|
||||
2. 如果公司不支持,**开始准备 Plan B**(自由职业或新的远程工作)
|
||||
3. **不要裸辞**——确保有稳定收入后再行动
|
||||
4. 处理好社保、公积金等事务
|
||||
|
||||
### 如果你有租房
|
||||
|
||||
1. 提前通知房东,按合同处理退租
|
||||
2. 重要物品寄回家或存放朋友处
|
||||
3. 不重要的东西——卖掉或捐掉
|
||||
|
||||
### 心理准备
|
||||
|
||||
* **接受不确定性**:第一个月会有各种意想不到的情况
|
||||
* **放下比较心**:你的节奏和别人不同,这没关系
|
||||
* **保持联系**:定期和家人朋友视频通话
|
||||
* **允许后悔**:如果不喜欢,回来就是了,这不是失败
|
||||
|
||||
---
|
||||
|
||||
## 第一个月生存指南
|
||||
|
||||
### 第 1 周:适应
|
||||
|
||||
* 调整时差和生活节奏
|
||||
* 找到你的"工作基地"(Coworking Space / 咖啡馆 / 住所)
|
||||
* 办理本地 SIM 卡
|
||||
* 熟悉周边环境(超市、药店、医院位置)
|
||||
* **不要急着工作**——给自己 2-3 天适应
|
||||
|
||||
### 第 2 周:建立节奏
|
||||
|
||||
* 确立你的工作时间表
|
||||
* 开始正常工作
|
||||
* 参加一次本地数字游民 Meetup
|
||||
* 探索 2-3 个不同的工作地点
|
||||
|
||||
### 第 3-4 周:深入
|
||||
|
||||
* 工作已进入正轨
|
||||
* 开始探索城市更多面(周末短途旅行)
|
||||
* 评估这个城市是否适合你
|
||||
* 如果满意,考虑续租或找长租
|
||||
|
||||
---
|
||||
|
||||
## 长期可持续策略
|
||||
|
||||
数字游民不是一场冲刺,而是一场马拉松。以下策略帮你走得更远:
|
||||
|
||||
### 1. 财务缓冲
|
||||
|
||||
始终保持 3-6 个月的生活费储蓄。这是你面对意外的安全网。
|
||||
|
||||
### 2. 健康管理
|
||||
|
||||
* 定期运动(跑步、瑜伽、健身房)
|
||||
* 注意饮食(不要天天吃外卖)
|
||||
* 关注心理健康(独处太久要警惕)
|
||||
* 定期体检
|
||||
|
||||
### 3. 社交投入
|
||||
|
||||
* 主动参加本地 Meetup 和社区活动
|
||||
* 考虑 Coliving(共居空间)
|
||||
* 保持和老朋友的联系
|
||||
|
||||
### 4. 技能持续升级
|
||||
|
||||
* 每月学习一项新技能或工具
|
||||
* 关注行业动态
|
||||
* 建立你的个人品牌
|
||||
|
||||
### 5. 定期复盘
|
||||
|
||||
每个月问自己:
|
||||
* 我快乐吗?
|
||||
* 我的收入在增长吗?
|
||||
* 我在学习新东西吗?
|
||||
* 我想继续这种生活方式吗?
|
||||
|
||||
---
|
||||
|
||||
## 🔑 本章要点回顾
|
||||
|
||||
* **检查清单**:收入、储蓄、签证、保险、住宿——缺一不可
|
||||
* **轻装上阵**:一个背包走天下
|
||||
* **循序渐进**:第一个月分为适应期、建立期、深入期
|
||||
* **长期思维**:财务缓冲、健康管理、社交投入、持续学习
|
||||
|
||||
---
|
||||
|
||||
## 🎉 恭喜你完成了 7 天学习路径!
|
||||
|
||||
如果你从 Day 1 一路看到这里,你已经具备了成为数字游民所需的全部知识:
|
||||
|
||||
* ✅ 理解了数字游民的本质
|
||||
* ✅ 找到了你的远程技能方向
|
||||
* ✅ 知道了如何构建收入体系
|
||||
* ✅ 配置了你的工具库
|
||||
* ✅ 搞清了签证和税务问题
|
||||
* ✅ 选好了你的第一个目的地
|
||||
* ✅ 制定了行动计划
|
||||
|
||||
**剩下的,就是行动。**
|
||||
|
||||
不需要等到一切完美。不需要等到存够了钱。不需要等到"时机成熟"。
|
||||
|
||||
**最好的时机,就是现在。**
|
||||
|
||||
买一张机票,带上你的背包和电脑,去你选好的城市,开始你的第一天。
|
||||
|
||||
---
|
||||
|
||||
> 🌍 **最后一条建议**:当你在新城市的第一个早晨醒来,打开电脑,连上 WiFi,开始工作的那一刻——你会意识到,数字游民不是一个标签,不是一种身份,而是一种你选择的活法。
|
||||
>
|
||||
> 欢迎来到这个世界。🌏
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
export function getDayData(id: number): DayData | undefined {
|
||||
return daysData.find((d) => d.day === id);
|
||||
}
|
||||
126
app/day/[id]/page.tsx
Normal file
126
app/day/[id]/page.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { getDayData, daysData } from "../../data/days";
|
||||
import DayContent from "../../components/DayContent";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return daysData.map((d) => ({ id: String(d.day) }));
|
||||
}
|
||||
|
||||
export default async function DayPage({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
const dayId = parseInt(id, 10);
|
||||
const data = getDayData(dayId);
|
||||
|
||||
if (!data) return notFound();
|
||||
|
||||
const prevDay = getDayData(dayId - 1);
|
||||
const nextDay = getDayData(dayId + 1);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Top bar */}
|
||||
<header className="sticky top-0 z-50 border-b border-slate-100 bg-white/80 backdrop-blur-lg">
|
||||
<div className="mx-auto flex h-14 max-w-4xl items-center justify-between px-4 sm:px-6">
|
||||
<a
|
||||
href="/"
|
||||
className="flex items-center gap-1.5 text-sm font-medium text-slate-600 transition-colors hover:text-sky-600"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
返回首页
|
||||
</a>
|
||||
<span className="text-sm text-slate-400">
|
||||
Day {data.day} / 7
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Article header */}
|
||||
<div className="mx-auto max-w-4xl px-4 pt-10 pb-6 sm:px-6 sm:pt-16 sm:pb-10">
|
||||
<div className="mb-6 flex flex-wrap items-center gap-3 text-sm text-slate-500">
|
||||
<span className="rounded-full bg-slate-100 px-3 py-1 font-medium">
|
||||
阅读时间{data.readingTime}
|
||||
</span>
|
||||
<span className="rounded-full bg-sky-50 px-3 py-1 font-medium text-sky-600">
|
||||
第 {data.day} 天
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-500 to-cyan-500 text-3xl text-white shadow-lg shadow-sky-500/20 sm:h-20 sm:w-20 sm:text-4xl">
|
||||
{data.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-extrabold tracking-tight text-slate-900 sm:text-4xl lg:text-5xl">
|
||||
{data.title}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto max-w-4xl px-4 sm:px-6">
|
||||
<hr className="border-slate-100" />
|
||||
</div>
|
||||
|
||||
{/* Markdown body */}
|
||||
<article className="mx-auto max-w-4xl px-4 py-10 sm:px-6 sm:py-14">
|
||||
<DayContent content={data.content} />
|
||||
</article>
|
||||
|
||||
{/* Prev / Next navigation */}
|
||||
<nav className="mx-auto max-w-4xl px-4 pb-20 sm:px-6">
|
||||
<div className="flex flex-col gap-4 border-t border-slate-100 pt-8 sm:flex-row sm:justify-between">
|
||||
{prevDay ? (
|
||||
<a
|
||||
href={`/day/${prevDay.day}`}
|
||||
className="group flex items-center gap-3 rounded-xl border border-slate-100 px-5 py-4 transition-all hover:border-sky-200 hover:bg-sky-50/50 sm:flex-1"
|
||||
>
|
||||
<svg className="h-5 w-5 shrink-0 text-slate-400 transition-colors group-hover:text-sky-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<div>
|
||||
<div className="text-xs text-slate-400">上一天</div>
|
||||
<div className="text-sm font-semibold text-slate-700 group-hover:text-sky-700">
|
||||
Day {prevDay.day}: {prevDay.title}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
) : (
|
||||
<div className="sm:flex-1" />
|
||||
)}
|
||||
{nextDay ? (
|
||||
<a
|
||||
href={`/day/${nextDay.day}`}
|
||||
className="group flex items-center justify-end gap-3 rounded-xl border border-slate-100 px-5 py-4 text-right transition-all hover:border-sky-200 hover:bg-sky-50/50 sm:flex-1"
|
||||
>
|
||||
<div>
|
||||
<div className="text-xs text-slate-400">下一天</div>
|
||||
<div className="text-sm font-semibold text-slate-700 group-hover:text-sky-700">
|
||||
Day {nextDay.day}: {nextDay.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg className="h-5 w-5 shrink-0 text-slate-400 transition-colors group-hover:text-sky-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
) : (
|
||||
<div className="sm:flex-1" />
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="border-t border-slate-100 bg-slate-50 py-8 text-center text-sm text-slate-400">
|
||||
<a href="/" className="font-medium text-slate-600 transition-colors hover:text-sky-600">
|
||||
🌍 数字游民指南
|
||||
</a>
|
||||
<span className="mx-2">·</span>
|
||||
开源免费 · 社区驱动
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
329
app/globals.css
Normal file
329
app/globals.css
Normal file
@@ -0,0 +1,329 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--color-primary: #0ea5e9;
|
||||
--color-primary-dark: #0284c7;
|
||||
--color-accent: #f59e0b;
|
||||
--color-accent-dark: #d97706;
|
||||
--animate-scroll: scroll 30s linear infinite;
|
||||
--animate-scroll-reverse: scroll 30s linear infinite reverse;
|
||||
--animate-fade-in: fadeIn 0.6s ease-out;
|
||||
--animate-float: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #0f172a;
|
||||
}
|
||||
|
||||
@keyframes scroll {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-50%); }
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-sans), system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.marquee-container {
|
||||
mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%);
|
||||
-webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%);
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, #0ea5e9, #06b6d4, #f59e0b);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.resource-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.resource-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* ===== Prose / Markdown Rendering ===== */
|
||||
.prose-custom {
|
||||
font-size: 1rem;
|
||||
line-height: 1.85;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.prose-custom h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.025em;
|
||||
color: #0f172a;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.prose-custom h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.prose-custom h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.prose-custom h4 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.prose-custom p {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.prose-custom a {
|
||||
color: #0ea5e9;
|
||||
font-weight: 500;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #bae6fd;
|
||||
text-underline-offset: 2px;
|
||||
transition: text-decoration-color 0.2s;
|
||||
}
|
||||
.prose-custom a:hover {
|
||||
text-decoration-color: #0ea5e9;
|
||||
}
|
||||
|
||||
.prose-custom strong {
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.prose-custom em {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.prose-custom ul {
|
||||
list-style-type: disc;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.prose-custom ol {
|
||||
list-style-type: decimal;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.prose-custom li {
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.prose-custom li > ul,
|
||||
.prose-custom li > ol {
|
||||
margin-top: 0.4rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.prose-custom blockquote {
|
||||
border-left: 4px solid #0ea5e9;
|
||||
background: #f0f9ff;
|
||||
padding: 1rem 1.25rem;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0 0.75rem 0.75rem 0;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.prose-custom blockquote p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.prose-custom hr {
|
||||
border: none;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.prose-custom code {
|
||||
background: #f1f5f9;
|
||||
color: #0f172a;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875em;
|
||||
font-family: var(--font-mono), ui-monospace, monospace;
|
||||
}
|
||||
|
||||
.prose-custom pre {
|
||||
background: #1e293b;
|
||||
color: #e2e8f0;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
overflow-x: auto;
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.prose-custom pre code {
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.prose-custom table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
overflow: hidden;
|
||||
border-radius: 0.75rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.prose-custom thead {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.prose-custom th {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: #0f172a;
|
||||
border-bottom: 2px solid #e2e8f0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.prose-custom td {
|
||||
padding: 0.65rem 1rem;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.prose-custom tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.prose-custom tbody tr:hover {
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.prose-custom img {
|
||||
max-width: 100%;
|
||||
border-radius: 0.75rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
/* Checkbox list styling */
|
||||
.prose-custom input[type="checkbox"] {
|
||||
margin-right: 0.5rem;
|
||||
accent-color: #0ea5e9;
|
||||
}
|
||||
|
||||
.prose-custom li:has(input[type="checkbox"]) {
|
||||
list-style-type: none;
|
||||
margin-left: -1.5rem;
|
||||
}
|
||||
|
||||
/* Mobile adjustments */
|
||||
@media (max-width: 640px) {
|
||||
.prose-custom h1 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
.prose-custom h2 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
.prose-custom h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.prose-custom table {
|
||||
font-size: 0.8rem;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.prose-custom th,
|
||||
.prose-custom td {
|
||||
padding: 0.5rem 0.65rem;
|
||||
}
|
||||
.prose-custom blockquote {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Form Inputs ===== */
|
||||
.form-input {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
color: #1e293b;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: #b2b2b2;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.form-input {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 0.75rem;
|
||||
padding: 0.65rem 0.875rem;
|
||||
font-size: 15px;
|
||||
background: #f8fafc;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.form-input:focus {
|
||||
border-color: #0ea5e9;
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
background: #fff;
|
||||
}
|
||||
textarea.form-input {
|
||||
padding: 0.75rem 0.875rem;
|
||||
}
|
||||
select.form-input {
|
||||
padding-right: 2.25rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
430
app/join/page.tsx
Normal file
430
app/join/page.tsx
Normal file
@@ -0,0 +1,430 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useRef, type FormEvent, type ChangeEvent } from "react";
|
||||
|
||||
const genderOptions = ["男", "女"];
|
||||
const singleOptions = ["单身", "恋爱中", "已婚"];
|
||||
const educationOptions = ["高中及以下", "大专", "本科", "硕士", "博士"];
|
||||
const graduationYears = Array.from({ length: 41 }, (_, i) => String(2026 - i));
|
||||
|
||||
interface FormData {
|
||||
nickname: string;
|
||||
gender: string;
|
||||
single: string;
|
||||
profession: string;
|
||||
intro: string;
|
||||
wechat: string;
|
||||
education: string;
|
||||
graduationYear: string;
|
||||
phone: string;
|
||||
}
|
||||
|
||||
interface MediaFile {
|
||||
file: File;
|
||||
preview: string;
|
||||
type: "image" | "video";
|
||||
}
|
||||
|
||||
export default function JoinPage() {
|
||||
const [form, setForm] = useState<FormData>({
|
||||
nickname: "",
|
||||
gender: "",
|
||||
single: "",
|
||||
profession: "",
|
||||
intro: "",
|
||||
wechat: "",
|
||||
education: "",
|
||||
graduationYear: "",
|
||||
phone: "",
|
||||
});
|
||||
const [media, setMedia] = useState<MediaFile | null>(null);
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const set = (key: keyof FormData, value: string) =>
|
||||
setForm((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
const handleSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setSubmitted(true);
|
||||
};
|
||||
|
||||
if (submitted) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-[#f0f4f8] px-4">
|
||||
<div className="w-full max-w-md animate-fade-in rounded-2xl bg-white p-10 text-center shadow-lg">
|
||||
<div className="mx-auto mb-5 flex h-20 w-20 items-center justify-center rounded-full bg-emerald-50 text-5xl">
|
||||
✅
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-slate-800">申请已提交</h2>
|
||||
<p className="mt-3 text-slate-500">
|
||||
我们会尽快审核你的信息
|
||||
<br />
|
||||
审核通过后将通过微信邀请你入群
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
className="mt-8 inline-flex items-center gap-2 rounded-full bg-sky-500 px-8 py-3 font-semibold text-white transition-colors hover:bg-sky-600"
|
||||
>
|
||||
← 返回首页
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#f0f4f8]">
|
||||
{/* ── PC: center column / H5: full width ── */}
|
||||
<div className="mx-auto max-w-2xl px-0 py-0 sm:px-6 sm:py-10 lg:py-14">
|
||||
{/* ── Banner ── */}
|
||||
<div className="overflow-hidden bg-white shadow-sm sm:rounded-t-2xl">
|
||||
{/* Hero image area */}
|
||||
<div className="relative h-40 overflow-hidden bg-gradient-to-br from-sky-400 via-cyan-500 to-teal-400 sm:h-52">
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center text-white">
|
||||
<div className="text-6xl sm:text-7xl">🌍</div>
|
||||
<div className="mt-2 text-sm font-medium opacity-80">
|
||||
Digital Nomad Community
|
||||
</div>
|
||||
</div>
|
||||
{/* Decorative blobs */}
|
||||
<div className="absolute -top-10 -left-10 h-40 w-40 rounded-full bg-white/10 blur-2xl" />
|
||||
<div className="absolute -right-10 -bottom-10 h-48 w-48 rounded-full bg-white/10 blur-2xl" />
|
||||
</div>
|
||||
|
||||
{/* Title block */}
|
||||
<div className="px-5 py-5 text-center sm:px-8 sm:py-7">
|
||||
<h1 className="text-xl font-bold text-slate-800 sm:text-2xl">
|
||||
🌍 数字游民社区报名
|
||||
</h1>
|
||||
<p className="mt-3 whitespace-pre-line text-sm leading-relaxed text-slate-400 sm:text-base">
|
||||
{"💼 结识志同道合的伙伴\n📍 线下聚会 + 线上分享\n🤝 互助成长,资源共享"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Form card ── */}
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="mt-0 bg-white px-5 pb-8 pt-2 shadow-sm sm:mt-5 sm:rounded-2xl sm:px-8 sm:py-8 sm:shadow-md"
|
||||
>
|
||||
{/* ---- Row group: nickname + gender (PC side-by-side) ---- */}
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-6">
|
||||
<Field label="🌟 昵称">
|
||||
<input
|
||||
type="text"
|
||||
maxLength={140}
|
||||
placeholder="请输入您的昵称"
|
||||
value={form.nickname}
|
||||
onChange={(e) => set("nickname", e.target.value)}
|
||||
required
|
||||
className="form-input"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field label="👤 性别">
|
||||
<select
|
||||
value={form.gender}
|
||||
onChange={(e) => set("gender", e.target.value)}
|
||||
required
|
||||
className={`form-input appearance-none ${
|
||||
form.gender ? "text-slate-800" : "text-slate-400"
|
||||
}`}
|
||||
>
|
||||
<option value="" disabled>
|
||||
请选择
|
||||
</option>
|
||||
{genderOptions.map((o) => (
|
||||
<option key={o} value={o}>
|
||||
{o}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown />
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
{/* ---- Row group: single + profession ---- */}
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-6">
|
||||
<Field label="💕 感情状态">
|
||||
<select
|
||||
value={form.single}
|
||||
onChange={(e) => set("single", e.target.value)}
|
||||
required
|
||||
className={`form-input appearance-none ${
|
||||
form.single ? "text-slate-800" : "text-slate-400"
|
||||
}`}
|
||||
>
|
||||
<option value="" disabled>
|
||||
请选择
|
||||
</option>
|
||||
{singleOptions.map((o) => (
|
||||
<option key={o} value={o}>
|
||||
{o}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown />
|
||||
</Field>
|
||||
|
||||
<Field label="💼 职业">
|
||||
<input
|
||||
type="text"
|
||||
maxLength={140}
|
||||
placeholder="您的职业或专业"
|
||||
value={form.profession}
|
||||
onChange={(e) => set("profession", e.target.value)}
|
||||
required
|
||||
className="form-input"
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
{/* ---- wechat + phone ---- */}
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-6">
|
||||
<Field label="💬 微信号">
|
||||
<input
|
||||
type="text"
|
||||
maxLength={140}
|
||||
placeholder="用于拉群"
|
||||
value={form.wechat}
|
||||
onChange={(e) => set("wechat", e.target.value)}
|
||||
required
|
||||
className="form-input"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field label="📱 手机号">
|
||||
<input
|
||||
type="tel"
|
||||
maxLength={11}
|
||||
pattern="^1[3-9]\d{9}$"
|
||||
placeholder="请输入11位中国手机号"
|
||||
value={form.phone}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value.replace(/\D/g, "").slice(0, 11);
|
||||
set("phone", v);
|
||||
}}
|
||||
className="form-input"
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
{/* ---- Intro (full width) ---- */}
|
||||
<div className="border-b border-slate-100 py-4 sm:border-b-0 sm:py-5">
|
||||
<label className="mb-2 block text-base font-bold text-slate-700 sm:text-[17px]">
|
||||
📝 自我介绍
|
||||
</label>
|
||||
<div className="relative">
|
||||
<textarea
|
||||
maxLength={500}
|
||||
rows={5}
|
||||
placeholder="分享您的经历、兴趣或加入原因,越详细越好哦~"
|
||||
value={form.intro}
|
||||
onChange={(e) => set("intro", e.target.value)}
|
||||
className="form-input min-h-[120px] resize-none sm:min-h-[140px]"
|
||||
/>
|
||||
<span className="absolute right-3 bottom-3 text-xs text-slate-300">
|
||||
{form.intro.length}/500
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ---- Row group: education + graduation ---- */}
|
||||
<div className="grid gap-0 sm:grid-cols-2 sm:gap-6">
|
||||
<Field label="🎓 学历">
|
||||
<select
|
||||
value={form.education}
|
||||
onChange={(e) => set("education", e.target.value)}
|
||||
className={`form-input appearance-none ${
|
||||
form.education ? "text-slate-800" : "text-slate-400"
|
||||
}`}
|
||||
>
|
||||
<option value="" disabled>
|
||||
请选择
|
||||
</option>
|
||||
{educationOptions.map((o) => (
|
||||
<option key={o} value={o}>
|
||||
{o}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown />
|
||||
</Field>
|
||||
|
||||
<Field label="📅 毕业时间">
|
||||
<select
|
||||
value={form.graduationYear}
|
||||
onChange={(e) => set("graduationYear", e.target.value)}
|
||||
className={`form-input appearance-none ${
|
||||
form.graduationYear ? "text-slate-800" : "text-slate-400"
|
||||
}`}
|
||||
>
|
||||
<option value="" disabled>
|
||||
请选择
|
||||
</option>
|
||||
{graduationYears.map((y) => (
|
||||
<option key={y} value={y}>
|
||||
{y}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown />
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
{/* ---- Media upload (optional) ---- */}
|
||||
<div className="py-4 sm:py-5">
|
||||
<label className="mb-1 block text-[15px] font-bold text-slate-700 sm:text-[17px]">
|
||||
📷 头像 / 自拍视频
|
||||
<span className="ml-2 text-xs font-normal text-slate-400">
|
||||
(可选)
|
||||
</span>
|
||||
</label>
|
||||
<p className="mb-3 text-xs text-slate-400">
|
||||
支持图片(JPG/PNG)或短视频(MP4),最大 20MB
|
||||
</p>
|
||||
|
||||
<input
|
||||
ref={fileRef}
|
||||
type="file"
|
||||
accept="image/jpeg,image/png,image/webp,video/mp4,video/quicktime"
|
||||
className="hidden"
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
if (file.size > 20 * 1024 * 1024) {
|
||||
alert("文件大小不能超过 20MB");
|
||||
return;
|
||||
}
|
||||
const isVideo = file.type.startsWith("video/");
|
||||
const preview = URL.createObjectURL(file);
|
||||
setMedia({ file, preview, type: isVideo ? "video" : "image" });
|
||||
}}
|
||||
/>
|
||||
|
||||
{media ? (
|
||||
<div className="relative inline-block">
|
||||
{media.type === "image" ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={media.preview}
|
||||
alt="preview"
|
||||
className="h-32 w-32 rounded-xl border border-slate-200 object-cover sm:h-40 sm:w-40"
|
||||
/>
|
||||
) : (
|
||||
<video
|
||||
src={media.preview}
|
||||
className="h-32 w-32 rounded-xl border border-slate-200 object-cover sm:h-40 sm:w-40"
|
||||
muted
|
||||
playsInline
|
||||
controls
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
URL.revokeObjectURL(media.preview);
|
||||
setMedia(null);
|
||||
if (fileRef.current) fileRef.current.value = "";
|
||||
}}
|
||||
className="absolute -top-2 -right-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500 text-xs text-white shadow-md transition-colors hover:bg-red-600"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => fileRef.current?.click()}
|
||||
className="flex h-32 w-32 flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-slate-200 text-slate-400 transition-colors hover:border-sky-300 hover:text-sky-500 sm:h-40 sm:w-40"
|
||||
>
|
||||
<svg className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<span className="text-xs">点击上传</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ── Submit ── */}
|
||||
<div className="mt-8 sm:mt-10">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full rounded-full bg-[#1aad19] py-3.5 text-lg font-semibold text-white shadow-md shadow-emerald-500/20 transition-all hover:bg-[#179b16] hover:shadow-lg hover:shadow-emerald-500/25 active:scale-[0.98] sm:py-4"
|
||||
>
|
||||
提交申请
|
||||
</button>
|
||||
|
||||
<p className="mt-4 whitespace-pre-line text-center text-sm leading-relaxed text-amber-500">
|
||||
{"🔍 提交后将进行审核\n💰 需支付基本场地/管理费"}
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* ── Back link (PC) ── */}
|
||||
<div className="mt-6 hidden text-center sm:block">
|
||||
<a
|
||||
href="/"
|
||||
className="text-sm text-slate-400 transition-colors hover:text-sky-500"
|
||||
>
|
||||
← 返回首页
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* ── Back link (H5, fixed bottom) ── */}
|
||||
<div className="mt-4 pb-6 text-center sm:hidden">
|
||||
<a
|
||||
href="/"
|
||||
className="text-sm text-slate-400 transition-colors hover:text-sky-500"
|
||||
>
|
||||
← 返回首页
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Reusable field wrapper ─── */
|
||||
function Field({
|
||||
label,
|
||||
children,
|
||||
noBorder,
|
||||
}: {
|
||||
label: string;
|
||||
children: React.ReactNode;
|
||||
noBorder?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`relative flex items-center gap-3 py-3.5 sm:flex-col sm:items-stretch sm:gap-0 sm:py-4 ${
|
||||
noBorder ? "" : "border-b border-slate-100 sm:border-b-0"
|
||||
}`}
|
||||
>
|
||||
<label className="w-[90px] shrink-0 text-[15px] font-bold text-slate-700 sm:mb-2 sm:w-auto sm:text-[17px]">
|
||||
{label}
|
||||
</label>
|
||||
<div className="relative min-w-0 flex-1">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Chevron icon for selects ─── */
|
||||
function ChevronDown() {
|
||||
return (
|
||||
<svg
|
||||
className="pointer-events-none absolute top-1/2 right-2 h-4 w-4 -translate-y-1/2 text-slate-400 sm:right-3"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
35
app/layout.tsx
Normal file
35
app/layout.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "数字游民指南 | Digital Nomad Guide",
|
||||
description:
|
||||
"从零开始,7天开启你的数字游民生活。远程工作、地点自由、技能变现 —— 一站式数字游民资源平台。",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
25
app/page.tsx
Normal file
25
app/page.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import Header from "./components/Header";
|
||||
import Hero from "./components/Hero";
|
||||
import Features from "./components/Features";
|
||||
import Roadmap from "./components/Roadmap";
|
||||
import Tools from "./components/Tools";
|
||||
import Resources from "./components/Resources";
|
||||
import Community from "./components/Community";
|
||||
import Footer from "./components/Footer";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
<Hero />
|
||||
<Features />
|
||||
<Roadmap />
|
||||
<Tools />
|
||||
<Resources />
|
||||
<Community />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user