Bootstrap 5.3 as CSS base + B3 theme layer; dialogs isolated as .dlg; offcanvas sidebar; icons via SVG assets + masks

This commit is contained in:
2026-10-02 23:44:00 +03:00
parent 8c75fd1c8e
commit 03b64586b2
12 changed files with 185 additions and 179 deletions

View File

@@ -16,6 +16,14 @@ body {
Цвет несёт смысл: акцент — действия и фокус, зелёный/янтарный — статусы защиты,
винный — деструктивные действия и негативная тональность. */
:root {
--bs-body-font-family: 'Inter', system-ui, -apple-system, sans-serif;
--bs-body-bg: #fafafa;
--bs-body-color: #131316;
--bs-border-color: #e6e6e9;
--bs-border-radius: 0.5rem;
--bs-border-radius-lg: 0.625rem;
--bs-link-color: #7a2333;
--bs-link-hover-color: #9d2b3c;
--c-bg: #fafafa;
--c-surface: #ffffff;
--c-text: #131316;
@@ -281,30 +289,30 @@ tr:last-child td { border-bottom: none; }
.confirm-text { margin: 0; font-size: 0.875rem; white-space: pre-line; overflow-wrap: anywhere; }
/* Modals */
dialog.modal {
dialog.dlg {
border: 1px solid var(--c-border); border-radius: var(--radius-lg); padding: 0;
background: var(--c-surface); color: var(--c-text);
width: min(34rem, calc(100vw - 2rem));
box-shadow: 0 16px 48px rgba(19, 19, 22, 0.28);
}
dialog.modal::backdrop { background: rgba(19, 19, 22, 0.5); }
dialog.dlg::backdrop { background: rgba(19, 19, 22, 0.5); }
/* Пока открыта модалка — страница не прокручивается, позиция скролла сохраняется;
прокрутка остаётся внутри .modal-body */
html.modal-open body {
position: fixed; left: 0; right: 0; width: 100%; top: var(--modal-top, 0);
padding-right: var(--modal-scrollbar, 0);
}
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); }
.modal-title { margin: 0; font-size: 1.0625rem; font-weight: 600; }
.modal-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; }
.modal-close:hover { color: var(--c-text); }
.modal-body { padding: 1.5rem; max-height: 70vh; overflow-y: auto; display: flex; flex-direction: column; }
.dlg-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); }
.dlg-title { margin: 0; font-size: 1.0625rem; font-weight: 600; }
.dlg-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; }
.dlg-close:hover { color: var(--c-text); }
.dlg-body { padding: 1.5rem; max-height: 70vh; overflow-y: auto; display: flex; flex-direction: column; }
/* Кнопки действий — внизу справа; при увеличенной модалке пустота снизу не остаётся */
.modal-body > form.form-stack:last-child { flex: 1 1 auto; }
.modal-body > form.form-stack:last-child > button:last-child,
.modal-body > form.form-stack:last-child > .flex:last-child,
.modal-body.form-stack > button:last-child,
.modal-body.form-stack > .flex:last-child,
.dlg-body > form.form-stack:last-child { flex: 1 1 auto; }
.dlg-body > form.form-stack:last-child > button:last-child,
.dlg-body > form.form-stack:last-child > .flex:last-child,
.dlg-body.form-stack > button:last-child,
.dlg-body.form-stack > .flex:last-child,
.modal-body > button:last-child,
.modal-body > .flex:last-child {
margin-top: auto;
@@ -462,8 +470,8 @@ code.code { padding: 0.125rem 0.5rem; border-radius: var(--radius-xs); font-fami
.js-pub-count.is-hidden { display: none; }
/* Увеличенный диалог (оценка + комментарии) */
dialog.modal.modal-lg { width: min(72rem, calc(100vw - 2rem)); }
dialog.modal.modal-lg .modal-body { max-height: 88vh; min-height: 62vh; }
dialog.dlg.dlg-lg { width: min(72rem, calc(100vw - 2rem)); }
dialog.dlg.dlg-lg .dlg-body { max-height: 88vh; min-height: 62vh; }
.mini-btn svg, .cell-btn svg { width: 1rem; height: 1rem; }
.chip { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 8px; border-radius: var(--radius-sm); font-size: 11.5px; line-height: 1.5; }
@@ -738,28 +746,19 @@ th.th-filterable { padding-bottom: 0.35rem; }
.sort-row .sort-title { flex: 1 1 auto; }
}
/* ---- Мобильное меню: бургер в хэдере, ссылки в выезжающем сайдбаре справа ---- */
/* ---- Мобильное меню: бургер в хэдере, сайдбар справа (BS offcanvas) ---- */
.nav-burger { display: none; }
.mobile-nav { display: none; }
.mobile-nav-overlay { display: none; }
#mobile-nav { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-border-color: var(--c-border); --bs-offcanvas-zindex: 120; }
#mobile-nav .mobile-nav-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
#mobile-nav .mobile-nav-links { display: flex; flex-direction: column; gap: 0.25rem; }
#mobile-nav .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
#mobile-nav .mobile-nav-user { display: flex; flex-direction: column; gap: 0.75rem; margin-top: auto; padding-top: 1rem; border-top: 1px solid var(--c-border); }
.mobile-nav-overlay { position: fixed; inset: 0; z-index: 1040; background: rgba(0, 0, 0, 0.45); }
html.nav-open, html.nav-open body { overflow: hidden; }
@media (max-width: 720px) {
.nav { display: none; }
.page-header .user { display: none; }
.page-header .theme-btn { margin-left: auto; }
.nav-burger { display: inline-flex; }
.mobile-nav {
display: flex; flex-direction: column; gap: 1rem;
position: fixed; top: 0; right: 0; bottom: 0; left: auto; width: 17rem; max-width: 86vw;
z-index: 120; background: var(--c-surface);
border-right: none; border-left: 1px solid var(--c-border);
padding: 1rem; overflow-y: auto;
transform: translateX(100%); transition: transform 0.2s;
}
.mobile-nav.open { transform: none; }
.mobile-nav-overlay { display: block; position: fixed; inset: 0; z-index: 110; background: rgba(0, 0, 0, 0.45); }
.mobile-nav-head { display: flex; align-items: center; justify-content: space-between; }
.mobile-nav-links { display: flex; flex-direction: column; gap: 0.25rem; }
.mobile-nav-links .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
.mobile-nav-user { display: flex; flex-direction: column; gap: 0.75rem; margin-top: auto; padding-top: 1rem; border-top: 1px solid var(--c-border); }
}
html.nav-open, html.nav-open body { overflow: hidden; }

File diff suppressed because one or more lines are too long

View File

@@ -166,7 +166,7 @@ function attachCommentAutocomplete(input) {
/* Если снизу внутри модалки мало места — раскрываем список вверх, чтобы он не обрезался. */
function positionList() {
var wrap = input.parentNode;
var scrollParent = input.closest('.modal-body') || document.documentElement;
var scrollParent = input.closest('.dlg-body') || document.documentElement;
var wr = wrap.getBoundingClientRect();
var sr = scrollParent.getBoundingClientRect();
var below = sr.bottom - wr.bottom;

View File

@@ -202,7 +202,7 @@
document.addEventListener('click', function (e) {
var el = e.target;
var close = el.closest('.modal-close');
var close = el.closest('.dlg-close');
if (close) {
var dlg = close.closest('dialog');
if (dlg) dlg.close();
@@ -246,7 +246,7 @@
var n = document.getElementById('mobile-nav');
var o = document.getElementById('mobile-nav-overlay');
var b = document.getElementById('nav-burger');
if (n) n.classList.add('open');
if (n) n.classList.add('show');
if (o) o.hidden = false;
if (b) b.setAttribute('aria-expanded', 'true');
document.documentElement.classList.add('nav-open');
@@ -255,7 +255,7 @@
var n = document.getElementById('mobile-nav');
var o = document.getElementById('mobile-nav-overlay');
var b = document.getElementById('nav-burger');
if (n) n.classList.remove('open');
if (n) n.classList.remove('show');
if (o) o.hidden = true;
if (b) b.setAttribute('aria-expanded', 'false');
document.documentElement.classList.remove('nav-open');