Добавлена нижняя навигационная панель для мобильных устройств
- Добавлена bottom navbar с 5 кнопками (Главная, Уведомления, Поиск, Календарь, Ещё) - Панель отображается только на мобильных устройствах (до 768px) - Использованы системные CSS переменные и стили - Удалена кнопка гамбургера из верхней панели (дублирование функционала) - Добавлена синхронизация бейджей уведомлений - Поддержка светлой и темной темы - Backdrop-filter для полупрозрачности в iOS-стиле
This commit is contained in:
parent
51e4b63def
commit
003bbab1ff
@ -83,3 +83,117 @@
|
||||
[data-bs-theme="dark"] .mobile-search-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────
|
||||
BOTTOM NAVBAR (только для мобильных)
|
||||
────────────────────────────────────────────────────────────── */
|
||||
.bottom-navbar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: var(--bs-primary);
|
||||
border-top: 0.5px solid var(--bs-border-color);
|
||||
z-index: 1040;
|
||||
padding: 0;
|
||||
box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* Темная тема */
|
||||
[data-bs-theme="dark"] .bottom-navbar {
|
||||
background-color: var(--bs-tertiary-bg);
|
||||
border-top-color: var(--bs-border-color);
|
||||
box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.bottom-navbar-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
padding: 0 8px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.bottom-nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 4px 8px;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Темная тема - другой цвет кнопок */
|
||||
[data-bs-theme="dark"] .bottom-nav-item {
|
||||
color: var(--bs-secondary-color);
|
||||
}
|
||||
|
||||
.bottom-nav-item:hover,
|
||||
.bottom-nav-item:focus,
|
||||
.bottom-nav-item:active {
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .bottom-nav-item:hover,
|
||||
[data-bs-theme="dark"] .bottom-nav-item:focus,
|
||||
[data-bs-theme="dark"] .bottom-nav-item:active {
|
||||
color: var(--bs-emphasis-color);
|
||||
background: var(--bs-secondary-bg);
|
||||
}
|
||||
|
||||
.bottom-nav-item i {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 2px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bottom-nav-label {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* Иконка с бейджем для уведомлений */
|
||||
.bottom-nav-icon-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.bottom-nav-badge {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -8px;
|
||||
background: var(--bs-danger);
|
||||
color: white;
|
||||
border-radius: var(--badge-radius);
|
||||
padding: 2px 5px;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
min-width: 18px;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Padding для body, чтобы контент не перекрывался нижней панелью */
|
||||
@media (max-width: 767.98px) {
|
||||
body {
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
81
backend/static/js/bottom-navbar.js
Normal file
81
backend/static/js/bottom-navbar.js
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Bottom Navigation Bar
|
||||
* Управление нижней панелью навигации для мобильных устройств
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Кнопка уведомлений в нижней панели
|
||||
const bottomNotificationToggle = document.getElementById('bottomNotificationToggle');
|
||||
const notificationDropdown = document.getElementById('notificationDropdown');
|
||||
const notificationBadge = document.getElementById('notificationBadge');
|
||||
const bottomNotificationBadge = document.getElementById('bottomNotificationBadge');
|
||||
|
||||
// Синхронизация бейджей между верхней и нижней панелью
|
||||
function syncNotificationBadges() {
|
||||
if (notificationBadge && bottomNotificationBadge) {
|
||||
const count = notificationBadge.textContent;
|
||||
const hasNotifications = !notificationBadge.classList.contains('d-none');
|
||||
|
||||
bottomNotificationBadge.textContent = count;
|
||||
if (hasNotifications) {
|
||||
bottomNotificationBadge.classList.remove('d-none');
|
||||
} else {
|
||||
bottomNotificationBadge.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Наблюдатель за изменениями бейджа уведомлений
|
||||
if (notificationBadge) {
|
||||
const observer = new MutationObserver(syncNotificationBadges);
|
||||
observer.observe(notificationBadge, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
subtree: true
|
||||
});
|
||||
// Первоначальная синхронизация
|
||||
syncNotificationBadges();
|
||||
}
|
||||
|
||||
// Открытие уведомлений из нижней панели
|
||||
if (bottomNotificationToggle && notificationDropdown) {
|
||||
bottomNotificationToggle.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const isVisible = notificationDropdown.style.display !== 'none';
|
||||
|
||||
if (isVisible) {
|
||||
notificationDropdown.style.display = 'none';
|
||||
} else {
|
||||
notificationDropdown.style.display = 'block';
|
||||
// Позиционируем над нижней панелью
|
||||
notificationDropdown.style.bottom = '70px';
|
||||
notificationDropdown.style.right = '10px';
|
||||
notificationDropdown.style.top = 'auto';
|
||||
notificationDropdown.style.left = 'auto';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Кнопка поиска в нижней панели
|
||||
const bottomSearchToggle = document.getElementById('bottomSearchToggle');
|
||||
|
||||
if (bottomSearchToggle) {
|
||||
bottomSearchToggle.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
// Перенаправляем на страницу поиска
|
||||
window.location.href = '/search/';
|
||||
});
|
||||
}
|
||||
|
||||
// Закрытие выпадающих элементов при клике вне их
|
||||
document.addEventListener('click', function(e) {
|
||||
if (notificationDropdown &&
|
||||
!notificationDropdown.contains(e.target) &&
|
||||
!bottomNotificationToggle?.contains(e.target)) {
|
||||
notificationDropdown.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1,19 +1,11 @@
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/components/navbar.css' %}">
|
||||
<script src="{% static 'js/navbar-mobile-search.js' %}" defer></script>
|
||||
<script src="{% static 'js/bottom-navbar.js' %}" defer></script>
|
||||
|
||||
<nav class="navbar navbar-expand bg-primary app-navbar" data-bs-theme="dark">
|
||||
<div class="container-fluid align-items-center">
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<!-- Моб. меню (иконка без подложки) -->
|
||||
<button class="menu-toggle d-lg-none me-2 navbar-icon" type="button"
|
||||
data-bs-toggle="offcanvas" data-bs-target="#sidebar" aria-controls="sidebar"
|
||||
aria-label="Открыть меню">
|
||||
<i class="bi-list fs-4"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% load static %}
|
||||
<a class="navbar-brand d-flex align-items-center gap-2 me-3 navbar-brand-item" href="/">
|
||||
<img src="{% static BRAND_LOGO %}"
|
||||
@ -28,23 +20,10 @@
|
||||
<!-- Группа: поиск + колокол -->
|
||||
<div class="d-flex align-items-center ms-4 gap-3">
|
||||
<!-- Поиск: иконка на мобильном, поле на десктопе -->
|
||||
<form class="d-flex align-items-center mobile-search-form" role="search"
|
||||
<form class="d-none d-md-flex align-items-center mobile-search-form" role="search"
|
||||
action="{% url 'search:search' %}" method="get" autocomplete="off">
|
||||
<!-- Мобильная версия: иконка или поле -->
|
||||
<button type="button" class="btn btn-link text-white p-0 d-md-none mobile-search-toggle" aria-label="Поиск">
|
||||
<i class="bi-search fs-5"></i>
|
||||
</button>
|
||||
<div class="mobile-search-input d-none align-items-center gap-2">
|
||||
<input
|
||||
class="form-control form-control-sm rounded-pill bg-white bg-opacity-10 border-0 text-white shadow-sm"
|
||||
type="search" name="q" placeholder="Поиск…" aria-label="Поиск" id="mobileSearchInput"
|
||||
style="width: 200px; height: 36px; padding-left: 12px;">
|
||||
<button type="submit" class="btn btn-link text-white p-0" aria-label="Найти">
|
||||
<i class="bi-arrow-right-circle fs-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Десктопная версия: поле -->
|
||||
<div class="position-relative ios-search d-none d-md-block" style="max-width: clamp(160px, 28vw, 300px);">
|
||||
<div class="position-relative ios-search" style="max-width: clamp(160px, 28vw, 300px);">
|
||||
<i class="bi-search"></i>
|
||||
<input
|
||||
class="form-control form-control-sm rounded-pill ios-search-input bg-white bg-opacity-10 border-0 text-white shadow-sm"
|
||||
@ -53,8 +32,8 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Уведомления: только иконка + плотный бейдж -->
|
||||
<div class="position-relative navbar-icon" id="notificationBell">
|
||||
<!-- Уведомления: только иконка + плотный бейдж (скрыть на мобильных) -->
|
||||
<div class="position-relative navbar-icon d-none d-md-block" id="notificationBell">
|
||||
<button class="btn btn-link text-white p-0"
|
||||
id="notificationToggle"
|
||||
type="button"
|
||||
@ -67,18 +46,8 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Календарь: только на мобильных устройствах -->
|
||||
<div class="position-relative navbar-icon d-lg-none">
|
||||
<button class="btn btn-link text-white p-0"
|
||||
type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#rightbarOffcanvas"
|
||||
aria-controls="rightbarOffcanvas"
|
||||
title="Календарь"
|
||||
aria-label="Календарь">
|
||||
<i class="bi-calendar-event fs-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Календарь: только на мобильных устройствах (перенесен в bottom navbar) -->
|
||||
<!-- Удалено, теперь в нижней панели -->
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -145,4 +114,47 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Navigation Bar (только для мобильных) -->
|
||||
<nav class="bottom-navbar d-md-none" id="bottomNav">
|
||||
<div class="bottom-navbar-container">
|
||||
<a href="/" class="bottom-nav-item" title="Главная" aria-label="Главная">
|
||||
<i class="bi-house-door"></i>
|
||||
<span class="bottom-nav-label">Главная</span>
|
||||
</a>
|
||||
|
||||
<button class="bottom-nav-item" id="bottomNotificationToggle" type="button" title="Уведомления" aria-label="Уведомления">
|
||||
<span class="bottom-nav-icon-wrapper">
|
||||
<i class="bi-bell"></i>
|
||||
<span class="bottom-nav-badge d-none" id="bottomNotificationBadge">0</span>
|
||||
</span>
|
||||
<span class="bottom-nav-label">Уведомления</span>
|
||||
</button>
|
||||
|
||||
<button class="bottom-nav-item" id="bottomSearchToggle" type="button" title="Поиск" aria-label="Поиск">
|
||||
<i class="bi-search"></i>
|
||||
<span class="bottom-nav-label">Поиск</span>
|
||||
</button>
|
||||
|
||||
<button class="bottom-nav-item" type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#rightbarOffcanvas"
|
||||
aria-controls="rightbarOffcanvas"
|
||||
title="Календарь"
|
||||
aria-label="Календарь">
|
||||
<i class="bi-calendar-event"></i>
|
||||
<span class="bottom-nav-label">Календарь</span>
|
||||
</button>
|
||||
|
||||
<button class="bottom-nav-item" type="button"
|
||||
data-bs-toggle="offcanvas"
|
||||
data-bs-target="#sidebar"
|
||||
aria-controls="sidebar"
|
||||
title="Меню"
|
||||
aria-label="Меню">
|
||||
<i class="bi-three-dots"></i>
|
||||
<span class="bottom-nav-label">Ещё</span>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user