diff --git a/public/index.html b/public/index.html index d4ddb4c..013a55d 100644 --- a/public/index.html +++ b/public/index.html @@ -62,17 +62,6 @@ - -
- Équipe -
-
- - -
-
-
-
@@ -224,21 +213,6 @@
- -
-
- ⚙ Options -
-
- - -
- - -
-
-
- diff --git a/public/src/auth.js b/public/src/auth.js index 3bca201..5d5aad5 100644 --- a/public/src/auth.js +++ b/public/src/auth.js @@ -1,5 +1,5 @@ import { apiLogin, apiRegister, apiGetMe } from "./api.js"; -import { setCurrentTeam, updateTeamSegmented, refreshFromServer } from "./game.js"; +import { setCurrentTeam, refreshFromServer } from "./game.js"; // ── DOM refs ────────────────────────────────────────────────────────────────── @@ -40,7 +40,6 @@ export function applyUser(user, token) { setCurrentTeam(user.team); userDisplayEl.textContent = `${user.username} [${user.team}]`; logoutBtn.classList.remove("hidden"); - updateTeamSegmented(); } function logout() { diff --git a/public/src/game.js b/public/src/game.js index ffc022e..506cb85 100644 --- a/public/src/game.js +++ b/public/src/game.js @@ -164,11 +164,6 @@ const econScoreRedEl = document.getElementById("econScoreRed"); const econDeltaBlueEl = document.getElementById("econDeltaBlue"); const econDeltaRedEl = document.getElementById("econDeltaRed"); const elemBonusTableEl = document.getElementById("elementBonusTableBody"); -const teamCorner = document.getElementById("teamCorner"); -const teamTrack = document.getElementById("teamSegmentedTrack"); -const teamBlueBtn = document.getElementById("teamBlue"); -const teamRedBtn = document.getElementById("teamRed"); - // ── Cell helpers ────────────────────────────────────────────────────────────── export function cellKey(x, y) { return `${x},${y}`; } @@ -211,8 +206,6 @@ export function applyConfigPayload(data) { updateResetCountdown(); - // Team switcher visibility is managed exclusively via unlockTeamSwitcher() / - // lockTeamSwitcher() — NOT by debugModeForTeams config. } export function updateResetCountdown() { @@ -226,17 +219,6 @@ export function updateResetCountdown() { String(s % 60).padStart(2, "0"); } -// ── Team switcher (admin-only) ──────────────────────────────────────────────── - -/** Show the team switcher widget. Called only after successful admin unlock. */ -export function unlockTeamSwitcher() { - teamCorner.classList.remove("teamCorner--hidden"); -} - -/** Hide the team switcher widget. */ -export function lockTeamSwitcher() { - teamCorner.classList.add("teamCorner--hidden"); -} // ── Scores ──────────────────────────────────────────────────────────────────── @@ -668,11 +650,6 @@ async function onCanvasClick(ev) { // ── Team segmented control ──────────────────────────────────────────────────── -export function updateTeamSegmented() { - teamTrack.dataset.active = currentTeam; - teamBlueBtn.setAttribute("aria-pressed", currentTeam === "blue" ? "true" : "false"); - teamRedBtn.setAttribute("aria-pressed", currentTeam === "red" ? "true" : "false"); -} // ── Lightweight grid refresh (called every second) ──────────────────────────── @@ -742,7 +719,3 @@ elemBonusTableEl?.addEventListener("click", (ev) => { canvas.addEventListener("mousemove", (ev) => { lastPointerEvent = ev; refreshCursor(ev); }); canvas.addEventListener("mouseleave", () => { lastPointerEvent = null; canvas.style.cursor = "default"; }); canvas.addEventListener("click", onCanvasClick); - -// Team switcher buttons (kept in codebase, only functional when admin-unlocked) -teamBlueBtn.addEventListener("click", () => { setCurrentTeam("blue"); updateTeamSegmented(); updateEconomyDisplay(); draw(); refreshCursorFromLast(); }); -teamRedBtn.addEventListener( "click", () => { setCurrentTeam("red"); updateTeamSegmented(); updateEconomyDisplay(); draw(); refreshCursorFromLast(); }); diff --git a/public/src/main.js b/public/src/main.js index 8eff9f8..d77c9b6 100644 --- a/public/src/main.js +++ b/public/src/main.js @@ -1,7 +1,6 @@ import { GAME_CONFIG, seedStr, - updateTeamSegmented, updateResetCountdown, fetchConfig, fetchGridForSeed, @@ -15,7 +14,6 @@ import { refreshGridDisplay, loadPlayfieldMask, draw, - unlockTeamSwitcher, } from "./game.js"; import { @@ -31,9 +29,6 @@ const cooldownEl = document.getElementById("cooldownConfig"); const burgerBtn = document.getElementById("burgerBtn"); const closeMenuBtn = document.getElementById("closeMenuBtn"); const infoColumn = document.getElementById("infoColumn"); -const adminPasswordIn = document.getElementById("adminPasswordInput"); -const adminUnlockBtn = document.getElementById("adminUnlockBtn"); -const adminStatus = document.getElementById("adminStatus"); // ── Polling ─────────────────────────────────────────────────────────────────── @@ -89,49 +84,9 @@ document.addEventListener("click", (ev) => { } }); -// ── Admin password unlock ───────────────────────────────────────────────────── - -function showAdminStatus(message, isOk) { - adminStatus.textContent = message; - adminStatus.className = "adminStatus " + (isOk ? "adminStatus--ok" : "adminStatus--err"); -} - -adminUnlockBtn.addEventListener("click", async () => { - const password = adminPasswordIn.value.trim(); - if (!password) { - showAdminStatus("Enter a password.", false); - return; - } - - try { - const res = await fetch("/api/admin/verify", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ password }), - }); - const data = await res.json(); - if (res.ok && data.ok) { - showAdminStatus("Admin unlocked — team switcher enabled.", true); - unlockTeamSwitcher(); - adminPasswordIn.value = ""; - } else { - showAdminStatus("Invalid password.", false); - } - } catch { - showAdminStatus("Could not verify — server unreachable.", false); - } -}); - -// Allow Enter key in password field -adminPasswordIn.addEventListener("keydown", (ev) => { - if (ev.key === "Enter") adminUnlockBtn.click(); -}); - // ── Boot ────────────────────────────────────────────────────────────────────── async function boot() { - updateTeamSegmented(); - // Load the SVG playfield mask before any drawing or data fetch await loadPlayfieldMask(); diff --git a/public/style.css b/public/style.css index e15b583..ace5cf4 100644 --- a/public/style.css +++ b/public/style.css @@ -192,85 +192,7 @@ body { background: rgba(113, 199, 255, 0.28); } -/* ── Team corner (admin only) ─────────────────────────────────────────────── */ -.teamCorner { - position: fixed; - top: 12px; - left: 12px; - z-index: 10; - display: flex; - align-items: center; - gap: 8px; - padding: 8px 10px; - border-radius: 12px; - border: 1px solid rgba(255, 255, 255, 0.12); - background: rgba(7, 10, 20, 0.85); - backdrop-filter: blur(8px); -} - -.teamCornerLabel { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.06em; - opacity: 0.75; -} - -.teamCorner--hidden { - display: none !important; -} - -.teamSegmented { - min-width: 148px; -} - -.teamSegmentedTrack { - position: relative; - display: grid; - grid-template-columns: 1fr 1fr; - border-radius: 12px; - overflow: hidden; - border: 1px solid rgba(255, 255, 255, 0.18); - background: rgba(0, 0, 0, 0.25); -} - -.teamSegmentedTrack::before { - content: ""; - position: absolute; - top: 2px; - bottom: 2px; - left: 2px; - width: calc(50% - 4px); - border-radius: 9px; - background: linear-gradient(180deg, rgba(90, 200, 255, 0.42), rgba(35, 95, 150, 0.55)); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12); - transition: left 0.22s ease, background 0.22s ease; - z-index: 0; - pointer-events: none; -} - -.teamSegmentedTrack[data-active="red"]::before { - left: calc(50% + 2px); - background: linear-gradient(180deg, rgba(255, 130, 130, 0.42), rgba(150, 45, 45, 0.55)); -} - -.teamSegmentedBtn { - position: relative; - z-index: 1; - margin: 0; - padding: 9px 12px; - border: none; - background: transparent; - color: #e9eef6; - font-weight: 700; - font-size: 13px; - cursor: pointer; -} - -.teamSegmentedBtn:hover { - color: #ffffff; -} /* ── Score board ──────────────────────────────────────────────────────────── */ @@ -972,97 +894,6 @@ button:hover { color: rgba(255, 220, 100, 0.9); } -/* ── Options / admin section ──────────────────────────────────────────────── */ - -.infoSection--options { - padding-top: 8px; -} - -.optionsDetails { - border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.07); - overflow: hidden; -} - -.optionsSummary { - padding: 8px 12px; - font-size: 11px; - font-weight: 600; - opacity: 0.6; - cursor: pointer; - list-style: none; - user-select: none; - display: flex; - align-items: center; -} - -.optionsSummary::after { - content: "›"; - margin-left: auto; - font-size: 16px; - font-weight: 400; - opacity: 0.4; - display: inline-block; - transform: rotate(0deg); - transition: transform 0.2s ease, opacity 0.15s; -} - -.optionsDetails[open] .optionsSummary::after { - transform: rotate(90deg); - opacity: 0.7; -} - -.optionsSummary::-webkit-details-marker { - display: none; -} - -.optionsSummary:hover { - opacity: 0.9; -} - -.optionsPanel { - padding: 12px; - display: flex; - flex-direction: column; - gap: 10px; - border-top: 1px solid rgba(255, 255, 255, 0.07); -} - -.optionsPanel .authField input[type="password"] { - padding: 8px 10px; - font-size: 12px; - font-family: "Courier New", Courier, monospace; -} - -.adminUnlockBtn { - padding: 7px 12px; - font-size: 12px; - align-self: flex-start; -} - -.adminStatus { - font-size: 11px; - padding: 6px 10px; - border-radius: 7px; - font-family: "Courier New", Courier, monospace; -} - -.adminStatus.hidden { - display: none; -} - -.adminStatus--ok { - color: rgba(90, 200, 130, 0.95); - background: rgba(30, 120, 60, 0.15); - border: 1px solid rgba(30, 150, 70, 0.25); -} - -.adminStatus--err { - color: rgba(255, 130, 100, 0.95); - background: rgba(200, 50, 30, 0.12); - border: 1px solid rgba(200, 50, 30, 0.25); -} - /* ── Galaxy: square, fills viewport height, 1:1 ratio ────────────────────── */ .galaxyMain { diff --git a/server/routes/game.js b/server/routes/game.js index e856d2a..3d00337 100644 --- a/server/routes/game.js +++ b/server/routes/game.js @@ -164,19 +164,6 @@ router.post("/cell/reveal", authMiddleware, async (req, res) => { } }); -// POST /api/admin/verify -router.post("/admin/verify", (req, res) => { - const password = String(req.body?.password ?? ""); - const adminPwd = process.env.ADMIN_PASSWORD; - if (!adminPwd) { - return res.status(503).json({ ok: false, error: "not_configured" }); - } - if (password && password === adminPwd) { - return res.json({ ok: true }); - } - return res.status(401).json({ ok: false, error: "invalid_password" }); -}); - // GET /api/econ-scores router.get("/econ-scores", async (_req, res) => { try {