From be66d9a7cf96f92122910409e60a65bbc230601f Mon Sep 17 00:00:00 2001 From: Jose Luis Date: Sat, 21 Mar 2026 03:15:31 +0100 Subject: [PATCH] feat: admin auto-solve button for quick level testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add adminMode toggle in AdminPanel (green "Admin ON/OFF" button) - Pass adminMode through GameApp → PuzzleView - Show purple "🛠 Resolver" button in puzzle toolbar when admin is active - Auto-solve gives 3 stars instantly and shows completion overlay - Lets admin skip through all 96 levels for rapid testing Co-Authored-By: Claude Opus 4.6 --- src/game/AdminPanel.jsx | 8 +++++++- src/game/GameApp.jsx | 4 ++++ src/game/PuzzleView.jsx | 18 +++++++++++++++++- src/index.css | 8 ++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/game/AdminPanel.jsx b/src/game/AdminPanel.jsx index 3e288c8..223128f 100644 --- a/src/game/AdminPanel.jsx +++ b/src/game/AdminPanel.jsx @@ -5,7 +5,7 @@ import React, { useState } from 'react'; import { loadProgress, saveProgress, resetProgress } from './gameState.js'; -export default function AdminPanel({ worlds, onClose }) { +export default function AdminPanel({ worlds, onClose, adminMode, onToggleAdmin }) { const [, refresh] = useState(0); const p = loadProgress(); const totalStars = Object.values(p.completedLevels).reduce((s, l) => s + (l.stars || 0), 0); @@ -63,6 +63,12 @@ export default function AdminPanel({ worlds, onClose }) {
+
diff --git a/src/game/GameApp.jsx b/src/game/GameApp.jsx index 82d0f11..3872f1a 100644 --- a/src/game/GameApp.jsx +++ b/src/game/GameApp.jsx @@ -23,6 +23,7 @@ export default function GameApp({ onSwitchToSandbox }) { const [currentLevelIndex, setCurrentLevelIndex] = useState(0); const [currentWorld, setCurrentWorld] = useState(null); const [showAdmin, setShowAdmin] = useState(false); + const [adminMode, setAdminMode] = useState(false); const handleSelectLevel = useCallback((level, world) => { const idx = world.levels.findIndex(l => l.id === level.id); @@ -67,6 +68,7 @@ export default function GameApp({ onSwitchToSandbox }) { worldLevels={currentWorld.levels} onBack={handleBack} onNextLevel={handleNextLevel} + adminMode={adminMode} /> ); } @@ -82,6 +84,8 @@ export default function GameApp({ onSwitchToSandbox }) { setShowAdmin(false)} + adminMode={adminMode} + onToggleAdmin={() => setAdminMode(a => !a)} /> )} diff --git a/src/game/PuzzleView.jsx b/src/game/PuzzleView.jsx index 23f0c31..e9b9684 100644 --- a/src/game/PuzzleView.jsx +++ b/src/game/PuzzleView.jsx @@ -9,7 +9,7 @@ import LevelComplete from './LevelComplete.jsx'; import { completeLevel, saveLevelPatch, getLevelPatch, markHintUsed, wasHintUsed } from './gameState.js'; import { playLevelComplete, playFail, playHint, playEngineStart, playEngineStop, playNav } from '../engine/uiSounds.js'; -export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onNextLevel }) { +export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onNextLevel, adminMode }) { const [, forceUpdate] = useState(0); const containerRef = useRef(null); const portPositions = useRef({}); @@ -285,6 +285,17 @@ export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onN } }; + // Admin auto-solve — gives 3 stars instantly + const handleAutoSolve = () => { + const checks = level.checks.map(check => ({ + ...check, + passed: true, + })); + completeLevel(level.id, 3); + setResult({ stars: 3, checks, hintPenalty: false }); + playLevelComplete(); + }; + const isLastLevel = levelIndex >= worldLevels.length - 1; return ( @@ -312,6 +323,11 @@ export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onN + {adminMode && ( + + )} diff --git a/src/index.css b/src/index.css index 62f18f8..ffd49cc 100644 --- a/src/index.css +++ b/src/index.css @@ -715,9 +715,17 @@ html, body, #root { } .admin-action-btn.gold { border-color: var(--yellow); color: var(--yellow); } .admin-action-btn.gold:hover { background: var(--yellow); color: var(--bg); } +.admin-action-btn.active { border-color: var(--green); color: var(--green); background: rgba(68, 255, 136, 0.1); } +.admin-action-btn.active:hover { background: var(--green); color: var(--bg); } .admin-action-btn.danger { border-color: var(--red); color: var(--red); } .admin-action-btn.danger:hover { background: var(--red); color: #fff; } +/* Admin auto-solve button in puzzle bar */ +.gm-btn.admin-solve { + background: rgba(170, 85, 255, 0.15); border-color: var(--purple); color: var(--purple); +} +.gm-btn.admin-solve:hover { background: var(--purple); color: #fff; } + .admin-world { margin-bottom: 16px; } .admin-world-header { display: flex; align-items: center; gap: 8px;