Files
Mana-Loop/src/components/game/tabs/LabTab.tsx
T
Refactoring Agent 8aacc2c88e Fix Spire Mode floor rendering and swarm floors (Tasks 5 & 6)
- Added enemy naming system with getEnemyName() function
- Updated EnemyState type to include name field
- Updated generateSwarmEnemies() and generateFloorState() to assign enemy names
- Fixed SpireTab.tsx (both versions) to display:
  - Floor type (Combat/Swarm/Speed/Guardian/Puzzle) with icons
  - Named enemies based on element and floor tier
  - Special floor properties (armor %, dodge chance)
  - Multiple enemies for swarm floors with individual HP bars
- Added ROOM_TYPE_LABELS to constants for display
- Verified floor type generation logic works correctly
- Build succeeds with npm run build
2026-04-28 13:36:16 +02:00

123 lines
4.3 KiB
TypeScript
Executable File

'use client';
import { GameCard, ElementBadge, ActionButton } from '@/components/ui';
import { Button } from '@/components/ui/button';
import { ELEMENTS } from '@/lib/game/constants';
interface LabTabProps {
store: {
rawMana: number;
elements: Record<string, { current: number; max: number; unlocked: boolean }>;
skills: Record<string, number>;
craftComposite: (target: string) => void;
};
}
export function LabTab({ store }: LabTabProps) {
// Render elemental mana grid - only show elements with current > 0
const renderElementsGrid = () => (
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2">
{Object.entries(store.elements || {})
.filter(([, state]) => state.unlocked && state.current > 0)
.map(([id, state]) => {
const def = ELEMENTS[id];
return (
<div
key={id}
className="p-2 rounded border border-[var(--border-subtle)] bg-[var(--bg-sunken)]"
>
<div className="text-lg text-center">
<ElementBadge elementId={id} size="sm" />
</div>
<div className="text-xs font-semibold text-center" style={{ color: `var(--mana-${id})` }}>{def?.name}</div>
<div className="text-xs text-[var(--text-secondary)] font-[var(--font-mono)] text-center">{state.current}/{state.max}</div>
</div>
);
})}
</div>
);
// Render composite crafting
const renderCompositeCrafting = () => {
const compositeElements = Object.entries(ELEMENTS)
.filter(([, def]) => def.recipe)
.filter(([id]) => (store.elements || {})[id]?.unlocked);
if (compositeElements.length === 0) return null;
return (
<GameCard>
<div className="pb-2">
<h3 className="text-sm font-semibold text-[var(--text-primary)]">Composite Crafting</h3>
</div>
<div className="space-y-2">
{compositeElements.map(([id, def]) => {
const recipe = def.recipe || [];
const canCraft = recipe.every(r => ((store.elements || {})[r]?.current || 0) >= 1);
const craftBonus = 1 + (store.skills.elemCrafting || 0) * 0.25;
const output = Math.floor(craftBonus);
return (
<div key={id} className="p-2 rounded border border-[var(--border-subtle)] bg-[var(--bg-sunken)] flex items-center justify-between">
<div className="flex items-center gap-2">
<ElementBadge elementId={id} size="md" />
<span className="text-sm" style={{ color: `var(--mana-${id})` }}>{def.name}</span>
<span className="text-xs text-[var(--text-muted)]">
({recipe.map(r => {
const rDef = ELEMENTS[r];
return rDef?.sym || r;
}).join(' + ')})
</span>
</div>
<Button
size="sm"
variant="outline"
disabled={!canCraft}
onClick={() => store.craftComposite(id)}
className={!canCraft ? 'opacity-50 cursor-not-allowed' : ''}
>
Craft ({output})
</Button>
</div>
);
})}
</div>
</GameCard>
);
};
// Check if there are any unlocked elements with current > 0
const hasUnlockedElements = Object.values(store.elements || {}).some(e => e.unlocked && e.current > 0);
if (!hasUnlockedElements) {
return (
<GameCard>
<div className="pt-6">
<div className="text-center text-[var(--text-muted)]">
No elemental mana available. Gather or convert mana to see elemental pools.
</div>
</div>
</GameCard>
);
}
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Elemental Mana Display */}
<GameCard className="lg:col-span-2">
<div className="pb-2">
<h3 className="text-sm font-semibold text-[var(--text-primary)]">Elemental Mana</h3>
</div>
<div>
{renderElementsGrid()}
</div>
</GameCard>
{/* Composite Crafting */}
{renderCompositeCrafting()}
</div>
);
}
LabTab.displayName = "LabTab";