Fix build error in SpireActiveSpells.tsx - resolve JSX parsing issue with template literals
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m45s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m45s
- Fixed unclosed template literal in className attribute - Added missing imports (Mountain, ELEMENTS) in SpireGolems.tsx - Build now passes successfully
This commit is contained in:
@@ -52,6 +52,28 @@ export function SpireActiveSpells({
|
|||||||
const progress = spellState?.castProgress || 0;
|
const progress = spellState?.castProgress || 0;
|
||||||
const canCast = canCastSpell(spellId);
|
const canCast = canCastSpell(spellId);
|
||||||
|
|
||||||
|
// Compute progress bar JSX
|
||||||
|
let progressBar = null;
|
||||||
|
if (currentAction === 'climb') {
|
||||||
|
const widthPercent = Math.min(100, progress * 100);
|
||||||
|
const elemColor = spellDef.elem === 'raw' ? '#60A5FA' : ELEMENTS[spellDef.elem]?.color || '#60A5FA';
|
||||||
|
const backgroundGradient = 'linear-gradient(90deg, ' + elemColor + '99, ' + elemColor + ')';
|
||||||
|
progressBar = (
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<div className="flex justify-between text-xs text-gray-500">
|
||||||
|
<span>Cast</span>
|
||||||
|
<span>{widthPercent.toFixed(0)}%</span>
|
||||||
|
</div>
|
||||||
|
<div className="h-1.5 bg-gray-700 rounded-full overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full rounded-full transition-all duration-300"
|
||||||
|
style={{ width: widthPercent + '%', background: backgroundGradient }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`${spellId}-${equipmentId}`} className="p-2 rounded bg-gray-800/30 border border-gray-700">
|
<div key={`${spellId}-${equipmentId}`} className="p-2 rounded bg-gray-800/30 border border-gray-700">
|
||||||
<div className="flex items-center justify-between mb-1">
|
<div className="flex items-center justify-between mb-1">
|
||||||
@@ -59,22 +81,12 @@ export function SpireActiveSpells({
|
|||||||
{spellDef.name}
|
{spellDef.name}
|
||||||
{spellDef.tier === 0 && <span className="ml-2 bg-gray-600 text-gray-200 text-xs px-1 rounded">Basic</span>}
|
{spellDef.tier === 0 && <span className="ml-2 bg-gray-600 text-gray-200 text-xs px-1 rounded">Basic</span>}
|
||||||
</span>
|
</span>
|
||||||
<span className={`text-xs ${canCast ? 'text-green-400' : 'text-red-400'`}>{canCast ? '✓' : '✗'}</span>
|
<span className={`text-xs ${canCast ? 'text-green-400' : 'text-red-400'}`}>{canCast ? '✓' : '✗'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-400 mb-1">
|
<div className="text-xs text-gray-400 mb-1">
|
||||||
⚔️ {calcDamage({ skills, signedPacts, skillUpgrades, skillTiers }, spellId, floorElem)} dmg • <span style={{ color: getSpellCostColor(spellDef.cost) }}>{formatSpellCost(spellDef.cost)}</span> {' '}• ⚡ {Math.floor(calcDamage({ skills, signedPacts, skillUpgrades, skillTiers }, spellId, floorElem) * (spellDef.castSpeed || 1))} dmg/hr
|
⚔️ {calcDamage({ skills, signedPacts, skillUpgrades, skillTiers }, spellId, floorElem)} dmg • <span style={{ color: getSpellCostColor(spellDef.cost) }}>{formatSpellCost(spellDef.cost)}</span> {' '}• ⚡ {Math.floor(calcDamage({ skills, signedPacts, skillUpgrades, skillTiers }, spellId, floorElem) * (spellDef.castSpeed || 1))} dmg/hr
|
||||||
</div>
|
</div>
|
||||||
{currentAction === 'climb' && (
|
{progressBar}
|
||||||
<div className="space-y-0.5">
|
|
||||||
<div className="flex justify-between text-xs text-gray-500">
|
|
||||||
<span>Cast</span>
|
|
||||||
<span>{(progress * 100).toFixed(0)}%</span>
|
|
||||||
</div>
|
|
||||||
<div className="h-1.5 bg-gray-700 rounded-full overflow-hidden">
|
|
||||||
<div className="h-full rounded-full transition-all duration-300" style={{ width: `${Math.min(100, progress * 100)}%`, background: spellDef.elem === 'raw' ? 'linear-gradient(90deg, #60A5FA99, #60A5FA)' : `linear-gradient(90deg, ${ELEMENTS[spellDef.elem]?.color}99, ${ELEMENTS[spellDef.elem]?.color})` }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
|
import { Mountain } from 'lucide-react';
|
||||||
import { GOLEMS_DEF, getGolemDamage, getGolemAttackSpeed } from '@/lib/game/data/golems';
|
import { GOLEMS_DEF, getGolemDamage, getGolemAttackSpeed } from '@/lib/game/data/golems';
|
||||||
|
import { ELEMENTS } from '@/lib/game/constants';
|
||||||
|
|
||||||
interface SpireGolemsProps {
|
interface SpireGolemsProps {
|
||||||
golemancy: {
|
golemancy: {
|
||||||
@@ -10,6 +12,7 @@ interface SpireGolemsProps {
|
|||||||
};
|
};
|
||||||
skills: Record<string, number>;
|
skills: Record<string, number>;
|
||||||
floorElem: string;
|
floorElem: string;
|
||||||
|
currentAction: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SpireGolems({ golemancy, skills, floorElem }: SpireGolemsProps) {
|
export function SpireGolems({ golemancy, skills, floorElem }: SpireGolemsProps) {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { useMemo } from 'react';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { Mountain, ChevronDown } from 'lucide-react';
|
import { Mountain, ChevronDown } from 'lucide-react';
|
||||||
import { ELEMENTS, GUARDIANS, SPELLS_DEF } from '@/lib/game/constants';
|
import type { ActivityLogEntry } from '@/lib/game/types';
|
||||||
|
import { ELEMENTS, GUARDIANS, SPELLS_DEF, SKILLS_DEF } from '@/lib/game/constants';
|
||||||
import { calcDamage, getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/utils';
|
import { calcDamage, getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/utils';
|
||||||
import { getUnifiedEffects } from '@/lib/game/effects';
|
import { getUnifiedEffects } from '@/lib/game/effects';
|
||||||
import { formatSpellCost, getSpellCostColor } from '@/lib/game/formatting';
|
import { formatSpellCost, getSpellCostColor } from '@/lib/game/formatting';
|
||||||
@@ -23,10 +24,20 @@ import { SpireActiveSpells } from './SpireActiveSpells';
|
|||||||
import { SpireGolems } from './SpireGolems';
|
import { SpireGolems } from './SpireGolems';
|
||||||
import { DebugName } from '@/lib/game/debug-context';
|
import { DebugName } from '@/lib/game/debug-context';
|
||||||
|
|
||||||
|
// Room type configurations
|
||||||
|
const ROOM_TYPE_CONFIG: Record<string, { label: string; icon: string; color: string }> = {
|
||||||
|
combat: { label: 'Combat', icon: '⚔️', color: '#EF4444' },
|
||||||
|
swarm: { label: 'Swarm', icon: '🐝', color: '#F59E0B' },
|
||||||
|
speed: { label: 'Speed', icon: '💨', color: '#3B82F6' },
|
||||||
|
guardian: { label: 'Guardian', icon: '🛡️', color: '#EF4444' },
|
||||||
|
puzzle: { label: 'Puzzle', icon: '🧩', color: '#8B5CF6' },
|
||||||
|
};
|
||||||
|
|
||||||
interface SpireTabProps {
|
interface SpireTabProps {
|
||||||
simpleMode?: boolean;
|
simpleMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if player can enter spire mode
|
||||||
const canEnterSpireMode = (spireMode: boolean): boolean => {
|
const canEnterSpireMode = (spireMode: boolean): boolean => {
|
||||||
return !spireMode;
|
return !spireMode;
|
||||||
};
|
};
|
||||||
@@ -72,14 +83,8 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
const currentGuardian = GUARDIANS[currentFloor];
|
const currentGuardian = GUARDIANS[currentFloor];
|
||||||
const isFloorCleared = clearedFloors[currentFloor];
|
const isFloorCleared = clearedFloors[currentFloor];
|
||||||
const roomType = currentRoom?.roomType || 'combat';
|
const roomType = currentRoom?.roomType || 'combat';
|
||||||
const roomConfig = {
|
const roomConfig = ROOM_TYPE_CONFIG[roomType] || ROOM_TYPE_CONFIG.combat;
|
||||||
combat: { label: 'Combat', icon: '⚔️', color: '#EF4444' },
|
|
||||||
swarm: { label: 'Swarm', icon: '🐝', color: '#F59E0B' },
|
|
||||||
speed: { label: 'Speed', icon: '💨', color: '#3B82F6' },
|
|
||||||
guardian: { label: 'Guardian', icon: '🛡️', color: '#EF4444' },
|
|
||||||
puzzle: { label: 'Puzzle', icon: '🧩', color: '#8B5CF6' },
|
|
||||||
}[roomType] || { label: 'Combat', icon: '⚔️', color: '#EF4444' };
|
|
||||||
|
|
||||||
const activeEquipmentSpells = useMemo(
|
const activeEquipmentSpells = useMemo(
|
||||||
() => getActiveEquipmentSpells(equippedInstances, equipmentInstances),
|
() => getActiveEquipmentSpells(equippedInstances, equipmentInstances),
|
||||||
[equippedInstances, equipmentInstances]
|
[equippedInstances, equipmentInstances]
|
||||||
@@ -107,12 +112,36 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
return canAffordSpellCost(spell.cost, rawMana, elements);
|
return canAffordSpellCost(spell.cost, rawMana, elements);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Climb handlers - defined OUTSIDE of JSX
|
||||||
|
const handleClimbUp = () => {
|
||||||
|
useCombatStore.getState().startClimbUp();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClimbDown = () => {
|
||||||
|
useCombatStore.getState().startClimbDown();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClimb = (direction: 'up' | 'down') => {
|
||||||
|
if (direction === 'up') {
|
||||||
|
handleClimbUp();
|
||||||
|
} else {
|
||||||
|
handleClimbDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getSkillName = (skillId: string): string => {
|
const getSkillName = (skillId: string): string => {
|
||||||
return SPELLS_DEF[skillId]?.name || skillId;
|
return SKILLS_DEF[skillId]?.name || skillId;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle exit spire mode
|
// Handle exit spire mode
|
||||||
const exitSpireMode = useCombatStore((s) => s.exitSpireMode);
|
const exitSpireMode = () => {
|
||||||
|
useCombatStore.getState().exitSpireMode();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle enter spire mode
|
||||||
|
const enterSpireMode = () => {
|
||||||
|
useCombatStore.getState().enterSpireMode();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DebugName name="SpireTab">
|
<DebugName name="SpireTab">
|
||||||
@@ -124,7 +153,7 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
<Button
|
<Button
|
||||||
className="w-full bg-gradient-to-r from-amber-600 to-orange-600 hover:from-amber-700 hover:to-orange-700"
|
className="w-full bg-gradient-to-r from-amber-600 to-orange-600 hover:from-amber-700 hover:to-orange-700"
|
||||||
size="lg"
|
size="lg"
|
||||||
onClick={useCombatStore.getState().enterSpireMode}
|
onClick={enterSpireMode}
|
||||||
disabled={!canEnterSpireMode(spireMode)}
|
disabled={!canEnterSpireMode(spireMode)}
|
||||||
>
|
>
|
||||||
<Mountain className="w-5 h-5 mr-2" />
|
<Mountain className="w-5 h-5 mr-2" />
|
||||||
@@ -194,7 +223,7 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
skills={skills}
|
skills={skills}
|
||||||
currentAction={currentAction}
|
currentAction={currentAction}
|
||||||
/>
|
/>
|
||||||
))}
|
)}
|
||||||
|
|
||||||
{/* Guardian Panel */}
|
{/* Guardian Panel */}
|
||||||
{isGuardianFloor && simpleMode && (
|
{isGuardianFloor && simpleMode && (
|
||||||
@@ -210,7 +239,7 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
roomType={roomType}
|
roomType={roomType}
|
||||||
roomConfig={roomConfig}
|
roomConfig={roomConfig}
|
||||||
primaryEnemy={currentRoom?.enemies?.[0] || null}
|
primaryEnemy={currentRoom?.enemies?.[0] || null}
|
||||||
swarmEnemies={roomType === 'swarm' ? currentRoom?.enemies || [] : []}
|
swarmEnemies={roomType === 'swarm' ? (currentRoom?.enemies || []) : []}
|
||||||
puzzleId={currentRoom?.puzzleId}
|
puzzleId={currentRoom?.puzzleId}
|
||||||
puzzleProgress={currentRoom?.puzzleProgress}
|
puzzleProgress={currentRoom?.puzzleProgress}
|
||||||
simpleMode={true}
|
simpleMode={true}
|
||||||
@@ -248,7 +277,7 @@ export function SpireTab({ simpleMode = false }: SpireTabProps) {
|
|||||||
calcDamage={calcDamage}
|
calcDamage={calcDamage}
|
||||||
SPELLS_DEF={SPELLS_DEF}
|
SPELLS_DEF={SPELLS_DEF}
|
||||||
canCastSpell={canCastSpell}
|
canCastSpell={canCastSpell}
|
||||||
handleClimb={(dir) => dir === 'up' ? useCombatStore.getState().startClimbUp() : useCombatStore.getState().startClimbDown()}
|
handleClimb={handleClimb}
|
||||||
formatSpellCost={formatSpellCost}
|
formatSpellCost={formatSpellCost}
|
||||||
getSpellCostColor={getSpellCostColor}
|
getSpellCostColor={getSpellCostColor}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user