nomadweb/frontend/src/components/OnboardingTour.tsx
eric 916ce30733 Add tax day counter, arrival checklist, cafe guide, and onboarding
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 00:13:19 -05:00

64 lines
1.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
const STEPS = [
{ id: "destinations", emoji: "🌍", title: "探索目的地", desc: "筛选城市、收藏与对比" },
{ id: "matcher", emoji: "🎯", title: "智能匹配", desc: "问卷推荐最适合你的城市" },
{ id: "trip", emoji: "🗓️", title: "规划行程", desc: "多城串联并估算预算" },
{ id: "tools", emoji: "🛠️", title: "用好工具", desc: "签证、保险、网速与账本" },
];
export default function OnboardingTour() {
const [open, setOpen] = useState(false);
const [step, setStep] = useState(0);
useEffect(() => {
if (localStorage.getItem("nomadro-onboarded")) return;
const t = setTimeout(() => setOpen(true), 2500);
return () => clearTimeout(t);
}, []);
const finish = () => {
localStorage.setItem("nomadro-onboarded", "1");
setOpen(false);
};
const next = () => {
if (step >= STEPS.length - 1) {
finish();
return;
}
const s = STEPS[step];
if (s.id === "matcher") {
window.dispatchEvent(new CustomEvent("open-matcher"));
} else {
document.getElementById(s.id)?.scrollIntoView({ behavior: "smooth" });
}
setStep((n) => n + 1);
};
if (!open) return null;
const current = STEPS[step];
return (
<div className="onboard-card" role="dialog" aria-label="新手引导">
<button className="onboard-skip" onClick={finish}>跳过</button>
<div className="onboard-step">
<span className="onboard-emoji">{current.emoji}</span>
<strong>{current.title}</strong>
<p>{current.desc}</p>
<div className="onboard-dots">
{STEPS.map((_, i) => (
<span key={i} className={i === step ? "active" : ""} />
))}
</div>
<button className="btn btn-primary btn-sm" onClick={next}>
{step >= STEPS.length - 1 ? "开始探索 🚀" : "下一步 →"}
</button>
</div>
</div>
);
}