SimpleHome.tsx 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. import { useState, useEffect } from 'react';
  2. import {
  3. Bot,
  4. MapPin,
  5. Cpu,
  6. ArrowRight,
  7. BarChart3,
  8. Gamepad2,
  9. Terminal,
  10. Ticket,
  11. Zap,
  12. Menu,
  13. X,
  14. Sun,
  15. Moon,
  16. Feather,
  17. BookOpen, // Used for the letter link
  18. BrainCircuit
  19. } from 'lucide-react';
  20. import { useNavigate, useLocation } from 'react-router-dom';
  21. import i18n from '../i18n';
  22. // 多语言配置
  23. const translations = {
  24. zh: {
  25. nav: {
  26. core: '业务板块',
  27. consulting: '企业咨询',
  28. tourism: '文旅运营',
  29. dev: '开发者',
  30. contact: '联系我们',
  31. },
  32. hero: {
  33. quote: '"玩"意味着一种无拘无束的自由状态。',
  34. quoteSub: '你会发现,每个真正懂得玩的人,他们玩的方式都是独一无二的,充满了自发的创造力与鲜明的个性。',
  35. // Logic update: Focusing on the "Why" and the ecosystem
  36. sectionTitle: '为了让大家能 "纯粹的玩",我们构建了三层业务生态',
  37. },
  38. cards: {
  39. // Step 1: Liberate
  40. consultingTitle: '第一步:解放时间',
  41. consultingDesc: '首先,我们用AI为企业降本增效。只有把人从繁琐工作中解放出来,才有时间去玩。',
  42. consultingLink: '查看企业AI方案',
  43. // Step 2: Create Fun
  44. tourismTitle: '第二步:创造乐趣',
  45. tourismDesc: '然后,我们用技术重塑文旅体验。打卡地图与游戏化运营,让旅行回归玩的本质。',
  46. tourismLink: '查看文旅案例',
  47. // Step 3: Support Creation
  48. devTitle: '第三步:支持创造',
  49. devDesc: '最后,我们为AI一人公司提供基建。让每一个想玩的灵魂,拥有实现梦想的算力。',
  50. devLink: '获取开发资源'
  51. },
  52. consulting: {
  53. tag: 'Consulting',
  54. title: '从繁杂中解放',
  55. titleHighlight: '回归创造',
  56. description: '我们为企业提供深度 IT 与 AI 咨询。这不是为了卷,而是为了降本提效,让团队从重复劳动中解脱出来。',
  57. items: [
  58. '企业私有知识库 (RAG)',
  59. '自动化研报/公文撰写',
  60. 'AI 辅助决策系统',
  61. '传统 IT 架构改造'
  62. ],
  63. reportTitle: '效率诊断',
  64. reportDesc: 'AI 自动生成深度行业研究报告,将 3 天的撰写周期缩短至 15 分钟。'
  65. },
  66. tourism: {
  67. tag: 'Cultural Tourism',
  68. title: '打通文旅地产',
  69. titleHighlight: '变现渠道',
  70. description: '我们推出了一套以打卡地图、商户优惠券发放、抽奖游戏活动为核心的文旅运营解决方案。',
  71. features: {
  72. map: { title: '打卡地图', desc: 'LBS 定位解锁景点' },
  73. coupon: { title: '优惠券', desc: '连接商户与游客' },
  74. game: { title: '抽奖活动', desc: '提升游客留存率' },
  75. data: { title: 'CPS分成', desc: '按效果获取收益' }
  76. },
  77. mockup: {
  78. title: '西湖寻宝季',
  79. gift: '🎁 待领取: 咖啡券',
  80. btn: '扫码打卡'
  81. }
  82. },
  83. dev: {
  84. tag: 'Infrastructure',
  85. title: '支持每一个',
  86. titleHighlight: '超级个体',
  87. description: '针对 AI 一人公司,我们提供基础设施服务,让你像玩乐高一样构建产品。',
  88. features: {
  89. token: { title: 'Token 分发', desc: 'OpenAI / Claude / DeepSeek 聚合接口' },
  90. compute: { title: '弹性算力', desc: '高性价比 GPU 租赁' },
  91. saas: { title: 'SaaS 套件', desc: '一键部署的创业脚手架' }
  92. }
  93. },
  94. contact: {
  95. title: '保持联系',
  96. description: '既然来了,我会尽一切努力让你纯粹的玩。',
  97. formTitle: '发送邮件',
  98. placeholderName: '你的称呼',
  99. placeholderEmail: '你的邮箱',
  100. submit: '发送',
  101. footerLetter: '阅读:给玩友们的一封信',
  102. footerShareholder: '阅读:2025年5月29日给股东们的信',
  103. footerNote: '"纯粹的玩"由几位股东共同创立,我作为现在的法人和大股东,拥有最终决策权。',
  104. copyright: '© 2026 杭州纯粹的玩品牌科技有限公司'
  105. }
  106. },
  107. en: {
  108. nav: {
  109. core: 'Sectors',
  110. consulting: 'Consulting',
  111. tourism: 'Tourism',
  112. dev: 'Developers',
  113. contact: 'Contact',
  114. },
  115. hero: {
  116. quote: '"Play" means a state of unrestrained freedom.',
  117. quoteSub: 'You will find that for everyone who truly knows how to play, their way of playing is unique, full of spontaneous creativity and distinct personality.',
  118. sectionTitle: 'To enable "Pure Play" for everyone, we focus on three pillars',
  119. },
  120. cards: {
  121. consultingTitle: 'Step 1: Liberate Time',
  122. consultingDesc: 'First, we use AI to optimize enterprise workflows. Freeing people from tedious work gives them time to play.',
  123. consultingLink: 'View Solutions',
  124. tourismTitle: 'Step 2: Create Fun',
  125. tourismDesc: 'Then, we reshape tourism with tech. Check-in maps and gamification bring the fun back to travel.',
  126. tourismLink: 'View Cases',
  127. devTitle: 'Step 3: Support Creation',
  128. devDesc: 'Finally, we empower AI solopreneurs. Providing the infrastructure for every soul to build their dreams.',
  129. devLink: 'Get Resources'
  130. },
  131. consulting: {
  132. tag: 'Consulting',
  133. title: 'Liberate from Chaos',
  134. titleHighlight: 'Return to Creation',
  135. description: 'We provide deep IT & AI consulting. Not to hustle harder, but to cut costs and increase efficiency, freeing teams from repetitive labor.',
  136. items: [
  137. 'Private Knowledge Base (RAG)',
  138. 'Automated Research/Docs',
  139. 'AI Decision Support',
  140. 'Legacy IT Upgrade'
  141. ],
  142. reportTitle: 'Efficiency',
  143. reportDesc: 'AI automatically generates in-depth research reports, reducing a 3-day writing cycle to 15 minutes.'
  144. },
  145. tourism: {
  146. tag: 'Cultural Tourism',
  147. title: 'Monetizing',
  148. titleHighlight: 'Tourism Assets',
  149. description: 'We launched a tourism operation solution centered on check-in maps, coupon distribution, and lucky draw games.',
  150. features: {
  151. map: { title: 'Check-in Map', desc: 'LBS unlock spots' },
  152. coupon: { title: 'Coupons', desc: 'Connecting merchants' },
  153. game: { title: 'Lucky Draw', desc: 'Boost retention' },
  154. data: { title: 'CPS RevShare', desc: 'Earn by results' }
  155. },
  156. mockup: {
  157. title: 'West Lake Hunt',
  158. gift: '🎁 Reward: Coffee',
  159. btn: 'Scan to Play'
  160. }
  161. },
  162. dev: {
  163. tag: 'Infrastructure',
  164. title: 'Supporting Every',
  165. titleHighlight: 'Super Individual',
  166. description: 'For AI Solopreneurs, we provide infrastructure services, letting you build products like playing Lego.',
  167. features: {
  168. token: { title: 'Token Relay', desc: 'OpenAI / Claude / DeepSeek Aggregation' },
  169. compute: { title: 'Elastic Compute', desc: 'Cost-effective GPU rental' },
  170. saas: { title: 'SaaS Kit', desc: 'All-in-one scaffold' }
  171. }
  172. },
  173. contact: {
  174. title: 'Keep in Touch',
  175. description: 'Since you are here, I will do my best to let you play purely.',
  176. formTitle: 'Send Email',
  177. placeholderName: 'Your Name',
  178. placeholderEmail: 'Your Email',
  179. submit: 'Send',
  180. footerLetter: 'Read: A Letter to Players',
  181. footerShareholder: 'Read: Letter to Shareholders (May 29, 2025)',
  182. footerNote: '"Pure Play" was co-founded by several shareholders. As the current legal representative, I have the final decision-making power.',
  183. copyright: '© 2026 Pure Play Technology Co., Ltd. Hangzhou.'
  184. }
  185. }
  186. };
  187. const SimpleHome = () => {
  188. const [isMenuOpen, setIsMenuOpen] = useState(false);
  189. // Default to Light Mode (isDark = false)
  190. const [isDark, setIsDark] = useState(localStorage.getItem('theme') === 'dark');
  191. // Sync theme on mount/change
  192. useEffect(() => {
  193. localStorage.setItem('theme', isDark ? 'dark' : 'light');
  194. }, [isDark]);
  195. const [lang, setLang] = useState<'zh' | 'en'>(i18n.language?.startsWith('zh') ? 'zh' : 'en');
  196. const [email, setEmail] = useState('');
  197. const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
  198. const [message, setMessage] = useState('');
  199. const navigate = useNavigate();
  200. const location = useLocation();
  201. // Handle Hash Scroll on Mount/Update
  202. useEffect(() => {
  203. if (location.hash) {
  204. const id = location.hash.replace('#', '');
  205. setTimeout(() => {
  206. const element = document.getElementById(id);
  207. if (element) {
  208. element.scrollIntoView({ behavior: 'smooth' });
  209. }
  210. }, 100); // Small delay to ensure render
  211. }
  212. }, [location]);
  213. // Handle global language sync if we want consistency with other pages using i18n
  214. // But SimpleHome seems to use local specific translations object `translations`.
  215. // Ideally SimpleHome should also use `useTranslation` hook so it shares state with Step1/Step2.
  216. // However, refactoring SimpleHome to use i18n completely is a big change (large file).
  217. // For now, let's at least make the Lang Toggle use the i18n instance if possible
  218. // OR just keep local lang state. The user asked to "perfect" Step1 and Step2.
  219. // If I change Lang in Step 1 (via i18n) and come back to Home, Home might still be default (zh).
  220. // Let's assume for now SimpleHome keeps its local state, but we try to initialize it from i18n if possible
  221. // or localStorage language detector.
  222. const t = translations[lang];
  223. const scrollToSection = (id: string) => {
  224. const element = document.getElementById(id);
  225. if (element) {
  226. element.scrollIntoView({ behavior: 'smooth' });
  227. setIsMenuOpen(false);
  228. }
  229. };
  230. const toggleTheme = () => setIsDark(!isDark);
  231. const toggleLang = () => {
  232. const newLang = lang === 'zh' ? 'en' : 'zh';
  233. setLang(newLang);
  234. i18n.changeLanguage(newLang);
  235. };
  236. const handleEmailSubmit = async () => {
  237. if (!email) return;
  238. const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  239. if (!emailRegex.test(email)) {
  240. setStatus('error');
  241. setMessage('请输入有效的邮箱地址');
  242. return;
  243. }
  244. setStatus('loading');
  245. setMessage('');
  246. try {
  247. const response = await fetch('/api/send-welcome-email', {
  248. method: 'POST',
  249. headers: {
  250. 'Content-Type': 'application/json',
  251. },
  252. body: JSON.stringify({ email }),
  253. });
  254. const data = await response.json();
  255. if (data.success) {
  256. setStatus('success');
  257. setMessage(data.message);
  258. setEmail('');
  259. } else {
  260. setStatus('error');
  261. setMessage(data.message || '发送失败,请稍后重试');
  262. }
  263. } catch (error) {
  264. console.error('API Error:', error);
  265. setStatus('error');
  266. setMessage('网络错误,请稍后重试');
  267. }
  268. };
  269. return (
  270. <div className={`min-h-screen font-sans transition-colors duration-500 ${isDark ? 'bg-stone-900 text-stone-100' : 'bg-[#FAFAFA] text-stone-800'}`}>
  271. {/* Navigation - Minimalist */}
  272. <nav className={`fixed w-full z-50 transition-all duration-300 ${isDark ? 'bg-stone-900/90 border-b border-stone-800' : 'bg-white/90 border-b border-stone-100'} backdrop-blur-sm`}>
  273. <div className="max-w-4xl mx-auto px-6 h-20 flex justify-between items-center">
  274. {/* Custom CCDW Logo */}
  275. <div className="flex items-center gap-3 cursor-pointer group" onClick={() => scrollToSection('hero')}>
  276. <div className="flex items-baseline font-bold text-3xl tracking-tighter" style={{ fontFamily: '"Nunito", sans-serif' }}>
  277. <span className="text-orange-400">CC</span>
  278. <span className="text-blue-500">D</span>
  279. <span className="text-cyan-400">W</span>
  280. </div>
  281. <div className={`h-6 w-px ${isDark ? 'bg-stone-700' : 'bg-stone-300'} mx-1`}></div>
  282. <span className={`text-sm tracking-widest ${isDark ? 'text-stone-400' : 'text-stone-500 group-hover:text-stone-800'} transition-colors`}>
  283. {lang === 'zh' ? '纯粹的玩' : 'Pure Play'}
  284. </span>
  285. </div>
  286. {/* Desktop Menu - Simple Links */}
  287. <div className="hidden md:flex items-center space-x-8">
  288. {[t.nav.consulting, t.nav.tourism, t.nav.dev].map((item, index) => {
  289. const ids = ['consulting', 'tourism', 'dev'];
  290. return (
  291. <button
  292. key={index}
  293. onClick={() => scrollToSection(ids[index])}
  294. className={`text-sm font-medium hover:-translate-y-0.5 transition-transform ${isDark ? 'text-stone-400 hover:text-white' : 'text-stone-500 hover:text-stone-900'}`}
  295. >
  296. {item}
  297. </button>
  298. );
  299. })}
  300. <div className="flex items-center gap-2 pl-4">
  301. <button onClick={toggleTheme} className={`p-2 rounded-full hover:bg-black/5 transition-colors ${isDark ? 'text-stone-400' : 'text-stone-400'}`}>
  302. {isDark ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
  303. </button>
  304. <button onClick={toggleLang} className={`text-xs font-bold px-2 py-1 rounded hover:bg-black/5 ${isDark ? 'text-stone-400' : 'text-stone-500'}`}>
  305. {lang === 'zh' ? 'EN' : '中'}
  306. </button>
  307. </div>
  308. </div>
  309. {/* Mobile Menu Toggle */}
  310. <div className="md:hidden">
  311. <button onClick={() => setIsMenuOpen(!isMenuOpen)} className={isDark ? 'text-stone-100' : 'text-stone-800'}>
  312. {isMenuOpen ? <X /> : <Menu />}
  313. </button>
  314. </div>
  315. </div>
  316. {/* Mobile Dropdown */}
  317. {isMenuOpen && (
  318. <div className={`md:hidden absolute top-full left-0 w-full p-6 shadow-lg border-b ${isDark ? 'bg-stone-900 border-stone-800' : 'bg-white border-stone-100'}`}>
  319. {[t.nav.consulting, t.nav.tourism, t.nav.dev, t.nav.contact].map((item, index) => {
  320. const ids = ['consulting', 'tourism', 'dev', 'contact'];
  321. return (
  322. <button
  323. key={index}
  324. onClick={() => scrollToSection(ids[index])}
  325. className={`block w-full text-left py-3 text-lg ${isDark ? 'text-stone-300' : 'text-stone-600'}`}
  326. >
  327. {item}
  328. </button>
  329. );
  330. })}
  331. </div>
  332. )}
  333. </nav>
  334. {/* Hero Section - Clean & Minimal */}
  335. <section id="hero" className="pt-40 pb-20 px-6">
  336. <div className="max-w-3xl mx-auto text-center mb-16">
  337. <p className={`text-xl md:text-2xl font-serif italic mb-8 leading-relaxed ${isDark ? 'text-stone-300' : 'text-stone-600'}`}>
  338. {t.hero.quote}
  339. </p>
  340. <p className={`text-sm md:text-base max-w-xl mx-auto leading-loose ${isDark ? 'text-stone-500' : 'text-stone-400'}`}>
  341. {t.hero.quoteSub}
  342. </p>
  343. </div>
  344. <div className="max-w-2xl mx-auto">
  345. <div className={`w-24 h-px mx-auto ${isDark ? 'bg-stone-800' : 'bg-stone-200'} mb-16`}></div>
  346. <div className="mb-12 text-center">
  347. <h2 className={`text-lg font-bold ${isDark ? 'text-stone-200' : 'text-stone-800'}`}>
  348. {t.hero.sectionTitle}
  349. </h2>
  350. </div>
  351. <div className="space-y-8">
  352. {/* Item 1 */}
  353. <div
  354. onClick={() => navigate('/step1')}
  355. className={`group p-6 rounded-xl border transition-all cursor-pointer ${isDark ? 'bg-stone-800/50 border-stone-700 hover:border-blue-500/50' : 'bg-white border-stone-200 hover:border-blue-400 shadow-sm hover:shadow-md'}`}
  356. >
  357. <div className="flex items-center justify-between mb-2">
  358. <h3 className={`font-serif font-bold text-xl ${isDark ? 'text-stone-200' : 'text-stone-800'}`}>{t.cards.consultingTitle}</h3>
  359. <BrainCircuit className={`w-5 h-5 ${isDark ? 'text-blue-400' : 'text-blue-600'}`} />
  360. </div>
  361. <p className={`text-sm leading-relaxed mb-4 ${isDark ? 'text-stone-400' : 'text-stone-500'}`}>{t.cards.consultingDesc}</p>
  362. <span className={`text-xs font-bold uppercase tracking-wider flex items-center ${isDark ? 'text-blue-400' : 'text-blue-600'}`}>
  363. {t.cards.consultingLink} <ArrowRight className="w-3 h-3 ml-1 group-hover:translate-x-1 transition-transform" />
  364. </span>
  365. </div>
  366. {/* Item 2 */}
  367. <div
  368. onClick={() => navigate('/step2')}
  369. className={`group p-6 rounded-xl border transition-all cursor-pointer ${isDark ? 'bg-stone-800/50 border-stone-700 hover:border-orange-500/50' : 'bg-white border-stone-200 hover:border-orange-400 shadow-sm hover:shadow-md'}`}
  370. >
  371. <div className="flex items-center justify-between mb-2">
  372. <h3 className={`font-serif font-bold text-xl ${isDark ? 'text-stone-200' : 'text-stone-800'}`}>{t.cards.tourismTitle}</h3>
  373. <Ticket className={`w-5 h-5 ${isDark ? 'text-orange-400' : 'text-orange-500'}`} />
  374. </div>
  375. <p className={`text-sm leading-relaxed mb-4 ${isDark ? 'text-stone-400' : 'text-stone-500'}`}>{t.cards.tourismDesc}</p>
  376. <span className={`text-xs font-bold uppercase tracking-wider flex items-center ${isDark ? 'text-orange-400' : 'text-orange-600'}`}>
  377. {t.cards.tourismLink} <ArrowRight className="w-3 h-3 ml-1 group-hover:translate-x-1 transition-transform" />
  378. </span>
  379. </div>
  380. {/* Item 3 */}
  381. <div
  382. onClick={() => navigate('/step3')}
  383. className={`group p-6 rounded-xl border transition-all cursor-pointer ${isDark ? 'bg-stone-800/50 border-stone-700 hover:border-cyan-500/50' : 'bg-white border-stone-200 hover:border-cyan-400 shadow-sm hover:shadow-md'}`}
  384. >
  385. <div className="flex items-center justify-between mb-2">
  386. <h3 className={`font-serif font-bold text-xl ${isDark ? 'text-stone-200' : 'text-stone-800'}`}>{t.cards.devTitle}</h3>
  387. <Terminal className={`w-5 h-5 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
  388. </div>
  389. <p className={`text-sm leading-relaxed mb-4 ${isDark ? 'text-stone-400' : 'text-stone-500'}`}>{t.cards.devDesc}</p>
  390. <span className={`text-xs font-bold uppercase tracking-wider flex items-center ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`}>
  391. {t.cards.devLink} <ArrowRight className="w-3 h-3 ml-1 group-hover:translate-x-1 transition-transform" />
  392. </span>
  393. </div>
  394. </div>
  395. </div>
  396. </section>
  397. {/* Detailed Sections - Minimalist Layout */}
  398. {/* Consulting */}
  399. <section id="consulting" className={`py-20 px-6 ${isDark ? 'bg-stone-900' : 'bg-white'}`}>
  400. <div className="max-w-4xl mx-auto">
  401. <div className="grid md:grid-cols-2 gap-12 items-center">
  402. <div>
  403. <span className={`text-xs font-bold tracking-widest uppercase mb-4 block ${isDark ? 'text-blue-400' : 'text-blue-600'}`}>{t.consulting.tag}</span>
  404. <h2 className="text-3xl font-serif font-bold mb-6 leading-tight">
  405. {t.consulting.title} <br />
  406. <span className={`decoration-4 underline decoration-blue-200 ${isDark ? 'decoration-blue-900' : ''}`}>{t.consulting.titleHighlight}</span>
  407. </h2>
  408. <p className={`mb-8 leading-relaxed ${isDark ? 'text-stone-400' : 'text-stone-600'}`}>{t.consulting.description}</p>
  409. <ul className="space-y-3">
  410. {t.consulting.items.map((item, i) => (
  411. <li key={i} className="flex items-center gap-3">
  412. <div className={`w-1.5 h-1.5 rounded-full ${isDark ? 'bg-blue-400' : 'bg-blue-600'}`}></div>
  413. <span className={`text-sm ${isDark ? 'text-stone-300' : 'text-stone-700'}`}>{item}</span>
  414. </li>
  415. ))}
  416. </ul>
  417. <div className="mt-8">
  418. <button
  419. onClick={() => navigate('/step1')}
  420. className={`text-sm font-bold uppercase tracking-wider flex items-center group ${isDark ? 'text-blue-400 hover:text-blue-300' : 'text-blue-600 hover:text-blue-700'}`}
  421. >
  422. {t.cards.consultingLink} <ArrowRight className="w-4 h-4 ml-2 transition-transform group-hover:translate-x-1" />
  423. </button>
  424. </div>
  425. </div>
  426. <div className={`p-8 rounded-lg border ${isDark ? 'bg-stone-800 border-stone-700' : 'bg-stone-50 border-stone-100'}`}>
  427. <BarChart3 className={`w-8 h-8 mb-4 ${isDark ? 'text-blue-400' : 'text-blue-600'}`} />
  428. <div className={`text-sm font-bold mb-2 ${isDark ? 'text-stone-200' : 'text-stone-800'}`}>{t.consulting.reportTitle}</div>
  429. <p className={`text-xs leading-relaxed ${isDark ? 'text-stone-400' : 'text-stone-500'}`}>{t.consulting.reportDesc}</p>
  430. <div className="mt-6 flex items-end gap-2">
  431. <div className="h-16 w-4 bg-stone-200 rounded-sm"></div>
  432. <div className="h-10 w-4 bg-stone-200 rounded-sm"></div>
  433. <div className={`h-24 w-4 rounded-sm ${isDark ? 'bg-blue-500' : 'bg-blue-600'}`}></div>
  434. <div className="h-14 w-4 bg-stone-200 rounded-sm"></div>
  435. </div>
  436. </div>
  437. </div>
  438. </div>
  439. </section>
  440. {/* Tourism */}
  441. <section id="tourism" className={`py-20 px-6 ${isDark ? 'bg-stone-800/30' : 'bg-stone-50'}`}>
  442. <div className="max-w-4xl mx-auto">
  443. <div className="grid md:grid-cols-2 gap-12 items-center">
  444. <div className="order-2 md:order-1 grid grid-cols-2 gap-4">
  445. <div className={`p-4 rounded-lg border text-center ${isDark ? 'bg-stone-800 border-stone-700' : 'bg-white border-stone-200'}`}>
  446. <MapPin className={`w-6 h-6 mx-auto mb-2 ${isDark ? 'text-orange-400' : 'text-orange-500'}`} />
  447. <div className="font-bold text-sm mb-1">{t.tourism.features.map.title}</div>
  448. <div className="text-[10px] text-stone-400">{t.tourism.features.map.desc}</div>
  449. </div>
  450. <div className={`p-4 rounded-lg border text-center ${isDark ? 'bg-stone-800 border-stone-700' : 'bg-white border-stone-200'}`}>
  451. <Ticket className={`w-6 h-6 mx-auto mb-2 ${isDark ? 'text-orange-400' : 'text-orange-500'}`} />
  452. <div className="font-bold text-sm mb-1">{t.tourism.features.coupon.title}</div>
  453. <div className="text-[10px] text-stone-400">{t.tourism.features.coupon.desc}</div>
  454. </div>
  455. <div className={`p-4 rounded-lg border text-center ${isDark ? 'bg-stone-800 border-stone-700' : 'bg-white border-stone-200'}`}>
  456. <Gamepad2 className={`w-6 h-6 mx-auto mb-2 ${isDark ? 'text-orange-400' : 'text-orange-500'}`} />
  457. <div className="font-bold text-sm mb-1">{t.tourism.features.game.title}</div>
  458. <div className="text-[10px] text-stone-400">{t.tourism.features.game.desc}</div>
  459. </div>
  460. <div className={`p-4 rounded-lg border text-center ${isDark ? 'bg-stone-800 border-stone-700' : 'bg-white border-stone-200'}`}>
  461. <Bot className={`w-6 h-6 mx-auto mb-2 ${isDark ? 'text-orange-400' : 'text-orange-500'}`} />
  462. <div className="font-bold text-sm mb-1">{t.tourism.features.data.title}</div>
  463. <div className="text-[10px] text-stone-400">{t.tourism.features.data.desc}</div>
  464. </div>
  465. </div>
  466. <div className="order-1 md:order-2">
  467. <span className={`text-xs font-bold tracking-widest uppercase mb-4 block ${isDark ? 'text-orange-400' : 'text-orange-500'}`}>{t.tourism.tag}</span>
  468. <h2 className="text-3xl font-serif font-bold mb-6 leading-tight">
  469. {t.tourism.title} <br />
  470. <span className={`decoration-4 underline decoration-orange-200 ${isDark ? 'decoration-orange-900' : ''}`}>{t.tourism.titleHighlight}</span>
  471. </h2>
  472. <p className={`mb-8 leading-relaxed ${isDark ? 'text-stone-400' : 'text-stone-600'}`}>{t.tourism.description}</p>
  473. <div className="mt-6">
  474. <button
  475. onClick={() => navigate('/step2')}
  476. className={`text-sm font-bold uppercase tracking-wider flex items-center group ${isDark ? 'text-orange-400 hover:text-orange-300' : 'text-orange-600 hover:text-orange-700'}`}
  477. >
  478. {t.cards.tourismLink} <ArrowRight className="w-4 h-4 ml-2 transition-transform group-hover:translate-x-1" />
  479. </button>
  480. </div>
  481. </div>
  482. </div>
  483. </div>
  484. </section>
  485. {/* Dev Services */}
  486. <section id="dev" className={`py-20 px-6 ${isDark ? 'bg-stone-900' : 'bg-white'}`}>
  487. <div className="max-w-4xl mx-auto">
  488. <div className="text-center mb-16">
  489. <span className={`text-xs font-bold tracking-widest uppercase mb-4 block ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`}>{t.dev.tag}</span>
  490. <h2 className="text-3xl font-serif font-bold mb-4">
  491. {t.dev.title} <span className={`decoration-4 underline decoration-cyan-200 ${isDark ? 'decoration-cyan-900' : ''}`}>{t.dev.titleHighlight}</span>
  492. </h2>
  493. <p className={`max-w-xl mx-auto ${isDark ? 'text-stone-400' : 'text-stone-600'}`}>{t.dev.description}</p>
  494. </div>
  495. <div className="grid md:grid-cols-3 gap-8">
  496. <div className={`p-6 border-t-2 ${isDark ? 'border-t-cyan-500 bg-stone-800/30' : 'border-t-cyan-500 bg-stone-50'}`}>
  497. <Zap className={`w-6 h-6 mb-4 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
  498. <h3 className="font-bold mb-2">{t.dev.features.token.title}</h3>
  499. <p className="text-sm text-stone-500">{t.dev.features.token.desc}</p>
  500. </div>
  501. <div className={`p-6 border-t-2 ${isDark ? 'border-t-cyan-500 bg-stone-800/30' : 'border-t-cyan-500 bg-stone-50'}`}>
  502. <Cpu className={`w-6 h-6 mb-4 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
  503. <h3 className="font-bold mb-2">{t.dev.features.compute.title}</h3>
  504. <p className="text-sm text-stone-500">{t.dev.features.compute.desc}</p>
  505. </div>
  506. <div className={`p-6 border-t-2 ${isDark ? 'border-t-cyan-500 bg-stone-800/30' : 'border-t-cyan-500 bg-stone-50'}`}>
  507. <Terminal className={`w-6 h-6 mb-4 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
  508. <h3 className="font-bold mb-2">{t.dev.features.saas.title}</h3>
  509. <p className="text-sm text-stone-500">{t.dev.features.saas.desc}</p>
  510. </div>
  511. </div>
  512. <div className="mt-12 text-center">
  513. <button
  514. onClick={() => navigate('/step3')}
  515. className={`text-sm font-bold uppercase tracking-wider flex items-center justify-center gap-2 mx-auto group ${isDark ? 'text-cyan-400 hover:text-cyan-300' : 'text-cyan-600 hover:text-cyan-700'}`}
  516. >
  517. {t.cards.devLink} <ArrowRight className="w-4 h-4 transition-transform group-hover:translate-x-1" />
  518. </button>
  519. </div>
  520. </div>
  521. </section>
  522. {/* Footer / Contact */}
  523. <section id="contact" className={`py-24 px-6 border-t ${isDark ? 'bg-stone-900 border-stone-800' : 'bg-[#FAFAFA] border-stone-200'}`}>
  524. <div className="max-w-2xl mx-auto text-center">
  525. <Feather className={`w-8 h-8 mx-auto mb-6 ${isDark ? 'text-stone-600' : 'text-stone-300'}`} />
  526. <h2 className="text-2xl font-serif font-bold mb-8">{t.contact.title}</h2>
  527. <p className={`mb-10 ${isDark ? 'text-stone-400' : 'text-stone-600'}`}>
  528. {t.contact.description}
  529. </p>
  530. <div className="flex flex-col sm:flex-row gap-4 mb-4">
  531. <input
  532. type="email"
  533. placeholder={t.contact.placeholderEmail}
  534. value={email}
  535. onChange={(e) => setEmail(e.target.value)}
  536. disabled={status === 'loading' || status === 'success'}
  537. className={`flex-1 px-4 py-3 rounded-lg border outline-none focus:ring-1 focus:ring-stone-400 transition-all ${isDark ? 'bg-stone-800 border-stone-700 text-stone-200' : 'bg-white border-stone-200 text-stone-800'}`}
  538. />
  539. <button
  540. onClick={handleEmailSubmit}
  541. disabled={status === 'loading' || status === 'success'}
  542. className={`px-8 py-3 rounded-lg font-bold transition-all disabled:opacity-50 disabled:cursor-not-allowed ${isDark ? 'bg-stone-100 text-stone-900 hover:bg-white' : 'bg-stone-900 text-white hover:bg-stone-800'}`}
  543. >
  544. {status === 'loading' ? '发送中...' : t.contact.submit}
  545. </button>
  546. </div>
  547. {/* Status Message */}
  548. {message && (
  549. <div className={`mb-12 text-sm font-medium ${status === 'success' ? 'text-green-500' : 'text-red-500'}`}>
  550. {message}
  551. </div>
  552. )}
  553. {!message && <div className="mb-16"></div>}
  554. <div className={`text-xs leading-loose pt-12 border-t ${isDark ? 'border-stone-800 text-stone-600' : 'border-stone-200 text-stone-400'}`}>
  555. {/* The Original Letter Links */}
  556. <div className="mb-4 flex flex-col items-center gap-2">
  557. {/* Letter to Players -> Letters.tsx -> /letters */}
  558. <a
  559. href="/letters"
  560. onClick={(e) => { e.preventDefault(); navigate('/letters'); }}
  561. className="inline-flex items-center gap-2 hover:underline decoration-stone-400 underline-offset-4 cursor-pointer"
  562. >
  563. <BookOpen className="w-3 h-3" />
  564. {t.contact.footerLetter}
  565. </a>
  566. {/* Shareholder Letter -> PDF Download */}
  567. <a
  568. href="/ltr/20250529ltr.pdf"
  569. target="_blank"
  570. rel="noopener noreferrer"
  571. className="inline-flex items-center gap-2 hover:underline decoration-stone-400 underline-offset-4 cursor-pointer"
  572. >
  573. <BookOpen className="w-3 h-3" />
  574. {t.contact.footerShareholder}
  575. </a>
  576. </div>
  577. <p>{t.contact.footerNote}</p>
  578. <p className="mt-4">{t.contact.copyright}</p>
  579. </div>
  580. </div>
  581. </section >
  582. </div >
  583. );
  584. };
  585. export default SimpleHome;