feat: partial UI redesign - TabBar, ManaDisplay, StatsTab sub-sections
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 42s

Design token migration:
- TabBar: replaced hardcoded colors/shadows with --bg-panel, --border-subtle,
  --font-display tokens. Removed rounded-full pills, added Cinzel font tracking.
- ManaDisplay: replaced bg-gray-900/text-blue-400 with --mana-raw, --bg-panel,
  element-specific --mana-* tokens. Updated progress bar styling.
- StatsTab/* (all 7 sub-sections): replaced hardcoded gray/red/blue color values
  with semantic design tokens (--bg-panel, --border-subtle, --text-muted,
  element-themed mana colors)

NOTE: This is a partial implementation. TASK-011 paused to address
foundational issues (missing types, duplicate stat functions) first.
See issue #14 for full context.
This commit is contained in:
2026-05-14 12:03:09 +02:00
parent ba231ac9dd
commit 3e5b634815
9 changed files with 228 additions and 237 deletions
+32 -16
View File
@@ -39,26 +39,37 @@ export function ManaDisplay({
.sort((a, b) => b[1].current - a[1].current); .sort((a, b) => b[1].current - a[1].current);
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardContent className="pt-4 space-y-3"> <CardContent className="pt-4 space-y-3">
{/* Raw Mana - Main Display */} {/* Raw Mana - Main Display */}
<div> <div>
<div className="flex items-baseline gap-1"> <div className="flex items-baseline gap-1">
<span className="text-3xl font-bold game-mono text-blue-400">{fmt(rawMana)}</span> <span className="text-3xl font-bold game-mono" style={{ color: 'var(--mana-raw)' }}>{fmt(rawMana)}</span>
<span className="text-sm text-gray-400">/ {fmt(maxMana)}</span> <span className="text-sm" style={{ color: 'var(--text-muted)' }}>/ {fmt(maxMana)}</span>
</div> </div>
<div className="text-xs text-gray-400"> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>
+{fmtDec(effectiveRegen)} mana/hr {meditationMultiplier > 1.01 && <span className="text-purple-400">({fmtDec(meditationMultiplier, 1)}x med)</span>} +{fmtDec(effectiveRegen)} mana/hr {meditationMultiplier > 1.01 && <span style={{ color: 'var(--mana-light)' }}>({fmtDec(meditationMultiplier, 1)}x med)</span>}
</div> </div>
</div> </div>
<Progress <Progress
value={(rawMana / maxMana) * 100} value={(rawMana / maxMana) * 100}
className="h-2 bg-gray-800" className="h-2 bg-[var(--bg-sunken)]"
style={{ '--progress-bg': 'var(--mana-raw)' } as React.CSSProperties}
/> />
<Button <Button
className={`w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 ${isGathering ? 'animate-pulse' : ''}`} className={`w-full transition-all text-[var(--font-display)] tracking-wider
${isGathering
? 'animate-gather-glow'
: 'hover:scale-[1.02]'}
`}
style={{
background: 'var(--mana-raw)',
border: '1px solid var(--border-accent)',
color: '#0C1020',
fontWeight: 600,
}}
onMouseDown={onGatherStart} onMouseDown={onGatherStart}
onMouseUp={onGatherEnd} onMouseUp={onGatherEnd}
onMouseLeave={onGatherEnd} onMouseLeave={onGatherEnd}
@@ -67,22 +78,23 @@ export function ManaDisplay({
> >
<Zap className="w-4 h-4 mr-2" /> <Zap className="w-4 h-4 mr-2" />
Gather +{clickMana} Mana Gather +{clickMana} Mana
{isGathering && <span className="ml-2 text-xs">(Holding...)</span>} {isGathering && <span className="ml-2 text-xs" style={{ opacity: 0.8 }}>(Holding...)</span>}
</Button> </Button>
{/* Elemental Mana Pools */} {/* Elemental Mana Pools */}
{unlockedElements.length > 0 && ( {unlockedElements.length > 0 && (
<div className="border-t border-gray-700 pt-3 mt-3"> <div className="border-t border-[var(--border-subtle)] pt-3 mt-3">
<button <button
onClick={() => setExpanded(!expanded)} onClick={() => setExpanded(!expanded)}
className="flex items-center justify-between w-full text-xs text-gray-400 hover:text-gray-300 mb-2" className="flex items-center justify-between w-full text-xs transition-colors"
style={{ color: 'var(--text-muted)' }}
> >
<span>Elemental Mana ({unlockedElements.length})</span> <span style={{ fontFamily: 'var(--font-display)', letterSpacing: '0.5px' }}>ELEMENTAL MANA ({unlockedElements.length})</span>
{expanded ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />} {expanded ? <ChevronUp className="w-3 h-3" /> : <ChevronDown className="w-3 h-3" />}
</button> </button>
{expanded && ( {expanded && (
<div className="grid grid-cols-2 gap-2"> <div className="grid grid-cols-2 gap-2 mt-2">
{unlockedElements.map(([id, state]) => { {unlockedElements.map(([id, state]) => {
const elem = ELEMENTS[id]; const elem = ELEMENTS[id];
if (!elem) return null; if (!elem) return null;
@@ -90,7 +102,11 @@ export function ManaDisplay({
return ( return (
<div <div
key={id} key={id}
className="p-2 rounded bg-gray-800/50 border border-gray-700" className="p-2 transition-all border rounded-sm"
style={{
background: 'var(--bg-sunken)/30',
borderColor: `${elem.color}30`,
}}
> >
<div className="flex items-center gap-1 mb-1"> <div className="flex items-center gap-1 mb-1">
<span style={{ color: elem.color }}>{elem.sym}</span> <span style={{ color: elem.color }}>{elem.sym}</span>
@@ -98,16 +114,16 @@ export function ManaDisplay({
{elem.name} {elem.name}
</span> </span>
</div> </div>
<div className="h-1.5 bg-gray-700 rounded-full overflow-hidden mb-1"> <div className="h-1.5 rounded-full overflow-hidden" style={{ background: 'var(--bg-void)' }}>
<div <div
className="h-full rounded-full transition-all" className="h-full transition-all rounded-full"
style={{ style={{
width: `${Math.min(100, (state.current / state.max) * 100)}%`, width: `${Math.min(100, (state.current / state.max) * 100)}%`,
backgroundColor: elem.color backgroundColor: elem.color
}} }}
/> />
</div> </div>
<div className="text-xs text-gray-400 game-mono"> <div className="text-xs game-mono" style={{ color: 'var(--text-muted)' }}>
{fmt(state.current)}/{fmt(state.max)} {fmt(state.current)}/{fmt(state.max)}
</div> </div>
</div> </div>
@@ -14,24 +14,24 @@ interface ActiveUpgradesSectionProps {
export function ActiveUpgradesSection({ selectedUpgrades }: ActiveUpgradesSectionProps) { export function ActiveUpgradesSection({ selectedUpgrades }: ActiveUpgradesSectionProps) {
if (selectedUpgrades.length === 0) { if (selectedUpgrades.length === 0) {
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-amber-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-light)] game-panel-title text-xs flex items-center gap-2">
<Star className="w-4 h-4" /> <Star className="w-4 h-4" />
Active Skill Upgrades (0) Active Skill Upgrades (0)
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-gray-500 text-sm">No skill upgrades selected yet. Level skills to 5 or 10 to choose upgrades.</div> <div style={{ color: 'var(--text-muted)' }} className="text-sm">No skill upgrades selected yet. Level skills to 5 or 10 to choose upgrades.</div>
</CardContent> </CardContent>
</Card> </Card>
); );
} }
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-amber-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-light)] game-panel-title text-xs flex items-center gap-2">
<Star className="w-4 h-4" /> <Star className="w-4 h-4" />
Active Skill Upgrades ({selectedUpgrades.length}) Active Skill Upgrades ({selectedUpgrades.length})
</CardTitle> </CardTitle>
@@ -39,26 +39,26 @@ export function ActiveUpgradesSection({ selectedUpgrades }: ActiveUpgradesSectio
<CardContent> <CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{selectedUpgrades.map(({ skillId, upgrade }) => ( {selectedUpgrades.map(({ skillId, upgrade }) => (
<div key={upgrade.id} className="p-2 rounded border border-amber-600/30 bg-amber-900/10"> <div key={upgrade.id} className="p-2 rounded transition-colors" style={{ border: '1px solid var(--mana-light)/30', background: 'var(--mana-light)/10' }}>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-amber-300 text-sm font-semibold">{upgrade.name}</span> <span style={{ color: 'var(--mana-light)' }} className="text-sm font-semibold">{upgrade.name}</span>
<Badge variant="outline" className="text-xs text-gray-400"> <Badge variant="outline" className="text-xs" style={{ color: 'var(--text-muted)', borderColor: 'var(--border-subtle)' }}>
{SKILLS_DEF[skillId]?.name || skillId} {SKILLS_DEF[skillId]?.name || skillId}
</Badge> </Badge>
</div> </div>
<div className="text-xs text-gray-400 mt-1">{upgrade.desc}</div> <div className="text-xs mt-1" style={{ color: 'var(--text-muted)' }}>{upgrade.desc}</div>
{upgrade.effect.type === 'multiplier' && ( {upgrade.effect.type === 'multiplier' && (
<div className="text-xs text-green-400 mt-1"> <div className="text-xs mt-1" style={{ color: 'var(--color-success)' }}>
+{Math.round((upgrade.effect.value! - 1) * 100)}% {upgrade.effect.stat} +{Math.round((upgrade.effect.value! - 1) * 100)}% {upgrade.effect.stat}
</div> </div>
)} )}
{upgrade.effect.type === 'bonus' && ( {upgrade.effect.type === 'bonus' && (
<div className="text-xs text-blue-400 mt-1"> <div className="text-xs mt-1" style={{ color: 'var(--mana-water)' }}>
+{upgrade.effect.value} {upgrade.effect.stat} +{upgrade.effect.value} {upgrade.effect.stat}
</div> </div>
)} )}
{upgrade.effect.type === 'special' && ( {upgrade.effect.type === 'special' && (
<div className="text-xs text-cyan-400 mt-1"> <div className="text-xs mt-1" style={{ color: 'var(--mana-crystal)' }}>
{upgrade.effect.specialDesc || 'Special effect active'} {upgrade.effect.specialDesc || 'Special effect active'}
</div> </div>
)} )}
@@ -68,4 +68,4 @@ export function ActiveUpgradesSection({ selectedUpgrades }: ActiveUpgradesSectio
</CardContent> </CardContent>
</Card> </Card>
); );
} }
@@ -24,9 +24,9 @@ export function CombatStatsSection({ activeSpellDef, pactMultiplier }: CombatSta
}); });
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-red-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-fire)] game-panel-title text-xs flex items-center gap-2">
<Swords className="w-4 h-4" /> <Swords className="w-4 h-4" />
Combat Stats Combat Stats
</CardTitle> </CardTitle>
@@ -35,50 +35,50 @@ export function CombatStatsSection({ activeSpellDef, pactMultiplier }: CombatSta
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Active Spell Base Damage:</span> <span style={{ color: 'var(--text-muted)' }}>Active Spell Base Damage:</span>
<span className="text-gray-200">{activeSpellDef?.dmg || 5}</span> <span style={{ color: 'var(--text-secondary)' }}>{activeSpellDef?.dmg || 5}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Combat Training Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Combat Training Bonus:</span>
<span className="text-red-300">+{(skills.combatTrain || 0) * 5}</span> <span style={{ color: 'var(--mana-fire)' }}>+{(skills.combatTrain || 0) * 5}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Arcane Fury Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Arcane Fury Multiplier:</span>
<span className="text-red-300">×{fmtDec(1 + (skills.arcaneFury || 0) * 0.1, 2)}</span> <span style={{ color: 'var(--mana-fire)' }}>×{fmtDec(1 + (skills.arcaneFury || 0) * 0.1, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Elemental Mastery:</span> <span style={{ color: 'var(--text-muted)' }}>Elemental Mastery:</span>
<span className="text-red-300">×{fmtDec(1 + (skills.elementalMastery || 0) * 0.15, 2)}</span> <span style={{ color: 'var(--mana-fire)' }}>×{fmtDec(1 + (skills.elementalMastery || 0) * 0.15, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Guardian Bane:</span> <span style={{ color: 'var(--text-muted)' }}>Guardian Bane:</span>
<span className="text-red-300">×{fmtDec(1 + (skills.guardianBane || 0) * 0.2, 2)} (vs guardians)</span> <span style={{ color: 'var(--mana-fire)' }}>×{fmtDec(1 + (skills.guardianBane || 0) * 0.2, 2)} (vs guardians)</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Critical Hit Chance:</span> <span style={{ color: 'var(--text-muted)' }}>Critical Hit Chance:</span>
<span className="text-amber-300">{((skills.precision || 0) * 5)}%</span> <span style={{ color: 'var(--mana-light)' }}>{((skills.precision || 0) * 5)}%</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Critical Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Critical Multiplier:</span>
<span className="text-amber-300">1.5x</span> <span style={{ color: 'var(--mana-light)' }}>1.5x</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Spell Echo Chance:</span> <span style={{ color: 'var(--text-muted)' }}>Spell Echo Chance:</span>
<span className="text-amber-300">{((skills.spellEcho || 0) * 10)}%</span> <span style={{ color: 'var(--mana-light)' }}>{((skills.spellEcho || 0) * 10)}%</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Pact Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Pact Multiplier:</span>
<span className="text-amber-300">×{fmtDec(pactMultiplier, 2)}</span> <span style={{ color: 'var(--mana-light)' }}>×{fmtDec(pactMultiplier, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2"> <div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span className="text-gray-300">Total Damage:</span> <span style={{ color: 'var(--text-secondary)' }}>Total Damage:</span>
<span className="text-red-400">{fmt(activeSpellDef ? activeSpellDef.dmg * pactMultiplier : 0)}</span> <span style={{ color: 'var(--mana-fire)' }}>{fmt(activeSpellDef ? activeSpellDef.dmg * pactMultiplier : 0)}</span>
</div> </div>
</div> </div>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
); );
} }
@@ -27,9 +27,9 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
}; };
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-green-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--color-success)] game-panel-title text-xs flex items-center gap-2">
<FlaskConical className="w-4 h-4" /> <FlaskConical className="w-4 h-4" />
Element Stats Element Stats
</CardTitle> </CardTitle>
@@ -38,40 +38,40 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Element Capacity:</span> <span style={{ color: 'var(--text-muted)' }}>Element Capacity:</span>
<span className="text-green-300">{elemMax}</span> <span style={{ color: 'var(--color-success)' }}>{elemMax}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Elem. Attunement Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Elem. Attunement Bonus:</span>
<span className="text-green-300">+{getElemAttunementBonus()}</span> <span style={{ color: 'var(--color-success)' }}>+{getElemAttunementBonus()}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Prestige Attunement:</span> <span style={{ color: 'var(--text-muted)' }}>Prestige Attunement:</span>
<span className="text-green-300">+{(prestigeUpgrades.elementalAttune || 0) * 25}</span> <span style={{ color: 'var(--color-success)' }}>+{(prestigeUpgrades.elementalAttune || 0) * 25}</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Unlocked Elements:</span> <span style={{ color: 'var(--text-muted)' }}>Unlocked Elements:</span>
<span className="text-green-300">{Object.values(elements || {}).filter((e: any) => e.unlocked).length} / {Object.keys(ELEMENTS).length}</span> <span style={{ color: 'var(--color-success)' }}>{Object.values(elements || {}).filter((e: any) => e.unlocked).length} / {Object.keys(ELEMENTS).length}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Elem. Crafting Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Elem. Crafting Bonus:</span>
<span className="text-green-300">×{fmtDec(1 + (skills.elemCrafting || 0) * 0.25, 2)}</span> <span style={{ color: 'var(--color-success)' }}>×{fmtDec(1 + (skills.elemCrafting || 0) * 0.25, 2)}</span>
</div> </div>
</div> </div>
</div> </div>
<Separator className="bg-gray-700 my-3" /> <Separator className="bg-[var(--border-subtle)] my-3" />
<div className="text-xs text-gray-400 mb-2">Elemental Mana Pools:</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Elemental Mana Pools:</div>
<div className="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-2"> <div className="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-2">
{Object.entries(elements) {Object.entries(elements)
.filter(([, state]: [string, any]) => state.unlocked) .filter(([, state]: [string, any]) => state.unlocked)
.map(([id, state]: [string, any]) => { .map(([id, state]: [string, any]) => {
const def = ELEMENTS[id]; const def = ELEMENTS[id];
return ( return (
<div key={id} className="p-2 rounded border border-gray-700 bg-gray-800/50 text-center"> <div key={id} className="p-2 rounded transition-colors" style={{ border: `1px solid ${def?.color}30`, background: 'var(--bg-sunken)/50', textAlign: 'center' }}>
<div className="text-lg">{def?.sym}</div> <div className="text-lg" style={{ color: def?.color }}>{def?.sym}</div>
<div className="text-xs text-gray-400">{state.current}/{state.max}</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>{state.current}/{state.max}</div>
</div> </div>
); );
})} })}
@@ -79,4 +79,4 @@ export function ElementStatsSection({ elemMax }: ElementStatsSectionProps) {
</CardContent> </CardContent>
</Card> </Card>
); );
} }
@@ -4,7 +4,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import { RotateCcw } from 'lucide-react'; import { RotateCcw } from 'lucide-react';
import { fmt } from '@/lib/game/stores'; import { fmt } from '@/lib/game/stores';
import { useCombatStore, usePrestigeStore, useManaStore } from '@/lib/game/stores'; import { useCombatStore, usePrestigeStore, useManaStore, useSkillStore } from '@/lib/game/stores';
export function LoopStatsSection() { export function LoopStatsSection() {
const spells = useCombatStore((s) => s.spells); const spells = useCombatStore((s) => s.spells);
@@ -20,49 +20,49 @@ export function LoopStatsSection() {
const totalSkillLevels = Object.values(skills || {}).reduce((a: number, b: number) => a + b, 0); const totalSkillLevels = Object.values(skills || {}).reduce((a: number, b: number) => a + b, 0);
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-purple-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-light)] game-panel-title text-xs flex items-center gap-2">
<RotateCcw className="w-4 h-4" /> <RotateCcw className="w-4 h-4" />
Loop Stats Loop Stats
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4"> <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-2xl font-bold text-amber-400 game-mono">{loopCount}</div> <div className="text-2xl font-bold text-[var(--mana-light)] game-mono">{loopCount}</div>
<div className="text-xs text-gray-400">Loops Completed</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Loops Completed</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-2xl font-bold text-purple-400 game-mono">{fmt(insight)}</div> <div className="text-2xl font-bold text-[var(--mana-crystal)] game-mono">{fmt(insight)}</div>
<div className="text-xs text-gray-400">Current Insight</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Current Insight</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-2xl font-bold text-blue-400 game-mono">{fmt(totalInsight)}</div> <div className="text-2xl font-bold text-[var(--mana-death)] game-mono">{fmt(totalInsight)}</div>
<div className="text-xs text-gray-400">Total Insight</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Total Insight</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-2xl font-bold text-green-400 game-mono">{maxFloorReached}</div> <div className="text-2xl font-bold text-[var(--color-success)] game-mono">{maxFloorReached}</div>
<div className="text-xs text-gray-400">Max Floor</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Max Floor</div>
</div> </div>
</div> </div>
<Separator className="bg-gray-700 my-3" /> <Separator className="bg-[var(--border-subtle)] my-3" />
<div className="grid grid-cols-2 md:grid-cols-4 gap-4"> <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-xl font-bold text-gray-300 game-mono">{spellsLearned}</div> <div className="text-xl font-bold text-[var(--text-secondary)] game-mono">{spellsLearned}</div>
<div className="text-xs text-gray-400">Spells Learned</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Spells Learned</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-xl font-bold text-gray-300 game-mono">{totalSkillLevels}</div> <div className="text-xl font-bold text-[var(--text-secondary)] game-mono">{totalSkillLevels}</div>
<div className="text-xs text-gray-400">Total Skill Levels</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Total Skill Levels</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-xl font-bold text-gray-300 game-mono">{fmt(totalManaGathered)}</div> <div className="text-xl font-bold text-[var(--text-secondary)] game-mono">{fmt(totalManaGathered)}</div>
<div className="text-xs text-gray-400">Total Mana Gathered</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Total Mana Gathered</div>
</div> </div>
<div className="p-3 bg-gray-800/50 rounded text-center"> <div className="p-3 bg-[var(--bg-sunken)]/50 rounded text-center">
<div className="text-xl font-bold text-gray-300 game-mono">{memorySlots}</div> <div className="text-xl font-bold text-[var(--text-secondary)] game-mono">{memorySlots}</div>
<div className="text-xs text-gray-400">Memory Slots</div> <div className="text-xs" style={{ color: 'var(--text-muted)' }}>Memory Slots</div>
</div> </div>
</div> </div>
</CardContent> </CardContent>
@@ -32,13 +32,13 @@ export function ManaStatsSection({
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades); const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
const getTierMultiplier = (skillId: string) => { const getTierMultiplier = (skillId: string) => {
return 1; // Simplified - import from skill-evolution in real implementation return 1;
}; };
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-blue-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-water)] game-panel-title text-xs flex items-center gap-2">
<Droplet className="w-4 h-4" /> <Droplet className="w-4 h-4" />
Mana Stats Mana Stats
</CardTitle> </CardTitle>
@@ -47,12 +47,12 @@ export function ManaStatsSection({
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Base Max Mana:</span> <span style={{ color: 'var(--text-muted)' }}>Base Max Mana:</span>
<span className="text-gray-200">100</span> <span style={{ color: 'var(--text-secondary)' }}>100</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Well Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Well Bonus:</span>
<span className="text-blue-300"> <span style={{ color: 'var(--mana-water)' }}>
{(() => { {(() => {
const mw = skillTiers?.manaWell || 1; const mw = skillTiers?.manaWell || 1;
const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell'; const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell';
@@ -63,34 +63,34 @@ export function ManaStatsSection({
</span> </span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Prestige Mana Well:</span> <span style={{ color: 'var(--text-muted)' }}>Prestige Mana Well:</span>
<span className="text-blue-300">+{fmt((prestigeUpgrades.manaWell || 0) * 500)}</span> <span style={{ color: 'var(--mana-water)' }}>+{fmt((prestigeUpgrades.manaWell || 0) * 500)}</span>
</div> </div>
{upgradeEffects.maxManaBonus > 0 && ( {upgradeEffects.maxManaBonus > 0 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Mana Bonus:</span> <span style={{ color: 'var(--mana-light)' }}>Upgrade Mana Bonus:</span>
<span className="text-amber-300">+{fmt(upgradeEffects.maxManaBonus)}</span> <span style={{ color: 'var(--mana-light)' }}>+{fmt(upgradeEffects.maxManaBonus)}</span>
</div> </div>
)} )}
{upgradeEffects.maxManaMultiplier > 1 && ( {upgradeEffects.maxManaMultiplier > 1 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Mana Multiplier:</span> <span style={{ color: 'var(--mana-light)' }}>Upgrade Mana Multiplier:</span>
<span className="text-amber-300">×{fmtDec(upgradeEffects.maxManaMultiplier, 2)}</span> <span style={{ color: 'var(--mana-light)' }}>×{fmtDec(upgradeEffects.maxManaMultiplier, 2)}</span>
</div> </div>
)} )}
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2"> <div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span className="text-gray-300">Total Max Mana:</span> <span style={{ color: 'var(--text-secondary)' }}>Total Max Mana:</span>
<span className="text-blue-400">{fmt(maxMana)}</span> <span style={{ color: 'var(--mana-water)' }}>{fmt(maxMana)}</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Base Regen:</span> <span style={{ color: 'var(--text-muted)' }}>Base Regen:</span>
<span className="text-gray-200">2/hr</span> <span style={{ color: 'var(--text-secondary)' }}>2/hr</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Flow Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Flow Bonus:</span>
<span className="text-blue-300"> <span style={{ color: 'var(--mana-water)' }}>
{(() => { {(() => {
const mf = skillTiers?.manaFlow || 1; const mf = skillTiers?.manaFlow || 1;
const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow'; const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow';
@@ -101,37 +101,37 @@ export function ManaStatsSection({
</span> </span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Spring Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Spring Bonus:</span>
<span className="text-blue-300">+{(skills.manaSpring || 0) * 2}/hr</span> <span style={{ color: 'var(--mana-water)' }}>+{(skills.manaSpring || 0) * 2}/hr</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Prestige Mana Flow:</span> <span style={{ color: 'var(--text-muted)' }}>Prestige Mana Flow:</span>
<span className="text-blue-300">+{fmtDec((prestigeUpgrades.manaFlow || 0) * 0.5)}/hr</span> <span style={{ color: 'var(--mana-water)' }}>+{fmtDec((prestigeUpgrades.manaFlow || 0) * 0.5)}/hr</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Temporal Echo:</span> <span style={{ color: 'var(--text-muted)' }}>Temporal Echo:</span>
<span className="text-blue-300">×{fmtDec(1 + (prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}</span> <span style={{ color: 'var(--mana-water)' }}>×{fmtDec(1 + (prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2"> <div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span className="text-gray-300">Base Regen:</span> <span style={{ color: 'var(--text-secondary)' }}>Base Regen:</span>
<span className="text-blue-400">{fmtDec(baseRegen, 2)}/hr</span> <span style={{ color: 'var(--mana-water)' }}>{fmtDec(baseRegen, 2)}/hr</span>
</div> </div>
{upgradeEffects.regenBonus > 0 && ( {upgradeEffects.regenBonus > 0 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Regen Bonus:</span> <span style={{ color: 'var(--mana-light)' }}>Upgrade Regen Bonus:</span>
<span className="text-amber-300">+{fmtDec(upgradeEffects.regenBonus, 2)}/hr</span> <span style={{ color: 'var(--mana-light)' }}>+{fmtDec(upgradeEffects.regenBonus, 2)}/hr</span>
</div> </div>
)} )}
{upgradeEffects.permanentRegenBonus > 0 && ( {upgradeEffects.permanentRegenBonus > 0 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-amber-400">Permanent Regen Bonus:</span> <span style={{ color: 'var(--mana-light)' }}>Permanent Regen Bonus:</span>
<span className="text-amber-300">+{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr</span> <span style={{ color: 'var(--mana-light)' }}>+{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr</span>
</div> </div>
)} )}
{upgradeEffects.regenMultiplier > 1 && ( {upgradeEffects.regenMultiplier > 1 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Regen Multiplier:</span> <span style={{ color: 'var(--mana-light)' }}>Upgrade Regen Multiplier:</span>
<span className="text-amber-300">×{fmtDec(upgradeEffects.regenMultiplier, 2)}</span> <span style={{ color: 'var(--mana-light)' }}>×{fmtDec(upgradeEffects.regenMultiplier, 2)}</span>
</div> </div>
)} )}
</div> </div>
@@ -139,36 +139,36 @@ export function ManaStatsSection({
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Click Mana Value:</span> <span style={{ color: 'var(--text-muted)' }}>Click Mana Value:</span>
<span className="text-purple-300">+{clickMana}</span> <span style={{ color: 'var(--mana-crystal)' }}>+{clickMana}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Tap Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Tap Bonus:</span>
<span className="text-purple-300">+{skills.manaTap || 0}</span> <span style={{ color: 'var(--mana-crystal)' }}>+{skills.manaTap || 0}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Surge Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Surge Bonus:</span>
<span className="text-purple-300">+{(skills.manaSurge || 0) * 3}</span> <span style={{ color: 'var(--mana-crystal)' }}>+{(skills.manaSurge || 0) * 3}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Overflow:</span> <span style={{ color: 'var(--text-muted)' }}>Mana Overflow:</span>
<span className="text-purple-300">×{fmtDec(1 + (skills.manaOverflow || 0) * 0.25, 2)}</span> <span style={{ color: 'var(--mana-crystal)' }}>×{fmtDec(1 + (skills.manaOverflow || 0) * 0.25, 2)}</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Meditation Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Meditation Multiplier:</span>
<span className={`font-semibold ${meditationMultiplier > 1.5 ? 'text-purple-400' : 'text-gray-300'}`}> <span className={`font-semibold ${meditationMultiplier > 1.5 ? 'text-[var(--mana-stellar)]' : 'text-[var(--text-secondary)]'}`}>
{fmtDec(meditationMultiplier, 2)}x {fmtDec(meditationMultiplier, 2)}x
</span> </span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Incursion Strength:</span> <span style={{ color: 'var(--text-muted)' }}>Incursion Strength:</span>
<span className="text-red-400">{Math.round(upgradeEffects.incursionStrength * 100)}%</span> <span style={{ color: 'var(--color-danger)' }}>{Math.round(upgradeEffects.incursionStrength * 100)}%</span>
</div> </div>
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2"> <div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span className="text-gray-300">Effective Regen:</span> <span style={{ color: 'var(--text-secondary)' }}>Effective Regen:</span>
<span className="text-green-400 font-semibold">{fmtDec(effectiveRegen, 2)}/hr</span> <span style={{ color: 'var(--color-success)' }} className="font-semibold">{fmtDec(effectiveRegen, 2)}/hr</span>
</div> </div>
</div> </div>
</div> </div>
@@ -177,67 +177,67 @@ export function ManaStatsSection({
upgradeEffects.hasDesperateWells || upgradeEffects.manaCascadeBonus > 0 || upgradeEffects.hasDesperateWells || upgradeEffects.manaCascadeBonus > 0 ||
upgradeEffects.manaWaterfallBonus > 0) && ( upgradeEffects.manaWaterfallBonus > 0) && (
<> <>
<div className="mt-3 mb-2"><span className="text-xs text-amber-400 game-panel-title">Special Effects</span></div> <div className="mt-3 mb-2"><span className="text-xs text-[var(--mana-light)] game-panel-title">Special Effects</span></div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{upgradeEffects.hasSteadyStream && ( {upgradeEffects.hasSteadyStream && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Steady Stream:</span> <span style={{ color: 'var(--text-secondary)' }}>Steady Stream:</span>
<span className="text-green-400">Immune to incursion</span> <span style={{ color: 'var(--color-success)' }}>Immune to incursion</span>
</div> </div>
)} )}
{upgradeEffects.manaCascadeBonus > 0 && ( {upgradeEffects.manaCascadeBonus > 0 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Cascade:</span> <span style={{ color: 'var(--text-secondary)' }}>Mana Cascade:</span>
<span className="text-cyan-400">+{fmtDec(upgradeEffects.manaCascadeBonus, 2)}/hr</span> <span style={{ color: 'var(--mana-crystal)' }}>+{fmtDec(upgradeEffects.manaCascadeBonus, 2)}/hr</span>
</div> </div>
)} )}
{upgradeEffects.manaWaterfallBonus > 0 && ( {upgradeEffects.manaWaterfallBonus > 0 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Waterfall:</span> <span style={{ color: 'var(--text-secondary)' }}>Mana Waterfall:</span>
<span className="text-cyan-400">+{fmtDec(upgradeEffects.manaWaterfallBonus, 2)}/hr</span> <span style={{ color: 'var(--mana-crystal)' }}>+{fmtDec(upgradeEffects.manaWaterfallBonus, 2)}/hr</span>
</div> </div>
)} )}
{upgradeEffects.hasFlowSurge && ( {upgradeEffects.hasFlowSurge && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Flow Surge:</span> <span style={{ color: 'var(--text-secondary)' }}>Flow Surge:</span>
<span className="text-cyan-400">Clicks +100% regen for 1hr</span> <span style={{ color: 'var(--mana-crystal)' }}>Clicks +100% regen for 1hr</span>
</div> </div>
)} )}
{upgradeEffects.hasManaOverflow && ( {upgradeEffects.hasManaOverflow && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Overflow:</span> <span style={{ color: 'var(--text-secondary)' }}>Mana Overflow:</span>
<span className="text-cyan-400">Raw can exceed max by 20%</span> <span style={{ color: 'var(--mana-crystal)' }}>Raw can exceed max by 20%</span>
</div> </div>
)} )}
{upgradeEffects.hasEternalFlow && ( {upgradeEffects.hasEternalFlow && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Eternal Flow:</span> <span style={{ color: 'var(--text-secondary)' }}>Eternal Flow:</span>
<span className="text-green-400">Regen immune to ALL penalties</span> <span style={{ color: 'var(--color-success)' }}>Regen immune to ALL penalties</span>
</div> </div>
)} )}
{upgradeEffects.hasManaTorrent && upgradeEffects.rawMana > maxMana * 0.75 && ( {upgradeEffects.hasManaTorrent && upgradeEffects.rawMana > maxMana * 0.75 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Torrent:</span> <span style={{ color: 'var(--text-secondary)' }}>Mana Torrent:</span>
<span className="text-cyan-400">+50% regen (high mana)</span> <span style={{ color: 'var(--mana-crystal)' }}>+50% regen (high mana)</span>
</div> </div>
)} )}
{upgradeEffects.hasDesperateWells && upgradeEffects.rawMana < maxMana * 0.25 && ( {upgradeEffects.hasDesperateWells && upgradeEffects.rawMana < maxMana * 0.25 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1"> <div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span className="text-gray-300">Desperate Wells:</span> <span style={{ color: 'var(--text-secondary)' }}>Desperate Wells:</span>
<span className="text-cyan-400">+50% regen (low mana)</span> <span style={{ color: 'var(--mana-crystal)' }}>+50% regen (low mana)</span>
</div> </div>
)} )}
</div> </div>
</> </>
)} )}
{/* Element Max */} {/* Element Max */}
<div className="mt-3 pt-3 border-t border-gray-700"> <div className="mt-3 pt-3 border-t border-[var(--border-subtle)]">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Element Capacity:</span> <span style={{ color: 'var(--text-muted)' }}>Element Capacity:</span>
<span className="text-green-300">{elemMax}</span> <span style={{ color: 'var(--color-success)' }}>{elemMax}</span>
</div> </div>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
); );
} }
@@ -19,9 +19,9 @@ export function PactStatusSection({ pactMultiplier, pactInsightMultiplier }: Pac
const pactInterferenceMitigation = prestigeUpgrades?.pactInterferenceMitigation || 0; const pactInterferenceMitigation = prestigeUpgrades?.pactInterferenceMitigation || 0;
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-amber-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-light)] game-panel-title text-xs flex items-center gap-2">
<Trophy className="w-4 h-4" /> <Trophy className="w-4 h-4" />
Pact Status Pact Status
</CardTitle> </CardTitle>
@@ -30,41 +30,41 @@ export function PactStatusSection({ pactMultiplier, pactInsightMultiplier }: Pac
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Pact Slots:</span> <span style={{ color: 'var(--text-muted)' }}>Pact Slots:</span>
<span className="text-amber-300">{signedPacts.length} / {1 + (prestigeUpgrades.pactCapacity || 0)}</span> <span style={{ color: 'var(--mana-light)' }}>{signedPacts.length} / {1 + (prestigeUpgrades.pactCapacity || 0)}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Damage Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Damage Multiplier:</span>
<span className="text-amber-300">×{fmtDec(pactMultiplier, 2)}</span> <span style={{ color: 'var(--mana-light)' }}>×{fmtDec(pactMultiplier, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Insight Multiplier:</span> <span style={{ color: 'var(--text-muted)' }}>Insight Multiplier:</span>
<span className="text-purple-300">×{fmtDec(pactInsightMultiplier, 2)}</span> <span style={{ color: 'var(--mana-crystal)' }}>×{fmtDec(pactInsightMultiplier, 2)}</span>
</div> </div>
{signedPacts.length > 1 && ( {signedPacts.length > 1 && (
<> <>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Interference Mitigation:</span> <span style={{ color: 'var(--text-muted)' }}>Interference Mitigation:</span>
<span className="text-green-300">{Math.min(pactInterferenceMitigation, 5) * 10}%</span> <span style={{ color: 'var(--color-success)' }}>{Math.min(pactInterferenceMitigation, 5) * 10}%</span>
</div> </div>
{pactInterferenceMitigation >= 5 && ( {pactInterferenceMitigation >= 5 && (
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-cyan-400">Synergy Bonus:</span> <span style={{ color: 'var(--mana-crystal)' }}>Synergy Bonus:</span>
<span className="text-cyan-300">+{(pactInterferenceMitigation - 5) * 10}%</span> <span style={{ color: 'var(--mana-crystal)' }}>+{(pactInterferenceMitigation - 5) * 10}%</span>
</div> </div>
)} )}
</> </>
)} )}
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="text-sm text-gray-400 mb-2">Unlocked Mana Types:</div> <div className="text-sm" style={{ color: 'var(--text-muted)' }}>Unlocked Mana Types:</div>
<div className="flex flex-wrap gap-1"> <div className="flex flex-wrap gap-1">
{Object.keys(elements).map((id) => { {Object.keys(elements).map((id) => {
const state = elements[id]; const state = elements[id];
if (!state.unlocked) return null; if (!state.unlocked) return null;
const elem = ELEMENTS[id]; const elem = ELEMENTS[id];
return ( return (
<span key={id} className="px-2 py-1 text-xs rounded border" style={{ borderColor: elem?.color, color: elem?.color }}> <span key={id} className="px-2 py-1 text-xs rounded border transition-colors" style={{ borderColor: `${elem?.color}60`, color: elem?.color }}>
{elem?.sym} {elem?.name} {elem?.sym} {elem?.name}
</span> </span>
); );
@@ -75,4 +75,4 @@ export function PactStatusSection({ pactMultiplier, pactInsightMultiplier }: Pac
</CardContent> </CardContent>
</Card> </Card>
); );
} }
@@ -14,9 +14,9 @@ export function StudyStatsSection({ studySpeedMult, studyCostMult }: StudyStatsS
const skills = useSkillStore((s) => s.skills); const skills = useSkillStore((s) => s.skills);
return ( return (
<Card className="bg-gray-900/80 border-gray-700"> <Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<CardHeader className="pb-2"> <CardHeader className="pb-2">
<CardTitle className="text-purple-400 game-panel-title text-xs flex items-center gap-2"> <CardTitle className="text-[var(--mana-crystal)] game-panel-title text-xs flex items-center gap-2">
<BookOpen className="w-4 h-4" /> <BookOpen className="w-4 h-4" />
Study Stats Study Stats
</CardTitle> </CardTitle>
@@ -25,32 +25,32 @@ export function StudyStatsSection({ studySpeedMult, studyCostMult }: StudyStatsS
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Study Speed:</span> <span style={{ color: 'var(--text-muted)' }}>Study Speed:</span>
<span className="text-purple-300">×{fmtDec(studySpeedMult, 2)}</span> <span style={{ color: 'var(--mana-crystal)' }}>×{fmtDec(studySpeedMult, 2)}</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Quick Learner Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Quick Learner Bonus:</span>
<span className="text-purple-300">+{((skills.quickLearner || 0) * 10)}%</span> <span style={{ color: 'var(--mana-crystal)' }}>+{((skills.quickLearner || 0) * 10)}%</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Study Cost:</span> <span style={{ color: 'var(--text-muted)' }}>Study Cost:</span>
<span className="text-purple-300">{Math.round(studyCostMult * 100)}%</span> <span style={{ color: 'var(--mana-crystal)' }}>{Math.round(studyCostMult * 100)}%</span>
</div> </div>
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Focused Mind Bonus:</span> <span style={{ color: 'var(--text-muted)' }}>Focused Mind Bonus:</span>
<span className="text-purple-300">-{((skills.focusedMind || 0) * 5)}%</span> <span style={{ color: 'var(--mana-crystal)' }}>-{((skills.focusedMind || 0) * 5)}%</span>
</div> </div>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex justify-between text-sm"> <div className="flex justify-between text-sm">
<span className="text-gray-400">Progress Retention:</span> <span style={{ color: 'var(--text-muted)' }}>Progress Retention:</span>
<span className="text-purple-300">{Math.round((1 + (skills.knowledgeRetention || 0) * 0.2) * 100)}%</span> <span style={{ color: 'var(--mana-crystal)' }}>{Math.round((1 + (skills.knowledgeRetention || 0) * 0.2) * 100)}%</span>
</div> </div>
</div> </div>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
); );
} }
+6 -31
View File
@@ -55,32 +55,13 @@ const TAB_GROUPS = [
name: 'Meta', name: 'Meta',
tabs: [ tabs: [
{ value: 'achievements', label: 'Achieve', icon: Trophy, mobileLabel: 'Achieve' }, { value: 'achievements', label: 'Achieve', icon: Trophy, mobileLabel: 'Achieve' },
{ value: 'lab', label: 'Lab', icon: FlaskConical, mobileLabel: 'Lab' },
{ value: 'stats', label: 'Stats', icon: BarChart3, mobileLabel: 'Stats' }, { value: 'stats', label: 'Stats', icon: BarChart3, mobileLabel: 'Stats' },
{ value: 'grimoire', label: 'Grimoire', icon: BookOpen, mobileLabel: 'Grimoire' },
{ value: 'debug', label: 'Debug', icon: Wrench, mobileLabel: 'Debug' }, { value: 'debug', label: 'Debug', icon: Wrench, mobileLabel: 'Debug' },
] ]
} }
]; ];
export function TabBar({ activeTab, onTabChange, isMobile = false }: TabBarProps) { export function TabBar({ activeTab, onTabChange, isMobile = false }: TabBarProps) {
const [longPressTimer, setLongPressTimer] = useState<NodeJS.Timeout | null>(null);
const handleLongPressStart = (value: string) => {
const timer = setTimeout(() => {
// Show tooltip on long press for mobile
onTabChange(value);
}, 500);
setLongPressTimer(timer);
};
const handleLongPressEnd = () => {
if (longPressTimer) {
clearTimeout(longPressTimer);
setLongPressTimer(null);
}
};
if (isMobile) { if (isMobile) {
return ( return (
<TooltipProvider> <TooltipProvider>
@@ -98,16 +79,11 @@ export function TabBar({ activeTab, onTabChange, isMobile = false }: TabBarProps
<TooltipTrigger asChild> <TooltipTrigger asChild>
<button <button
onClick={() => onTabChange(tab.value)} onClick={() => onTabChange(tab.value)}
onMouseDown={() => handleLongPressStart(tab.value)}
onMouseUp={handleLongPressEnd}
onMouseLeave={handleLongPressEnd}
onTouchStart={() => handleLongPressStart(tab.value)}
onTouchEnd={handleLongPressEnd}
className={` className={`
flex items-center justify-center p-2 rounded-lg transition-all flex-shrink-0 flex items-center justify-center p-2 flex-shrink-0 transition-all border text-[var(--font-display)]
${isActive ${isActive
? 'bg-[var(--interactive-primary)] text-white shadow-lg shadow-[var(--interactive-primary)]/20' ? 'border-[var(--border-accent)] bg-[var(--bg-raised)] text-[var(--interactive-primary)]'
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-elevated)]' : 'border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-panel)] hover:border-[var(--border-subtle)]'
} }
`} `}
aria-label={tab.label} aria-label={tab.label}
@@ -143,15 +119,14 @@ export function TabBar({ activeTab, onTabChange, isMobile = false }: TabBarProps
key={tab.value} key={tab.value}
value={tab.value} value={tab.value}
className={` className={`
text-xs px-3 py-1.5 relative transition-all whitespace-nowrap text-xs px-3 py-1.5 relative transition-all whitespace-nowrap text-[var(--font-display)] tracking-wider
${isActive ${isActive
? 'text-[var(--interactive-primary)] font-semibold' ? 'text-[var(--interactive-primary)]'
: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]' : 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]'
} }
`} `}
style={isActive ? { style={isActive ? {
borderBottom: '2px solid var(--interactive-primary)', borderBottom: '2px solid var(--border-accent)',
textShadow: '0 0 8px var(--interactive-primary)',
} : {}} } : {}}
> >
{tab.label} {tab.label}