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