diff --git a/frontend/teacher-guide.html b/frontend/teacher-guide.html
index 45d7c67..af0ac21 100644
--- a/frontend/teacher-guide.html
+++ b/frontend/teacher-guide.html
@@ -157,7 +157,12 @@
.tg-hero-chip svg { width: 13px; height: 13px; }
/* Chapter */
- .tg-chapter { margin-bottom: 56px; }
+ .tg-chapter { margin-bottom: 0; display: none; }
+ .tg-chapter.tg-active { display: block; animation: tgFadeIn 0.28s ease; }
+ @keyframes tgFadeIn { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
+ /* Search mode: reveal all chapters so matches are visible */
+ .tg-content.tg-search-mode .tg-chapter { display: block; margin-bottom: 32px; }
+ .tg-content.tg-search-mode .tg-chapter.search-hidden { display: none; }
.tg-chapter-header {
display: flex; align-items: center; gap: 16px;
padding: 28px 0 18px;
@@ -1061,56 +1066,54 @@
});
lucide.createIcons();
- function navChapterClick(chId, btn) {
- const chapter = btn.closest('.tg-nav-chapter');
- chapter.classList.toggle('open');
- scrollToChapter(chId);
- }
-
- function scrollToChapter(chId) {
- const el = document.getElementById(chId);
- if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
- }
-
- function scrollToSection(secId) {
- const el = document.getElementById(secId);
- if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
- }
-
- /* ── Scroll progress ── */
+ /* ── Chapter switching ── */
const scrollEl = document.getElementById('tg-scroll');
const progBar = document.getElementById('tg-prog-bar');
+ const tgContent = document.querySelector('.tg-content');
+ let _activeChId = null;
- scrollEl.addEventListener('scroll', () => {
- const pct = scrollEl.scrollTop / (scrollEl.scrollHeight - scrollEl.clientHeight);
- progBar.style.width = Math.round(Math.min(pct, 1) * 100) + '%';
- });
-
- /* ── Scroll spy (sections) ── */
- const allSections = document.querySelectorAll('.tg-section');
- const allNavSecs = document.querySelectorAll('.tg-nav-sec-link');
-
- const sectionObs = new IntersectionObserver((entries) => {
- entries.forEach(e => {
- if (!e.isIntersecting) return;
- const id = e.target.id;
- allNavSecs.forEach(a => a.classList.toggle('active', a.dataset.sec === id));
- // Also open+highlight parent chapter
- const ch = CHAPTERS.find(c => c.sections.includes(id));
- if (ch) {
- document.querySelectorAll('.tg-nav-ch-btn').forEach(b => {
- const parentDiv = b.closest('.tg-nav-chapter');
- const isThis = parentDiv.dataset.ch === ch.id;
- b.classList.toggle('active', isThis);
- if (isThis && !parentDiv.classList.contains('open')) parentDiv.classList.add('open');
- });
- }
+ function showChapter(chId, sectionId) {
+ const newEl = document.getElementById(chId);
+ if (!newEl) return;
+ if (_activeChId) {
+ const prev = document.getElementById(_activeChId);
+ if (prev) prev.classList.remove('tg-active');
+ }
+ newEl.classList.add('tg-active');
+ _activeChId = chId;
+ history.replaceState(null, '', '#' + chId);
+ scrollEl.scrollTop = 0;
+ if (sectionId) {
+ requestAnimationFrame(() => {
+ const sec = document.getElementById(sectionId);
+ if (sec) {
+ const top = sec.offsetTop - 80;
+ scrollEl.scrollTo({ top, behavior: 'smooth' });
+ }
+ });
+ }
+ // Nav: highlight active chapter, open its sub-list
+ document.querySelectorAll('.tg-nav-chapter').forEach(div => {
+ const isThis = div.dataset.ch === chId;
+ div.querySelector('.tg-nav-ch-btn').classList.toggle('active', isThis);
+ if (isThis && !div.classList.contains('open')) div.classList.add('open');
});
- }, { root: scrollEl, rootMargin: '-15% 0px -70% 0px' });
+ document.querySelectorAll('.tg-nav-sec-link').forEach(a => a.classList.remove('active'));
+ markRead(chId);
+ }
- allSections.forEach(s => sectionObs.observe(s));
+ function scrollToChapter(chId) { showChapter(chId); }
+ function scrollToSection(secId) {
+ const ch = CHAPTERS.find(c => c.sections.includes(secId));
+ if (ch) showChapter(ch.id, secId);
+ }
- /* ── Chapter read tracking ── */
+ function navChapterClick(chId, btn) {
+ btn.closest('.tg-nav-chapter').classList.toggle('open');
+ showChapter(chId);
+ }
+
+ /* ── Read tracking ── */
const READ_KEY = 'ls_tg_read';
let readChapters = JSON.parse(localStorage.getItem(READ_KEY) || '[]');
@@ -1118,28 +1121,20 @@
if (!readChapters.includes(chId)) {
readChapters.push(chId);
localStorage.setItem(READ_KEY, JSON.stringify(readChapters));
- updateReadUI();
}
+ updateReadUI();
}
function updateReadUI() {
document.querySelectorAll('.tg-nav-chapter').forEach(div => {
- const isRead = readChapters.includes(div.dataset.ch);
- div.querySelector('.tg-nav-ch-btn').classList.toggle('read', isRead);
+ div.querySelector('.tg-nav-ch-btn').classList.toggle('read', readChapters.includes(div.dataset.ch));
});
const n = readChapters.length;
document.getElementById('tg-prog-text').textContent = `${n} из ${CHAPTERS.length} глав прочитано`;
+ progBar.style.width = Math.round(n / CHAPTERS.length * 100) + '%';
}
updateReadUI();
- const chapterObs = new IntersectionObserver((entries) => {
- entries.forEach(e => {
- if (e.isIntersecting && e.intersectionRatio >= 0.15) markRead(e.target.id);
- });
- }, { root: scrollEl, threshold: 0.15 });
-
- document.querySelectorAll('.tg-chapter').forEach(c => chapterObs.observe(c));
-
/* ── Checklist ── */
const CL_KEY = 'ls_tg_checklist';
const clState = JSON.parse(localStorage.getItem(CL_KEY) || '{}');
@@ -1154,7 +1149,6 @@
localStorage.setItem(CL_KEY, JSON.stringify(clState));
updateChecklist();
});
- // prevent link from triggering checkbox
item.querySelector('.tg-cl-link')?.addEventListener('click', e => e.stopPropagation());
});
@@ -1168,44 +1162,29 @@
/* ── Accordion ── */
function toggleAcc(head) {
- const item = head.closest('.tg-acc-item');
- item.classList.toggle('open');
+ head.closest('.tg-acc-item').classList.toggle('open');
}
- /* ── Nav search ── */
+ /* ── Search: show all chapters matching query ── */
document.getElementById('tg-search').addEventListener('input', function() {
const q = this.value.trim().toLowerCase();
if (!q) {
+ tgContent.classList.remove('tg-search-mode');
document.querySelectorAll('.tg-chapter, .tg-section').forEach(el => el.classList.remove('search-hidden'));
return;
}
+ tgContent.classList.add('tg-search-mode');
document.querySelectorAll('.tg-section').forEach(sec => {
- const text = sec.textContent.toLowerCase();
- sec.classList.toggle('search-hidden', !text.includes(q));
+ sec.classList.toggle('search-hidden', !sec.textContent.toLowerCase().includes(q));
});
document.querySelectorAll('.tg-chapter').forEach(ch => {
- const visibleSecs = ch.querySelectorAll('.tg-section:not(.search-hidden)');
- ch.classList.toggle('search-hidden', visibleSecs.length === 0);
+ ch.classList.toggle('search-hidden', ch.querySelectorAll('.tg-section:not(.search-hidden)').length === 0);
});
});
- /* ── Card entrance animation ── */
- const chapObs = new IntersectionObserver((entries) => {
- entries.forEach(e => {
- if (e.isIntersecting) {
- e.target.style.opacity = '1';
- e.target.style.transform = 'translateY(0)';
- chapObs.unobserve(e.target);
- }
- });
- }, { root: scrollEl, threshold: 0.05 });
-
- document.querySelectorAll('.tg-chapter').forEach((ch, i) => {
- ch.style.opacity = '0';
- ch.style.transform = 'translateY(20px)';
- ch.style.transition = `opacity 0.4s ease ${i * 0.03}s, transform 0.4s ease ${i * 0.03}s`;
- chapObs.observe(ch);
- });
+ /* ── Init from hash or default ch-1 ── */
+ const initHash = location.hash.replace('#', '');
+ showChapter(CHAPTERS.find(c => c.id === initHash) ? initHash : 'ch-1');