Refactor large files into modular components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s
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:
@@ -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';
|
||||
Reference in New Issue
Block a user