From d45fa49a46a638a787cb1f88b374bb4853080fc4 Mon Sep 17 00:00:00 2001 From: Jonathan Sykes Date: Thu, 15 Oct 2026 11:21:49 +0800 Subject: [PATCH] Settings: hidden Admin entry (opens /admin in the app window); admin page keeps a back link on phones --- frontend/admin.html | 4 ++-- frontend/views-core.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/frontend/admin.html b/frontend/admin.html index 0d8cbc4..36152a9 100644 --- a/frontend/admin.html +++ b/frontend/admin.html @@ -287,7 +287,7 @@ } .nav { display: none; } @media (max-width: 760px) { - .tabs, .top .ghost.desk { display: none; } + .tabs, .top .desk-only { display: none; } .top { padding: 10px 14px; } .nav { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; @@ -343,7 +343,7 @@ Lyrics Studio - ← Back to app + ← Back to App diff --git a/frontend/views-core.js b/frontend/views-core.js index 49f6b65..56b705a 100644 --- a/frontend/views-core.js +++ b/frontend/views-core.js @@ -1074,6 +1074,15 @@ async function renderSettings() { … + `; c.appendChild(wrap); @@ -1456,6 +1465,34 @@ async function renderSettings() { }); updateProfileStatus(); + // ---- About: Admin entry. Shown once this device has signed in as admin, + // or after a long-press / five taps on the version (then remembered). It + // opens /admin inside the app window, which has no address bar on iPhone. + if (WEB) { + const ADMIN_KEY = 'ytpAdminEntry'; + const revealAdmin = (remember) => { + const row = $('aboutAdminRow'); + if (row) row.classList.remove('hidden'); + if (remember) { try { localStorage.setItem(ADMIN_KEY, '1'); } catch {} } + }; + try { if (localStorage.getItem(ADMIN_KEY) === '1') revealAdmin(false); } catch {} + fetch('/api/admin/me', { cache: 'no-store', credentials: 'same-origin' }) + .then((r) => (r.ok ? r.json() : null)).then((me) => { if (me && me.admin) revealAdmin(true); }).catch(() => {}); + const ver = $('aboutVersion'); + if (ver) { + let taps = 0, tapTimer = null, holdTimer = null; + const unlock = () => { if ($('aboutAdminRow')?.classList.contains('hidden')) { revealAdmin(true); toast('Admin entry shown in About'); } }; + ver.addEventListener('pointerdown', () => { clearTimeout(holdTimer); holdTimer = setTimeout(unlock, 700); }); + for (const n of ['pointerup', 'pointerleave', 'pointercancel']) ver.addEventListener(n, () => clearTimeout(holdTimer)); + ver.addEventListener('click', () => { + taps++; clearTimeout(tapTimer); tapTimer = setTimeout(() => { taps = 0; }, 1500); + if (taps >= 5) { taps = 0; unlock(); } + }); + ver.addEventListener('contextmenu', (e) => e.preventDefault()); + ver.style.webkitUserSelect = 'none'; ver.style.userSelect = 'none'; + } + } + // ---- About: append server build tag + build time (WEB mode only) ---- if (WEB) { try {