import React, { useState, useEffect } from 'react'; import { Sparkles, Scroll, RefreshCcw, Star, MapPin, Hourglass, User, Info, BookOpen, Skull, Globe } from 'lucide-react'; export default function App() { const [step, setStep] = useState('input'); // input, loading, result const [formData, setFormData] = useState({ name: '', gender: 'male', birthDate: '', birthTime: '', birthPlace: '', }); const [result, setResult] = useState(null); const [loadingText, setLoadingText] = useState('正在連結阿卡西紀錄...'); // 模擬載入過程的神秘語句 - 加入更多歷史考據感 const loadingMessages = [ "正在檢索《史記》與各國編年史...", "正在分析歷史上的離奇死因...", "正在比對古代鹽商與皇室名冊...", "計算靈魂質量與業力...", "定位時空座標:西元前...", "解鎖塵封的記憶..." ]; // 資料庫:年代 (擴充版) const eras = [ { name: "唐朝盛世", period: "西元 618 - 907 年", desc: "萬國來朝,長安城的酒香與詩歌飄散在空氣中,是一個極度開放與自信的時代。" }, { name: "維多利亞時代", period: "西元 1837 - 1901 年", desc: "工業革命的煙霧籠罩倫敦,紳士與貧民窟並存,理性與神秘主義同時興盛。" }, { name: "古埃及新王國", period: "西元前 1550 - 1069 年", desc: "底比斯的黃金時代,對死後世界的重視達到巔峰,祭司掌握著至高權力。" }, { name: "日本戰國時代", period: "西元 1467 - 1615 年", desc: "下剋上的亂世,武士刀與茶道並存,稍有不慎便會身首異處。" }, { name: "文藝復興佛羅倫斯", period: "西元 15 世紀", desc: "梅迪奇家族資助著藝術家,人性的光輝試圖衝破中世紀的黑暗。" }, { name: "法國大革命前夕", period: "西元 1789 年前", desc: "凡爾賽宮的奢靡達到了頂點,而巴黎街頭的怒火正在積蓄。" }, { name: "古希臘雅典", period: "西元前 5 世紀", desc: "蘇格拉底在廣場辯論,民主制度初見雛形,哲學與肉體的崇拜。" }, { name: "民國初年上海灘", period: "西元 1920 年代", desc: "十里洋場,幫派、軍閥與外國租界錯綜複雜,機會與死亡只有一線之隔。" }, { name: "北宋汴京", period: "西元 960 - 1127 年", desc: "商業高度發達,夜市燈火通明,重文輕武導致繁華背後隱藏著外患危機。" }, { name: "加勒比海盜黃金期", period: "西元 1650 - 1730 年", desc: "無政府的海洋,自由與掠奪的樂園,蘭姆酒與火藥味混合的年代。" } ]; // 資料庫:身份 (大幅擴充,加入搜尋到的歷史職業) const identities = [ { title: "私鹽販子", type: "wealth", desc: "從事古代利潤最高也最危險的行業,富可敵國但隨時可能被官府抄家。" }, { title: "不得志的落第秀才", type: "intellect", desc: "滿腹經綸卻屢試不第,最終成為了驚動天下的幕後謀士(如左宗棠般的大器晚成)。" }, { title: "瘋狂畫家", type: "art", desc: "為了追求極致的藝術,不惜解剖屍體或直視烈日,被世人視為瘋子。" }, { title: "短命皇帝", type: "status", desc: "雖登大位,但身處權力風暴中心,每日活在被毒殺與政變的恐懼中。" }, { title: "長壽太監", type: "survival", desc: "看盡宮廷鬥爭,雖然身體殘缺,卻比所有主子都活得久,掌握著無數秘密。" }, { title: "邊疆和親公主", type: "tragedy", desc: "為了國家的和平,遠嫁異域,終其一生未能再見故鄉一面。" }, { title: "神祕煉金術士", type: "mystic", desc: "在地下室試圖將鉛變成金,卻意外發現了化學的奧秘。" }, { title: "維京狂戰士", type: "strength", desc: "相信戰死沙場才能進入英靈殿,戰鬥時會進入無痛覺的狂暴狀態。" }, { title: "絲路駱駝客", type: "adventure", desc: "行走在長安與羅馬之間,精通多國語言,是文化交流的地下媒介。" }, { title: "天橋下的說書人", type: "speech", desc: "憑藉一張嘴,能讓市井小民哭笑不得,掌握著民間輿論的風向。" }, { title: "皇家試毒官", type: "danger", desc: "每一餐都是豪賭,雖然享用著御膳,卻不知能否見到明天的太陽。" }, { title: "修道院抄寫員", type: "patience", desc: "一生在昏暗的燭光下抄寫古籍,守護著文明的火種。" } ]; // 資料庫:死因 (加入搜尋到的離奇真實死因) const deaths = [ "因為看到荒謬的事物,大笑不止導致心臟驟停(史稱『致命的歡鬧』)", "為了追求長生不老,長期服用含有水銀的丹藥而中毒", "在一次豪華宴會中,因為消化不良加上過度歡愉而暴斃(參考國王馬丁一世)", "被自己發明的飛行裝置摔死", "因為太過富有,被嫉妒的親戚合謀在睡夢中悶死", "在戰場上毫髮無傷,卻在凱旋歸來時被慶祝的煙火炸死", "為了證明自己的醫術,親身試吃劇毒草藥而亡", "平靜地老死,但在遺囑中透露了震驚皇室的秘密", "因為一首諷刺朝政的詩,被皇帝賜死", "看書時太過入迷,忘記吃飯喝水,最終體力不支倒在書堆中" ]; // 資料庫:靈魂課題 (新增區塊) const soulTasks = [ { title: "學會示弱", desc: "前世的你太過逞強,習慣獨自承擔一切。今生你需要學習依賴他人,展現脆弱並不可恥。" }, { title: "建立界線", desc: "前世的你為了討好權貴或他人,失去了自我。今生你的課題是學會說『不』,找回自己的價值。" }, { title: "放下執著", desc: "前世你對金錢或權力有極深的執念,導致孤獨終老。今生你需要學習分享,體驗無條件的愛。" }, { title: "勇敢表達", desc: "前世你因言獲罪或被迫沉默。今生你擁有自由的喉嚨,任務是大聲說出你的真理。" }, { title: "接納平凡", desc: "前世你身處高位或極度戲劇化。今生你需要學習在平淡的日常柴米油鹽中,找到內心的平靜。" }, { title: "原諒背叛", desc: "前世你帶著被親信背叛的恨意離世。今生的課題是寬恕,放過他人其實是放過你自己。" } ]; // 輔助函數:計算生命靈數 (1-9) const calculateLifePathNumber = (dateString) => { if (!dateString) return 5; const digits = dateString.replace(/-/g, '').split('').map(Number); let sum = digits.reduce((a, b) => a + b, 0); while (sum > 9) { const tempDigits = sum.toString().split('').map(Number); sum = tempDigits.reduce((a, b) => a + b, 0); } return sum; }; // 輔助函數:字串雜湊 const stringHash = (str) => { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; } return Math.abs(hash); }; // 輔助函數:獲取時辰 const getShichen = (time) => { if (!time) return "未知時辰"; const hour = parseInt(time.split(':')[0], 10); if (hour >= 23 || hour < 1) return "子時 (23:00-01:00) - 靈性與直覺"; if (hour >= 1 && hour < 3) return "丑時 (01:00-03:00) - 毅力與沈穩"; if (hour >= 3 && hour < 5) return "寅時 (03:00-05:00) - 行動力與開創"; if (hour >= 5 && hour < 7) return "卯時 (05:00-07:00) - 機智與圓融"; if (hour >= 7 && hour < 9) return "辰時 (07:00-09:00) - 自信與尊貴"; if (hour >= 9 && hour < 11) return "巳時 (09:00-11:00) - 洞察與敏銳"; if (hour >= 11 && hour < 13) return "午時 (11:00-13:00) - 熱情與光耀"; if (hour >= 13 && hour < 15) return "未時 (13:00-15:00) - 優雅與和平"; if (hour >= 15 && hour < 17) return "申時 (15:00-17:00) - 多變與聰慧"; if (hour >= 17 && hour < 19) return "酉時 (17:00-19:00) - 美感與細節"; if (hour >= 19 && hour < 21) return "戌時 (19:00-21:00) - 忠誠與守護"; if (hour >= 21 && hour < 23) return "亥時 (21:00-23:00) - 豐富與包容"; return "未知時辰"; }; const handleGenerate = () => { if (!formData.name || !formData.birthDate || !formData.birthTime || !formData.birthPlace) { alert("請填寫所有欄位(包含出生地)以獲得準確的靈魂讀取"); return; } setStep('loading'); let msgIndex = 0; const interval = setInterval(() => { setLoadingText(loadingMessages[msgIndex % loadingMessages.length]); msgIndex++; }, 600); setTimeout(() => { clearInterval(interval); generateResult(); setStep('result'); }, 3500); }; const generateResult = () => { const lifePath = calculateLifePathNumber(formData.birthDate); const nameSeed = stringHash(formData.name); const placeSeed = stringHash(formData.birthPlace); const yearSeed = parseInt(formData.birthDate.split('-')[0]); // 將出生地加入總種子運算,影響結果 const totalSeed = nameSeed + lifePath + yearSeed + placeSeed; const month = parseInt(formData.birthDate.split('-')[1]); const eraIndex = totalSeed % eras.length; const era = eras[eraIndex]; const identityIndex = (totalSeed + month) % identities.length; const identity = identities[identityIndex]; const deathIndex = (nameSeed + placeSeed + month) % deaths.length; // 計算靈魂課題 const taskIndex = (lifePath + placeSeed + month) % soulTasks.length; const stats = { intelligence: (totalSeed * 13 % 40) + 60, charisma: (nameSeed * 7 % 40) + 60, strength: (lifePath * 11 % 40) + 60, luck: (month * 17 % 40) + 60, spirituality: (yearSeed * 3 % 40) + 60 }; setResult({ era, identity, death: deaths[deathIndex], soulTask: soulTasks[taskIndex], shichen: getShichen(formData.birthTime), lifePath, stats, story: `在${era.name},你是一名${identity.title}。${era.desc}你性格${lifePath % 2 === 0 ? "內斂深沉,喜歡在暗處觀察局勢" : "熱情奔放,總是成為人群的焦點"}。${identity.desc}` }); }; return (
{/* 背景裝飾 */}
{/* Header */}

靈魂迴響 2.1

基於歷史數據庫的前世解碼

{/* INPUT STEP */} {step === 'input' && (
setFormData({...formData, name: e.target.value})} placeholder="請輸入真實姓名" className="w-full bg-slate-900/50 border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-purple-500/50 transition-all text-slate-200 placeholder:text-slate-600" />
setFormData({...formData, birthPlace: e.target.value})} placeholder="城市或國家 (影響靈魂座標)" className="w-full bg-slate-900/50 border border-slate-700 rounded-xl px-4 py-3 pl-10 focus:outline-none focus:ring-2 focus:ring-purple-500/50 transition-all text-slate-200 placeholder:text-slate-600" />
setFormData({...formData, birthTime: e.target.value})} className="w-full bg-slate-900/50 border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-purple-500/50 transition-all text-slate-200" />
setFormData({...formData, birthDate: e.target.value})} className="w-full bg-slate-900/50 border border-slate-700 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-purple-500/50 transition-all text-slate-200" />

*系統已連接至擴充歷史資料庫,包含罕見職業與特殊死因

)} {/* LOADING STEP */} {step === 'loading' && (

{loadingText}

)} {/* RESULT STEP */} {step === 'result' && result && (
{/* 主要卡片 */}
Your Past Life

{result.identity.title}

{result.era.name} · {result.era.period}

{result.story}

{/* 靈魂課題 (新增) */}
今生靈魂課題

{result.soulTask.title}

{result.soulTask.desc}

{/* 詳細資訊 Grid */}
出生時辰

{result.shichen}

生命靈數

數字 {result.lifePath}

{/* 死因 */}
前世終章 (歷史數據庫)

"{result.death}"

{/* 屬性條 */}

靈魂屬性殘留

{[ { label: "靈性", val: result.stats.spirituality, color: "bg-purple-500" }, { label: "魅力", val: result.stats.charisma, color: "bg-pink-500" }, { label: "智慧", val: result.stats.intelligence, color: "bg-blue-500" }, { label: "力量", val: result.stats.strength, color: "bg-amber-500" }, ].map((stat, idx) => (
{stat.label}
{Math.floor(stat.val)}
))}
)}
); }