Phase 2: Remove unreferenced GameHeader, GameSidebar, GameOverScreen components
This commit is contained in:
@@ -1,78 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
|
||||||
import { Pause, Play } from 'lucide-react';
|
|
||||||
import { useGameContext } from '../GameContext';
|
|
||||||
import { formatTime } from '../types';
|
|
||||||
import { MAX_DAY, INCURSION_START_DAY } from '@/lib/game/constants';
|
|
||||||
import { fmt } from '@/lib/game/stores';
|
|
||||||
|
|
||||||
export function GameHeader() {
|
|
||||||
const { store } = useGameContext();
|
|
||||||
|
|
||||||
// Calendar rendering
|
|
||||||
const renderCalendar = () => {
|
|
||||||
const days: React.ReactElement[] = [];
|
|
||||||
for (let d = 1; d <= MAX_DAY; d++) {
|
|
||||||
let dayClass = 'w-7 h-7 rounded text-xs flex items-center justify-center font-mono border transition-all ';
|
|
||||||
|
|
||||||
if (d < store.day) {
|
|
||||||
dayClass += 'bg-blue-900/30 border-blue-800/50 text-blue-400';
|
|
||||||
} else if (d === store.day) {
|
|
||||||
dayClass += 'bg-blue-600/40 border-blue-500 text-blue-300 shadow-lg shadow-blue-500/30';
|
|
||||||
} else {
|
|
||||||
dayClass += 'bg-gray-800/30 border-gray-700/50 text-gray-500';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d >= INCURSION_START_DAY) {
|
|
||||||
dayClass += ' border-red-600/50';
|
|
||||||
}
|
|
||||||
|
|
||||||
days.push(
|
|
||||||
<Tooltip key={d}>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<div className={dayClass}>{d}</div>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>Day {d}</p>
|
|
||||||
{d >= INCURSION_START_DAY && <p className="text-red-400">Incursion Active</p>}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return days;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className="sticky top-0 z-50 bg-gradient-to-b from-gray-900 to-gray-900/80 border-b border-gray-700 px-4 py-2">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h1 className="text-xl font-bold game-title tracking-wider">MANA LOOP</h1>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-lg font-bold game-mono text-amber-400">Day {store.day}</div>
|
|
||||||
<div className="text-xs text-gray-400">{formatTime(store.hour)}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-lg font-bold game-mono text-purple-400">{fmt(store.insight)}</div>
|
|
||||||
<div className="text-xs text-gray-400">Insight</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => store.togglePause()}
|
|
||||||
className="text-gray-400 hover:text-white"
|
|
||||||
>
|
|
||||||
{store.paused ? <Play className="w-4 h-4" /> : <Pause className="w-4 h-4" />}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Calendar */}
|
|
||||||
<div className="mt-2 flex gap-1 overflow-x-auto pb-1">{renderCalendar()}</div>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { Progress } from '@/components/ui/progress';
|
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
|
||||||
import { Zap, Sparkles, Swords, BookOpen, FlaskConical, type LucideIcon } from 'lucide-react';
|
|
||||||
import { useGameContext } from '../GameContext';
|
|
||||||
import { fmt, fmtDec } from '@/lib/game/stores';
|
|
||||||
import type { GameAction } from '@/lib/game/types';
|
|
||||||
|
|
||||||
export function GameSidebar() {
|
|
||||||
const {
|
|
||||||
store,
|
|
||||||
maxMana,
|
|
||||||
clickMana,
|
|
||||||
effectiveRegen,
|
|
||||||
meditationMultiplier,
|
|
||||||
floorElemDef,
|
|
||||||
} = useGameContext();
|
|
||||||
|
|
||||||
const [isGathering, setIsGathering] = useState(false);
|
|
||||||
|
|
||||||
// Auto-gather while holding
|
|
||||||
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 handleGatherStart = useCallback(() => {
|
|
||||||
setIsGathering(true);
|
|
||||||
store.gatherMana();
|
|
||||||
}, [store]);
|
|
||||||
|
|
||||||
const handleGatherEnd = useCallback(() => {
|
|
||||||
setIsGathering(false);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Action buttons
|
|
||||||
const actions: { id: GameAction; label: string; icon: LucideIcon }[] = [
|
|
||||||
{ id: 'meditate', label: 'Meditate', icon: Sparkles },
|
|
||||||
{ id: 'climb', label: 'Climb', icon: Swords },
|
|
||||||
{ id: 'study', label: 'Study', icon: BookOpen },
|
|
||||||
{ id: 'convert', label: 'Convert', icon: FlaskConical },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<aside className="w-full md:w-64 bg-gray-900/50 border-b md:border-b-0 md:border-r border-gray-700 p-4 space-y-4">
|
|
||||||
{/* Mana Panel */}
|
|
||||||
<Card className="bg-gray-900/80 border-gray-700">
|
|
||||||
<CardContent className="pt-4 space-y-3">
|
|
||||||
<div>
|
|
||||||
<div className="flex items-baseline gap-1">
|
|
||||||
<span className="text-3xl font-bold game-mono text-blue-400">{fmt(store.rawMana)}</span>
|
|
||||||
<span className="text-sm text-gray-400">/ {fmt(maxMana)}</span>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-gray-400">
|
|
||||||
+{fmtDec(effectiveRegen)} mana/hr{' '}
|
|
||||||
{meditationMultiplier > 1.01 && (
|
|
||||||
<span className="text-purple-400">({fmtDec(meditationMultiplier, 1)}x med)</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Progress value={(store.rawMana / maxMana) * 100} className="h-2 bg-gray-800" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
className={`w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 ${
|
|
||||||
isGathering ? 'animate-pulse' : ''
|
|
||||||
}`}
|
|
||||||
onMouseDown={handleGatherStart}
|
|
||||||
onMouseUp={handleGatherEnd}
|
|
||||||
onMouseLeave={handleGatherEnd}
|
|
||||||
onTouchStart={handleGatherStart}
|
|
||||||
onTouchEnd={handleGatherEnd}
|
|
||||||
>
|
|
||||||
<Zap className="w-4 h-4 mr-2" />
|
|
||||||
Gather +{clickMana} Mana
|
|
||||||
{isGathering && <span className="ml-2 text-xs">(Holding...)</span>}
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Actions */}
|
|
||||||
<Card className="bg-gray-900/80 border-gray-700">
|
|
||||||
<CardContent className="pt-4">
|
|
||||||
<div className="text-xs text-amber-400 game-panel-title mb-2">Current Action</div>
|
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
{actions.map(({ id, label, icon: Icon }) => (
|
|
||||||
<Button
|
|
||||||
key={id}
|
|
||||||
variant={store.currentAction === id ? 'default' : 'outline'}
|
|
||||||
size="sm"
|
|
||||||
className={`h-9 ${
|
|
||||||
store.currentAction === id
|
|
||||||
? 'bg-blue-600 hover:bg-blue-700'
|
|
||||||
: 'bg-gray-800/50 hover:bg-gray-700/50 border-gray-600'
|
|
||||||
}`}
|
|
||||||
onClick={() => store.setAction(id)}
|
|
||||||
>
|
|
||||||
<Icon className="w-4 h-4 mr-1" />
|
|
||||||
{label}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Floor Status */}
|
|
||||||
<Card className="bg-gray-900/80 border-gray-700">
|
|
||||||
<CardContent className="pt-4 space-y-2">
|
|
||||||
<div className="text-xs text-amber-400 game-panel-title mb-2">Floor Status</div>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<span className="text-sm text-gray-400">Current</span>
|
|
||||||
<span className="text-lg font-bold" style={{ color: floorElemDef?.color }}>
|
|
||||||
{store.currentFloor}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<Progress value={(store.floorHP / store.floorMaxHP) * 100} className="h-2 bg-gray-800" />
|
|
||||||
<div className="text-xs text-gray-400 game-mono">
|
|
||||||
{fmt(store.floorHP)} / {fmt(store.floorMaxHP)} HP
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</aside>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { useGameContext } from '../GameContext';
|
|
||||||
import { fmt } from '@/lib/game/stores';
|
|
||||||
import { MemorySlotPicker } from './MemorySlotPicker';
|
|
||||||
|
|
||||||
export function GameOverScreen() {
|
|
||||||
const { store } = useGameContext();
|
|
||||||
const [memoriesConfirmed, setMemoriesConfirmed] = useState(false);
|
|
||||||
|
|
||||||
if (!store.gameOver) return null;
|
|
||||||
|
|
||||||
const handleStartNewLoop = () => {
|
|
||||||
store.startNewLoop();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="fixed inset-0 game-overlay flex items-center justify-center z-50 overflow-auto py-4">
|
|
||||||
<div className="max-w-lg w-full mx-4 space-y-4">
|
|
||||||
<Card className="bg-gray-900 border-gray-600 shadow-2xl">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle
|
|
||||||
className={`text-3xl text-center game-title ${store.victory ? 'text-amber-400' : 'text-red-400'}`}
|
|
||||||
>
|
|
||||||
{store.victory ? '🏆 VICTORY!' : '⏰ LOOP ENDS'}
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-4">
|
|
||||||
<p className="text-center text-gray-400">
|
|
||||||
{store.victory
|
|
||||||
? 'The Awakened One falls! Your power echoes through eternity.'
|
|
||||||
: 'The time loop resets... but you remember.'}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
|
||||||
<div className="p-3 bg-gray-800 rounded">
|
|
||||||
<div className="text-xl font-bold text-amber-400 game-mono">{fmt(store.loopInsight)}</div>
|
|
||||||
<div className="text-xs text-gray-400">Insight Gained</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-3 bg-gray-800 rounded">
|
|
||||||
<div className="text-xl font-bold text-blue-400 game-mono">{store.maxFloorReached}</div>
|
|
||||||
<div className="text-xs text-gray-400">Best Floor</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-3 bg-gray-800 rounded">
|
|
||||||
<div className="text-xl font-bold text-purple-400 game-mono">{store.signedPacts.length}</div>
|
|
||||||
<div className="text-xs text-gray-400">Pacts Signed</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-3 bg-gray-800 rounded">
|
|
||||||
<div className="text-xl font-bold text-green-400 game-mono">{store.loopCount + 1}</div>
|
|
||||||
<div className="text-xs text-gray-400">Total Loops</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Memory Slot Picker */}
|
|
||||||
{store.memorySlots > 0 && !memoriesConfirmed && (
|
|
||||||
<MemorySlotPicker onConfirm={() => setMemoriesConfirmed(true)} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700"
|
|
||||||
size="lg"
|
|
||||||
onClick={handleStartNewLoop}
|
|
||||||
disabled={store.memorySlots > 0 && !memoriesConfirmed}
|
|
||||||
>
|
|
||||||
Begin New Loop
|
|
||||||
{store.memorySlots > 0 && !memoriesConfirmed && ' (Confirm Memories First)'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user