Settings: hidden Admin entry (opens /admin in the app window); admin page keeps a back link on phones
This commit is contained in:
@@ -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 @@
|
||||
<a class="brand" href="/admin#editor" data-home style="text-decoration:none;color:inherit"><i><svg viewBox="0 0 24 24"><path d="M9 18V6l10-2v12"/><circle cx="6.5" cy="18" r="2.5"/><circle cx="16.5" cy="16" r="2.5"/></svg></i>Lyrics Studio</a>
|
||||
<nav class="tabs" role="tablist" id="tabsTop"></nav>
|
||||
<span class="grow"></span>
|
||||
<a class="ghost desk" href="/">← Back to app</a>
|
||||
<a class="ghost back-app" href="/">← <span class="desk-only">Back to </span>App</a>
|
||||
<button id="logoutBtn" class="ghost">Sign out</button>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -1074,6 +1074,15 @@ async function renderSettings() {
|
||||
</span>
|
||||
<span id="aboutBuildTime" class="about-version">…</span>
|
||||
</div>
|
||||
<div class="set-row hidden" id="aboutAdminRow">
|
||||
<span>
|
||||
Admin
|
||||
<small>Lyrics studio, reports, library and server tools. Needs the admin password.</small>
|
||||
</span>
|
||||
<div class="set-actions" style="margin:0">
|
||||
<a class="btn" href="/admin" id="aboutAdminLink" style="text-decoration:none;display:inline-flex;align-items:center">Open admin</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user