d2d28887b1
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
108 lines
3.4 KiB
TypeScript
108 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Mountain } from 'lucide-react';
|
|
import { ManaDisplay } from '@/components/game';
|
|
import { ActionButtons } from '@/components/game';
|
|
import { CalendarDisplay } from '@/components/game';
|
|
import { DebugName } from '@/lib/game/debug-context';
|
|
import type { GameStore } from '@/lib/game/store';
|
|
import { computeMaxMana, computeClickMana, getMeditationBonus, getUnifiedEffects } from '@/lib/game/store';
|
|
import { useGameLoop } from '@/lib/game/stores/gameHooks';
|
|
|
|
interface LeftPanelProps {
|
|
store: GameStore;
|
|
effectiveRegen: number;
|
|
incursionStrength: number;
|
|
}
|
|
|
|
export function LeftPanel({ store, effectiveRegen, incursionStrength }: LeftPanelProps) {
|
|
const [isGathering, setIsGathering] = useState(false);
|
|
|
|
const handleGatherStart = () => {
|
|
setIsGathering(true);
|
|
store.gatherMana();
|
|
};
|
|
|
|
const handleGatherEnd = () => {
|
|
setIsGathering(false);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!isGathering) return;
|
|
|
|
let lastGatherTime = 0;
|
|
const minGatherInterval = 100;
|
|
let animationFrameId: number;
|
|
|
|
const gatherLoop = (timestamp: number) => {
|
|
if (timestamp - lastGatherTime >= minGatherInterval) {
|
|
store.gatherMana();
|
|
lastGatherTime = timestamp;
|
|
}
|
|
animationFrameId = requestAnimationFrame(gatherLoop);
|
|
};
|
|
|
|
animationFrameId = requestAnimationFrame(gatherLoop);
|
|
return () => cancelAnimationFrame(animationFrameId);
|
|
}, [isGathering, store]);
|
|
|
|
const maxMana = computeMaxMana(store, getUnifiedEffects(store));
|
|
const clickMana = computeClickMana(store);
|
|
const meditationMultiplier = getMeditationBonus(store.meditateTicks, store.skills, getUnifiedEffects(store).meditationEfficiency);
|
|
|
|
return (
|
|
<div className="md:w-80 space-y-4 flex-shrink-0">
|
|
<DebugName name="ManaDisplay">
|
|
<ManaDisplay
|
|
rawMana={store.rawMana}
|
|
maxMana={maxMana}
|
|
effectiveRegen={effectiveRegen}
|
|
meditationMultiplier={meditationMultiplier}
|
|
clickMana={clickMana}
|
|
isGathering={isGathering}
|
|
onGatherStart={handleGatherStart}
|
|
onGatherEnd={handleGatherEnd}
|
|
elements={store.elements}
|
|
/>
|
|
</DebugName>
|
|
|
|
{!store.spireMode && (
|
|
<DebugName name="ClimbSpireButton">
|
|
<Button
|
|
className="w-full bg-gradient-to-r from-amber-600 to-orange-600 hover:from-amber-700 hover:to-orange-700"
|
|
size="lg"
|
|
onClick={() => store.enterSpireMode()}
|
|
>
|
|
<Mountain className="w-5 h-5 mr-2" />
|
|
Climb the Spire
|
|
</Button>
|
|
</DebugName>
|
|
)}
|
|
|
|
{!store.spireMode && (
|
|
<DebugName name="ActionButtons">
|
|
<ActionButtons
|
|
currentAction={store.currentAction}
|
|
currentStudyTarget={store.currentStudyTarget}
|
|
designProgress={store.designProgress}
|
|
designProgress2={store.designProgress2}
|
|
preparationProgress={store.preparationProgress}
|
|
applicationProgress={store.applicationProgress}
|
|
equipmentCraftingProgress={store.equipmentCraftingProgress}
|
|
/>
|
|
</DebugName>
|
|
)}
|
|
|
|
<DebugName name="CalendarDisplay">
|
|
<CalendarDisplay
|
|
day={store.day}
|
|
hour={store.hour}
|
|
incursionStrength={incursionStrength}
|
|
/>
|
|
</DebugName>
|
|
</div>
|
|
);
|
|
}
|