Rework on Bootstrap 5: standard navbar+offcanvas (fixed empty menu), Bootstrap Icons, complete B3 theme via BS vars, row/col grids

This commit is contained in:
2026-10-03 00:05:52 +03:00
parent 03b64586b2
commit f65a60462e
39 changed files with 229 additions and 311 deletions

View File

@@ -81,37 +81,18 @@ a:not(.btn):hover { color: var(--c-accent-hover); }
/* Layout */
.page { display: flex; flex-direction: column; min-height: 100vh; }
.page-header { position: sticky; top: 0; z-index: 10; border-bottom: 1px solid var(--c-border); background: var(--c-surface); }
.page-header-inner { max-width: 1200px; margin: 0 auto; display: flex; align-items: center; gap: 0.5rem 1.75rem; flex-wrap: wrap; padding: 0.875rem 1.75rem; }
@media (max-width: 640px) {
.page-header-inner { padding: 0.5rem 0.875rem; gap: 0.5rem 1rem; }
.nav { gap: 0.5rem 0.75rem; flex-wrap: wrap; }
.user { gap: 0.5rem; }
.nav-user { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
}
.page-main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 2.5rem 1.75rem 3.5rem; }
@media (max-width: 720px) { .page-main { padding: 1.5rem 0.875rem 2.5rem; } }
.page-footer { text-align: center; color: var(--c-text-muted); font-size: 0.75rem; padding: 1.5rem; }
/* Nav */
.nav { display: flex; align-items: center; gap: 1.125rem; flex: 1 1 auto; flex-wrap: wrap; font-size: 0.84375rem; }
.nav-link { color: var(--c-accent); text-decoration: none; font-weight: 500; }
.nav-link:hover { color: var(--c-accent-hover); }
.nav-link.active { color: var(--c-accent); font-weight: 700; }
.nav-sep { color: var(--c-text-muted); }
.logo { font-size: 1rem; font-weight: 700; color: var(--c-text); text-decoration: none; letter-spacing: -0.01em; }
.logo b { color: var(--c-accent); }
.user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.84375rem; margin-left: auto; }
.nav-user { font-weight: 500; color: var(--c-text); }
.nav-user:hover { color: var(--c-accent); }
.nav-user.defense-active { color: var(--c-accent); }
.nav-user.defense-active::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--c-accent); margin-right: 0.4rem; vertical-align: middle; }
.score-big { display: inline-block; margin-left: 0.5rem; font-size: 1.75rem; font-weight: 700; line-height: 1; color: var(--c-tone-pos); font-variant-numeric: tabular-nums; vertical-align: middle; }
.variant-name { font-weight: 600; }
.variant-name b { font-variant-numeric: tabular-nums; }
p { margin-top: 0; }
.theme-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.3rem 0.5rem; }
.theme-icon { width: 1.05rem; height: 1.05rem; display: block; }
.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; }
.breadcrumb .nav-sep { user-select: none; }
.check-list { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.25rem; max-height: 12rem; overflow-y: auto; }
@@ -148,35 +129,51 @@ p { margin-top: 0; }
.hint { margin-top: 0.25rem; font-size: 0.75rem; color: var(--c-text-muted); }
/* ---- Icons: SVG-файлы из /icons, подключаются CSS-масками (цвет = currentColor) ---- */
.ico {
display: inline-block; flex: 0 0 auto;
background-color: currentColor;
-webkit-mask-position: center; mask-position: center;
-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
-webkit-mask-size: contain; mask-size: contain;
/* ===== B3-тема поверх Bootstrap: navbar, offcanvas, кнопки, ссылки ===== */
.b3-navbar { background: var(--c-surface); border-bottom: 1px solid var(--c-border); }
.b3-navbar .container, .page-main.container { max-width: 1200px; }
.b3-navbar .navbar-brand { color: var(--c-text); font-weight: 700; font-size: 1rem; }
.b3-navbar .navbar-brand b { color: var(--c-accent); }
.b3-navbar .navbar-toggler { border: 1px solid var(--c-border-strong); color: var(--c-accent); padding: 0.25rem 0.5rem; line-height: 1; }
.b3-navbar .navbar-toggler:focus { box-shadow: none; }
.nav-link { --bs-nav-link-color: var(--c-accent); --bs-nav-link-hover-color: var(--c-accent-hover); font-weight: 500; font-size: 0.875rem; }
.nav-link.active { color: var(--c-accent) !important; font-weight: 700; }
.navbar-close { border: 0; background: none; color: var(--c-text-muted); font-size: 1.1rem; line-height: 1; }
.navbar-close:hover { color: var(--c-text); }
#mobileNav { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-color: var(--c-text); --bs-offcanvas-border-color: var(--c-border); }
#mobileNav .offcanvas-header { border-bottom: 1px solid var(--c-border); }
#mobileNav .navbar-nav { gap: 0.25rem; }
#mobileNav .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
@media (max-width: 767.98px) {
#mobileNav .offcanvas-body { display: flex; flex-direction: column; justify-content: space-between; gap: 1rem; }
}
.ico-eye-open { -webkit-mask-image: url('../icons/eye-open.svg'); mask-image: url('../icons/eye-open.svg'); }
.ico-eye-closed { -webkit-mask-image: url('../icons/eye-closed.svg'); mask-image: url('../icons/eye-closed.svg'); }
.ico-pencil { -webkit-mask-image: url('../icons/pencil.svg'); mask-image: url('../icons/pencil.svg'); }
.ico-hand { -webkit-mask-image: url('../icons/hand.svg'); mask-image: url('../icons/hand.svg'); }
.ico-trash { -webkit-mask-image: url('../icons/trash.svg'); mask-image: url('../icons/trash.svg'); }
.ico-menu { -webkit-mask-image: url('../icons/menu.svg'); mask-image: url('../icons/menu.svg'); }
.ico-chevron-down { -webkit-mask-image: url('../icons/chevron-down.svg'); mask-image: url('../icons/chevron-down.svg'); }
.ico-theme { -webkit-mask-image: url('../icons/theme.svg'); mask-image: url('../icons/theme.svg'); }
.ico-md-bold { -webkit-mask-image: url('../icons/md-bold.svg'); mask-image: url('../icons/md-bold.svg'); }
.ico-md-italic { -webkit-mask-image: url('../icons/md-italic.svg'); mask-image: url('../icons/md-italic.svg'); }
.ico-md-h2 { -webkit-mask-image: url('../icons/md-h2.svg'); mask-image: url('../icons/md-h2.svg'); }
.ico-md-ul { -webkit-mask-image: url('../icons/md-ul.svg'); mask-image: url('../icons/md-ul.svg'); }
.ico-md-ol { -webkit-mask-image: url('../icons/md-ol.svg'); mask-image: url('../icons/md-ol.svg'); }
.ico-md-quote { -webkit-mask-image: url('../icons/md-quote.svg'); mask-image: url('../icons/md-quote.svg'); }
.ico-md-link { -webkit-mask-image: url('../icons/md-link.svg'); mask-image: url('../icons/md-link.svg'); }
.ico-md-code { -webkit-mask-image: url('../icons/md-code.svg'); mask-image: url('../icons/md-code.svg'); }
.ico-md-codeblock { -webkit-mask-image: url('../icons/md-codeblock.svg'); mask-image: url('../icons/md-codeblock.svg'); }
.ico-md-table { -webkit-mask-image: url('../icons/md-table.svg'); mask-image: url('../icons/md-table.svg'); }
.ico-md-figure { -webkit-mask-image: url('../icons/md-figure.svg'); mask-image: url('../icons/md-figure.svg'); }
.ico-md-video { -webkit-mask-image: url('../icons/md-video.svg'); mask-image: url('../icons/md-video.svg'); }
.ico-md-spoiler { -webkit-mask-image: url('../icons/md-spoiler.svg'); mask-image: url('../icons/md-spoiler.svg'); }
.nav-user { font-weight: 500; color: var(--c-accent); text-decoration: none; }
.nav-user:hover { color: var(--c-accent-hover); }
.nav-user.defense-active::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--c-accent); margin-right: 0.4rem; vertical-align: middle; }
.page-main { padding: 2.5rem 1.75rem 3.5rem; }
@media (max-width: 720px) { .page-main { padding: 1.5rem 0.875rem 2.5rem; } }
/* Кнопки: B3-палитра через переменные Bootstrap */
.btn {
--bs-btn-bg: var(--c-accent); --bs-btn-border-color: var(--c-accent); --bs-btn-color: #ffffff;
--bs-btn-hover-bg: var(--c-accent-hover); --bs-btn-hover-border-color: var(--c-accent-hover); --bs-btn-hover-color: #ffffff;
--bs-btn-active-bg: #6a1d2c; --bs-btn-active-border-color: #6a1d2c; --bs-btn-active-color: #ffffff;
--bs-btn-disabled-bg: var(--c-accent); --bs-btn-disabled-border-color: var(--c-accent); --bs-btn-disabled-color: #ffffff;
--bs-btn-font-size: 0.8125rem; --bs-btn-padding-y: 0.5rem; --bs-btn-padding-x: 1rem;
--bs-btn-border-radius: var(--radius);
}
.btn-primary { --bs-btn-bg: var(--c-accent); --bs-btn-border-color: var(--c-accent); --bs-btn-color: #ffffff;
--bs-btn-hover-bg: var(--c-accent-hover); --bs-btn-hover-border-color: var(--c-accent-hover); --bs-btn-hover-color: #ffffff;
--bs-btn-active-bg: #6a1d2c; --bs-btn-active-border-color: #6a1d2c; --bs-btn-active-color: #ffffff; }
.btn-secondary { --bs-btn-bg: var(--c-surface); --bs-btn-border-color: var(--c-border-strong); --bs-btn-color: var(--c-text);
--bs-btn-hover-bg: var(--c-bg); --bs-btn-hover-border-color: var(--c-border-strong); --bs-btn-hover-color: var(--c-text);
--bs-btn-active-bg: var(--c-bg); --bs-btn-active-border-color: var(--c-border-strong); --bs-btn-active-color: var(--c-text); }
.btn-danger { --bs-btn-bg: var(--c-surface); --bs-btn-border-color: #dcb9be; --bs-btn-color: var(--c-accent);
--bs-btn-hover-bg: var(--c-accent-soft); --bs-btn-hover-border-color: var(--c-accent); --bs-btn-hover-color: var(--c-accent);
--bs-btn-active-bg: var(--c-accent-soft); --bs-btn-active-border-color: var(--c-accent); --bs-btn-active-color: var(--c-accent); }
.btn-sm { --bs-btn-padding-y: 0.25rem; --bs-btn-padding-x: 0.6rem; --bs-btn-font-size: 0.75rem; }
a { --bs-link-color: var(--c-accent); --bs-link-hover-color: var(--c-accent-hover); text-decoration: none; }
/* Cards */
.card { border-radius: var(--radius-lg); background: var(--c-surface); border: 1px solid var(--c-border); }
@@ -497,7 +494,7 @@ dialog.dlg.dlg-lg .dlg-body { max-height: 88vh; min-height: 62vh; }
background: none; cursor: pointer; color: var(--c-text-muted);
}
.sub-toggle:hover { color: var(--c-text); }
.sub-arrow .ico { width: 1rem; height: 1rem; }
.sub-arrow i { font-size: 1rem; line-height: 1; }
.sub-arrow { transform: rotate(0deg); transition: transform 0.2s; }
.sub-acc.collapsed .sub-arrow { transform: rotate(0deg); }
.sub-acc:not(.collapsed) .sub-arrow { transform: rotate(180deg); }
@@ -588,9 +585,7 @@ dialog.dlg.dlg-lg .dlg-body { max-height: 88vh; min-height: 62vh; }
.actions-col .inline-form { display: block; width: 100%; }
.actions-col .btn { display: block; width: 100%; text-align: center; }
/* Иконки — SVG-файлы из /icons через CSS-маски: цвет наследуется от текста */
.cell-ico {
width: 0.95rem; height: 0.95rem; display: block;
}
.cell-ico { font-size: 0.95rem; line-height: 1; }
/* tablekit: сортируемые таблицы и поиск */
th.th-sortable { cursor: pointer; user-select: none; }
@@ -671,9 +666,7 @@ th.th-filterable { padding-bottom: 0.35rem; }
.md-btn:hover { background: var(--c-surface); border-color: var(--c-border); }
.md-btn:active { transform: translateY(1px); }
.md-btn:focus-visible { outline: 2px solid var(--c-text-link); outline-offset: 1px; }
.md-ico {
width: 1.15rem; height: 1.15rem;
}
.md-ico { font-size: 1.15rem; line-height: 1; }
.md-sep { width: 1px; align-self: stretch; margin: 0.2rem 0.3rem; background: var(--c-border); }
.md-editor-head {
display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
@@ -746,19 +739,4 @@ th.th-filterable { padding-bottom: 0.35rem; }
.sort-row .sort-title { flex: 1 1 auto; }
}
/* ---- Мобильное меню: бургер в хэдере, сайдбар справа (BS offcanvas) ---- */
.nav-burger { 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; }
}