571 lines
25 KiB
TypeScript
571 lines
25 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import { VideoCard } from "./VideoCard";
|
||
import { useVideoProgress } from "./useVideoProgress";
|
||
import AuthModal from "../components/AuthModal";
|
||
|
||
function getStoredUser(): string | null {
|
||
if (typeof window === "undefined") return null;
|
||
try {
|
||
const raw = localStorage.getItem("pb_user");
|
||
if (!raw) return null;
|
||
const user = JSON.parse(raw);
|
||
return user?.email ?? null;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/* ─── 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: "从选目的地到打包出发,手把手带你完成首次数字游民体验",
|
||
},
|
||
];
|
||
|
||
// 示例视频:w3schools 公开样本,可替换为 MinIO CDN URL(如 https://minioweb.hackrobot.cn/hackrobot/course/xxx.mp4)
|
||
const SAMPLE_VIDEO = "https://www.w3schools.com/html/mov_bbb.mp4";
|
||
|
||
// 一级:part 二级:section 三级:lesson
|
||
const curriculum = [
|
||
{
|
||
emoji: "🚀",
|
||
part: "基础篇",
|
||
sections: [
|
||
{ name: "认识数字游民", lessons: [{ id: "01", title: "什么是数字游民?破除 5 个常见误解", duration: "12:30", videoUrl: SAMPLE_VIDEO }, { id: "02", title: "数字游民三种模式:蜜蜂、乌龟、候鸟", duration: "08:45", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "💡",
|
||
part: "技能篇",
|
||
sections: [
|
||
{ name: "远程工作能力", lessons: [{ id: "03", title: "远程高薪技能全景图:找到你的方向", duration: "14:20", videoUrl: SAMPLE_VIDEO }, { id: "04", title: "30天技能升级路线:从评估到接单", duration: "11:15", videoUrl: SAMPLE_VIDEO }, { id: "05", title: "建立个人品牌:让客户主动找你", duration: "09:40", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "💰",
|
||
part: "收入篇",
|
||
sections: [
|
||
{ name: "构建收入体系", lessons: [{ id: "06", title: "远程全职 vs 自由职业:选哪条路?", duration: "10:05", videoUrl: SAMPLE_VIDEO }, { id: "07", title: "自由职业平台实操:Upwork / Toptal / 电鸭", duration: "13:50", videoUrl: SAMPLE_VIDEO }, { id: "08", title: "被动收入搭建:数字产品 & 在线课程", duration: "12:20", videoUrl: SAMPLE_VIDEO }, { id: "09", title: "定价的艺术:如何报价不心虚", duration: "07:30", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "🛠️",
|
||
part: "工具篇",
|
||
sections: [
|
||
{ name: "移动办公装备", lessons: [{ id: "10", title: "硬件极简主义:一个背包装下办公室", duration: "06:45", videoUrl: SAMPLE_VIDEO }, { id: "11", title: "远程协作工具栈:Slack / Notion / Linear", duration: "08:30", videoUrl: SAMPLE_VIDEO }, { id: "12", title: "安全必修课:VPN / 密码管理 / 2FA", duration: "05:55", videoUrl: SAMPLE_VIDEO }, { id: "13", title: "跨境财务工具:Wise / Stripe / Revolut", duration: "07:10", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "📋",
|
||
part: "合规篇",
|
||
sections: [
|
||
{ name: "签证税务保险", lessons: [{ id: "14", title: "55 国数字游民签证政策全解读", duration: "15:30", videoUrl: SAMPLE_VIDEO }, { id: "15", title: "税务居民身份与合规规划", duration: "11:40", videoUrl: SAMPLE_VIDEO }, { id: "16", title: "数字游民保险选购指南", duration: "06:20", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "🗺️",
|
||
part: "目的地篇",
|
||
sections: [
|
||
{ name: "选择你的城市", lessons: [{ id: "17", title: "亚洲三城:清迈 / 巴厘岛 / 首尔深度对比", duration: "10:50", videoUrl: SAMPLE_VIDEO }, { id: "18", title: "欧洲双雄:里斯本 / 巴塞罗那生活实录", duration: "09:25", videoUrl: SAMPLE_VIDEO }, { id: "19", title: "美洲探索:墨西哥城 / 麦德林旅居指南", duration: "08:15", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
{
|
||
emoji: "🏆",
|
||
part: "实战篇",
|
||
sections: [
|
||
{ name: "启程出发", lessons: [{ id: "20", title: "出发前检查清单 & 打包哲学", duration: "07:40", videoUrl: SAMPLE_VIDEO }, { id: "21", title: "第一个月生存指南 & 长期可持续策略", duration: "13:10", videoUrl: SAMPLE_VIDEO }] },
|
||
],
|
||
},
|
||
];
|
||
|
||
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);
|
||
const [authOpen, setAuthOpen] = useState(false);
|
||
const [userEmail, setUserEmail] = useState<string | null>(null);
|
||
const [expandedPart, setExpandedPart] = useState<string | null>(null);
|
||
const { markCompleted, isCompleted, isPartCompleted } = useVideoProgress();
|
||
|
||
useEffect(() => {
|
||
setUserEmail(getStoredUser());
|
||
}, []);
|
||
|
||
const handleLogout = () => {
|
||
localStorage.removeItem("pb_token");
|
||
localStorage.removeItem("pb_user");
|
||
setUserEmail(null);
|
||
};
|
||
|
||
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 gap-3 px-4 sm:px-6">
|
||
<a href="/" className="flex items-center gap-2 text-sm font-bold">
|
||
<span className="text-lg">🌍</span>
|
||
数字游民指南
|
||
</a>
|
||
<div className="flex items-center gap-2 sm:gap-3">
|
||
{userEmail ? (
|
||
<>
|
||
<span className="hidden max-w-[120px] truncate text-sm text-slate-600 sm:inline">
|
||
{userEmail}
|
||
</span>
|
||
<button
|
||
onClick={handleLogout}
|
||
className="rounded-full border border-slate-200 px-3 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-50"
|
||
>
|
||
退出
|
||
</button>
|
||
</>
|
||
) : (
|
||
<button
|
||
onClick={() => setAuthOpen(true)}
|
||
className="rounded-full border border-slate-200 px-3 py-1.5 text-sm font-medium text-slate-600 transition-colors hover:bg-slate-50"
|
||
>
|
||
登录 / 注册
|
||
</button>
|
||
)}
|
||
<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>
|
||
</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="relative overflow-hidden bg-gradient-to-b from-white via-slate-50/50 to-slate-50 py-24 sm:py-28">
|
||
<div className="mx-auto max-w-4xl px-4 sm:px-6">
|
||
{/* 标题区:大数字 + 学习路径感 */}
|
||
<div className="mb-16 text-center">
|
||
<div className="inline-flex items-baseline gap-2">
|
||
<span className="gradient-text text-6xl font-extrabold tabular-nums tracking-tight sm:text-7xl">
|
||
21
|
||
</span>
|
||
<span className="text-2xl font-bold text-slate-800 sm:text-3xl">
|
||
节实战课程
|
||
</span>
|
||
</div>
|
||
<p className="mt-4 text-slate-500">
|
||
从入门到启程 · 完整的学习路径
|
||
</p>
|
||
<div className="mx-auto mt-6 h-px w-24 rounded-full bg-gradient-to-r from-transparent via-sky-300/60 to-transparent" />
|
||
</div>
|
||
|
||
{/* 垂直时间线:左侧竖线 + 节点 */}
|
||
<div className="relative">
|
||
{/* 中央竖线 */}
|
||
<div
|
||
className="absolute left-[19px] top-6 bottom-6 w-0.5 bg-gradient-to-b from-sky-200/80 via-sky-300/60 to-sky-200/80 sm:left-[23px]"
|
||
aria-hidden
|
||
/>
|
||
|
||
<div className="space-y-0">
|
||
{curriculum.map((ch, idx) => {
|
||
const allLessons = ch.sections.flatMap((s) => s.lessons);
|
||
const partCompleted = isPartCompleted(allLessons.map((l) => l.id));
|
||
const isExpanded = expandedPart === ch.part;
|
||
const totalLessons = allLessons.length;
|
||
return (
|
||
<div key={ch.part} className="relative flex gap-6 pb-10 last:pb-0">
|
||
{/* 左侧节点圆:完成时显示 ✓ */}
|
||
<div className="relative z-10 flex shrink-0 items-start pt-0.5">
|
||
<div
|
||
className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-full text-sm font-bold shadow-sm transition-colors sm:h-12 sm:w-12 ${
|
||
partCompleted
|
||
? "border-2 border-emerald-300 bg-emerald-50 text-emerald-600"
|
||
: "border-2 border-sky-200 bg-white text-sky-600"
|
||
}`}
|
||
>
|
||
{partCompleted ? (
|
||
<svg className="h-5 w-5 sm:h-6 sm:w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
|
||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
|
||
</svg>
|
||
) : (
|
||
idx + 1
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* 右侧内容卡片 */}
|
||
<div className="min-w-0 flex-1">
|
||
<div
|
||
className={`overflow-hidden rounded-2xl border shadow-sm transition-colors ${
|
||
partCompleted ? "border-emerald-200/80 bg-emerald-50/30" : "border-slate-200/80 bg-white"
|
||
}`}
|
||
>
|
||
{/* 一级:Part 标题,点击展开/收起 */}
|
||
<button
|
||
type="button"
|
||
onClick={() => setExpandedPart(isExpanded ? null : ch.part)}
|
||
className="flex w-full items-center justify-between gap-3 px-5 py-4 text-left transition-colors hover:bg-slate-50/80 sm:px-6"
|
||
>
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-2xl">{ch.emoji}</span>
|
||
<h3 className="font-bold text-slate-800">{ch.part}</h3>
|
||
{partCompleted && (
|
||
<span className="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-medium text-emerald-700">
|
||
已完成
|
||
</span>
|
||
)}
|
||
</div>
|
||
<span className="flex items-center gap-2 text-sm text-slate-400">
|
||
<span>{totalLessons} 节</span>
|
||
<svg
|
||
className={`h-4 w-4 shrink-0 transition-transform duration-200 ${
|
||
isExpanded ? "rotate-180" : ""
|
||
}`}
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
stroke="currentColor"
|
||
>
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||
</svg>
|
||
</span>
|
||
</button>
|
||
|
||
{/* 展开后:二级 section + 三级 lesson */}
|
||
{isExpanded && (
|
||
<div className="border-t border-slate-100 bg-slate-50/40">
|
||
{ch.sections.map((sec) => (
|
||
<div key={sec.name} className="border-b border-slate-100 last:border-b-0">
|
||
{/* 二级标题 */}
|
||
<div className="flex items-center gap-3 border-b border-slate-100/80 bg-slate-50/60 px-5 py-3.5 sm:px-6">
|
||
<span className="flex h-6 w-1 shrink-0 rounded-full bg-gradient-to-b from-sky-400 to-sky-500" />
|
||
<h4 className="text-sm font-semibold text-slate-700">
|
||
{sec.name}
|
||
</h4>
|
||
<span className="rounded-full bg-slate-200/60 px-2 py-0.5 text-xs font-medium text-slate-500">
|
||
{sec.lessons.length} 节
|
||
</span>
|
||
</div>
|
||
{/* 三级:视频卡片网格 */}
|
||
<div className="grid gap-5 p-5 sm:grid-cols-2 sm:p-6 lg:grid-cols-3">
|
||
{sec.lessons.map((lesson) => (
|
||
<VideoCard
|
||
key={lesson.id}
|
||
lesson={lesson as { id: string; title: string; duration: string; videoUrl?: string }}
|
||
completed={isCompleted(lesson.id)}
|
||
onComplete={() => markCompleted(lesson.id)}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</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>
|
||
|
||
<AuthModal
|
||
isOpen={authOpen}
|
||
onClose={() => setAuthOpen(false)}
|
||
onSuccess={(email) => setUserEmail(email)}
|
||
/>
|
||
|
||
{/* ── 报名 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>
|
||
);
|
||
}
|