feat(phys8 hub): Phase 5 — hub polish + cross-cutting

Hub улучшения:
- .ch-card: подъём на hover (-6px scale 1.01) с тематической box-shadow
  по цвету главы.
- .ch-cover::after: shimmer-overlay при наведении (diagonal sweep).
- .ch-cover-wm: micro-перемещение и scale на hover.
- .ch-action svg: стрелка едет вправо на hover.
- .po-xp: пульсирующая тень для overall progress XP-badge (3s loop).

Accessibility:
- aria-label на каждой ch-card с понятным названием темы.
- :focus-visible с 3px outline в brand-цвете для chapter cards.
- :focus-visible с белым outline для hdr-btn на градиенте.
- prefers-reduced-motion: блокирует все анимации.

Mobile responsiveness:
- @media ≤580px: уменьшение шрифта h1 1.4rem, ch-cover-wm 3.8rem.

Footer: '40 параграфов, 7 ЛР, 47 IV-6 интерактивов'.
This commit is contained in:
Maxim Dolgolyov
2026-05-30 10:31:05 +03:00
parent 382dff3879
commit 29a2bae7d9
2 changed files with 121 additions and 4 deletions
+79
View File
@@ -0,0 +1,79 @@
// Phase 5 — Hub polish: добавить тематические SVG watermarks для каждой
// chapter-карточки, hover-микро-анимации, live-индикатор прогресса.
'use strict';
const fs = require('fs');
const path = require('path');
const DST = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_8_hub.html');
let h = fs.readFileSync(DST, 'utf8');
// === 1. Add hub-level animations CSS (inline into <style>) ===
const HUB_EXTRA_CSS = `
/* === Phase 5 hub polish === */
.ch-card{transition:transform .35s cubic-bezier(.16,1,.3,1),box-shadow .35s,border-color .25s}
.ch-card:hover{transform:translateY(-6px) scale(1.01);box-shadow:0 18px 44px rgba(124,58,237,.22)}
.ch-cover{position:relative;overflow:hidden}
.ch-cover::after{content:'';position:absolute;inset:0;background:linear-gradient(135deg,transparent 40%,rgba(255,255,255,.10) 50%,transparent 60%);background-size:300% 300%;background-position:200% 200%;transition:background-position .85s ease-out;pointer-events:none}
.ch-card:hover .ch-cover::after{background-position:-100% -100%}
.ch-card .ch-cover-wm{transition:transform .5s cubic-bezier(.16,1,.3,1),opacity .35s}
.ch-card:hover .ch-cover-wm{transform:translateX(-6px) translateY(8px) scale(1.08);opacity:.30}
.ch-action svg{transition:transform .25s}
.ch-action:hover svg{transform:translateX(4px)}
/* Topic-themed glow on action button */
.ch-card.ch1-card:hover .ch-action{box-shadow:0 6px 16px rgba(220,38,38,.35)}
.ch-card.ch2-card:hover .ch-action{box-shadow:0 6px 16px rgba(217,119,6,.35)}
.ch-card.ch3-card:hover .ch-action{box-shadow:0 6px 16px rgba(8,145,178,.35)}
.ch-card.ch4-card:hover .ch-action{box-shadow:0 6px 16px rgba(16,185,129,.35)}
/* Overall progress XP-pulse */
@keyframes po-xp-pulse{0%,100%{box-shadow:0 4px 12px rgba(124,58,237,.24)}50%{box-shadow:0 4px 16px rgba(124,58,237,.40),0 0 0 4px rgba(124,58,237,.08)}}
.po-xp{animation:po-xp-pulse 3s ease-in-out infinite}
/* Mobile responsiveness */
@media(max-width:580px){
.hdr{padding:24px 16px 20px}
.hdr h1{font-size:1.4rem}
.ch-cover-wm{font-size:3.8rem;right:-4px;top:-12px}
}
/* Focus-visible accessibility */
.ch-card:focus-visible{outline:3px solid var(--p8-brand,#7c3aed);outline-offset:3px;border-radius:18px}
.hdr-btn:focus-visible,.hdr-back:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* Reduced motion */
@media (prefers-reduced-motion: reduce){
.ch-card,.ch-card .ch-cover-wm,.ch-cover::after,.po-xp,.ch-action svg{animation:none!important;transition:none!important}
}
`;
if (!h.includes('Phase 5 hub polish')) {
h = h.replace('</style>', HUB_EXTRA_CSS + '\n</style>');
console.log('Hub polish CSS injected');
}
// === 2. Make chapter card titles accessibility-friendly + add aria-labels ===
// Add aria-label на каждую .ch-card если её нет
const cardLabels = {
'ch1-card': 'Глава 1: Тепловые явления',
'ch2-card': 'Глава 2: Электромагнитные явления',
'ch3-card': 'Глава 3: Световые явления',
'ch4-card': 'Лабораторный практикум — 7 ЛР'
};
for (const [cls, label] of Object.entries(cardLabels)) {
const regex = new RegExp(`(<a [^>]*class="ch-card ${cls}"[^>]*)>`, 'g');
h = h.replace(regex, (match, before) => {
if (/aria-label=/.test(before)) return match;
return `${before} aria-label="${label}">`;
});
}
// === 3. Footer "Created with..." note (or replace existing if any) ===
// Optional — add a soft footer
const FOOTER_HTML = `
<footer style="max-width:1100px;margin:50px auto 30px;padding:20px;color:var(--muted);font-size:.78rem;text-align:center;border-top:1px solid var(--border);line-height:1.55">
Физика 8 · LearnSpace · 40 параграфов, 7 ЛР, 47 IV-6 интерактивов
</footer>
`;
if (!h.includes('47 IV-6 интерактивов')) {
h = h.replace('</body>', FOOTER_HTML + '\n</body>');
console.log('Footer added');
}
fs.writeFileSync(DST, h);
console.log('hub size:', h.length);
+42 -4
View File
@@ -199,6 +199,39 @@ html.dark .final-cta-sub{color:#c4b5fd}
.final-cta-btn{padding:10px 18px;border-radius:10px;background:linear-gradient(135deg,var(--pri),#a78bfa);color:#fff;text-decoration:none;font-weight:800;font-size:.9rem;display:inline-flex;align-items:center;gap:7px;transition:filter .15s}
.final-cta-btn:hover{filter:brightness(1.1)}
.final-cta-btn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* === Phase 5 hub polish === */
.ch-card{transition:transform .35s cubic-bezier(.16,1,.3,1),box-shadow .35s,border-color .25s}
.ch-card:hover{transform:translateY(-6px) scale(1.01);box-shadow:0 18px 44px rgba(124,58,237,.22)}
.ch-cover{position:relative;overflow:hidden}
.ch-cover::after{content:'';position:absolute;inset:0;background:linear-gradient(135deg,transparent 40%,rgba(255,255,255,.10) 50%,transparent 60%);background-size:300% 300%;background-position:200% 200%;transition:background-position .85s ease-out;pointer-events:none}
.ch-card:hover .ch-cover::after{background-position:-100% -100%}
.ch-card .ch-cover-wm{transition:transform .5s cubic-bezier(.16,1,.3,1),opacity .35s}
.ch-card:hover .ch-cover-wm{transform:translateX(-6px) translateY(8px) scale(1.08);opacity:.30}
.ch-action svg{transition:transform .25s}
.ch-action:hover svg{transform:translateX(4px)}
/* Topic-themed glow on action button */
.ch-card.ch1-card:hover .ch-action{box-shadow:0 6px 16px rgba(220,38,38,.35)}
.ch-card.ch2-card:hover .ch-action{box-shadow:0 6px 16px rgba(217,119,6,.35)}
.ch-card.ch3-card:hover .ch-action{box-shadow:0 6px 16px rgba(8,145,178,.35)}
.ch-card.ch4-card:hover .ch-action{box-shadow:0 6px 16px rgba(16,185,129,.35)}
/* Overall progress XP-pulse */
@keyframes po-xp-pulse{0%,100%{box-shadow:0 4px 12px rgba(124,58,237,.24)}50%{box-shadow:0 4px 16px rgba(124,58,237,.40),0 0 0 4px rgba(124,58,237,.08)}}
.po-xp{animation:po-xp-pulse 3s ease-in-out infinite}
/* Mobile responsiveness */
@media(max-width:580px){
.hdr{padding:24px 16px 20px}
.hdr h1{font-size:1.4rem}
.ch-cover-wm{font-size:3.8rem;right:-4px;top:-12px}
}
/* Focus-visible accessibility */
.ch-card:focus-visible{outline:3px solid var(--p8-brand,#7c3aed);outline-offset:3px;border-radius:18px}
.hdr-btn:focus-visible,.hdr-back:focus-visible{outline:2px solid #fff;outline-offset:2px}
/* Reduced motion */
@media (prefers-reduced-motion: reduce){
.ch-card,.ch-card .ch-cover-wm,.ch-cover::after,.po-xp,.ch-action svg{animation:none!important;transition:none!important}
}
</style>
</head>
<body>
@@ -238,7 +271,7 @@ html.dark .final-cta-sub{color:#c4b5fd}
<div class="ch-grid">
<a href="/textbook/physics-8-ch1" class="ch-card ch1-card" id="ch-1">
<a href="/textbook/physics-8-ch1" class="ch-card ch1-card" id="ch-1" aria-label="Глава 1: Тепловые явления">
<div class="ch-cover ch1">
<div class="ch-cover-wm">Q</div>
<div class="ch-num">Глава 1</div>
@@ -258,7 +291,7 @@ html.dark .final-cta-sub{color:#c4b5fd}
</div>
</a>
<a href="/textbook/physics-8-ch2" class="ch-card ch2-card" id="ch-2">
<a href="/textbook/physics-8-ch2" class="ch-card ch2-card" id="ch-2" aria-label="Глава 2: Электромагнитные явления">
<div class="ch-cover ch2">
<div class="ch-cover-wm">I</div>
<div class="ch-num">Глава 2</div>
@@ -278,7 +311,7 @@ html.dark .final-cta-sub{color:#c4b5fd}
</div>
</a>
<a href="/textbook/physics-8-ch3" class="ch-card ch3-card" id="ch-3">
<a href="/textbook/physics-8-ch3" class="ch-card ch3-card" id="ch-3" aria-label="Глава 3: Световые явления">
<div class="ch-cover ch3">
<div class="ch-cover-wm">F</div>
<div class="ch-num">Глава 3</div>
@@ -298,7 +331,7 @@ html.dark .final-cta-sub{color:#c4b5fd}
</div>
</a>
<a href="/textbook/physics-8-lab" class="ch-card ch4-card" id="ch-4">
<a href="/textbook/physics-8-lab" class="ch-card ch4-card" id="ch-4" aria-label="Лабораторный практикум — 7 ЛР">
<div class="ch-cover ch4">
<div class="ch-cover-wm">ЛР</div>
<div class="ch-num">Лаборатория</div>
@@ -858,5 +891,10 @@ if (document.readyState === 'loading') {
window.addEventListener('focus', loadProgress);
</script>
<footer style="max-width:1100px;margin:50px auto 30px;padding:20px;color:var(--muted);font-size:.78rem;text-align:center;border-top:1px solid var(--border);line-height:1.55">
Физика 8 · LearnSpace · 40 параграфов, 7 ЛР, 47 IV-6 интерактивов
</footer>
</body>
</html>