import { state } from './data.js'; import { RegistrationWizard, AppPages } from './components.js'; const DOM = { onboarding: document.getElementById('onboarding'), wizardContent: document.getElementById('wizard-content'), mainContent: document.getElementById('main-content'), pageRender: document.getElementById('page-render'), bottomNav: document.getElementById('bottom-nav'), musicToggle: document.getElementById('music-toggle'), bgMusic: document.getElementById('bg-music'), musicDisc: document.getElementById('music-disc'), profileBtn: document.getElementById('profile-btn') }; function initStars() { const starContainer = document.getElementById('stars'); starContainer.innerHTML = ''; for (let i = 0; i < 60; i++) { const star = document.createElement('div'); star.className = 'star'; const size = Math.random() * 3 + 1; const xMove = (Math.random() - 0.5) * 100; const yMove = (Math.random() - 0.5) * 100; const duration = 15 + Math.random() * 20; const delay = Math.random() * -20; const opacity = 0.2 + Math.random() * 0.5; star.style.width = `${size}px`; star.style.height = `${size}px`; star.style.left = `${Math.random() * 100}%`; star.style.top = `${Math.random() * 100}%`; star.style.setProperty('--x', `${xMove}px`); star.style.setProperty('--y', `${yMove}px`); star.style.setProperty('--duration', `${duration}s`); star.style.setProperty('--opacity', opacity); star.style.animationDelay = `${delay}s`; starContainer.appendChild(star); } } function updateWizard() { DOM.wizardContent.innerHTML = `
${RegistrationWizard.renderStep(state.onboardingStep, state.user)}
${[0, 1, 2, 3, 4].map(i => `
`).join('')}
`; lucide.createIcons(); document.getElementById('next-step').addEventListener('click', () => { saveCurrentStepData(); if (state.onboardingStep < 4) { state.onboardingStep++; gsap.fromTo('#wizard-content > div:first-child', { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out" }); updateWizard(); } else { completeOnboarding(); } }); } function saveCurrentStepData() { const s = state.onboardingStep; if (s === 0) { state.user.nickname = document.getElementById('nickname').value; state.user.gender = document.getElementById('gender').value; state.user.zodiac = document.getElementById('zodiac').value; state.user.mbti = document.getElementById('mbti').value; state.user.hobbies = document.getElementById('hobbies').value.split(',').map(v => v.trim()).filter(v => v); } else if (s === 1) { state.user.childhood = document.getElementById('childhood').value; state.user.childhoodDate = document.getElementById('childhood-date').value; } else if (s === 2) { state.user.happyMoment = document.getElementById('happy-moment').value; state.user.happyDate = document.getElementById('happy-date').value; } else if (s === 3) { state.user.lowPoint = document.getElementById('low-point').value; state.user.lowDate = document.getElementById('low-date').value; } else if (s === 4) { state.user.aspirations = document.getElementById('aspirations').value; } } function completeOnboarding() { gsap.to(DOM.onboarding, { opacity: 0, duration: 1.5, ease: "power3.inOut", onComplete: () => { DOM.onboarding.style.display = 'none'; DOM.mainContent.style.display = 'flex'; DOM.bottomNav.style.display = 'flex'; switchTab('record'); } }); } function switchTab(tab) { document.querySelectorAll('.nav-item').forEach(el => { el.classList.toggle('active', el.dataset.tab === tab); }); let content = ""; if (tab === 'record') content = AppPages.record(state.events); if (tab === 'script') content = AppPages.script(state.scripts, state.isGenerating, state.scriptConfig, state.npcConfig, state.user, state.customPersonas); if (tab === 'path') content = AppPages.path(state.currentPath); if (tab === 'profile') content = AppPages.profile(state.user); DOM.pageRender.innerHTML = content; lucide.createIcons(); if (tab === 'record') { document.getElementById('save-event').addEventListener('click', handleSaveEvent); } if (tab === 'script') { document.getElementById('gen-script')?.addEventListener('click', handleGenerateScript); document.getElementById('edit-name')?.addEventListener('input', (e) => state.user.nickname = e.target.value); document.getElementById('edit-zodiac')?.addEventListener('change', (e) => state.user.zodiac = e.target.value); document.getElementById('edit-mbti')?.addEventListener('change', (e) => state.user.mbti = e.target.value); document.getElementById('edit-job')?.addEventListener('input', (e) => state.user.profession = e.target.value); document.getElementById('add-persona-btn')?.addEventListener('click', () => { const name = document.getElementById('npc-name').value; const role = document.getElementById('npc-role').value; if (name) { state.customPersonas.push({ name, role, id: Date.now() }); switchTab('script'); } }); document.querySelectorAll('.delete-persona-btn').forEach(btn => { btn.addEventListener('click', (e) => { const idx = e.currentTarget.dataset.idx; state.customPersonas.splice(idx, 1); switchTab('script'); }); }); document.getElementById('npc-name')?.addEventListener('input', (e) => state.npcConfig.name = e.target.value); document.getElementById('npc-role')?.addEventListener('change', (e) => state.npcConfig.role = e.target.value); document.getElementById('npc-relation')?.addEventListener('change', (e) => state.npcConfig.relation = e.target.value); document.getElementById('npc-desc')?.addEventListener('input', (e) => state.npcConfig.desc = e.target.value); document.querySelectorAll('.style-btn').forEach(btn => { btn.addEventListener('click', () => { state.scriptConfig.style = btn.dataset.val; switchTab('script'); }); }); document.querySelectorAll('.length-btn').forEach(btn => { btn.addEventListener('click', () => { state.scriptConfig.length = btn.dataset.val; switchTab('script'); }); }); document.querySelectorAll('.select-script').forEach(btn => { btn.addEventListener('click', (e) => { const id = e.currentTarget.dataset.id; state.currentPath = state.scripts.find(s => s.id == id); switchTab('path'); }); }); } } function handleSaveEvent() { const title = document.getElementById('event-title').value; const time = document.getElementById('event-time').value; const content = document.getElementById('event-content').value; if (!title || !content) return; const newEvent = { id: Date.now(), title, time: time || new Date().toISOString().split('T')[0], content, aiReply: "星河守望者正在解读这段紫色波频...", isNew: true }; state.events.unshift(newEvent); switchTab('record'); setTimeout(() => { const fullReply = `这段记忆碎片在星海中漾起涟漪。你在${title}中展现的特质,正在重新定义你人生OS的底层代码。继续保持这份觉知。`; state.events[0].aiReply = fullReply; state.events[0].isNew = false; switchTab('record'); }, 1500); } function handleGenerateScript() { const theme = document.getElementById('script-theme').value; if (!theme) return; if (state.isGenerating) return; state.isGenerating = true; switchTab('script'); setTimeout(() => { const { name, role, relation, desc } = state.npcConfig; const npcFrag = name ? `,在 ${name}(你的${role},关系:${relation})的陪伴下,` : ","; const script = { id: Date.now(), title: `《${theme}》· 星源篇`, summary: `基于你(${state.user.nickname},一名${state.user.profession})过往的紫气东来,在${state.scriptConfig.style}的世界观中${npcFrag}你将重新定义自我。${desc ? '命运齿轮已然转动:' + desc : ''}`, persona: state.user.mbti || "追光者", steps: [ { task: "紫微入命", desc: `在"${theme}"的意志中开启新的人生循环。`, done: true }, { task: "能量共振", desc: name ? `与 ${name} 达成灵魂契约。` : "在孤独中寻找真理,掌握世界的运行法则。", done: true }, { task: "代码重写", desc: "在最为艰难的时刻,将过去的所有记录化作突围的力量。", done: false }, { task: "最终归宿", desc: "达成人生OS的最高成就,实现与理想自我的合一。", done: false } ] }; state.scripts.unshift(script); state.isGenerating = false; switchTab('script'); }, 2500); } DOM.musicToggle.addEventListener('click', () => { if (state.isPlaying) { DOM.bgMusic.pause(); DOM.musicDisc.classList.remove('animate-spin-slow'); DOM.musicToggle.classList.add('opacity-40'); } else { DOM.bgMusic.play(); DOM.musicDisc.classList.add('animate-spin-slow'); DOM.musicToggle.classList.remove('opacity-40'); } state.isPlaying = !state.isPlaying; }); DOM.bottomNav.addEventListener('click', (e) => { const btn = e.target.closest('button'); if (btn) switchTab(btn.dataset.tab); }); DOM.profileBtn.addEventListener('click', () => switchTab('profile')); initStars(); updateWizard(); lucide.createIcons();