5381679c68
Зафиксирована накопленная незакоммиченная работа рабочего дерева, КРОМЕ файлов учебника «Химия 7» (migration 046, chemistry_7_*.html, chem7_svg.js, тест — оставлены незакоммиченными по запросу). Включает: модуль биохимии (ядро BIO, 3D VSEPR, химдвижок, баланс, challenges, пути из БД), System Health Level 1 (вердикт/мониторинг), а также frontend- страницы и lab/textbooks-правки параллельной сессии. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
308 lines
17 KiB
JavaScript
308 lines
17 KiB
JavaScript
// Генератор physics_10_hub.html на основе algebra_11_hub.html
|
|
'use strict';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const SRC = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'algebra_11_hub.html');
|
|
const DST = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_10_hub.html');
|
|
|
|
let h = fs.readFileSync(SRC, 'utf8');
|
|
|
|
// === 1. Palette + dark mode ===
|
|
h = h.replace(
|
|
/:root\{[\s\S]*?--bg:#ecfdf5; --card:#fff;[\s\S]*?--sh-h:0 12px 36px rgba\(13,148,136,\.18\);[\s\S]*?\}/,
|
|
`:root{
|
|
--bg:#fffbeb; --card:#fff;
|
|
--text:#0f172a; --muted:#475569;
|
|
--border:#fde68a;
|
|
--pri:#ca8a04; --pri-d:#a16207;
|
|
--pri-soft:#fef3c7;
|
|
--ch1:#2563eb; --ch1-d:#1d4ed8;
|
|
--ch2:#059669; --ch2-d:#047857;
|
|
--ch3:#7c3aed; --ch3-d:#6d28d9;
|
|
--ch4:#db2777; --ch4-d:#be185d;
|
|
--ch5:#0891b2; --ch5-d:#0e7490;
|
|
--ch6:#10b981; --ch6-d:#059669;
|
|
--sh:0 4px 16px rgba(202,138,4,.10);
|
|
--sh-h:0 12px 36px rgba(202,138,4,.18);
|
|
}`);
|
|
|
|
h = h.replace(
|
|
/html\.dark\{[\s\S]*?--pri-soft:rgba\(13,148,136,\.16\);[\s\S]*?\}/,
|
|
`html.dark{
|
|
--bg:#1a1500; --card:#2a2410;
|
|
--text:#fef3c7; --muted:#d4b88f;
|
|
--border:#3d2f0a;
|
|
--pri-soft:rgba(202,138,4,.16);
|
|
}`);
|
|
|
|
// === 2. Header ===
|
|
h = h.replace(
|
|
/\.hdr\{position:relative;background:linear-gradient\(110deg,#115e59 0%,#0d9488 55%,#5eead4 100%\)[^}]*\}/,
|
|
`.hdr{position:relative;background:linear-gradient(110deg,#713f12 0%,#ca8a04 55%,#fde047 100%);color:#fff;padding:32px 24px 28px;overflow:hidden;border-bottom:2px solid rgba(254,243,199,.18)}`);
|
|
|
|
h = h.replace(/АЛГЕБРА/g, 'ФИЗИКА');
|
|
h = h.replace(/rgba\(204,251,241,\.12\)/g, 'rgba(254,243,199,.12)');
|
|
|
|
// === 3. po-icon gradient ===
|
|
h = h.replace(
|
|
/\.po-icon\{[^}]*background:linear-gradient\(135deg,#0d9488,#5eead4\)[^}]*\}/,
|
|
`.po-icon{width:46px;height:46px;border-radius:12px;background:linear-gradient(135deg,#ca8a04,#fde047);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit',sans-serif;font-size:1.4rem;font-weight:900;font-style:italic}`);
|
|
h = h.replace(/\.po-bar\{height:8px;background:rgba\(13,148,136,\.14\)/, '.po-bar{height:8px;background:rgba(202,138,4,.14)');
|
|
h = h.replace(/\.po-fill\{height:100%;background:linear-gradient\(90deg,var\(--pri\),#5eead4\)/, '.po-fill{height:100%;background:linear-gradient(90deg,var(--pri),#fde047)');
|
|
h = h.replace(/\.po-xp\{[^}]*background:linear-gradient\(135deg,#f59e0b,var\(--pri\)\)[^}]*\}/,
|
|
".po-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;background:linear-gradient(135deg,#f59e0b,var(--pri));color:#fff;border-radius:99px;font-size:.8rem;font-weight:800;font-family:'Unbounded',sans-serif;letter-spacing:.02em;box-shadow:0 4px 12px rgba(202,138,4,.24)}");
|
|
|
|
// === 4. Chapter grid: 3 → 6 cards ===
|
|
h = h.replace(
|
|
/\.ch-grid\{display:grid;grid-template-columns:1fr;gap:18px;margin-bottom:30px\}\s*@media\(min-width:680px\)\{\.ch-grid\{grid-template-columns:1fr 1fr\}\}\s*@media\(min-width:1000px\)\{\.ch-grid\{grid-template-columns:repeat\(3,1fr\)\}\}/,
|
|
`.ch-grid{display:grid;grid-template-columns:1fr;gap:18px;margin-bottom:30px}
|
|
@media(min-width:680px){.ch-grid{grid-template-columns:1fr 1fr}}
|
|
@media(min-width:1000px){.ch-grid{grid-template-columns:repeat(3,1fr)}}`);
|
|
|
|
// Replace cover gradients (ch1 ch2 ch3) and add ch4 ch5 ch6
|
|
h = h.replace(
|
|
/\.ch-cover\.ch1\{background:[^}]+\}\s*\.ch-cover\.ch2\{background:[^}]+\}\s*\.ch-cover\.ch3\{background:[^}]+\}/,
|
|
`.ch-cover.ch1{background:linear-gradient(135deg,#1e3a8a,#2563eb 60%,#60a5fa)}
|
|
.ch-cover.ch2{background:linear-gradient(135deg,#064e3b,#059669 60%,#34d399)}
|
|
.ch-cover.ch3{background:linear-gradient(135deg,#3b0764,#7c3aed 60%,#a78bfa)}
|
|
.ch-cover.ch4{background:linear-gradient(135deg,#831843,#db2777 60%,#f472b6)}
|
|
.ch-cover.ch5{background:linear-gradient(135deg,#164e63,#0891b2 60%,#22d3ee)}
|
|
.ch-cover.ch6{background:linear-gradient(135deg,#064e3b,#10b981 60%,#6ee7b7)}`);
|
|
|
|
// Replace chN-card progress fill and action gradients
|
|
h = h.replace(
|
|
/\.ch-card\.ch1-card \.ch-prog-fill\{background:linear-gradient\(90deg,var\(--ch1\),var\(--ch1-d\)\)\}\s*\.ch-card\.ch2-card \.ch-prog-fill\{background:linear-gradient\(90deg,var\(--ch2\),var\(--ch2-d\)\)\}\s*\.ch-card\.ch3-card \.ch-prog-fill\{background:linear-gradient\(90deg,var\(--ch3\),var\(--ch3-d\)\)\}/,
|
|
`.ch-card.ch1-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch1),var(--ch1-d))}
|
|
.ch-card.ch2-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch2),var(--ch2-d))}
|
|
.ch-card.ch3-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch3),var(--ch3-d))}
|
|
.ch-card.ch4-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch4),var(--ch4-d))}
|
|
.ch-card.ch5-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch5),var(--ch5-d))}
|
|
.ch-card.ch6-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch6),var(--ch6-d))}`);
|
|
|
|
h = h.replace(
|
|
/\.ch-card\.ch1-card \.ch-action\{background:linear-gradient\(135deg,var\(--ch1\),#fbbf24\)\}\s*\.ch-card\.ch2-card \.ch-action\{background:linear-gradient\(135deg,var\(--ch2\),#a78bfa\)\}\s*\.ch-card\.ch3-card \.ch-action\{background:linear-gradient\(135deg,var\(--ch3\),#22d3ee\)\}/,
|
|
`.ch-card.ch1-card .ch-action{background:linear-gradient(135deg,var(--ch1),#60a5fa)}
|
|
.ch-card.ch2-card .ch-action{background:linear-gradient(135deg,var(--ch2),#34d399)}
|
|
.ch-card.ch3-card .ch-action{background:linear-gradient(135deg,var(--ch3),#a78bfa)}
|
|
.ch-card.ch4-card .ch-action{background:linear-gradient(135deg,var(--ch4),#f472b6)}
|
|
.ch-card.ch5-card .ch-action{background:linear-gradient(135deg,var(--ch5),#22d3ee)}
|
|
.ch-card.ch6-card .ch-action{background:linear-gradient(135deg,var(--ch6),#6ee7b7)}`);
|
|
|
|
// Final header gradient
|
|
h = h.replace(
|
|
/\.final-head\{padding:18px 22px;background:linear-gradient\(135deg,#115e59 0%,#0d9488 55%,#0891b2 100%\)/,
|
|
'.final-head{padding:18px 22px;background:linear-gradient(135deg,#713f12 0%,#ca8a04 55%,#f59e0b 100%)');
|
|
|
|
// title
|
|
h = h.replace(/<title>Алгебра 11 класс — учебник<\/title>/, '<title>Физика 10 класс — учебник</title>');
|
|
|
|
// localStorage keys
|
|
h = h.replace(/algebra11_theme/g, 'physics10_theme');
|
|
h = h.replace(/algebra11_xp/g, 'physics10_xp');
|
|
h = h.replace(/algebra11_course_master/g, 'physics10_course_master');
|
|
h = h.replace(/algebra11_course_bosses/g, 'physics10_course_bosses');
|
|
h = h.replace(/algebra11-master/g, 'physics10-master');
|
|
h = h.replace(/'fin-boss-'/g, "'fin-boss-'"); // unchanged
|
|
|
|
// Header H1 + subtitle
|
|
h = h.replace(/<h1>Алгебра — 11 класс<\/h1>/, '<h1>Физика — 10 класс</h1>');
|
|
h = h.replace(
|
|
/<div class="hdr-sub">Полный курс: степени и логарифмы, показательная и логарифмическая функции, уравнения и неравенства<\/div>/,
|
|
'<div class="hdr-sub">Полный курс физики 10 класса: молекулярная физика, термодинамика, электростатика, магнитное поле, ток в средах</div>'
|
|
);
|
|
|
|
// po-icon "a" → "f"
|
|
h = h.replace(/<div class="po-icon">a<\/div>/, '<div class="po-icon">f</div>');
|
|
|
|
// === 5. Заменяем блок с 3 главами целиком на блок с 6 главами ===
|
|
const chBlock = `
|
|
<a href="/textbook/physics-10-ch1" class="ch-card ch1-card" id="ch-1">
|
|
<div class="ch-cover ch1">
|
|
<div class="ch-cover-wm">T</div>
|
|
<div class="ch-num">Глава 1</div>
|
|
<div class="ch-title">Основы МКТ</div>
|
|
<div class="ch-range">§1–§10 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">Молекулярно-кинетическая теория, идеальный газ, изопроцессы, строение твёрдых тел и жидкостей, влажность воздуха.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-1">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-1" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-1">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/textbook/physics-10-ch2" class="ch-card ch2-card" id="ch-2">
|
|
<div class="ch-cover ch2">
|
|
<div class="ch-cover-wm">ΔU</div>
|
|
<div class="ch-num">Глава 2</div>
|
|
<div class="ch-title">Термодинамика</div>
|
|
<div class="ch-range">§11–§15 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">Внутренняя энергия, работа и количество теплоты, первый закон термодинамики, тепловые двигатели, цикл Карно.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-2">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-2" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-2">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/textbook/physics-10-ch3" class="ch-card ch3-card" id="ch-3">
|
|
<div class="ch-cover ch3">
|
|
<div class="ch-cover-wm">+q</div>
|
|
<div class="ch-num">Глава 3</div>
|
|
<div class="ch-title">Электростатика</div>
|
|
<div class="ch-range">§16–§24 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">Электрический заряд, закон Кулона, напряжённость и потенциал электростатического поля, конденсаторы, энергия поля.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-3">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-3" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-3">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/textbook/physics-10-ch4" class="ch-card ch4-card" id="ch-4">
|
|
<div class="ch-cover ch4">
|
|
<div class="ch-cover-wm">I</div>
|
|
<div class="ch-num">Глава 4</div>
|
|
<div class="ch-title">Постоянный ток</div>
|
|
<div class="ch-range">§25–§26 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">ЭДС источника, закон Ома для полной электрической цепи, КПД источника.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-4">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-4" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-4">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/textbook/physics-10-ch5" class="ch-card ch5-card" id="ch-5">
|
|
<div class="ch-cover ch5">
|
|
<div class="ch-cover-wm">B</div>
|
|
<div class="ch-num">Глава 5</div>
|
|
<div class="ch-title">Магнитное поле</div>
|
|
<div class="ch-range">§27–§33 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">Магнитное поле, сила Ампера, сила Лоренца, электромагнитная индукция, закон Фарадея, самоиндукция.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-5">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-5" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-5">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
<a href="/textbook/physics-10-ch6" class="ch-card ch6-card" id="ch-6">
|
|
<div class="ch-cover ch6">
|
|
<div class="ch-cover-wm">n/p</div>
|
|
<div class="ch-num">Глава 6</div>
|
|
<div class="ch-title">Ток в средах</div>
|
|
<div class="ch-range">§34–§37 + Финал</div>
|
|
</div>
|
|
<div class="ch-body">
|
|
<div class="ch-desc">Электрический ток в металлах и сверхпроводимость, электролиз, разряды в газах и плазма, полупроводники.</div>
|
|
<div class="ch-prog">
|
|
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-6">0%</span></div>
|
|
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-6" style="width:0%"></div></div>
|
|
</div>
|
|
<div class="ch-action">
|
|
<span id="btn-6">Открыть главу</span>
|
|
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
`;
|
|
|
|
// Replace the entire <a href="/textbook/algebra-11-ch1"...</a><a ch2></a><a ch3></a> block
|
|
h = h.replace(/\s*<a href="\/textbook\/algebra-11-ch1"[\s\S]*?<\/a>\s*<a href="\/textbook\/algebra-11-ch2"[\s\S]*?<\/a>\s*<a href="\/textbook\/algebra-11-ch3"[\s\S]*?<\/a>\s*/,
|
|
chBlock);
|
|
|
|
// Final placeholder — заменим cheat-grid + bosses на placeholder
|
|
h = h.replace(/<div class="fin-section-title">\s*<svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h10"\/><\/svg>\s*Шпаргалка курса\s*<\/div>\s*<div class="cheat-grid">[\s\S]*?<\/div>\s*<div class="fin-section-title">\s*<svg viewBox="0 0 24 24"><path d="M14\.5 3\.5l[^"]+"\/><\/svg>\s*7 интегрированных боссов\s*<\/div>\s*<div class="boss-overall-bar">[\s\S]*?<\/div>\s*<div id="fin-bosses-container"><\/div>/,
|
|
`<div class="fin-placeholder">
|
|
<h3>Финал курса — в разработке</h3>
|
|
<p>Итоговая шпаргалка по всем 37 параграфам и 8–10 интегрированных боссов появятся в Phase 7 (после завершения всех 6 глав).</p>
|
|
</div>
|
|
<div id="fin-bosses-container" style="display:none"></div>`);
|
|
|
|
// Remove FIN_BOSSES array — заменим на пустой
|
|
h = h.replace(/var FIN_BOSSES = \[[\s\S]*?\];/, 'var FIN_BOSSES = [];');
|
|
|
|
// final-head-sub
|
|
h = h.replace(
|
|
/<div class="final-head-sub">Итоговая шпаргалка и интегрированные боссы\. Победи всех — получи «Магистр алгебры 11» и \+50 XP\.<\/div>/,
|
|
'<div class="final-head-sub">Шпаргалка курса и интегрированные боссы по всем 6 главам. В разработке (Phase 7).</div>'
|
|
);
|
|
h = h.replace(/<div class="final-cta-title">Курс Алгебра 11 пройден!<\/div>/, '<div class="final-cta-title">Курс Физика 10 пройден!</div>');
|
|
h = h.replace(/«Магистр алгебры 11»/g, '«Магистр физики 10»');
|
|
h = h.replace(/Магистр алгебры 11/g, 'Магистр физики 10');
|
|
|
|
// Footer
|
|
h = h.replace(/Интерактивный учебник «Алгебра — 11 класс»/, 'Интерактивный учебник «Физика — 10 класс»');
|
|
|
|
// Achievement strip
|
|
h = h.replace(/Прочитайте все 10 параграфов трёх глав/, 'Прочитайте все 37 параграфов курса, чтобы получить достижение');
|
|
|
|
// === 6. TOTAL + CH_PARA + CH_IDX ===
|
|
h = h.replace(/var TOTAL = 10;[\s\S]*?var CH_IDX = \{[\s\S]*?\};/, `var TOTAL = 37;
|
|
var CH_PARA = {
|
|
'physics-10-ch1': 10,
|
|
'physics-10-ch2': 5,
|
|
'physics-10-ch3': 9,
|
|
'physics-10-ch4': 2,
|
|
'physics-10-ch5': 7,
|
|
'physics-10-ch6': 4,
|
|
};
|
|
var CH_IDX = {
|
|
'physics-10-ch1': 1,
|
|
'physics-10-ch2': 2,
|
|
'physics-10-ch3': 3,
|
|
'physics-10-ch4': 4,
|
|
'physics-10-ch5': 5,
|
|
'physics-10-ch6': 6,
|
|
};`);
|
|
|
|
// API endpoint slug
|
|
h = h.replace(/'\/api\/textbooks\/algebra-11\/children'/, "'/api/textbooks/physics-10/children'");
|
|
|
|
// На текстах ачивок: "Вы прочитали весь курс алгебры 11 класса."
|
|
h = h.replace(/Вы прочитали весь курс алгебры 11 класса\./, 'Вы прочитали весь курс физики 10 класса.');
|
|
|
|
fs.writeFileSync(DST, h);
|
|
console.log('OK hub →', DST, 'bytes:', h.length);
|
|
|
|
// Quick sanity: extract <script> blocks and check parseable JS
|
|
const scriptMatches = [...h.matchAll(/<script>([\s\S]*?)<\/script>/g)];
|
|
console.log('inline <script> count:', scriptMatches.length);
|
|
for (const m of scriptMatches) {
|
|
try { new Function(m[1]); }
|
|
catch(e) { console.error('JS PARSE FAIL:', e.message); process.exit(1); }
|
|
}
|
|
console.log('all inline JS parses OK');
|