refactor(App): enhance vertical sidebar layout and styling for improved usability and consistency
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 3m19s

This commit is contained in:
2026-02-16 16:38:26 +07:00
parent 62387aa6d5
commit 0e0f4380d7
2 changed files with 83 additions and 96 deletions
+22
View File
@@ -54,6 +54,28 @@
.navbar-vertical > .container-fluid {
padding-left: 1rem;
padding-right: 1rem;
display: flex;
flex-direction: column;
min-height: 100%;
}
.navbar-vertical .collapse.navbar-collapse {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.navbar-vertical .collapse .navbar-nav.pt-lg-3 {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
}
.navbar-vertical .navbar-sidebar-footer {
flex-shrink: 0;
border-top-color: rgba(255, 255, 255, 0.1) !important;
}
.navbar-vertical .navbar-sidebar-footer .nav-link {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
/* Стрелка только у пунктов с подменю (dropdown-toggle), не у обычных ссылок и не у бренда */
.navbar-vertical .nav-link:not(.dropdown-toggle)::after {
+61 -96
View File
@@ -469,11 +469,71 @@ function MainLayout() {
</li>
))}
</ul>
{/* Кнопки внизу сайдбара: язык, раскладка, тема, горячие клавиши, настройки */}
<div className="navbar-sidebar-footer navbar-nav flex-column border-top pt-2 mt-auto">
<div className="nav-item dropdown">
<a
href="#"
className="nav-link dropdown-toggle px-3 py-2"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
title="Язык"
>
<span className="badge">{lang.toUpperCase()}</span>
</a>
<div className="dropdown-menu dropdown-menu-end">
<a href="#" className={`dropdown-item ${lang === 'ru' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setLang('ru'); }}>Русский</a>
<a href="#" className={`dropdown-item ${lang === 'en' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setLang('en'); }}>English</a>
</div>
</div>
<div className="nav-item dropdown">
<a
href="#"
className="nav-link dropdown-toggle px-3 py-2"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
title={t('layoutSidebar')}
>
{layout === LAYOUT_FLUID ? <IconLayoutSidebarLeftExpand size={20} /> : <IconLayoutNavbar size={20} />}
</a>
<div className="dropdown-menu dropdown-menu-end">
<a href="#" className={`dropdown-item d-flex align-items-center ${layout === LAYOUT_FLUID ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setLayout(LAYOUT_FLUID); }}>
<IconLayoutSidebarLeftExpand className="me-2" size={18} /> {t('layoutSidebar')}
</a>
<a href="#" className={`dropdown-item d-flex align-items-center ${layout === LAYOUT_HORIZONTAL ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setLayout(LAYOUT_HORIZONTAL); }}>
<IconLayoutNavbar className="me-2" size={18} /> {t('layoutHorizontal')}
</a>
</div>
</div>
<div className="nav-item dropdown">
<a
href="#"
className="nav-link dropdown-toggle px-3 py-2"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
title={t('light') + ' / ' + t('dark')}
>
{theme === 'dark' ? '🌙' : '☀️'}
</a>
<div className="dropdown-menu dropdown-menu-end">
<a href="#" className={`dropdown-item ${theme === 'light' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setTheme('light'); }}> {t('light')}</a>
<a href="#" className={`dropdown-item ${theme === 'dark' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); setTheme('dark'); }}>🌙 {t('dark')}</a>
</div>
</div>
<div className="nav-item">
<KeyboardShortcutsButton className="nav-link px-3 py-2" title="Горячие клавиши" />
</div>
<div className="nav-item">
<a href="#" className="nav-link px-3 py-2" onClick={(e) => { e.preventDefault(); setSettingsOpen(true); }} title="Настройки">
<IconSettings size={20} />
</a>
</div>
</div>
</div>
</div>
</header>
{/* Верхний навбар (как в Tabler fluid vertical) */}
{/* Верхний навбар (только тогглер меню на мобильных; кнопки — внизу сайдбара) */}
<header className="navbar navbar-expand-md d-print-none">
<div className="container-fluid">
<button
@@ -486,101 +546,6 @@ function MainLayout() {
>
<IconMenu2 />
</button>
<div className="navbar-nav flex-row order-md-last flex-grow-1 justify-content-end">
<div className="nav-item dropdown">
<a
href="#"
className="nav-link px-2 dropdown-toggle"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
>
<span className="badge">{lang.toUpperCase()}</span>
</a>
<div className="dropdown-menu dropdown-menu-end">
<a
href="#"
className={`dropdown-item ${lang === 'ru' ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setLang('ru'); }}
>
Русский
</a>
<a
href="#"
className={`dropdown-item ${lang === 'en' ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setLang('en'); }}
>
English
</a>
</div>
</div>
<div className="nav-item dropdown">
<a
href="#"
className="nav-link px-2 dropdown-toggle"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
>
{layout === LAYOUT_FLUID ? <IconLayoutSidebarLeftExpand size={20} /> : <IconLayoutNavbar size={20} />}
</a>
<div className="dropdown-menu dropdown-menu-end">
<a
href="#"
className={`dropdown-item d-flex align-items-center ${layout === LAYOUT_FLUID ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setLayout(LAYOUT_FLUID); }}
>
<IconLayoutSidebarLeftExpand className="me-2" size={18} />
{t('layoutSidebar')}
</a>
<a
href="#"
className={`dropdown-item d-flex align-items-center ${layout === LAYOUT_HORIZONTAL ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setLayout(LAYOUT_HORIZONTAL); }}
>
<IconLayoutNavbar className="me-2" size={18} />
{t('layoutHorizontal')}
</a>
</div>
</div>
<div className="nav-item dropdown">
<a
href="#"
className="nav-link px-2 dropdown-toggle"
data-bs-toggle="dropdown"
onClick={(e) => e.preventDefault()}
>
{theme === 'dark' ? '🌙' : '☀️'}
</a>
<div className="dropdown-menu dropdown-menu-end">
<a
href="#"
className={`dropdown-item ${theme === 'light' ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setTheme('light'); }}
>
{t('light')}
</a>
<a
href="#"
className={`dropdown-item ${theme === 'dark' ? 'active' : ''}`}
onClick={(e) => { e.preventDefault(); setTheme('dark'); }}
>
🌙 {t('dark')}
</a>
</div>
</div>
<div className="nav-item">
<KeyboardShortcutsButton className="nav-link px-2" />
</div>
<div className="nav-item">
<a
href="#"
className="nav-link px-2"
onClick={(e) => { e.preventDefault(); setSettingsOpen(true); }}
title="Настройки"
>
<IconSettings size={20} />
</a>
</div>
</div>
</div>
</header>