Refactor large files into modular components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s

- Refactored page.tsx (613→252 lines) with GameOverScreen and LeftPanel extracted
- Refactored StatsTab.tsx (584→92 lines) with section components
- Refactored SkillsTab.tsx (434→54 lines) with sub-components
- Created modular structure for GameContext, LootInventory, and other components
- All extracted components organized into feature directories
This commit is contained in:
Refactoring Agent
2026-05-02 17:35:03 +02:00
parent c9ae2576f4
commit d2d28887b1
194 changed files with 16862 additions and 15729 deletions
@@ -0,0 +1,152 @@
'use client';
import { GameCard } from '@/components/ui/game-card';
import { SectionHeader } from '@/components/ui/section-header';
import { ActionButton } from '@/components/ui/action-button';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Separator } from '@/components/ui/separator';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { AlertCircle, Wand2, Plus, Minus } from 'lucide-react';
import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from '@/lib/game/data/enchantment-effects';
import type { EffectSelectorProps } from './types';
export function EffectSelector({
selectedEquipmentType,
selectedEffects,
setSelectedEffects,
availableEffects,
incompatibleEffects,
enchantingLevel,
efficiencyBonus,
designProgress,
addEffect,
removeEffect,
getIncompatibilityReason,
}: EffectSelectorProps) {
return (
<>
{enchantingLevel < 1 ? (
<div className="text-center text-[var(--text-muted)] py-8">
<Wand2 className="w-12 h-12 mx-auto mb-2 opacity-50 text-[var(--text-disabled)]" />
<p>Learn Enchanting skill to design enchantments</p>
</div>
) : designProgress ? (
<div className="space-y-2">
<div className="text-sm text-[var(--text-secondary)]">Design in progress...</div>
{designProgress.effects.map(eff => {
const def = ENCHANTMENT_EFFECTS[eff.effectId];
return (
<div key={eff.effectId} className="flex justify-between text-sm text-[var(--text-primary)]">
<span>{def?.name} x{eff.stacks}</span>
<span className="text-[var(--text-muted)]">{eff.capacityCost} cap</span>
</div>
);
})}
</div>
) : !selectedEquipmentType ? (
<div className="text-center text-[var(--text-muted)] py-8">
Select an equipment type first
</div>
) : (
<>
<ScrollArea className="h-48 mb-4">
<div className="space-y-2">
{/* Compatible Effects */}
{availableEffects.map(effect => {
const selected = selectedEffects.find(e => e.effectId === effect.id);
const cost = calculateEffectCapacityCost(effect.id, (selected?.stacks || 0) + 1, efficiencyBonus);
return (
<div
key={effect.id}
className={`p-2 rounded border transition-all
${selected
? 'border-[var(--mana-stellar)] bg-[var(--mana-stellar)]/10'
: 'border-[var(--border-default)] bg-[var(--bg-sunken)]/50'
}`}
>
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="text-sm font-semibold text-[var(--text-primary)]">{effect.name}</div>
<div className="text-xs text-[var(--text-muted)]">{effect.description}</div>
<div className="text-xs text-[var(--text-disabled)] mt-1">
Cost: {effect.baseCapacityCost} cap | Max: {effect.maxStacks}
</div>
</div>
<div className="flex gap-1">
{selected && (
<ActionButton
size="sm"
variant="outline"
className="h-6 w-6 p-0"
onClick={() => removeEffect(effect.id)}
>
<Minus className="w-3 h-3" />
</ActionButton>
)}
<ActionButton
size="sm"
variant="outline"
className="h-6 w-6 p-0"
onClick={() => addEffect(effect.id)}
disabled={!selected && selectedEffects.length >= 5}
>
<Plus className="w-3 h-3" />
</ActionButton>
</div>
</div>
{selected && (
<Badge variant="outline" className="mt-1 text-xs border-[var(--mana-stellar)] text-[var(--mana-stellar)]">
{selected.stacks}/{effect.maxStacks}
</Badge>
)}
</div>
);
})}
{/* Incompatible Effects - Requirement: greyed-out "Unavailable" section with tooltips */}
{incompatibleEffects.length > 0 && (
<>
<Separator className="bg-[var(--border-subtle)] my-2" />
<div className="text-xs font-semibold text-[var(--text-disabled)] uppercase tracking-wider mb-2">
Unavailable
</div>
{incompatibleEffects.map(effect => {
const reason = getIncompatibilityReason(effect);
return (
<TooltipProvider key={effect.id}>
<Tooltip>
<TooltipTrigger asChild>
<div
className="p-2 rounded border border-[var(--border-subtle)] bg-[var(--bg-sunken)]/30 opacity-50 cursor-not-allowed"
>
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="text-sm font-semibold text-[var(--text-disabled)]">{effect.name}</div>
<div className="text-xs text-[var(--text-disabled)]">{effect.description}</div>
</div>
<AlertCircle size={14} className="text-[var(--text-disabled)]" />
</div>
</div>
</TooltipTrigger>
<TooltipContent className="bg-[var(--bg-elevated)] border-[var(--border-default)] text-[var(--text-primary)]">
<p className="font-semibold">Incompatible Effect</p>
<p className="text-xs text-[var(--text-muted)] mt-1">{reason}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
})}
</>
)}
</div>
</ScrollArea>
</>
)}
</>
);
}
EffectSelector.displayName = 'EffectSelector';