mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-01 16:58:06 +00:00
feat(web): mobile navigation drawer + responsive CSS gap fixes
Phones previously got the desktop layout squeezed: ~12 system tabs plus one tab per installed plugin wrapped into many rows of small pill buttons, and the header's settings-search and system-stats widgets were dropped entirely (hidden below their breakpoints, never relocated). - Off-canvas nav drawer below md: the existing nav markup (system tab row + #plugin-tabs-row, including dynamically injected plugin tabs) is wrapped in a #site-nav container that CSS repositions into a slide-in drawer on small screens. Same DOM nodes, same @click handlers, nothing duplicated. Tabs become full-width rows with 44px+ touch targets. A hamburger button (md:hidden) in the header and a backdrop toggle the new mobileNavOpen Alpine state (added to both app() definitions, mirroring activeTab). Clicking any tab, a search result, or the backdrop closes the drawer. At md+ hard CSS guards make all drawer styles inert - desktop renders exactly as before. - Header widgets relocated, not hidden: placeHeaderWidgets() in app.js moves the #settings-search-wrap and #system-stats nodes (same elements, listeners intact - both are looked up by id from SSE/search code, so they must never be duplicated) into the drawer below md and back into the header above it, via a matchMedia listener. - Fixed 13 breakpoint utility classes that templates referenced but app.css never defined (sm:block, sm:grid-cols-2, sm:text-sm, md:block, md:w-auto, lg:block, lg:flex, lg:w-64, xl:grid-cols-2/3, 2xl:grid-cols-2/3/4). This was a live bug: 'hidden sm:block' on the search box and 'hidden lg:flex' on the stats meant BOTH were invisible at every screen width. Audit method (repeatable): diff classes used in templates vs defined in app.css. - Mobile modal sizing: one global rule caps .modal-content at 95vw/90vh with internal scroll below 640px - covers every modal without per-template changes. - Horizontal-scroll affordance: pure-CSS edge-fade shadows on .overflow-x-auto containers (scrolling-shadows technique), plus larger in-table touch targets below md. Validation: breakpoint used-vs-defined audit now returns zero gaps; Jinja parse of base.html passes; all changes to desktop behavior are additive (new utilities) or scoped inside max-width media queries. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d2b49c4ff2
commit
1ae3b7fa24
@@ -273,3 +273,38 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
// ===== Mobile nav: header-widget relocation =====
|
||||
// Below the md breakpoint the settings-search box and system-stats block are
|
||||
// MOVED (same DOM nodes, listeners intact) from the header into the nav
|
||||
// drawer's #drawer-widgets slot; at md and up they move back. Single-instance
|
||||
// constraint: settings-search.js and the SSE stats updater both look these
|
||||
// elements up by id, so they must never be duplicated.
|
||||
window.placeHeaderWidgets = function() {
|
||||
const drawer = document.getElementById('drawer-widgets');
|
||||
const header = document.getElementById('header-widgets');
|
||||
const search = document.getElementById('settings-search-wrap');
|
||||
const stats = document.getElementById('system-stats');
|
||||
if (!drawer || !header) return;
|
||||
|
||||
const desktop = window.matchMedia('(min-width: 768px)').matches;
|
||||
if (desktop) {
|
||||
// Restore original header order: search before the theme toggle,
|
||||
// stats as the last item.
|
||||
const themeToggle = document.getElementById('theme-toggle');
|
||||
if (search && search.parentElement !== header) {
|
||||
header.insertBefore(search, themeToggle || null);
|
||||
}
|
||||
if (stats && stats.parentElement !== header) {
|
||||
header.appendChild(stats);
|
||||
}
|
||||
} else {
|
||||
if (search && search.parentElement !== drawer) drawer.appendChild(search);
|
||||
if (stats && stats.parentElement !== drawer) drawer.appendChild(stats);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
window.placeHeaderWidgets();
|
||||
window.matchMedia('(min-width: 768px)').addEventListener('change', window.placeHeaderWidgets);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user