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();