feat(phys9 ch): добавлен блок задач параграфа из legacy POOLS

Раньше в монолите physics_9.html на каждый § был блок задач
(navDots, taskArea, fb, sum, progress-bar и chip-ok), но в новых
ch-страницах physics_9_ch{1..5}.html этого не было.

Изменения:

1. В каждой ch1..ch5.html добавлен hook поверх ensureBuilt:
   - Функция _makeTaskBlock(sec) генерирует HTML контейнеров
     legacy-tasks (#taskArea<sec>, #navDots<sec>, #fb<sec>, #sum<sec>,
     #prog<sec>, #ok<sec>, #cur<sec>, #max<sec>, кнопка «Заново»,
     кнопка «Следующая»).
   - _injectTasks(id) добавляет блок в #<id>-body если есть
     window.POOLS[id], и вызывает window.renderTask(id) +
     window.renderNav(id) для рендера первой задачи.
   - ensureBuilt обёрнут так, чтобы вызывать _injectTasks
     после оригинального билда.

2. В phys9_legacy.js добавлен экспорт POOLS и STATE в window
   (раньше они были скрыты внутри IIFE).

Стили блока задач используют CSS-переменные секции (var(--sec-acc, ...))
и работают с любой темой главы.

Теперь по каждому §1-§36 показывается соответствующий пул задач
(TASKS_P1..P36).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-30 09:17:38 +03:00
parent 1f17fb40dc
commit c34fd27c6a
6 changed files with 147 additions and 0 deletions
+29
View File
@@ -746,6 +746,35 @@ function buildParaSelector(){
const BUILT=new Set();
const BUILDERS = { p25:()=>build_p25(), p26:()=>build_p26(), p27:()=>build_p27(), p28:()=>build_p28(), p29:()=>build_p29(), p30:()=>build_p30(), final3:()=>build_final3() };
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
function _makeTaskBlock(sec){
return ''
+ '<div class="legacy-tasks" id="ptab-' + sec + '" style="margin-top:20px;padding:16px 18px;background:var(--card,#fff);border:1.5px solid var(--border,#e2e8f0);border-radius:14px">'
+ '<div class="score-bar" style="display:flex;gap:10px;align-items:center;margin-bottom:10px;flex-wrap:wrap">'
+ '<div style="font-weight:700;color:var(--text)">Задачи параграфа</div>'
+ '<div class="chip chip-ok" style="margin-left:auto;padding:3px 10px;border-radius:99px;background:#dcfce7;color:#065f46;font-weight:700;font-size:.82rem"><span id="ok' + sec + '">0</span>&nbsp;верно</div>'
+ '<div class="chip chip-tot" style="padding:3px 10px;border-radius:99px;background:rgba(15,23,42,.06);color:var(--muted);font-weight:700;font-size:.82rem"><span id="cur' + sec + '">0</span>/<span id="max' + sec + '">?</span></div>'
+ '<button class="btn" onclick="if(window.resetTasks)window.resetTasks(\'' + sec + '\')" style="padding:5px 11px;font-size:.78rem;border-radius:8px;background:transparent;border:1px solid var(--border);color:var(--text)">Заново</button>'
+ '</div>'
+ '<div class="prog-wrap" style="height:5px;background:rgba(0,0,0,.07);border-radius:3px;overflow:hidden;margin-bottom:10px"><div id="prog' + sec + '" style="height:100%;width:0%;background:linear-gradient(90deg,var(--sec-acc,#2563eb),var(--sec-acc-d,#1d4ed8));transition:width .4s"></div></div>'
+ '<div class="nav-dots" id="navDots' + sec + '" style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:10px"></div>'
+ '<div id="taskArea' + sec + '"></div>'
+ '<div class="feedback" id="fb' + sec + '" style="margin-top:8px"></div>'
+ '<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end"><button class="btn primary" id="nextBtn' + sec + '" onclick="if(window.nextTask)window.nextTask(\'' + sec + '\')" style="display:none;padding:8px 16px;border-radius:9px;background:var(--sec-acc,#2563eb);color:#fff;border:0;font-weight:700">Следующая &rarr;</button></div>'
+ '<div class="summary" id="sum' + sec + '" style="display:none;text-align:center;padding:16px;margin-top:10px;background:linear-gradient(135deg,var(--sec-acc-soft,#dbeafe),var(--card));border-radius:11px"><div style="font-weight:700;margin-bottom:6px">Параграф пройден!</div><div class="big-score" id="sumScore' + sec + '" style="font-size:1.6rem;font-weight:900;color:var(--sec-acc-d,#1d4ed8)"></div><div class="sum-grade" id="sumGrade' + sec + '" style="margin:6px 0;color:var(--muted)"></div></div>'
+ '</div>';
}
function _injectTasks(id){
if(!id || !id.startsWith('p')) return;
if(!window.POOLS || !window.POOLS[id]) return;
var body = document.getElementById(id + '-body');
if(!body || body.querySelector('.legacy-tasks')) return;
body.insertAdjacentHTML('beforeend', _makeTaskBlock(id));
setTimeout(function(){ try { if(window.renderTask) window.renderTask(id); if(window.renderNav) window.renderNav(id); } catch(e){} }, 60);
}
var _origEnsureBuilt = ensureBuilt;
ensureBuilt = function(id){ _origEnsureBuilt(id); _injectTasks(id); };
function goTo(id){
STATE.current=id; ensureBuilt(id);
document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));