v0.5.2: offline report + tab UI + persist race fix

- New: Offline earnings report dialog (welcome back popup with gain/duration/rate/progress)
  - src/lib/game/offlineReport.ts: module-level store + custom event
  - src/components/game/OfflineReportDialog.tsx: Radix Dialog UI
  - gameStore.init: setPendingOfflineReport before set()
- Fix: useGameLoop waits for persist.hasHydrated() before init
  - Root cause: Zustand persist rehydrate is async (Promise.resolve wrapper)
  - Before fix: init read INITIAL_STATE (lastTick=undefined), skipped offline branch
  - After fix: init waits for rehydrate, correctly reads saved lastTick
- UI: Tab bar redesign with per-tab accent colors + flex-col layout
- Version: v0.5 -> v0.5.2
This commit is contained in:
2026-06-23 17:04:28 +00:00
parent bd28219b65
commit 296c609479
5 changed files with 273 additions and 33 deletions
+46
View File
@@ -0,0 +1,46 @@
// 回响星核 / Echo Nexus — 离线收益报告(v0.5.2
// 模块级存储 + 自定义事件通知 UI,不污染 GameState
export interface OfflineReport {
elapsedSec: number; // 离线秒数(已 cap
rawElapsedSec: number; // 实际离线秒数(未 cap
gain: number; // 获得晶体
rate: number; // 离线时产能 /s
eff: number; // 离线效率 0-1
capped: boolean; // 是否触达 8h 上限
crystalsBefore: number; // 补发前晶体
crystalsAfter: number; // 补发后晶体
crystalCap: number; // 仓库上限
}
let pending: OfflineReport | null = null;
export function setPendingOfflineReport(r: OfflineReport) {
pending = r;
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("echo-nexus-offline-report"));
}
}
export function getPendingOfflineReport(): OfflineReport | null {
return pending;
}
export function consumeOfflineReport(): OfflineReport | null {
const r = pending;
pending = null;
return r;
}
/** 格式化时长为中文 */
export function formatDuration(sec: number): string {
if (sec < 60) return `${Math.floor(sec)}`;
const m = Math.floor(sec / 60);
if (m < 60) return `${m}分钟`;
const h = Math.floor(m / 60);
const remM = m % 60;
if (h < 24) return remM > 0 ? `${h}小时${remM}` : `${h}小时`;
const d = Math.floor(h / 24);
const remH = h % 24;
return remH > 0 ? `${d}${remH}小时` : `${d}`;
}