Files
Learn_System/scripts/apply-sidebar.js
Maxim Dolgolyov edb4c211a0 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>
2026-04-13 21:22:21 +03:00

75 lines
2.5 KiB
JavaScript

#!/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.`);