- Created comprehensive badges-telegram-style.css (240 lines) based on Telegram Web K - Updated all badge markup in templates (navbar, sidebar, chat_list, chat_detail, chat_title) - Replaced Bootstrap badge classes with .badge-telegram classes - Implemented Telegram specifications: 20px height, 10px radius, 11px font, 600 weight - Added smooth animations: pulse (on update), animate-in (on mount), animate-out (on unmount) - Updated JavaScript: replaced .d-none with style.display for badge visibility - Updated 5 JS files: bottom-navbar, notification-manager, chatBadgeHandler, chatBadgeManager, chatListRealtime - Added pulse animation on badge value increase - Improved shadows and transitions with cubic-bezier easing - Added badges-telegram-style.css to base.html for global availability - Created documentation: TELEGRAM_BADGES_GUIDE.md, TELEGRAM_BADGES_UPDATE.md Technical details: - Research: Analyzed 50+ files from Telegram Web K GitHub repository - Perfect circles: border-radius: 10px (not 50%) - Spring animation: cubic-bezier(0.175, 0.885, 0.32, 1.275) - Auto-hide: :empty and [data-count='0'] selectors - Responsive design + dark theme support
84 lines
3.2 KiB
JavaScript
84 lines
3.2 KiB
JavaScript
/**
|
|
* 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 isVisible = notificationBadge.style.display !== 'none';
|
|
|
|
bottomNotificationBadge.textContent = count;
|
|
if (isVisible && count !== '0') {
|
|
bottomNotificationBadge.style.display = '';
|
|
bottomNotificationBadge.classList.add('pulse');
|
|
setTimeout(() => bottomNotificationBadge.classList.remove('pulse'), 600);
|
|
} else {
|
|
bottomNotificationBadge.style.display = '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';
|
|
}
|
|
});
|
|
});
|