import { useEffect, useMemo, useState } from 'react'; import './App.css'; import { StoryEngine } from './engine/engine'; import { BRANCHES } from './engine/branches'; import { LocalStorageEventStore } from './engine/eventStore'; import { LocalStorageProgressStore } from './engine/progress'; import { SqliteEventStore, isTauriRuntime } from './engine/sqliteEventStore'; import type { Chapter } from './engine/types'; import { getJevClient } from './services/jev'; import { StoryPlayer } from './ui/StoryPlayer'; import { ConsentGate } from './ui/ConsentGate'; import { ReportPage } from './ui/report/ReportPage'; import chapter1 from '../content/chapters/chapter1.json'; import chapter2 from '../content/chapters/chapter2.json'; import chapter3 from '../content/chapters/chapter3.json'; const chapters = [chapter1, chapter2, chapter3] as Chapter[]; export default function App() { const [screen, setScreen] = useState<'story' | 'report'>('story'); // consent: unknown=查询中 / needed=待同意 / granted=已同意(事件存证命中,同意门只出现一次) const [consent, setConsent] = useState<'unknown' | 'needed' | 'granted'>('unknown'); // 引擎与存储整个会话只建一次;重玩走 engine.replay()(新 sessionId,旧事件保留) // 运行时选择:Tauri 原生端用 SQLite,浏览器 dev 用 localStorage(同一 append-only 接口) const { engine, store, jev, progress } = useMemo(() => { const store = isTauriRuntime() ? new SqliteEventStore() : new LocalStorageEventStore(); const jev = getJevClient(); const progress = new LocalStorageProgressStore(); return { engine: new StoryEngine(chapters, store, jev, undefined, progress, BRANCHES), store, jev, progress }; }, []); useEffect(() => { void (async () => { const ok = await engine.hasConsent(); // 同意门之后才恢复剧情进度(刷新/热更新前的断点) if (ok) await engine.restore(progress.load()); setConsent(ok ? 'granted' : 'needed'); })(); }, [engine, progress]); if (consent !== 'granted') { return (
{consent === 'needed' && ( { await engine.grantConsent(); setConsent('granted'); }} /> )}
); } return (
{screen === 'story' ? ( setScreen('report')} /> ) : ( { engine.replay('chapter1'); setScreen('story'); }} /> )}
); }