feat: universal sidebar via sidebar.js + stale ID cleanup
- Add js/sidebar.js: generates full sidebar HTML into #app-sidebar, handles role-based visibility, active link (with prefix matching), toggle wiring, collapsed state, board/features/notif init - Replace <aside class="sidebar">...</aside> with <aside id="app-sidebar"> across all 35 standard-layout pages via scripts/apply-sidebar.js - Add notifications.js to 5 pages that were missing it - Fix api.js initPage(): skip toggle re-wiring if data-sb-wired set, fix active link selector .sb-item → .sb-link - Remove stale sbl-*/nav-admin/btn-upload-nav getElementById calls that crashed after sidebar replacement (lab, classes, collection, crossword, hangman, knowledge-map, library, pet, profile) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+5
-34
@@ -831,40 +831,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<span class="sb-link active"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></span>
|
||||
</nav>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="sb-content">
|
||||
|
||||
<div class="container">
|
||||
@@ -1894,6 +1861,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
if (!isTeacher) { window.location.href = '/dashboard'; throw new Error(); }
|
||||
@@ -1909,6 +1877,8 @@
|
||||
document.getElementById('admin-nav-system-label').style.display = '';
|
||||
}
|
||||
LS.showBoardIfAllowed();
|
||||
LS.hideDisabledFeatures?.();
|
||||
LS.notif?.init();
|
||||
const MODES = { exam:'Экзамен', practice:'Тренировка', repeat:'Обычный', ct:'ЦТ/ЦЭ', topic:'По теме', random:'Случайный' };
|
||||
const DIFFS = { 1:'Лёгкий', 2:'Средний', 3:'Сложный' };
|
||||
|
||||
@@ -5257,6 +5227,7 @@
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
</body>
|
||||
|
||||
+2
-47
@@ -241,53 +241,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link nav-active"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -334,6 +288,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw new Error();
|
||||
|
||||
|
||||
@@ -262,57 +262,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout" id="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/biochem-library" class="sb-link sb-sub-link active"><i data-lucide="library" class="sb-icon"></i><span class="sb-lbl">↳ Библиотека</span></a>
|
||||
<a href="/biochem-reactions" class="sb-link sb-sub-link"><i data-lucide="arrow-right-left" class="sb-icon"></i><span class="sb-lbl">↳ Реакции</span></a>
|
||||
<a href="/biochem-properties" class="sb-link sb-sub-link"><i data-lucide="table-properties" class="sb-icon"></i><span class="sb-lbl">↳ Свойства</span></a>
|
||||
<a href="/biochem-pathways" class="sb-link sb-sub-link"><i data-lucide="route" class="sb-icon"></i><span class="sb-lbl">↳ Пути</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -389,6 +339,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
@@ -342,57 +342,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout" id="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/biochem-library" class="sb-link sb-sub-link"><i data-lucide="library" class="sb-icon"></i><span class="sb-lbl">↳ Библиотека</span></a>
|
||||
<a href="/biochem-reactions" class="sb-link sb-sub-link"><i data-lucide="arrow-right-left" class="sb-icon"></i><span class="sb-lbl">↳ Реакции</span></a>
|
||||
<a href="/biochem-properties" class="sb-link sb-sub-link"><i data-lucide="table-properties" class="sb-icon"></i><span class="sb-lbl">↳ Свойства</span></a>
|
||||
<a href="/biochem-pathways" class="sb-link sb-sub-link active"><i data-lucide="route" class="sb-icon"></i><span class="sb-lbl">↳ Пути</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -520,6 +470,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// PATHWAY DATA
|
||||
|
||||
@@ -175,57 +175,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout" id="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/biochem-library" class="sb-link sb-sub-link"><i data-lucide="library" class="sb-icon"></i><span class="sb-lbl">↳ Библиотека</span></a>
|
||||
<a href="/biochem-reactions" class="sb-link sb-sub-link"><i data-lucide="arrow-right-left" class="sb-icon"></i><span class="sb-lbl">↳ Реакции</span></a>
|
||||
<a href="/biochem-properties" class="sb-link sb-sub-link active"><i data-lucide="table-properties" class="sb-icon"></i><span class="sb-lbl">↳ Свойства</span></a>
|
||||
<a href="/biochem-pathways" class="sb-link sb-sub-link"><i data-lucide="route" class="sb-icon"></i><span class="sb-lbl">↳ Пути</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content" style="overflow:hidden;display:flex;flex-direction:column">
|
||||
@@ -267,6 +217,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
@@ -298,57 +298,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout" id="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/biochem-library" class="sb-link sb-sub-link"><i data-lucide="library" class="sb-icon"></i><span class="sb-lbl">↳ Библиотека</span></a>
|
||||
<a href="/biochem-reactions" class="sb-link sb-sub-link active"><i data-lucide="arrow-right-left" class="sb-icon"></i><span class="sb-lbl">↳ Реакции</span></a>
|
||||
<a href="/biochem-properties" class="sb-link sb-sub-link"><i data-lucide="table-properties" class="sb-icon"></i><span class="sb-lbl">↳ Свойства</span></a>
|
||||
<a href="/biochem-pathways" class="sb-link sb-sub-link"><i data-lucide="route" class="sb-icon"></i><span class="sb-lbl">↳ Пути</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -393,6 +343,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
+6
-52
@@ -316,57 +316,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout" id="app">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link active"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/biochem-library" class="sb-link sb-sub-link"><i data-lucide="library" class="sb-icon"></i><span class="sb-lbl">↳ Библиотека</span></a>
|
||||
<a href="/biochem-reactions" class="sb-link sb-sub-link"><i data-lucide="arrow-right-left" class="sb-icon"></i><span class="sb-lbl">↳ Реакции</span></a>
|
||||
<a href="/biochem-properties" class="sb-link sb-sub-link"><i data-lucide="table-properties" class="sb-icon"></i><span class="sb-lbl">↳ Свойства</span></a>
|
||||
<a href="/biochem-pathways" class="sb-link sb-sub-link"><i data-lucide="route" class="sb-icon"></i><span class="sb-lbl">↳ Пути</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -537,6 +487,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
@@ -2071,7 +2022,10 @@ window.addEventListener('keydown', e => {
|
||||
|
||||
if (window.lucide) lucide.createIcons();
|
||||
LS.notif?.init();
|
||||
LS.hideDisabledFeatures?.();
|
||||
LS.loadFeatures?.().then(feats => {
|
||||
if (feats?.biochem === false) window.location.replace('/403');
|
||||
else LS.hideDisabledFeatures?.();
|
||||
}).catch(() => LS.hideDisabledFeatures?.());
|
||||
</script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
|
||||
+2
-47
@@ -256,53 +256,7 @@
|
||||
<canvas id="bg-canvas"></canvas>
|
||||
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<span class="sb-link active"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></span>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -353,6 +307,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw 0;
|
||||
|
||||
+2
-48
@@ -546,53 +546,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<span class="sb-link active"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></span>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="nav-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content classes-split">
|
||||
|
||||
@@ -1072,12 +1026,12 @@
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
if (!user) throw new Error('Not logged in');
|
||||
if (!isTeacher) { window.location.href='/dashboard'; throw new Error(); }
|
||||
if (isAdmin) document.getElementById('nav-admin').style.display = '';
|
||||
|
||||
const SUBJECTS = { bio:'Биология', chem:'Химия', math:'Математика', phys:'Физика', other:'Задание' };
|
||||
const MODES = { exam:'Экзамен', practice:'Тренировка' };
|
||||
|
||||
+72
-115
@@ -2073,53 +2073,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link nav-active"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -2984,6 +2938,8 @@
|
||||
<script src="/js/whiteboard.js"></script>
|
||||
<script src="/js/classroom-rtc.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
/* ── User prefs ─────────────────────────────────────────────────────────── */
|
||||
const CR_PREFS_KEY = 'ls_cr_prefs';
|
||||
@@ -3271,16 +3227,8 @@
|
||||
_statusTimers.set(id, timer);
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
stopPolling();
|
||||
_pollPart = setInterval(pollParticipants, 10_000); // participants backup (10s)
|
||||
_pollChatTimer = setInterval(_pollChat, 15_000); // chat backup (15s)
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
clearInterval(_pollPart); _pollPart = null;
|
||||
clearInterval(_pollChatTimer); _pollChatTimer = null;
|
||||
}
|
||||
function startPolling() { /* backup polls removed — WS delivers all events with SSE fallback */ }
|
||||
function stopPolling() { /* no-op */ }
|
||||
|
||||
async function _pollChat() {
|
||||
if (!_sessionId) return;
|
||||
@@ -3427,9 +3375,11 @@
|
||||
_sessionId = data.session.id;
|
||||
|
||||
if (isTeacher) {
|
||||
// Teacher: always reconnect — rejoin to refresh attendance
|
||||
// Teacher: always reconnect — rejoin to refresh attendance, then fetch fresh data
|
||||
await LS.post(`/api/classroom/${_sessionId}/join`).catch(() => {});
|
||||
enterActiveState(data.session);
|
||||
const fresh = await LS.get(`/api/classroom/${_sessionId}`).catch(() => data.session);
|
||||
_session = fresh;
|
||||
enterActiveState(fresh);
|
||||
loadChat();
|
||||
return;
|
||||
} else {
|
||||
@@ -3474,13 +3424,18 @@
|
||||
|
||||
/* ── SSE handler ── */
|
||||
/* eslint-disable eqeqeq */
|
||||
function handleSSE(data) {
|
||||
function handleSSE(data, fromWS = false) {
|
||||
// When WS is active, classroom events are delivered via WS.
|
||||
// Ignore classroom_ events that arrive via SSE to avoid duplicates.
|
||||
// Events coming from WS (fromWS=true) are always processed.
|
||||
if (!fromWS && _crWsReady && data.type?.startsWith('classroom_') && data.type !== '_sse_reconnect') return;
|
||||
|
||||
// Use == for sessionId comparison throughout — guards against string/number mismatch
|
||||
// when _sessionId comes from JSON (number) vs SSE data (could be string in edge cases).
|
||||
if (data.type === 'classroom_started') {
|
||||
onClassroomStarted(data);
|
||||
} else if (data.type === 'classroom_ended') {
|
||||
if (_sessionId == data.sessionId) onClassroomEnded();
|
||||
if (_sessionId == data.sessionId) onClassroomEnded(true); // teacher ended remotely → show toast
|
||||
} else if (data.type === 'classroom_user_joined') {
|
||||
if (_sessionId == data.sessionId) onUserJoined(data);
|
||||
} else if (data.type === 'classroom_user_left') {
|
||||
@@ -3707,7 +3662,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
function onClassroomEnded() {
|
||||
function onClassroomEnded(showToast = true) {
|
||||
if (!_sessionId) return; // guard against double-call (direct + WS event)
|
||||
stopPolling();
|
||||
wbStopBatch();
|
||||
_crWsClose();
|
||||
@@ -3763,7 +3719,7 @@
|
||||
// Close sim panel if open
|
||||
if (_simActive) onSimClose();
|
||||
updateParticipantsList();
|
||||
LS.toast('Урок завершён', 'info');
|
||||
if (showToast) LS.toast('Урок завершён', 'info');
|
||||
}
|
||||
|
||||
function onUserJoined(data) {
|
||||
@@ -4007,6 +3963,8 @@
|
||||
document.getElementById('chat-no-session').style.display = active ? 'none' : 'flex';
|
||||
document.getElementById('chat-active').style.display = active ? 'flex' : 'none';
|
||||
document.getElementById('participants-no-session').style.display = active ? 'none' : 'flex';
|
||||
// Hide the right panel entirely when no session is active (avoids empty strip on mobile)
|
||||
document.getElementById('cr-right').style.display = active ? '' : 'none';
|
||||
}
|
||||
|
||||
/* ── whiteboard ── */
|
||||
@@ -4103,8 +4061,7 @@
|
||||
// Read-only student: poll every 2s as a fallback in case SSE events are missed
|
||||
wbStartPoll();
|
||||
}
|
||||
// Periodic draw permission check — catches missed SSE draw_permitted events
|
||||
if (!_drawPermPollTimer) _drawPermPollTimer = setInterval(_checkDrawPermission, 5000);
|
||||
// Draw permission delivered via WS — no periodic poll needed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4258,10 +4215,21 @@
|
||||
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const token = LS.getToken() || '';
|
||||
_crWs = new WebSocket(`${proto}//${location.host}/ws?token=${encodeURIComponent(token)}`);
|
||||
_crWs.onopen = () => { _crWsReady = true; };
|
||||
_crWs.onclose = () => { _crWsReady = false; };
|
||||
_crWs.onopen = () => {
|
||||
_crWsReady = true;
|
||||
// Register in session so server delivers events via WS instead of SSE
|
||||
if (_sessionId) _crWs.send(JSON.stringify({ type: 'classroom_join', sessionId: _sessionId }));
|
||||
};
|
||||
_crWs.onclose = () => {
|
||||
_crWsReady = false;
|
||||
// Auto-reconnect after 2s (SSE stays active as fallback during gap)
|
||||
if (_sessionId) setTimeout(() => { if (_sessionId) _crWsConnect(); }, 2000);
|
||||
};
|
||||
_crWs.onerror = () => { _crWsReady = false; };
|
||||
// No incoming messages expected (server→client still uses SSE)
|
||||
// All classroom server→client events arrive here (WS replaces SSE for classroom)
|
||||
_crWs.onmessage = e => {
|
||||
try { handleSSE(JSON.parse(e.data), true); } catch {}
|
||||
};
|
||||
}
|
||||
|
||||
function _crWsClose() {
|
||||
@@ -5005,7 +4973,7 @@
|
||||
if (!ok) return;
|
||||
_wb.clearPage();
|
||||
_wbBatch = [];
|
||||
try { await LS.post(`/api/classroom/${_sessionId}/clear-page`, { page_num: _wbCurrentPage }); } catch {}
|
||||
_crWsSend({ type: 'page_clear', sessionId: _sessionId, pageNum: _wbCurrentPage });
|
||||
wbUpdateThumbnail(_wbCurrentPage);
|
||||
}
|
||||
|
||||
@@ -5016,7 +4984,8 @@
|
||||
if (!ok) return;
|
||||
try {
|
||||
await LS.del(`/api/classroom/${_sessionId}`);
|
||||
onClassroomEnded();
|
||||
onClassroomEnded(false);
|
||||
LS.toast('Урок завершён', 'info');
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
}
|
||||
|
||||
@@ -5024,7 +4993,11 @@
|
||||
if (!_sessionId) return;
|
||||
try {
|
||||
await LS.post(`/api/classroom/${_sessionId}/leave`);
|
||||
onClassroomEnded();
|
||||
onClassroomEnded(false);
|
||||
LS.toast('Вы вышли из урока', 'info');
|
||||
// If the session is still active, show the join banner so student can rejoin without refresh
|
||||
const data = await LS.get('/api/classroom/my/session').catch(() => null);
|
||||
if (data?.session) showJoinBanner(data.session);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -5198,14 +5171,15 @@
|
||||
const ids = Object.keys(_participants);
|
||||
document.getElementById('participants-count').textContent = ids.length;
|
||||
|
||||
if (!_sessionId || !ids.length) {
|
||||
// Always clear previous DOM entries first
|
||||
list.querySelectorAll('.cr-participant').forEach(el => el.remove());
|
||||
|
||||
if (!_sessionId) {
|
||||
noSession.style.display = 'flex';
|
||||
return;
|
||||
}
|
||||
noSession.style.display = 'none';
|
||||
|
||||
const existing = list.querySelectorAll('.cr-participant');
|
||||
existing.forEach(el => el.remove());
|
||||
noSession.style.display = ids.length ? 'none' : 'flex';
|
||||
if (!ids.length) return;
|
||||
|
||||
const isTeacherView = _me?.role === 'teacher' || _me?.role === 'admin';
|
||||
ids.forEach(uid => {
|
||||
@@ -5271,22 +5245,14 @@
|
||||
}
|
||||
|
||||
/* ── hand raise ── */
|
||||
async function crToggleHand() {
|
||||
function crToggleHand() {
|
||||
if (!_sessionId) return;
|
||||
_handRaised = !_handRaised;
|
||||
const btn = document.getElementById('cr-hand-btn');
|
||||
const lbl = document.getElementById('cr-hand-label');
|
||||
btn.classList.toggle('raised', _handRaised);
|
||||
lbl.textContent = _handRaised ? 'Опустить руку' : 'Поднять руку';
|
||||
try {
|
||||
if (_handRaised) await LS.post(`/api/classroom/${_sessionId}/hand`);
|
||||
else await LS.del(`/api/classroom/${_sessionId}/hand`);
|
||||
} catch {
|
||||
// revert on error
|
||||
_handRaised = !_handRaised;
|
||||
btn.classList.toggle('raised', _handRaised);
|
||||
lbl.textContent = _handRaised ? 'Опустить руку' : 'Поднять руку';
|
||||
}
|
||||
_crWsSend({ type: _handRaised ? 'hand_raise' : 'hand_lower', sessionId: _sessionId });
|
||||
}
|
||||
|
||||
function onHandRaised(userId, userName) {
|
||||
@@ -5429,10 +5395,10 @@
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
}
|
||||
|
||||
async function wbSetPageTemplate(template) {
|
||||
function wbSetPageTemplate(template) {
|
||||
if (!_sessionId || !_wb) return;
|
||||
_wb.setTemplate(template);
|
||||
try { await LS.patch(`/api/classroom/${_sessionId}/page-template`, { template }); } catch {}
|
||||
_crWsSend({ type: 'template_change', sessionId: _sessionId, pageNum: _wbCurrentPage, template });
|
||||
wbUpdateThumbnail(_wbCurrentPage);
|
||||
}
|
||||
|
||||
@@ -5498,10 +5464,10 @@
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
}
|
||||
|
||||
async function wbPageClear(pageNum) {
|
||||
function wbPageClear(pageNum) {
|
||||
wbHidePageMenu();
|
||||
if (!_sessionId) return;
|
||||
try { await LS.post(`/api/classroom/${_sessionId}/clear-page`, { page_num: pageNum }); } catch {}
|
||||
_crWsSend({ type: 'page_clear', sessionId: _sessionId, pageNum });
|
||||
if (pageNum === _wbCurrentPage && _wb) { _wb.clearPage(); _wbMaxSeq = 0; _wbClearGen++; }
|
||||
wbUpdateThumbnail(pageNum);
|
||||
}
|
||||
@@ -5543,15 +5509,15 @@
|
||||
async function _wbChangePage(pageNum) {
|
||||
if (!_sessionId) return;
|
||||
_wbBatch = []; // discard unsent strokes from old page
|
||||
try {
|
||||
await LS.put(`/api/classroom/${_sessionId}/page`, { page_num: pageNum });
|
||||
// SSE will echo back page_changed; teacher handles locally too
|
||||
// Send via WS (server updates DB + broadcasts to all)
|
||||
_crWsSend({ type: 'page_change', sessionId: _sessionId, pageNum });
|
||||
// Navigate locally without waiting for echo
|
||||
_wbCurrentPage = pageNum;
|
||||
_wbMaxSeq = 0;
|
||||
_wbClearGen++;
|
||||
_wbMaxSeq = 0; _wbClearGen++;
|
||||
updatePageLabel();
|
||||
if (_wb) {
|
||||
_wb.clearPage();
|
||||
try {
|
||||
const res = await LS.get(`/api/classroom/${_sessionId}/strokes?page_num=${pageNum}`);
|
||||
const strokes = res.strokes || [];
|
||||
_wbUpdateMaxSeq(strokes);
|
||||
@@ -5564,9 +5530,9 @@
|
||||
if (res.name !== undefined) _pageNames[pageNum] = res.name || null;
|
||||
_wbUpdateBgBtn();
|
||||
wbRebuildThumbnails();
|
||||
}
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
}
|
||||
}
|
||||
|
||||
/* ── tabs ── */
|
||||
function crToggleRightPanel() {
|
||||
@@ -6612,7 +6578,7 @@
|
||||
if (_rtc.isSharing()) {
|
||||
_rtc.stopScreenShare();
|
||||
document.getElementById('cr-screen-btn').classList.remove('cr-btn-sharing');
|
||||
LS.del(`/api/classroom/${_sessionId}/screen`).catch(() => {});
|
||||
_crWsSend({ type: 'screen_stop', sessionId: _sessionId });
|
||||
} else {
|
||||
crOpenScreenPicker();
|
||||
}
|
||||
@@ -6755,14 +6721,12 @@
|
||||
};
|
||||
}
|
||||
document.getElementById('cr-screen-btn').classList.add('cr-btn-sharing');
|
||||
LS.post(`/api/classroom/${_sessionId}/screen`).catch(() => {});
|
||||
_crWsSend({ type: 'screen_start', sessionId: _sessionId });
|
||||
}
|
||||
|
||||
async function onScreenShareStopped() {
|
||||
function onScreenShareStopped() {
|
||||
document.getElementById('cr-screen-btn').classList.remove('cr-btn-sharing');
|
||||
if (_sessionId) {
|
||||
try { await LS.del(`/api/classroom/${_sessionId}/screen`); } catch {}
|
||||
}
|
||||
if (_sessionId) _crWsSend({ type: 'screen_stop', sessionId: _sessionId });
|
||||
}
|
||||
|
||||
/* ── Simulation integration ──────────────────────────────────────────── */
|
||||
@@ -6946,31 +6910,24 @@
|
||||
}, 300);
|
||||
});
|
||||
|
||||
async function crToggleDrawPermission(uid) {
|
||||
function crToggleDrawPermission(uid) {
|
||||
if (!_sessionId) return;
|
||||
const numUid = Number(uid);
|
||||
const hasPermit = _permittedStudents.has(numUid);
|
||||
try {
|
||||
if (hasPermit) {
|
||||
await LS.del(`/api/classroom/${_sessionId}/allow-draw/${numUid}`);
|
||||
_permittedStudents.delete(numUid);
|
||||
_crWsSend({ type: 'revoke_draw', sessionId: _sessionId, targetUserId: numUid });
|
||||
} else {
|
||||
await LS.post(`/api/classroom/${_sessionId}/allow-draw/${numUid}`);
|
||||
_permittedStudents.add(numUid);
|
||||
_crWsSend({ type: 'allow_draw', sessionId: _sessionId, targetUserId: numUid });
|
||||
}
|
||||
updateParticipantsList();
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
}
|
||||
|
||||
async function crMutePeer(uid) {
|
||||
function crMutePeer(uid) {
|
||||
if (!_sessionId) return;
|
||||
try {
|
||||
await LS.post(`/api/classroom/${_sessionId}/mute`, { user_id: uid });
|
||||
if (_participants[uid]) {
|
||||
_participants[uid].micMuted = true;
|
||||
updateParticipantsList();
|
||||
}
|
||||
} catch (e) { LS.toast(e.message || 'Ошибка', 'error'); }
|
||||
_crWsSend({ type: 'mute_peer', sessionId: _sessionId, targetUserId: Number(uid) });
|
||||
if (_participants[uid]) { _participants[uid].micMuted = true; updateParticipantsList(); }
|
||||
}
|
||||
|
||||
/* ── notifications ── */
|
||||
|
||||
@@ -288,6 +288,7 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
<script>
|
||||
/* ── State ── */
|
||||
|
||||
@@ -220,53 +220,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<span class="sb-link active"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></span>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -396,6 +350,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
(async () => {
|
||||
@@ -406,14 +361,13 @@
|
||||
document.getElementById('nav-avatar').textContent =
|
||||
(user.name||'LS').split(' ').slice(0,2).map(w=>w[0]?.toUpperCase()||'').join('')||'LS';
|
||||
document.getElementById('nav-user').textContent = user.name || '—';
|
||||
if (user.role === 'admin') document.getElementById('sbl-admin').style.display = '';
|
||||
LS.showBoardIfAllowed();
|
||||
if (user.role !== 'student') {
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
}
|
||||
}
|
||||
LS.sidebar?.init();
|
||||
lucide.createIcons();
|
||||
const feats = await LS.loadFeatures();
|
||||
if (feats.collection === false) { window.location.replace('/403'); return; }
|
||||
LS.hideDisabledFeatures?.();
|
||||
await loadCollection();
|
||||
})();
|
||||
|
||||
|
||||
+2
-43
@@ -398,49 +398,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link active"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -555,6 +513,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw new Error();
|
||||
|
||||
|
||||
+2
-52
@@ -182,53 +182,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<span class="sb-link active"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></span>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -323,6 +277,7 @@
|
||||
<div class="cw-toast" id="cw-toast"></div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
@@ -345,12 +300,7 @@ let _subjectSlug = '';
|
||||
document.getElementById('nav-avatar').textContent =
|
||||
(user.name||'LS').split(' ').slice(0,2).map(w=>w[0]?.toUpperCase()||'').join('')||'LS';
|
||||
document.getElementById('nav-user').textContent = user.name || '—';
|
||||
if (user.role === 'admin')
|
||||
document.getElementById('sbl-admin').style.display = '';
|
||||
LS.showBoardIfAllowed();
|
||||
if (user.role !== 'student') {
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
}
|
||||
}
|
||||
LS.sidebar?.init();
|
||||
lucide.createIcons();
|
||||
|
||||
@@ -444,6 +444,13 @@ body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* notif wrap — visually separate from nav items */
|
||||
#notif-wrap {
|
||||
border-top: 1.5px solid var(--border);
|
||||
margin-top: 6px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
/* notif drop anchored relative to sidebar */
|
||||
.notif-drop {
|
||||
position: fixed;
|
||||
|
||||
+2
-48
@@ -1172,54 +1172,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<span class="sb-link active"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></span>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<button class="sb-link" id="btn-join" style="display:none" onclick="openJoinModal()"><i data-lucide="user-plus" class="sb-icon"></i><span class="sb-lbl">Вступить в класс</span></button>
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -1568,6 +1521,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
|
||||
@@ -225,37 +225,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/" class="sb-logo">Learn<span>Space</span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть"><i data-lucide="panel-left-close" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/flashcards" class="sb-link active"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Карточки</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<div class="sb-spacer"></div>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar"></div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<main class="sb-content">
|
||||
<div class="fc-wrap">
|
||||
@@ -395,6 +365,8 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
|
||||
|
||||
+2
-47
@@ -194,53 +194,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link nav-active"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -295,6 +249,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw new Error();
|
||||
|
||||
|
||||
+2
-56
@@ -264,53 +264,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<span class="sb-link active"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></span>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<div class="sb-content">
|
||||
<div class="hm-wrap">
|
||||
@@ -421,6 +375,7 @@
|
||||
<div id="hm-toast"><i data-lucide="award" style="width:16px;height:16px"></i><span id="hm-toast-txt"></span></div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
@@ -504,15 +459,6 @@ function showToast(msg) {
|
||||
const user = LS.getUser();
|
||||
LS.initPage();
|
||||
|
||||
// sbl-classes — только для учителей/админов
|
||||
if (user.role !== 'student') {
|
||||
const el = document.getElementById('sbl-classes');
|
||||
if (el) el.style.display = '';
|
||||
}
|
||||
if (user.role === 'admin') {
|
||||
const a = document.getElementById('sbl-admin');
|
||||
if (a) a.style.display = '';
|
||||
}
|
||||
LS.showBoardIfAllowed();
|
||||
|
||||
LS.notif.init();
|
||||
|
||||
+2
-47
@@ -145,53 +145,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
<div class="container">
|
||||
@@ -257,6 +211,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
|
||||
@@ -359,53 +359,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<span class="sb-link active"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></span>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -546,6 +500,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
@@ -625,19 +580,13 @@ let _dashOffset = 0; // animated dash offset for link flow
|
||||
const user = LS.getUser();
|
||||
LS.initPage();
|
||||
|
||||
// sbl-classes — только для учителей/админов
|
||||
if (user.role !== 'student') {
|
||||
const el = document.getElementById('sbl-classes');
|
||||
if (el) el.style.display = '';
|
||||
}
|
||||
if (user.role === 'admin') {
|
||||
const a = document.getElementById('sbl-admin');
|
||||
if (a) a.style.display = '';
|
||||
}
|
||||
LS.showBoardIfAllowed();
|
||||
|
||||
LS.notif.init();
|
||||
lucide.createIcons();
|
||||
const feats = await LS.loadFeatures();
|
||||
if (feats.knowledge_map === false) { window.location.replace('/403'); return; }
|
||||
LS.hideDisabledFeatures?.();
|
||||
|
||||
document.querySelector('.sb-toggle')?.addEventListener('click', () => {
|
||||
setTimeout(() => { resizeCanvas(); recenter(); }, 310);
|
||||
|
||||
+3
-49
@@ -648,51 +648,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<span class="sb-link active"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></span>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -3689,6 +3645,7 @@
|
||||
</div><!-- /.app-layout -->
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
|
||||
<script src="/js/labs/graph.js"></script>
|
||||
<script src="/js/labs/magnetic.js"></script>
|
||||
@@ -3713,10 +3670,7 @@
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
window._simQuizAllowed = true; // default; overridden after permission fetch for students
|
||||
LS.showBoardIfAllowed();
|
||||
if (isTeacher) {
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
document.getElementById('sbl-admin').style.display = '';
|
||||
}
|
||||
|
||||
|
||||
/* ════════════════════════════════
|
||||
SIM CATALOGUE (defined after P_* consts below)
|
||||
|
||||
@@ -1001,6 +1001,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw new Error();
|
||||
const user = LS.getUser();
|
||||
|
||||
@@ -819,51 +819,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<span class="sb-link active"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></span>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
<button class="sb-link" id="btn-join" style="display:none" onclick="openJoinModal()"><i data-lucide="user-plus" class="sb-icon"></i><span class="sb-lbl">Вступить в класс</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info"><div class="sb-user-name" id="nav-user">...</div><div class="sb-user-role" id="nav-role"></div></div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<main class="sb-content">
|
||||
<div class="lh-wrap">
|
||||
@@ -1114,6 +1070,8 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
<script src="/js/whiteboard.js"></script>
|
||||
<script>
|
||||
|
||||
+2
-43
@@ -770,49 +770,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link active"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
<div class="lesson-layout">
|
||||
@@ -874,6 +832,7 @@
|
||||
</div><!-- /app-layout -->
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
if (!LS.requireAuth()) throw new Error();
|
||||
|
||||
|
||||
+2
-53
@@ -190,56 +190,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<span class="sb-link active"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></span>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<button class="sb-link" id="btn-upload-nav" style="display:none" onclick="openUpload()">
|
||||
<i data-lucide="upload" class="sb-icon"></i><span class="sb-lbl">Загрузить файл</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -489,6 +440,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/search.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
@@ -497,11 +449,8 @@
|
||||
|
||||
LS.showBoardIfAllowed();
|
||||
if (isTeacher) {
|
||||
document.getElementById('btn-upload-nav').style.display = '';
|
||||
document.getElementById('btn-upload-main').style.display = '';
|
||||
document.getElementById('btn-new-folder').style.display = '';
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
document.getElementById('sbl-admin').style.display = '';
|
||||
}
|
||||
|
||||
/* ── constants ── */
|
||||
|
||||
+2
-47
@@ -336,53 +336,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link nav-active"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -495,6 +449,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
|
||||
<script>
|
||||
|
||||
@@ -441,51 +441,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<span class="sb-link active"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Мои уроки</span></span>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
<button class="sb-link" id="btn-join" style="display:none" onclick="openJoinModal()"><i data-lucide="user-plus" class="sb-icon"></i><span class="sb-lbl">Вступить в класс</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info"><div class="sb-user-name" id="nav-user">...</div><div class="sb-user-role" id="nav-role"></div></div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<main class="sb-content">
|
||||
<div class="ml-wrap">
|
||||
@@ -664,6 +620,8 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
<script src="/js/whiteboard.js"></script>
|
||||
<script>
|
||||
|
||||
+2
-51
@@ -330,53 +330,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<span class="sb-link active"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></span>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
|
||||
<div class="sb-content">
|
||||
@@ -587,6 +541,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script>
|
||||
/* ── Constants ── */
|
||||
@@ -653,11 +608,7 @@ let _petCooldownTimer = null;
|
||||
document.getElementById('nav-avatar').textContent =
|
||||
(user.name||'LS').split(' ').slice(0,2).map(w=>w[0]?.toUpperCase()||'').join('')||'LS';
|
||||
document.getElementById('nav-user').textContent = user.name || '—';
|
||||
if (user.role === 'admin') document.getElementById('sbl-admin').style.display = '';
|
||||
LS.showBoardIfAllowed();
|
||||
if (user.role !== 'student') {
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
}
|
||||
}
|
||||
LS.sidebar?.init();
|
||||
lucide.createIcons();
|
||||
|
||||
+4
-43
@@ -529,45 +529,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="sbl-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="sbl-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="sbl-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
|
||||
<div class="sb-content">
|
||||
<div class="profile-layout">
|
||||
@@ -832,13 +794,12 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
LS.showBoardIfAllowed();
|
||||
if (isTeacher) {
|
||||
document.getElementById('sbl-classes').style.display = '';
|
||||
if (isAdmin) document.getElementById('sbl-admin').style.display = '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ROLE_LABELS = { student:'Ученик', teacher:'Учитель', admin:'Администратор' };
|
||||
|
||||
@@ -223,53 +223,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" onclick="toggleSidebar()" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<a href="/theory" class="sb-link"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></a>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link nav-active"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="toggleNotifDrop()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -384,6 +338,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
|
||||
<script>
|
||||
|
||||
@@ -213,6 +213,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
Biome definitions
|
||||
|
||||
@@ -253,6 +253,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script>
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
State & constants
|
||||
|
||||
@@ -285,6 +285,7 @@
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
<script>
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -767,6 +767,7 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/mobile.js"></script>
|
||||
<script>
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
@@ -789,8 +790,10 @@ const XP_MAP = { CR: 50, EN: 40, VU: 30, NT: 20, LC: 10 };
|
||||
Init
|
||||
══════════════════════════════════════════════════════════════════════════ */
|
||||
async function init() {
|
||||
LS.hideDisabledFeatures?.();
|
||||
lucide.createIcons();
|
||||
const feats = await LS.loadFeatures().catch(() => ({}));
|
||||
if (feats.red_book === false) { window.location.replace('/403'); return; }
|
||||
LS.hideDisabledFeatures?.();
|
||||
|
||||
// Auth (sidebar)
|
||||
const user = LS.getUser?.() || null;
|
||||
|
||||
+2
-47
@@ -284,53 +284,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar">
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
<a href="/dashboard" class="sb-link"><i data-lucide="home" class="sb-icon"></i><span class="sb-lbl">Дашборд</span></a>
|
||||
<a href="/board" class="sb-link" id="btn-board" style="display:none"><i data-lucide="layout-dashboard" class="sb-icon"></i><span class="sb-lbl">Доска</span></a>
|
||||
<a href="/classes" class="sb-link" id="btn-classes" style="display:none"><i data-lucide="graduation-cap" class="sb-icon"></i><span class="sb-lbl">Классы</span></a>
|
||||
<a href="/library" class="sb-link"><i data-lucide="book-open" class="sb-icon"></i><span class="sb-lbl">Библиотека</span></a>
|
||||
<span class="sb-link active"><i data-lucide="brain" class="sb-icon"></i><span class="sb-lbl">Теория</span></span>
|
||||
<a href="/lab" class="sb-link"><i data-lucide="atom" class="sb-icon"></i><span class="sb-lbl">Лаборатория</span></a>
|
||||
<a href="/biochem" class="sb-link"><i data-lucide="flask-conical" class="sb-icon"></i><span class="sb-lbl">Биохимия</span></a>
|
||||
<a href="/hangman" class="sb-link"><i data-lucide="gamepad-2" class="sb-icon"></i><span class="sb-lbl">Виселица</span></a>
|
||||
<a href="/crossword" class="sb-link"><i data-lucide="grid-3x3" class="sb-icon"></i><span class="sb-lbl">Кроссворд</span></a>
|
||||
<a href="/pet" class="sb-link"><i data-lucide="heart" class="sb-icon"></i><span class="sb-lbl">Питомец</span></a>
|
||||
<a href="/collection" class="sb-link"><i data-lucide="layers" class="sb-icon"></i><span class="sb-lbl">Коллекция</span></a>
|
||||
<a href="/knowledge-map" class="sb-link"><i data-lucide="share-2" class="sb-icon"></i><span class="sb-lbl">Карта знаний</span></a>
|
||||
<a href="/red-book.html" class="sb-link"><i data-lucide="leaf" class="sb-icon"></i><span class="sb-lbl">Красная книга</span></a>
|
||||
<a href="/classroom" class="sb-link"><i data-lucide="presentation" class="sb-icon"></i><span class="sb-lbl">Онлайн-урок</span></a>
|
||||
<a href="/lesson-history" class="sb-link"><i data-lucide="archive" class="sb-icon"></i><span class="sb-lbl">Архив уроков</span></a>
|
||||
<div class="sb-divider"></div>
|
||||
<a href="/analytics" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="bar-chart-2" class="sb-icon"></i><span class="sb-lbl">Аналитика</span></a>
|
||||
<a href="/question-bank" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="database" class="sb-icon"></i><span class="sb-lbl">Банк вопросов</span></a>
|
||||
<a href="/live-quiz" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="radio" class="sb-icon"></i><span class="sb-lbl">Live-квиз</span></a>
|
||||
<a href="/gradebook" class="sb-link sb-teacher-only" style="display:none"><i data-lucide="table" class="sb-icon"></i><span class="sb-lbl">Журнал</span></a>
|
||||
<a href="/admin" class="sb-link" id="btn-admin" style="display:none"><i data-lucide="settings" class="sb-icon"></i><span class="sb-lbl">Управление</span></a>
|
||||
</nav>
|
||||
<div style="padding: 4px 2px">
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">?</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">—</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="sidebar" id="app-sidebar"></aside>
|
||||
<div class="notif-drop" id="notif-drop"></div>
|
||||
<div class="sb-content">
|
||||
|
||||
@@ -418,6 +372,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script>
|
||||
const { user, isTeacher, isAdmin } = LS.initPage();
|
||||
|
||||
@@ -491,19 +491,21 @@ function initPage({ requireLogin = true } = {}) {
|
||||
document.querySelector('.app-layout')?.classList.add('sb-collapsed');
|
||||
}
|
||||
|
||||
// Sidebar toggle wiring
|
||||
// Sidebar toggle wiring (skip if sidebar.js already wired it via data-sb-wired)
|
||||
const togBtn = document.querySelector('.sb-toggle');
|
||||
if (togBtn) togBtn.addEventListener('click', () => {
|
||||
if (togBtn && !togBtn.dataset.sbWired) {
|
||||
togBtn.addEventListener('click', () => {
|
||||
const layout = document.querySelector('.app-layout');
|
||||
const collapsed = layout.classList.toggle('sb-collapsed');
|
||||
localStorage.setItem('ls_sb_collapsed', collapsed ? '1' : '0');
|
||||
});
|
||||
}
|
||||
|
||||
// Sidebar active link
|
||||
// Sidebar active link (fallback for pages without sidebar.js)
|
||||
const currentPath = location.pathname.replace(/\.html$/, '').replace(/^\//, '') || 'dashboard';
|
||||
document.querySelectorAll('.sidebar .sb-item').forEach(a => {
|
||||
document.querySelectorAll('.sidebar .sb-link').forEach(a => {
|
||||
const href = a.getAttribute('href')?.replace(/^\//, '').replace(/\.html$/, '') || '';
|
||||
if (href === currentPath) a.classList.add('active');
|
||||
if (href && href === currentPath) a.classList.add('active');
|
||||
});
|
||||
|
||||
// Cosmetics
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
// Universal sidebar — LearnSpace
|
||||
// Generates full sidebar HTML into <aside id="app-sidebar">
|
||||
// Load after api.js, before page-specific scripts.
|
||||
(function () {
|
||||
'use strict';
|
||||
const el = document.getElementById('app-sidebar');
|
||||
if (!el) return;
|
||||
|
||||
const user = (typeof LS !== 'undefined') ? LS.getUser?.() : null;
|
||||
const role = user?.role || 'student';
|
||||
const isTch = ['teacher', 'admin'].includes(role);
|
||||
const isAdm = role === 'admin';
|
||||
const isStu = role === 'student';
|
||||
|
||||
// Clean current path (strip .html extension)
|
||||
const path = location.pathname.replace(/\.html$/, '');
|
||||
|
||||
// Active link: exact match OR prefix match (e.g. /biochem active for /biochem-library)
|
||||
function isActive(href) {
|
||||
const h = href.replace(/\.html$/, '');
|
||||
if (path === h) return true;
|
||||
if (h !== '/' && path.startsWith(h + '-')) return true;
|
||||
if (h !== '/' && path.startsWith(h + '/')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
return s ? String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') : '';
|
||||
}
|
||||
|
||||
// Build an <a> sidebar link
|
||||
function L(href, icon, label, { id = '', cls = '', hidden = false } = {}) {
|
||||
const active = isActive(href) ? ' active' : '';
|
||||
const classes = ['sb-link', active, cls].filter(Boolean).join(' ');
|
||||
const idA = id ? ` id="${id}"` : '';
|
||||
const hidA = hidden ? ' style="display:none"' : '';
|
||||
return `<a href="${esc(href)}" class="${classes}"${idA}${hidA}><i data-lucide="${icon}" class="sb-icon"></i><span class="sb-lbl">${label}</span></a>`;
|
||||
}
|
||||
|
||||
const initials = (user?.name || 'LS').split(' ').slice(0, 2).map(w => (w[0] || '').toUpperCase()).join('') || 'LS';
|
||||
const displayName = esc(user?.name || user?.email || '—');
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="sb-brand">
|
||||
<a href="/dashboard" class="sb-logo"><span class="sb-lbl">Learn<span>Space</span></span></a>
|
||||
<button class="sb-toggle" title="Свернуть меню" data-sb-wired="1"><i data-lucide="chevron-left" class="sb-icon"></i></button>
|
||||
</div>
|
||||
<nav class="sb-nav">
|
||||
<button class="sb-link" onclick="typeof lsSearchOpen!=='undefined'&&lsSearchOpen()" title="Ctrl+K"><i data-lucide="search" class="sb-icon"></i><span class="sb-lbl">Поиск</span></button>
|
||||
${L('/dashboard', 'home', 'Дашборд')}
|
||||
${L('/board', 'layout-dashboard', 'Доска', { id: 'btn-board', hidden: true })}
|
||||
${L('/classes', 'graduation-cap', 'Классы', { id: 'btn-classes', hidden: !isTch })}
|
||||
${L('/library', 'book-open', 'Библиотека')}
|
||||
${L('/theory', 'brain', 'Теория')}
|
||||
${L('/lab', 'atom', 'Лаборатория')}
|
||||
${L('/biochem', 'flask-conical', 'Биохимия')}
|
||||
${L('/hangman', 'gamepad-2', 'Виселица')}
|
||||
${L('/crossword', 'grid-3x3', 'Кроссворд')}
|
||||
${L('/pet', 'heart', 'Питомец')}
|
||||
${L('/collection', 'layers', 'Коллекция')}
|
||||
${L('/knowledge-map', 'share-2', 'Карта знаний')}
|
||||
${L('/red-book', 'leaf', 'Красная книга')}
|
||||
${L('/classroom', 'presentation', 'Онлайн-урок')}
|
||||
${L('/lesson-history','archive', 'Архив уроков')}
|
||||
<div class="sb-divider"></div>
|
||||
${L('/analytics', 'bar-chart-2', 'Аналитика', { cls: 'sb-teacher-only', hidden: !isTch })}
|
||||
${L('/question-bank', 'database', 'Банк вопросов', { cls: 'sb-teacher-only', hidden: !isTch })}
|
||||
${L('/live-quiz', 'radio', 'Live-квиз', { cls: 'sb-teacher-only', hidden: !isTch })}
|
||||
${L('/gradebook', 'table', 'Журнал', { cls: 'sb-teacher-only', hidden: !isTch })}
|
||||
${L('/admin', 'settings', 'Управление', { id: 'btn-admin', hidden: !isTch })}
|
||||
</nav>
|
||||
<div style="padding:4px 2px">
|
||||
${isStu ? '<button class="sb-link" id="btn-join" style="display:none" onclick="typeof openJoinModal!==\'undefined\'&&openJoinModal()"><i data-lucide="user-plus" class="sb-icon"></i><span class="sb-lbl">Вступить в класс</span></button>' : ''}
|
||||
<div id="notif-wrap">
|
||||
<button class="sb-link" id="notif-btn" onclick="LS.notif?.toggle()">
|
||||
<i data-lucide="bell" class="sb-icon"></i><span class="sb-lbl">Уведомления</span>
|
||||
<span class="sb-badge" id="notif-badge" style="display:none"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sb-foot">
|
||||
<a href="/profile" class="sb-user-row" style="text-decoration:none">
|
||||
<div class="sb-avatar" id="nav-avatar">${esc(initials)}</div>
|
||||
<div class="sb-user-info">
|
||||
<div class="sb-user-name" id="nav-user">${displayName}</div>
|
||||
<span class="sb-logout" style="pointer-events:none">Мой профиль</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>`;
|
||||
|
||||
// Insert notif-drop sibling after <aside> if not already present
|
||||
if (!document.getElementById('notif-drop')) {
|
||||
const nd = document.createElement('div');
|
||||
nd.className = 'notif-drop';
|
||||
nd.id = 'notif-drop';
|
||||
el.insertAdjacentElement('afterend', nd);
|
||||
}
|
||||
|
||||
// Apply collapsed state
|
||||
if (localStorage.getItem('ls_sb_collapsed') === '1') {
|
||||
document.querySelector('.app-layout')?.classList.add('sb-collapsed');
|
||||
}
|
||||
|
||||
// Wire sidebar toggle
|
||||
el.querySelector('.sb-toggle')?.addEventListener('click', () => {
|
||||
const layout = document.querySelector('.app-layout');
|
||||
if (!layout) return;
|
||||
const collapsed = layout.classList.toggle('sb-collapsed');
|
||||
localStorage.setItem('ls_sb_collapsed', collapsed ? '1' : '0');
|
||||
});
|
||||
|
||||
// Re-render Lucide icons
|
||||
if (window.lucide) lucide.createIcons();
|
||||
|
||||
// Async: board visibility, feature flags, notifications
|
||||
if (typeof LS !== 'undefined') {
|
||||
LS.showBoardIfAllowed?.();
|
||||
LS.hideDisabledFeatures?.();
|
||||
LS.notif?.init?.();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env node
|
||||
// Replace sidebar HTML with <aside class="sidebar" id="app-sidebar"></aside>
|
||||
// and add <script src="/js/sidebar.js"></script> after api.js on each page.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const FRONTEND = path.join(__dirname, '..', 'frontend');
|
||||
|
||||
// Pages that get the universal sidebar (excludes test-run.html, login.html, 403/404/500, parent.html, guest-board.html)
|
||||
const PAGES = [
|
||||
'admin', 'analytics',
|
||||
'biochem', 'biochem-library', 'biochem-pathways', 'biochem-properties', 'biochem-reactions',
|
||||
'board', 'classes', 'classroom', 'collection', 'collection-rb', 'course', 'crossword',
|
||||
'dashboard', 'flashcards', 'gradebook', 'hangman', 'homework',
|
||||
'knowledge-map', 'lab', 'lesson', 'lesson-editor', 'lesson-history', 'library', 'live-quiz',
|
||||
'my-lessons', 'pet', 'profile', 'question-bank',
|
||||
'red-book', 'red-book-biomes', 'red-book-ecosystem', 'red-book-games',
|
||||
'theory',
|
||||
];
|
||||
|
||||
// Regex: match <aside class="sidebar" ...> ... </aside>
|
||||
// Handles optional extra attributes and multi-line content
|
||||
const ASIDE_RE = /<aside\b[^>]*\bclass="sidebar"[^>]*>[\s\S]*?<\/aside>/;
|
||||
|
||||
// Match existing sidebar.js script tag
|
||||
const SIDEBAR_SCRIPT_RE = /<script\s+src="\/js\/sidebar\.js"><\/script>/;
|
||||
|
||||
// Match api.js script tag
|
||||
const API_SCRIPT_RE = /(<script\s+src="\/js\/api\.js"><\/script>)/;
|
||||
|
||||
let changed = 0;
|
||||
let skipped = 0;
|
||||
let errors = 0;
|
||||
|
||||
for (const name of PAGES) {
|
||||
const file = path.join(FRONTEND, `${name}.html`);
|
||||
if (!fs.existsSync(file)) {
|
||||
console.log(` SKIP ${name}.html (not found)`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
let src = fs.readFileSync(file, 'utf8');
|
||||
let modified = false;
|
||||
|
||||
// 1. Replace sidebar <aside>
|
||||
if (ASIDE_RE.test(src)) {
|
||||
src = src.replace(ASIDE_RE, '<aside class="sidebar" id="app-sidebar"></aside>');
|
||||
modified = true;
|
||||
} else if (!src.includes('id="app-sidebar"')) {
|
||||
console.log(` WARN ${name}.html — no <aside class="sidebar"> found`);
|
||||
}
|
||||
|
||||
// 2. Add sidebar.js script after api.js (if not already present)
|
||||
if (!SIDEBAR_SCRIPT_RE.test(src)) {
|
||||
if (API_SCRIPT_RE.test(src)) {
|
||||
src = src.replace(API_SCRIPT_RE, '$1\n <script src="/js/sidebar.js"></script>');
|
||||
modified = true;
|
||||
} else {
|
||||
console.log(` WARN ${name}.html — no api.js script tag found`);
|
||||
}
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
fs.writeFileSync(file, src, 'utf8');
|
||||
console.log(` OK ${name}.html`);
|
||||
changed++;
|
||||
} else {
|
||||
console.log(` - ${name}.html (no changes)`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nDone: ${changed} updated, ${skipped} skipped, ${errors} errors.`);
|
||||
Reference in New Issue
Block a user