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,13 +32,13 @@ export function ManaStatsSection({
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
const getTierMultiplier = (skillId: string) => {
return 1; // Simplified - import from skill-evolution in real implementation
return 1;
};
return (
<Card className="bg-gray-900/80 border-gray-700">
<Card className="bg-[var(--bg-panel)] border-[var(--border-subtle)]">
<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" />
Mana Stats
</CardTitle>
@@ -47,12 +47,12 @@ export function ManaStatsSection({
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span className="text-gray-400">Base Max Mana:</span>
<span className="text-gray-200">100</span>
<span style={{ color: 'var(--text-muted)' }}>Base Max Mana:</span>
<span style={{ color: 'var(--text-secondary)' }}>100</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Well Bonus:</span>
<span className="text-blue-300">
<span style={{ color: 'var(--text-muted)' }}>Mana Well Bonus:</span>
<span style={{ color: 'var(--mana-water)' }}>
{(() => {
const mw = skillTiers?.manaWell || 1;
const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell';
@@ -63,34 +63,34 @@ export function ManaStatsSection({
</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Prestige Mana Well:</span>
<span className="text-blue-300">+{fmt((prestigeUpgrades.manaWell || 0) * 500)}</span>
<span style={{ color: 'var(--text-muted)' }}>Prestige Mana Well:</span>
<span style={{ color: 'var(--mana-water)' }}>+{fmt((prestigeUpgrades.manaWell || 0) * 500)}</span>
</div>
{upgradeEffects.maxManaBonus > 0 && (
<div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Mana Bonus:</span>
<span className="text-amber-300">+{fmt(upgradeEffects.maxManaBonus)}</span>
<span style={{ color: 'var(--mana-light)' }}>Upgrade Mana Bonus:</span>
<span style={{ color: 'var(--mana-light)' }}>+{fmt(upgradeEffects.maxManaBonus)}</span>
</div>
)}
{upgradeEffects.maxManaMultiplier > 1 && (
<div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Mana Multiplier:</span>
<span className="text-amber-300">×{fmtDec(upgradeEffects.maxManaMultiplier, 2)}</span>
<span style={{ color: 'var(--mana-light)' }}>Upgrade Mana Multiplier:</span>
<span style={{ color: 'var(--mana-light)' }}>×{fmtDec(upgradeEffects.maxManaMultiplier, 2)}</span>
</div>
)}
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2">
<span className="text-gray-300">Total Max Mana:</span>
<span className="text-blue-400">{fmt(maxMana)}</span>
<div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span style={{ color: 'var(--text-secondary)' }}>Total Max Mana:</span>
<span style={{ color: 'var(--mana-water)' }}>{fmt(maxMana)}</span>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span className="text-gray-400">Base Regen:</span>
<span className="text-gray-200">2/hr</span>
<span style={{ color: 'var(--text-muted)' }}>Base Regen:</span>
<span style={{ color: 'var(--text-secondary)' }}>2/hr</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Flow Bonus:</span>
<span className="text-blue-300">
<span style={{ color: 'var(--text-muted)' }}>Mana Flow Bonus:</span>
<span style={{ color: 'var(--mana-water)' }}>
{(() => {
const mf = skillTiers?.manaFlow || 1;
const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow';
@@ -101,37 +101,37 @@ export function ManaStatsSection({
</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Spring Bonus:</span>
<span className="text-blue-300">+{(skills.manaSpring || 0) * 2}/hr</span>
<span style={{ color: 'var(--text-muted)' }}>Mana Spring Bonus:</span>
<span style={{ color: 'var(--mana-water)' }}>+{(skills.manaSpring || 0) * 2}/hr</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Prestige Mana Flow:</span>
<span className="text-blue-300">+{fmtDec((prestigeUpgrades.manaFlow || 0) * 0.5)}/hr</span>
<span style={{ color: 'var(--text-muted)' }}>Prestige Mana Flow:</span>
<span style={{ color: 'var(--mana-water)' }}>+{fmtDec((prestigeUpgrades.manaFlow || 0) * 0.5)}/hr</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Temporal Echo:</span>
<span className="text-blue-300">×{fmtDec(1 + (prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}</span>
<span style={{ color: 'var(--text-muted)' }}>Temporal Echo:</span>
<span style={{ color: 'var(--mana-water)' }}>×{fmtDec(1 + (prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}</span>
</div>
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2">
<span className="text-gray-300">Base Regen:</span>
<span className="text-blue-400">{fmtDec(baseRegen, 2)}/hr</span>
<div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span style={{ color: 'var(--text-secondary)' }}>Base Regen:</span>
<span style={{ color: 'var(--mana-water)' }}>{fmtDec(baseRegen, 2)}/hr</span>
</div>
{upgradeEffects.regenBonus > 0 && (
<div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Regen Bonus:</span>
<span className="text-amber-300">+{fmtDec(upgradeEffects.regenBonus, 2)}/hr</span>
<span style={{ color: 'var(--mana-light)' }}>Upgrade Regen Bonus:</span>
<span style={{ color: 'var(--mana-light)' }}>+{fmtDec(upgradeEffects.regenBonus, 2)}/hr</span>
</div>
)}
{upgradeEffects.permanentRegenBonus > 0 && (
<div className="flex justify-between text-sm">
<span className="text-amber-400">Permanent Regen Bonus:</span>
<span className="text-amber-300">+{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr</span>
<span style={{ color: 'var(--mana-light)' }}>Permanent Regen Bonus:</span>
<span style={{ color: 'var(--mana-light)' }}>+{fmtDec(upgradeEffects.permanentRegenBonus, 2)}/hr</span>
</div>
)}
{upgradeEffects.regenMultiplier > 1 && (
<div className="flex justify-between text-sm">
<span className="text-amber-400">Upgrade Regen Multiplier:</span>
<span className="text-amber-300">×{fmtDec(upgradeEffects.regenMultiplier, 2)}</span>
<span style={{ color: 'var(--mana-light)' }}>Upgrade Regen Multiplier:</span>
<span style={{ color: 'var(--mana-light)' }}>×{fmtDec(upgradeEffects.regenMultiplier, 2)}</span>
</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="space-y-2">
<div className="flex justify-between text-sm">
<span className="text-gray-400">Click Mana Value:</span>
<span className="text-purple-300">+{clickMana}</span>
<span style={{ color: 'var(--text-muted)' }}>Click Mana Value:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+{clickMana}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Tap Bonus:</span>
<span className="text-purple-300">+{skills.manaTap || 0}</span>
<span style={{ color: 'var(--text-muted)' }}>Mana Tap Bonus:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+{skills.manaTap || 0}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Surge Bonus:</span>
<span className="text-purple-300">+{(skills.manaSurge || 0) * 3}</span>
<span style={{ color: 'var(--text-muted)' }}>Mana Surge Bonus:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+{(skills.manaSurge || 0) * 3}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Mana Overflow:</span>
<span className="text-purple-300">×{fmtDec(1 + (skills.manaOverflow || 0) * 0.25, 2)}</span>
<span style={{ color: 'var(--text-muted)' }}>Mana Overflow:</span>
<span style={{ color: 'var(--mana-crystal)' }}>×{fmtDec(1 + (skills.manaOverflow || 0) * 0.25, 2)}</span>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span className="text-gray-400">Meditation Multiplier:</span>
<span className={`font-semibold ${meditationMultiplier > 1.5 ? 'text-purple-400' : 'text-gray-300'}`}>
<span style={{ color: 'var(--text-muted)' }}>Meditation Multiplier:</span>
<span className={`font-semibold ${meditationMultiplier > 1.5 ? 'text-[var(--mana-stellar)]' : 'text-[var(--text-secondary)]'}`}>
{fmtDec(meditationMultiplier, 2)}x
</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">Incursion Strength:</span>
<span className="text-red-400">{Math.round(upgradeEffects.incursionStrength * 100)}%</span>
<span style={{ color: 'var(--text-muted)' }}>Incursion Strength:</span>
<span style={{ color: 'var(--color-danger)' }}>{Math.round(upgradeEffects.incursionStrength * 100)}%</span>
</div>
<div className="flex justify-between text-sm font-semibold border-t border-gray-700 pt-2">
<span className="text-gray-300">Effective Regen:</span>
<span className="text-green-400 font-semibold">{fmtDec(effectiveRegen, 2)}/hr</span>
<div className="flex justify-between text-sm font-semibold border-t border-[var(--border-subtle)] pt-2">
<span style={{ color: 'var(--text-secondary)' }}>Effective Regen:</span>
<span style={{ color: 'var(--color-success)' }} className="font-semibold">{fmtDec(effectiveRegen, 2)}/hr</span>
</div>
</div>
</div>
@@ -177,67 +177,67 @@ export function ManaStatsSection({
upgradeEffects.hasDesperateWells || upgradeEffects.manaCascadeBonus > 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">
{upgradeEffects.hasSteadyStream && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Steady Stream:</span>
<span className="text-green-400">Immune to incursion</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Steady Stream:</span>
<span style={{ color: 'var(--color-success)' }}>Immune to incursion</span>
</div>
)}
{upgradeEffects.manaCascadeBonus > 0 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Cascade:</span>
<span className="text-cyan-400">+{fmtDec(upgradeEffects.manaCascadeBonus, 2)}/hr</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Mana Cascade:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+{fmtDec(upgradeEffects.manaCascadeBonus, 2)}/hr</span>
</div>
)}
{upgradeEffects.manaWaterfallBonus > 0 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Waterfall:</span>
<span className="text-cyan-400">+{fmtDec(upgradeEffects.manaWaterfallBonus, 2)}/hr</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Mana Waterfall:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+{fmtDec(upgradeEffects.manaWaterfallBonus, 2)}/hr</span>
</div>
)}
{upgradeEffects.hasFlowSurge && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Flow Surge:</span>
<span className="text-cyan-400">Clicks +100% regen for 1hr</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Flow Surge:</span>
<span style={{ color: 'var(--mana-crystal)' }}>Clicks +100% regen for 1hr</span>
</div>
)}
{upgradeEffects.hasManaOverflow && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Overflow:</span>
<span className="text-cyan-400">Raw can exceed max by 20%</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Mana Overflow:</span>
<span style={{ color: 'var(--mana-crystal)' }}>Raw can exceed max by 20%</span>
</div>
)}
{upgradeEffects.hasEternalFlow && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Eternal Flow:</span>
<span className="text-green-400">Regen immune to ALL penalties</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Eternal Flow:</span>
<span style={{ color: 'var(--color-success)' }}>Regen immune to ALL penalties</span>
</div>
)}
{upgradeEffects.hasManaTorrent && upgradeEffects.rawMana > maxMana * 0.75 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Mana Torrent:</span>
<span className="text-cyan-400">+50% regen (high mana)</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Mana Torrent:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+50% regen (high mana)</span>
</div>
)}
{upgradeEffects.hasDesperateWells && upgradeEffects.rawMana < maxMana * 0.25 && (
<div className="flex justify-between text-xs bg-gray-800/50 rounded px-2 py-1">
<span className="text-gray-300">Desperate Wells:</span>
<span className="text-cyan-400">+50% regen (low mana)</span>
<div className="flex justify-between text-xs bg-[var(--bg-sunken)]/50 rounded px-2 py-1">
<span style={{ color: 'var(--text-secondary)' }}>Desperate Wells:</span>
<span style={{ color: 'var(--mana-crystal)' }}>+50% regen (low mana)</span>
</div>
)}
</div>
</>
)}
{/* 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">
<span className="text-gray-400">Element Capacity:</span>
<span className="text-green-300">{elemMax}</span>
<span style={{ color: 'var(--text-muted)' }}>Element Capacity:</span>
<span style={{ color: 'var(--color-success)' }}>{elemMax}</span>
</div>
</div>
</CardContent>
</Card>
);
}
}