Spaces:
Paused
Paused
| | |
| <html lang="ru" data-bs-theme="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Columbus boutique — {% block title %}Платформа{% endblock %}</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <link rel="icon" href="{{ url_for('static', filename='img/boutique-logo.webp') }}" type="image/webp"> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet"> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet"> | |
| <link href="{{ url_for('static', filename='css/dashboard.css', v='20260707a') }}" rel="stylesheet"> | |
| {% block extra_head %}{% endblock %} | |
| </head> | |
| <body> | |
| {% if not no_main_wrapper and current_user.is_authenticated %} | |
| {# ===== DASHBOARD LAYOUT (authenticated users) ===== #} | |
| <div class="d-layout"> | |
| <!-- Overlay for mobile --> | |
| <div class="d-overlay" id="dOverlay"></div> | |
| <!-- Sidebar --> | |
| <aside class="d-sidebar" id="dSidebar"> | |
| <div class="d-sidebarg"> | |
| <a href="{{ url_for('main.main_page') }}" class="d-logo"> | |
| <div class="d-logo-img">CB</div> | |
| <div> | |
| <div class="d-logo-text">Columbus</div> | |
| <div class="d-logo-sub">KPI Dashboard</div> | |
| </div> | |
| </a> | |
| <nav class="d-nav"> | |
| <div class="d-nav-label">Навигация</div> | |
| <a href="{{ url_for('main.main_page') }}" class="d-nav-item {% if request.endpoint == 'main.main_page' %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-grid-1x2-fill"></i></div><span class="d-nav-label-text">Главная</span> | |
| </a> | |
| <a href="{{ url_for('main.kpi_overview') }}" class="d-nav-item {% if request.endpoint and 'kpi_overview' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-bar-chart-fill"></i></div><span class="d-nav-label-text">KPI</span> | |
| </a> | |
| <a href="{{ url_for('main.ranking') }}" class="d-nav-item {% if request.endpoint and 'ranking' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-trophy-fill"></i></div><span class="d-nav-label-text">Ранкинг</span> | |
| </a> | |
| <a href="{{ url_for('main.employees_list') }}" class="d-nav-item {% if request.endpoint and ('employees' in request.endpoint or request.endpoint == 'main.employee') %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-people-fill"></i></div><span class="d-nav-label-text">Сотрудники</span> | |
| </a> | |
| <a href="{{ url_for('main.schedule') }}" class="d-nav-item {% if request.endpoint and 'schedule' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-calendar-week-fill"></i></div><span class="d-nav-label-text">График</span> | |
| </a> | |
| <a href="{{ url_for('admin.tasks') }}" class="d-nav-item {% if request.endpoint and 'tasks' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-check-circle-fill"></i></div><span class="d-nav-label-text">Задачи</span> | |
| {% set task_count = tasks_count if tasks_count is defined else 0 %} | |
| {% if task_count > 0 %}<span class="d-nav-badge">{{ task_count }}</span>{% endif %} | |
| </a> | |
| <a href="{{ url_for('admin.trainings') }}" class="d-nav-item {% if request.endpoint and 'trainings' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-book-fill"></i></div><span class="d-nav-label-text">Обучения</span> | |
| </a> | |
| <a href="{{ url_for('main.notifications') }}" class="d-nav-item {% if request.endpoint and 'notifications' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-bell-fill"></i></div><span class="d-nav-label-text">Уведомления</span> | |
| {% if unread_notifications_count is defined and unread_notifications_count > 0 %} | |
| <span class="d-nav-badge" style="background:var(--red);">{{ unread_notifications_count }}</span> | |
| {% endif %} | |
| </a> | |
| {% if current_user.can_edit() %} | |
| <div class="d-sidebar-divider"></div> | |
| <div class="d-nav-label">Администрирование</div> | |
| <a href="{{ url_for('admin.admin_dashboard') }}" class="d-nav-item {% if request.endpoint and 'dashboard' in request.endpoint %}active{% endif %}"> | |
| <span class="d-nav-iconbox"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg></span> | |
| <span class="d-nav-text">Дашборд</span> | |
| </a> | |
| <a href="{{ url_for('admin.users') }}" class="d-nav-item {% if request.endpoint and 'users' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-person-gear"></i></div><span class="d-nav-label-text">Пользователи</span> | |
| </a> | |
| <a href="{{ url_for('admin.kpi_tools') }}" class="d-nav-item {% if request.endpoint and 'kpi_tools' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-tools"></i></div><span class="d-nav-label-text">Управление KPI</span> | |
| </a> | |
| <a href="{{ url_for('main.kpi_test') }}" class="d-nav-item {% if request.endpoint and 'kpi_test' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-table"></i></div><span class="d-nav-label-text">KPI Тест</span> | |
| </a> | |
| <a href="{{ url_for('admin.upload_file') }}" class="d-nav-item {% if request.endpoint and 'upload' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-upload"></i></div><span class="d-nav-label-text">Загрузка файлов</span> | |
| </a> | |
| <a href="{{ url_for('admin.audits_list') }}" class="d-nav-item {% if request.endpoint and 'audit' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-shield-check"></i></div><span class="d-nav-label-text">Аудиты</span> | |
| </a> | |
| <a href="{{ url_for('main.kpi_sync_test') }}" class="d-nav-item {% if request.endpoint and 'kpi_sync_test' in request.endpoint %}active{% endif %}"> | |
| <div class="d-nav-iconbox"><i class="bi bi-arrow-repeat"></i></div><span class="d-nav-label-text">Sync Test</span> | |
| </a> | |
| {% endif %} | |
| </nav> | |
| <div class="d-sidebar-footer"> | |
| <button class="d-theme-btn" id="dThemeToggle" title="Тема"> | |
| <i class="bi bi-moon-stars-fill"></i> | |
| <span id="dThemeLabel">Тёмная</span> | |
| </button> | |
| <button class="d-theme-btn" id="dSidebarCollapse" title="Свернуть боковую панель" style="flex:0;padding:8px;"> | |
| <i class="bi bi-chevron-left"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </aside> | |
| <!-- Main Area --> | |
| <div class="d-main" id="dMain"> | |
| <!-- Top Bar --> | |
| <header class="d-topbar"> | |
| <div class="d-topbar-left"> | |
| <button class="d-sidebar-toggle" id="dSidebarToggle" aria-label="Меню"> | |
| <i class="bi bi-list"></i> | |
| </button> | |
| <div class="d-page-title">{% block page_title %}Панель управления{% endblock %}</div> | |
| </div> | |
| <div class="d-topbar-right"> | |
| <!-- Notifications dropdown --> | |
| <div class="dropdown"> | |
| <button class="d-topbar-btn" data-bs-toggle="dropdown" aria-label="Уведомления"> | |
| <i class="bi bi-bell"></i> | |
| {% if unread_notifications_count is defined and unread_notifications_count > 0 %} | |
| <span class="d-topbar-badge"></span> | |
| {% endif %} | |
| </button> | |
| <div class="dropdown-menu dropdown-menu-end dropdown-apple" style="width:340px;"> | |
| <div class="d-flex justify-content-between align-items-center px-3 py-2 border-bottom" style="border-color:var(--card-border)!important;"> | |
| <strong style="font-size:14px;font-weight:600;">Уведомления</strong> | |
| <a href="{{ url_for('main.notifications') }}" style="font-size:13px;color:var(--accent);text-decoration:none;">Все</a> | |
| </div> | |
| <div id="notif-list"> | |
| <div class="text-center py-3" style="color:var(--text-secondary);font-size:13px;">Загрузка...</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- User dropdown --> | |
| <div class="dropdown"> | |
| <a href="#" class="d-user-dropdown" data-bs-toggle="dropdown" id="dUserDropdown"> | |
| <div class="d-user-avatar">{{ current_user.full_name[:1] }}</div> | |
| <span class="d-user-name">{{ current_user.full_name.split()[-1] }}</span> | |
| </a> | |
| <div class="dropdown-menu dropdown-menu-end dropdown-apple"> | |
| <div class="px-3 py-2 border-bottom" style="border-color:var(--card-border)!important;"> | |
| <div style="font-weight:600;font-size:14px;">{{ current_user.full_name }}</div> | |
| <div style="font-size:12px;color:var(--text-secondary);">{{ {'admin':'Админ','junior_expert':'Младший эксперт','sm':'Руководитель','senior_expert':'Старший эксперт','employee':'Эксперт','guest':'Гость'}.get(current_user.role, current_user.role) }}</div> | |
| </div> | |
| <a class="dropdown-item" href="{{ url_for('main.ranking') }}"><i class="bi bi-trophy me-2"></i>Ранкинг</a> | |
| <a class="dropdown-item" href="{{ url_for('auth.profile') }}"><i class="bi bi-person-circle me-2"></i>Профиль</a> | |
| <div class="dropdown-divider"></div> | |
| <button class="dropdown-item" id="dThemeToggleDropdown"><i class="bi bi-moon-stars-fill me-2"></i><span>Тёмная тема</span></button> | |
| <div class="dropdown-divider"></div> | |
| <a class="dropdown-item" href="{{ url_for('auth.logout') }}"><i class="bi bi-box-arrow-right me-2"></i>Выйти</a> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Flash Messages --> | |
| {% with messages = get_flashed_messages(with_categories=true) %} | |
| {% if messages %} | |
| <div style="padding:16px 24px 0;"> | |
| {% for category, message in messages %} | |
| <div class="alert-apple {{ category }} mb-2">{{ message }}</div> | |
| {% endfor %} | |
| </div> | |
| {% endif %} | |
| {% endwith %} | |
| <!-- Breadcrumbs --> | |
| {% if breadcrumbs %} | |
| <div class="d-breadcrumbs" style="padding:16px 24px 0;"> | |
| <a href="{{ url_for('main.main_page') }}"><i class="bi bi-house-door-fill"></i></a> | |
| {% for b in breadcrumbs %} | |
| <span class="sep">/</span> | |
| {% if b.url %}<a href="{{ b.url }}">{{ b.label }}</a>{% else %}<span>{{ b.label }}</span>{% endif %} | |
| {% endfor %} | |
| </div> | |
| {% endif %} | |
| <!-- Content --> | |
| <div class="d-content"> | |
| {% block content %}{% endblock %} | |
| </div> | |
| <!-- Footer --> | |
| <footer class="cb-footer" style="margin-top:0;"> | |
| <div class="cb-footer-inner"> | |
| <div class="cb-footer-bottom"> | |
| <span>© 2026 Columbus boutique. Все права защищены.</span> | |
| </div> | |
| </div> | |
| </footer> | |
| </div> | |
| </div> | |
| {% else %} | |
| {# ===== LOGIN / LANDING LAYOUT (no sidebar) ===== #} | |
| <!-- CB Topbar --> | |
| <div class="cb-topbar" id="cbTopbar"> | |
| <div class="cb-topbar-inner"> | |
| <a href="{{ url_for('main.main_page') }}" class="cb-logo"> | |
| <img class="cb-logo-img" src="{{ url_for('static', filename='img/boutique-logo.webp') }}" alt="CB" onerror="this.parentElement.style.display='none'"> | |
| COLUMBUS BOUTIQUE | |
| </a> | |
| <div class="cb-nav" id="cbNav"> | |
| <a href="{{ url_for('main.main_page') }}" class="{% if request.endpoint == 'main.main_page' %}cb-active{% endif %}">Главная</a> | |
| <a href="{{ url_for('main.schedule') }}" class="{% if request.endpoint == 'main.schedule' %}cb-active{% endif %}">График</a> | |
| {% if current_user.is_authenticated %} | |
| <a href="{{ url_for('admin.tasks') }}" class="{% if request.endpoint and 'tasks' in request.endpoint %}cb-active{% endif %}">Задачи</a> | |
| {% endif %} | |
| </div> | |
| <div class="cb-topbar-right"> | |
| {% if current_user.is_authenticated %} | |
| <div class="dropdown"> | |
| <a href="#" data-bs-toggle="dropdown" class="cb-user-dropdown" id="userDropdown"> | |
| <div class="cb-avatar">{{ current_user.full_name[:1] }}</div> | |
| <span class="cb-user-name d-none d-md-inline">{{ current_user.full_name.split()[-1] }}</span> | |
| </a> | |
| <div class="dropdown-menu dropdown-menu-end dropdown-apple"> | |
| <div class="px-3 py-2 border-bottom" style="border-color:rgba(255,255,255,0.05)!important;"> | |
| <div style="font-weight:600;font-size:14px;">{{ current_user.full_name }}</div> | |
| <div style="font-size:12px;color:#A0A5B5;">{{ {'admin':'Админ','junior_expert':'Младший эксперт','sm':'Руководитель','senior_expert':'Старший эксперт','employee':'Эксперт','guest':'Гость'}.get(current_user.role, current_user.role) }}</div> | |
| </div> | |
| <a class="dropdown-item" href="{{ url_for('main.ranking') }}"><i class="bi bi-trophy me-2"></i>Ранкинг</a> | |
| <a class="dropdown-item" href="{{ url_for('auth.profile') }}"><i class="bi bi-person-circle me-2"></i>Профиль</a> | |
| <div class="dropdown-divider"></div> | |
| <a class="dropdown-item" href="#" id="theme-toggle-legacy"><i class="bi bi-moon-stars-fill me-2"></i><span>Тёмная тема</span></a> | |
| <a class="dropdown-item" href="{{ url_for('auth.logout') }}"><i class="bi bi-box-arrow-right me-2"></i>Выйти</a> | |
| </div> | |
| </div> | |
| {% endif %} | |
| <button class="cb-hamburger" id="cbMenuToggle" aria-label="Меню"> | |
| <svg viewBox="0 0 96 96" width="24" height="24"><path d="M13,57V52h70v5Zm0-26V26h70v5Zm0-26V0h70v5Z"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Mobile Menu --> | |
| <div class="cb-mobile-menu" id="cbMobileMenu"> | |
| <div class="cb-mobile-header"> | |
| <span style="font-weight:700;font-size:16px;">Меню</span> | |
| <button class="cb-mobile-close" id="cbMenuClose">×</button> | |
| </div> | |
| <div class="cb-mobile-nav"> | |
| <a href="{{ url_for('main.main_page') }}" class="cb-mobile-link">Главная</a> | |
| <a href="{{ url_for('main.schedule') }}" class="cb-mobile-link">График</a> | |
| {% if current_user.is_authenticated %} | |
| <a href="{{ url_for('main.kpi_overview') }}" class="cb-mobile-link">KPI</a> | |
| <a href="{{ url_for('main.ranking') }}" class="cb-mobile-link">Ранкинг</a> | |
| <a href="{{ url_for('main.employees_list') }}" class="cb-mobile-link">Сотрудники</a> | |
| <a href="{{ url_for('admin.tasks') }}" class="cb-mobile-link">Задачи</a> | |
| <a href="{{ url_for('admin.trainings') }}" class="cb-mobile-link">Обучения</a> | |
| <a href="{{ url_for('main.notifications') }}" class="cb-mobile-link"> | |
| {% if unread_notifications_count > 0 %} | |
| <span style="font-size:10px;font-weight:600;padding:1px 7px;border-radius:999px;background:#0075FF;color:#fff;margin-right:3px;">{{ unread_notifications_count }}</span> | |
| {% endif %} | |
| Уведомления | |
| </a> | |
| {% if current_user.can_edit() %} | |
| <div class="cb-mobile-divider"></div> | |
| <a href="{{ url_for('admin.users') }}" class="cb-mobile-link">👤 Пользователи</a> | |
| <a href="{{ url_for('admin.upload_file') }}" class="cb-mobile-link">📤 Загрузка файлов</a> | |
| <a href="{{ url_for('admin.kpi_tools') }}" class="cb-mobile-link">🔧 Управление KPI</a> | |
| <a href="{{ url_for('admin.audits_list') }}" class="cb-mobile-link">🛡 Аудиты</a> | |
| <a href="{{ url_for('main.kpi_sync_test') }}" class="cb-mobile-link">🔄 Sync Test</a> | |
| {% endif %} | |
| <div class="cb-mobile-divider"></div> | |
| <a href="{{ url_for('auth.profile') }}" class="cb-mobile-link">Профиль</a> | |
| <a href="{{ url_for('auth.logout') }}" class="cb-mobile-link" style="color:#dc2626;">Выйти</a> | |
| {% else %} | |
| <div class="cb-mobile-divider"></div> | |
| <a href="{{ url_for('auth.login') }}" class="btn-login" style="width:100%;justify-content:center;padding:12px;text-decoration:none;margin-top:8px;">Войти</a> | |
| {% endif %} | |
| </div> | |
| </div> | |
| <!-- Flash Messages --> | |
| {% with messages = get_flashed_messages(with_categories=true) %} | |
| {% if messages %} | |
| <div class="flash-wrap"> | |
| {% for category, message in messages %} | |
| <div class="alert-apple {{ category }}">{{ message }}</div> | |
| {% endfor %} | |
| </div> | |
| {% endif %} | |
| {% endwith %} | |
| {% if breadcrumbs %} | |
| <div style="padding:12px 24px 0;font-size:12px;color:#A0A5B5;"> | |
| {% for b in breadcrumbs %} | |
| {% if b.url %}<a href="{{ b.url }}" style="color:#A0A5B5;text-decoration:none;">{{ b.label }}</a>{% else %}<span>{{ b.label }}</span>{% endif %} | |
| {% if not loop.last %}<span style="margin:0 6px;">›</span>{% endif %} | |
| {% endfor %} | |
| </div> | |
| {% endif %} | |
| {% block content_full %}{% endblock %} | |
| {% if not no_main_wrapper %}<div class="main-content" id="mainContent">{% endif %} | |
| {% block login_content %}{% endblock %} | |
| {% if not no_main_wrapper %}</div>{% endif %} | |
| <!-- Footer (landing/login) --> | |
| <footer class="cb-footer"> | |
| <div class="cb-footer-inner"> | |
| <div class="cb-footer-bottom"> | |
| <span>© 2026 Columbus boutique. Все права защищены.</span> | |
| </div> | |
| </div> | |
| </footer> | |
| {% endif %} | |
| {# Override in child templates if custom footer needed #} | |
| {% block footer %}{% endblock %} | |
| <!-- PDF Viewer Modal --> | |
| <div class="modal fade" id="pdfViewerModal" tabindex="-1" aria-hidden="true"> | |
| <div class="modal-dialog modal-xl modal-dialog-centered"> | |
| <div class="modal-content" style="border-radius:14px;overflow:hidden;"> | |
| <div class="modal-header" style="border:none;padding:12px 16px;"> | |
| <span style="font-weight:600;font-size:14px;" id="pdfViewerTitle">Просмотр файла</span> | |
| <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | |
| </div> | |
| <div class="modal-body" style="padding:0 16px 16px;height:80vh;"> | |
| <iframe id="pdfViewerIframe" src="" style="width:100%;height:100%;border:none;border-radius:8px;"></iframe> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script> | |
| <script src="{{ url_for('static', filename='js/main.js') }}"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // ===== THEME ===== | |
| function getTheme() { return document.documentElement.getAttribute('data-bs-theme') || 'dark'; } | |
| function setTheme(t) { | |
| document.documentElement.setAttribute('data-bs-theme', t); | |
| localStorage.setItem('cb-theme', t); | |
| var icons = document.querySelectorAll('#dThemeToggle i, #dThemeToggleDropdown i'); | |
| var labels = document.querySelectorAll('#dThemeLabel, #dThemeToggleDropdown span'); | |
| var isDark = t === 'dark'; | |
| icons.forEach(function(el) { el.className = isDark ? 'bi bi-moon-stars-fill' : 'bi bi-sun-fill'; }); | |
| labels.forEach(function(el) { if (el.textContent.trim() === 'Тёмная тема' || el.textContent.trim() === 'Светлая тема') el.textContent = isDark ? 'Тёмная тема' : 'Светлая тема'; }); | |
| } | |
| var savedTheme = localStorage.getItem('cb-theme') || 'dark'; | |
| setTheme(savedTheme); | |
| document.querySelectorAll('#dThemeToggle, #dThemeToggleDropdown, #theme-toggle-legacy').forEach(function(el) { | |
| if (el) el.addEventListener('click', function(e) { e.preventDefault(); setTheme(getTheme() === 'dark' ? 'light' : 'dark'); }); | |
| }); | |
| // ===== SIDEBAR TOGGLE ===== | |
| var sidebar = document.getElementById('dSidebar'); | |
| var overlay = document.getElementById('dOverlay'); | |
| var toggle = document.getElementById('dSidebarToggle'); | |
| var collapseBtn = document.getElementById('dSidebarCollapse'); | |
| function isMobile() { return window.innerWidth <= 768; } | |
| function toggleSidebar() { | |
| if (isMobile()) { | |
| sidebar.classList.toggle('open'); | |
| if (overlay) overlay.classList.toggle('show'); | |
| } else { | |
| sidebar.classList.toggle('hidden'); | |
| var isHidden = sidebar.classList.contains('hidden'); | |
| localStorage.setItem('d-sidebar-hidden', isHidden ? '1' : '0'); | |
| } | |
| } | |
| function collapseSidebar() { | |
| if (isMobile()) return; | |
| sidebar.classList.remove('hidden'); | |
| sidebar.classList.toggle('collapsed'); | |
| var isCollapsed = sidebar.classList.contains('collapsed'); | |
| localStorage.setItem('d-sidebar-collapsed', isCollapsed ? '1' : '0'); | |
| if (collapseBtn) collapseBtn.innerHTML = isCollapsed ? '<i class=\'bi bi-chevron-right\'></i>' : '<i class=\'bi bi-chevron-left\'></i>'; | |
| } | |
| if (toggle) toggle.addEventListener('click', toggleSidebar); | |
| if (collapseBtn) collapseBtn.addEventListener('click', collapseSidebar); | |
| if (overlay) { | |
| overlay.addEventListener('click', function() { | |
| sidebar.classList.remove('open'); | |
| overlay.classList.remove('show'); | |
| }); | |
| } | |
| var savedHidden = localStorage.getItem('d-sidebar-hidden'); | |
| if (savedHidden === '1' && !isMobile()) { | |
| sidebar.classList.add('hidden'); | |
| } | |
| var savedCollapsed = localStorage.getItem('d-sidebar-collapsed'); | |
| if (savedCollapsed === '1' && !isMobile()) { | |
| sidebar.classList.add('collapsed'); | |
| if (collapseBtn) collapseBtn.innerHTML = '<i class=\'bi bi-chevron-right\'></i>'; | |
| } | |
| // ===== MOBILE MENU (legacy) ===== | |
| var cbToggle = document.getElementById('cbMenuToggle'); | |
| var cbMenu = document.getElementById('cbMobileMenu'); | |
| var cbClose = document.getElementById('cbMenuClose'); | |
| if (cbToggle && cbMenu) { | |
| cbToggle.addEventListener('click', function() { cbMenu.classList.add('open'); }); | |
| cbClose.addEventListener('click', function() { cbMenu.classList.remove('open'); }); | |
| cbMenu.addEventListener('click', function(e) { if (e.target === cbMenu) cbMenu.classList.remove('open'); }); | |
| } | |
| }); | |
| function openPdfViewer(url, title) { | |
| document.getElementById('pdfViewerTitle').textContent = title || 'Просмотр файла'; | |
| document.getElementById('pdfViewerIframe').src = url; | |
| var modal = new bootstrap.Modal(document.getElementById('pdfViewerModal')); | |
| modal.show(); | |
| } | |
| document.addEventListener('hidden.bs.modal', function(e) { | |
| if (e.target.id === 'pdfViewerModal') { | |
| document.getElementById('pdfViewerIframe').src = ''; | |
| } | |
| }); | |
| </script> | |
| {% block extra_js %}{% endblock %} | |
| </body> | |
| </html> | |