mobile drawer + responsive polish

This commit is contained in:
Dinarassan 2026-05-22 14:39:02 +05:00
parent 276d188637
commit 972d2be0d0

19
app.js
View File

@ -27,6 +27,7 @@ const CLIENT_STATUSES = ['active', 'on_hold', 'archived'];
let STATE = loadState() ?? clone(window.SEED);
let MODAL = null; // { title, body, footer } object
let DROPDOWN = null; // 'notifications' | null
let SIDEBAR_OPEN = false; // mobile drawer state
function clone(o) { return JSON.parse(JSON.stringify(o)); }
function loadState() {
@ -151,7 +152,7 @@ function parseHash() {
const query = Object.fromEntries(new URLSearchParams(queryStr || ''));
return { path: '/' + segments.join('/'), segments, query };
}
function navigate(hash) { location.hash = hash; }
function navigate(hash) { SIDEBAR_OPEN = false; location.hash = hash; }
window.addEventListener('hashchange', render);
window.addEventListener('DOMContentLoaded', render);
@ -165,7 +166,12 @@ function render() {
}
const route = parseHash();
root.innerHTML =
`<div class="shell">${renderSidebar(route)}${renderTopbar(route)}<main class="main">${renderMain(route)}</main></div>` +
`<div class="shell ${SIDEBAR_OPEN ? 'sidebar-open' : ''}">` +
renderSidebar(route) +
renderTopbar(route) +
`<main class="main">${renderMain(route)}</main>` +
(SIDEBAR_OPEN ? '<div class="sidebar-backdrop" data-action="close-sidebar"></div>' : '') +
`</div>` +
(MODAL ? renderModalEl() : '');
attachGlobalListeners();
}
@ -243,6 +249,7 @@ function renderTopbar(route) {
const unread = unreadNotifications().length;
return `
<header class="topbar">
<button class="icon-button mobile-menu-btn" data-action="toggle-sidebar" aria-label="Меню">☰</button>
<form class="topbar-search" data-form="search">
<input type="search" name="q" placeholder="Глобальный поиск…" value="${esc(q)}" />
</form>
@ -1142,6 +1149,14 @@ function bindDelegatedListeners() {
apply((s) => { s.currentUserId = el.dataset.userId; });
location.hash = '#/';
break;
case 'toggle-sidebar':
SIDEBAR_OPEN = !SIDEBAR_OPEN;
render();
break;
case 'close-sidebar':
SIDEBAR_OPEN = false;
render();
break;
case 'logout':
apply((s) => { s.currentUserId = null; });
location.hash = '';