- nav.js owns a light/dark toggle (persisted, default light) across all owner pages
- /nav API: spaces, store-layout, rack/{id}, crate/{id} over migrated virtual_* geometry
- /search rebuilt as Store→Rack→Crate drill-down (true rack rotation, per-level slot grid,
crate facing arrows + BACK/FRONT/L/R, search→locate)
- facing convention (directionYaw, slot-grid, rotatedArrows, world composition) in RECORDGOD_NAVIGATOR_PLAN.md
- no-cache HTML routes so deploys show instantly
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
4.7 KiB
JavaScript
78 lines
4.7 KiB
JavaScript
// Unified RecordGod owner nav — included on the back-office pages (admin / builder / dash / pos / search).
|
|
// One source of truth: edit the links here, every page updates. Kept OFF the customer shop/store.
|
|
// Also owns the LIGHT/DARK theme switch for every page (default light — the shop-admin readability default).
|
|
(function () {
|
|
const LINKS = [
|
|
{ href: '/admin', label: 'Admin' },
|
|
{ href: '/search', label: 'Search' },
|
|
{ href: '/pos', label: 'Sales' },
|
|
{ href: '/builder', label: 'Builder' },
|
|
{ href: '/shop', label: 'Shop' },
|
|
{ href: '/store/', label: '3D store' },
|
|
];
|
|
|
|
// ── theme: set the attribute ASAP (deferred script, so a brief light flash is possible) ──
|
|
const savedTheme = (() => { try { return localStorage.getItem('rg_theme'); } catch (_) { return null; } })();
|
|
document.documentElement.dataset.theme = savedTheme || 'light';
|
|
|
|
const here = (location.pathname.replace(/\/+$/, '') || '/');
|
|
const css = document.createElement('style');
|
|
css.textContent =
|
|
// light nav (default)
|
|
'#rg-nav{position:fixed;top:0;left:0;right:0;height:44px;display:flex;align-items:center;gap:4px;' +
|
|
'padding:0 16px;background:#ffffff;border-bottom:1px solid #e2e2ea;z-index:99999;font:14px system-ui}' +
|
|
'#rg-nav .b{font-weight:700;color:#1b1b22;text-decoration:none;margin-right:14px}' +
|
|
'#rg-nav .b i{color:#d10f7a;font-style:normal}' +
|
|
'#rg-nav a.l{color:#2a2a30;text-decoration:none;padding:6px 11px;border-radius:7px}' +
|
|
'#rg-nav a.l:hover{background:#f3f3f6}' +
|
|
'#rg-nav a.l.on{background:#fdeef6;color:#d10f7a}' +
|
|
'#rg-nav .sp{flex:1}' +
|
|
'#rg-theme{cursor:pointer;border:1px solid #e2e2ea;background:#fff;color:#2a2a30;border-radius:7px;' +
|
|
'padding:5px 9px;font-size:14px;line-height:1}' +
|
|
'#rg-theme:hover{background:#f3f3f6}' +
|
|
'body{padding-top:44px}' +
|
|
// ── DARK OVERRIDE — forces dark on the common surfaces across all (inline-styled, inconsistent) pages.
|
|
// !important is deliberate: it has to beat each page's own inline :root tokens + literals. ──
|
|
'html[data-theme="dark"]{color-scheme:dark}' +
|
|
'html[data-theme="dark"] body{background:#0f0f13 !important;color:#e8e8ec !important}' +
|
|
'html[data-theme="dark"] .panel,html[data-theme="dark"] .card,html[data-theme="dark"] .box,' +
|
|
'html[data-theme="dark"] .drop,html[data-theme="dark"] #gate{background:#17171c !important;' +
|
|
'border-color:#2a2a32 !important;color:#e8e8ec !important;box-shadow:none !important}' +
|
|
'html[data-theme="dark"] #gate{background:#0f0f13 !important}' +
|
|
'html[data-theme="dark"] input,html[data-theme="dark"] select,html[data-theme="dark"] textarea{' +
|
|
'background:#0e0e11 !important;color:#e8e8ec !important;border-color:#2a2a32 !important}' +
|
|
'html[data-theme="dark"] .ghost{background:#1d1d22 !important;color:#d8d8de !important;border-color:#2a2a32 !important}' +
|
|
'html[data-theme="dark"] .muted,html[data-theme="dark"] .lbl,html[data-theme="dark"] th{color:#9a9aa6 !important}' +
|
|
'html[data-theme="dark"] td,html[data-theme="dark"] th{border-color:#23232a !important}' +
|
|
'html[data-theme="dark"] .ri:hover{background:#22222a !important}' +
|
|
'html[data-theme="dark"] .panel h2,html[data-theme="dark"] h1.pg{color:#e6e6ec !important}' +
|
|
'html[data-theme="dark"] .tabs button.on{background:#17171c !important}' +
|
|
'html[data-theme="dark"] #rg-nav{background:#0a0a0c !important;border-color:#23232a !important}' +
|
|
'html[data-theme="dark"] #rg-nav .b{color:#eee !important}' +
|
|
'html[data-theme="dark"] #rg-nav a.l{color:#cfcfd6 !important}' +
|
|
'html[data-theme="dark"] #rg-nav a.l:hover{background:#17171c !important}' +
|
|
'html[data-theme="dark"] #rg-theme{background:#17171c !important;color:#cfcfd6 !important;border-color:#2a2a32 !important}';
|
|
document.head.appendChild(css);
|
|
|
|
const bar = document.createElement('nav');
|
|
bar.id = 'rg-nav';
|
|
bar.innerHTML = '<a class="b" href="/">Record<i>God</i></a>' +
|
|
LINKS.map(p => {
|
|
const on = here === p.href.replace(/\/+$/, '');
|
|
return `<a class="l${on ? ' on' : ''}" href="${p.href}">${p.label}</a>`;
|
|
}).join('') +
|
|
'<span class="sp"></span>' +
|
|
'<button id="rg-theme" title="Toggle light / dark"></button>';
|
|
document.body.insertBefore(bar, document.body.firstChild);
|
|
|
|
const btn = document.getElementById('rg-theme');
|
|
const paint = () => { btn.textContent = document.documentElement.dataset.theme === 'dark' ? '☀️' : '🌙'; };
|
|
paint();
|
|
btn.addEventListener('click', () => {
|
|
const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
|
|
document.documentElement.dataset.theme = next;
|
|
try { localStorage.setItem('rg_theme', next); } catch (_) {}
|
|
paint();
|
|
});
|
|
})();
|