import { useEffect, useState, type CSSProperties } from 'react'; import type { AdventureLogEntry, EquipmentItem, HeroQuest, HeroState } from '../game/types'; import { EquipmentPaperDoll } from './EquipmentPaperDoll'; import { InventoryGrid } from './InventoryGrid'; import { HeroStatsContent } from './HeroPanel'; import { AdventureLogEntries } from './AdventureLog'; import { QuestLogList } from './QuestLog'; import { useT, useLocale, type Locale } from '../i18n'; export type HeroSheetTab = 'stats' | 'character' | 'inventory' | 'journal' | 'quests' | 'settings'; const overlay: CSSProperties = { position: 'fixed', inset: 0, zIndex: 800, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 12, pointerEvents: 'auto', }; const backdrop: CSSProperties = { position: 'absolute', inset: 0, backgroundColor: 'rgba(0, 0, 0, 0.55)', backdropFilter: 'blur(4px)', }; const panel: CSSProperties = { position: 'relative', width: '100%', maxWidth: 420, height: 'min(88vh, 640px)', maxHeight: 'min(88vh, 640px)', display: 'flex', flexDirection: 'column', borderRadius: 14, border: '1px solid rgba(255, 255, 255, 0.12)', backgroundColor: 'rgba(12, 14, 22, 0.94)', boxShadow: '0 12px 48px rgba(0,0,0,0.55)', overflow: 'hidden', }; const header: CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 12px', borderBottom: '1px solid rgba(255,255,255,0.08)', flexShrink: 0, }; const titleStyle: CSSProperties = { fontSize: 15, fontWeight: 700, color: '#e8e8e8', }; const closeBtn: CSSProperties = { background: 'none', border: 'none', color: '#888', fontSize: 22, cursor: 'pointer', padding: '2px 8px', lineHeight: 1, }; const tabsRow: CSSProperties = { display: 'flex', borderBottom: '1px solid rgba(255,255,255,0.08)', flexShrink: 0, }; const tabBtn = (active: boolean): CSSProperties => ({ flex: 1, padding: '8px 2px', fontSize: 9, fontWeight: 700, border: 'none', cursor: 'pointer', fontFamily: 'inherit', textTransform: 'uppercase', letterSpacing: 0.4, background: active ? 'rgba(80, 120, 200, 0.22)' : 'transparent', color: active ? '#c8d8ff' : '#778', borderBottom: active ? '2px solid #6a9eef' : '2px solid transparent', WebkitTapHighlightColor: 'transparent', }); const body: CSSProperties = { flex: 1, minHeight: 0, overflowY: 'auto', padding: '12px 12px 16px', fontSize: 12, color: '#ccc', WebkitOverflowScrolling: 'touch', }; const goldBar: CSSProperties = { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, padding: '8px 10px', borderRadius: 8, background: 'rgba(255, 215, 0, 0.08)', border: '1px solid rgba(255, 215, 0, 0.2)', color: '#ffd700', fontWeight: 700, fontSize: 14, }; interface HeroSheetModalProps { open: boolean; onClose: () => void; initialTab?: HeroSheetTab; hero: HeroState; nowMs: number; equipment: Record; logEntries: AdventureLogEntry[]; quests: HeroQuest[]; onQuestClaim: (heroQuestId: number) => void; onQuestAbandon: (heroQuestId: number) => void; /** Disable claim while hero is dead (HP 0 / death phase). */ questClaimDisabled?: boolean; } export function HeroSheetModal({ open, onClose, initialTab = 'stats', hero, nowMs, equipment, logEntries, quests, onQuestClaim, onQuestAbandon, questClaimDisabled = false, }: HeroSheetModalProps) { const [tab, setTab] = useState(initialTab); const tr = useT(); const { locale, setLocale } = useLocale(); useEffect(() => { if (open) setTab(initialTab); }, [open, initialTab]); useEffect(() => { if (!open) return; const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [open, onClose]); if (!open) return null; return (
{tr.hero} ยท {tr.level}.{hero.level}
{tab === 'stats' && } {tab === 'character' && } {tab === 'inventory' && ( <>
{'\uD83E\uDE99'} {hero.gold.toLocaleString()} {tr.gold.toLowerCase()}
)} {tab === 'journal' && } {tab === 'quests' && ( )} {tab === 'settings' && ( )}
); } // ---- Settings Tab ---- const settingRow: CSSProperties = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 0', borderBottom: '1px solid rgba(255,255,255,0.06)', }; const langBtn = (active: boolean): CSSProperties => ({ padding: '6px 16px', borderRadius: 6, border: active ? '2px solid #ffd700' : '1px solid rgba(255,255,255,0.15)', background: active ? 'rgba(255, 215, 0, 0.15)' : 'rgba(255,255,255,0.04)', color: active ? '#ffd700' : '#aaa', fontWeight: active ? 700 : 400, fontSize: 13, cursor: 'pointer', transition: 'all 150ms ease', }); interface SettingsContentProps { locale: Locale; setLocale: (l: Locale) => void; tr: { settings: string; language: string; english: string; russian: string }; } function SettingsContent({ locale, setLocale, tr }: SettingsContentProps) { return (
{tr.settings}
{tr.language}
); }