nas / templates /base.html
Starchik1's picture
Upload 25 files
9da4125 verified
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}CloudStorage{% endblock %}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<style>
:root {
--bs-primary: {{ session.get('color_scheme', '#0d6efd') }};
--bs-primary-rgb: {{ session.get('color_scheme', '#0d6efd')|hex_to_rgb }};
}
.btn-primary {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
}
.bg-primary {
background-color: var(--bs-primary) !important;
}
.text-primary {
color: var(--bs-primary) !important;
}
/* Исправление проблемы с перекрытием элементов */
.modal-backdrop {
z-index: 1040 !important;
}
.modal {
z-index: 1050 !important;
}
.dropdown-menu {
z-index: 1060 !important;
}
</style>
{% block head %}{% endblock %}
</head>
<body class="bg-image" style="background-image: url('{{ url_for('static', filename='backgrounds/' + background) }}');">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="{{ url_for('index') }}">CloudStorage</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
{% if session.user_id %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="filesDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Мои файлы
</a>
<ul class="dropdown-menu" aria-labelledby="filesDropdown">
<li><a class="dropdown-item" href="{{ url_for('dashboard') }}">Мои файлы</a></li>
<li><a class="dropdown-item" href="{{ url_for('shared_with_me') }}">Доступные мне</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link {% if request.path.startswith('/contacts') %}active{% endif %}" href="{{ url_for('contacts') }}">
<i class="fas fa-address-book me-1"></i> Контакты
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.path.startswith('/messages') %}active{% endif %}" href="{{ url_for('messages', contact_id=0) if session.user_id else '#' }}">
<i class="fas fa-comments me-1"></i> Сообщения
<span id="unreadBadge" class="badge bg-danger ms-2" style="display: none;">0</span>
</a>
</li>
{% endif %}
</ul>
<ul class="navbar-nav">
{% if session.user_id %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
{{ session.username }}
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{{ url_for('settings') }}"><i class="fas fa-cog"></i> Настройки</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ url_for('logout') }}"><i class="fas fa-sign-out-alt"></i> Выйти</a></li>
</ul>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">Войти</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register') }}">Регистрация</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category if category != 'error' else 'danger' }} alert-dismissible fade show">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<!-- Модальное окно для изменения фона -->
{% if session.user_id %}
<div class="modal fade" id="changeBackgroundModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Изменить фоновое изображение</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="{{ url_for('change_background') }}" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label for="background_file" class="form-label">Выберите изображение</label>
<input type="file" class="form-control" id="background_file" name="background_file" accept="image/*" required>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Загрузить и применить</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const colorSchemeSelect = document.getElementById('color_scheme');
if (colorSchemeSelect) {
colorSchemeSelect.value = '{{ session.get("color_scheme", "#0d6efd") }}';
colorSchemeSelect.addEventListener('change', function() {
document.documentElement.style.setProperty('--bs-primary', this.value);
document.documentElement.style.setProperty('--bs-primary-rgb', this.value.replace('#', '').match(/.{2}/g).join(', '));
});
}
});
</script>
{% if session.user_id %}
<script>
// Обновление счетчика непрочитанных сообщений
function updateUnreadCount() {
fetch('/get_unread_count')
.then(response => response.json())
.then(data => {
const unreadBadge = document.getElementById('unreadBadge');
if (unreadBadge) {
// Проверяем, изменилось ли количество непрочитанных сообщений
const currentCount = parseInt(unreadBadge.getAttribute('data-count') || '0');
const newCount = data.unread_count;
// Обновляем счетчик
if (newCount > 0) {
unreadBadge.textContent = newCount;
unreadBadge.style.display = 'inline';
} else {
unreadBadge.style.display = 'none';
}
// Если количество увеличилось, показываем уведомление
if (newCount > currentCount && currentCount >= 0) {
showMessageNotification(newCount - currentCount);
}
// Сохраняем новое значение счетчика
unreadBadge.setAttribute('data-count', newCount);
}
})
.catch(error => console.error('Ошибка при обновлении счетчика:', error));
}
// Функция для воспроизведения звука уведомления
function playNotificationSound() {
const audio = new Audio('{{ url_for("static", filename="sounds/notification.mp3") }}');
audio.play().catch(error => console.error('Ошибка воспроизведения звука:', error));
}
// Функция для запроса разрешения на отправку уведомлений
async function requestNotificationPermission() {
try {
const permission = await Notification.requestPermission();
return permission === 'granted';
} catch (error) {
console.error('Ошибка при запросе разрешения на уведомления:', error);
return false;
}
}
// Функция для отображения уведомления о новом сообщении
async function showMessageNotification(count) {
// Воспроизводим звук уведомления
playNotificationSound();
// Проверяем поддержку и разрешение на уведомления
if (!('Notification' in window)) {
console.log('Этот браузер не поддерживает уведомления');
showToastNotification(count);
return;
}
// Если разрешение не получено, запрашиваем его
if (Notification.permission !== 'granted') {
const permissionGranted = await requestNotificationPermission();
if (!permissionGranted) {
showToastNotification(count);
return;
}
}
// Создаем системное уведомление
const title = 'Новое сообщение';
const options = {
body: `У вас ${count} ${count === 1 ? 'новое сообщение' : 'новых сообщений'}!`,
icon: '{{ url_for("static", filename="favicon.ico") }}',
badge: '{{ url_for("static", filename="favicon.ico") }}',
tag: 'new-message',
requireInteraction: true
};
try {
const notification = new Notification(title, options);
notification.onclick = function() {
window.focus();
window.location.href = '{{ url_for("messages", contact_id=0) }}';
notification.close();
};
} catch (error) {
console.error('Ошибка при создании уведомления:', error);
showToastNotification(count);
}
}
// Функция для отображения уведомления внутри страницы
function showToastNotification(count) {
// Создаем элемент уведомления
const notification = document.createElement('div');
notification.className = 'toast show';
notification.style.position = 'fixed';
notification.style.bottom = '20px';
notification.style.right = '20px';
notification.style.minWidth = '250px';
notification.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
notification.style.boxShadow = '0 0.5rem 1rem rgba(0, 0, 0, 0.15)';
notification.style.borderRadius = '0.25rem';
notification.style.zIndex = '9999';
// Добавляем содержимое уведомления
notification.innerHTML = `
<div class="toast-header bg-primary text-white">
<i class="fas fa-envelope me-2"></i>
<strong class="me-auto">Новое сообщение</strong>
<button type="button" class="btn-close btn-close-white" onclick="this.parentNode.parentNode.remove()"></button>
</div>
<div class="toast-body">
<p>У вас ${count} ${count === 1 ? 'новое сообщение' : 'новых сообщений'}!</p>
<div class="mt-2 pt-2 border-top">
<a href="{{ url_for('messages', contact_id=0) }}" class="btn btn-primary btn-sm">Перейти к сообщениям</a>
</div>
</div>
`;
// Добавляем уведомление на страницу
document.body.appendChild(notification);
// Удаляем уведомление через 5 секунд
setTimeout(() => {
notification.remove();
}, 5000);
}
// Функция для проверки и запроса разрешения на уведомления при загрузке страницы
async function checkNotificationPermission() {
if ('Notification' in window) {
if (Notification.permission !== 'granted' && Notification.permission !== 'denied') {
// Запрашиваем разрешение на уведомления
await requestNotificationPermission();
}
}
}
// Обновление при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
// Инициализируем счетчик с нулевым значением при первой загрузке
const unreadBadge = document.getElementById('unreadBadge');
if (unreadBadge) {
unreadBadge.setAttribute('data-count', '0');
}
// Проверяем и запрашиваем разрешение на уведомления
checkNotificationPermission();
updateUnreadCount();
// Обновление каждые 15 секунд
setInterval(updateUnreadCount, 15000);
});
</script>
{% endif %}
</body>
</html>