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