Analyzing diff...
index.html+67 −1
index 45ed840..b8239ff 100644 @@ -199,7 +199,7 @@ } .weeks-grid { display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + grid-template-columns: minmax(0, 1fr); gap: 30px; align-items: start; } @@ -444,8 +444,10 @@ grid-template-columns: repeat(7, 1fr); gap: 4px; margin-top: 8px; + min-width: 0; } .dot { + min-width: 0; border: 0; border-radius: 8px; aspect-ratio: 1; @@ -455,6 +457,14 @@ font-weight: 800; cursor: pointer; } + .celebration-canvas { + position: fixed; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 9999; + } .dot.active { background: var(--yellow); color: var(--navy); @@ -923,6 +933,7 @@ ]; const DAYS = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]; const KEY = "sekta-plan-alyona-w8-w9-v1"; + const gameLineCounts = new WeakMap(); let state = JSON.parse( localStorage.getItem(KEY) || '{"done":{},"comments":{},"practice":{}}', ); @@ -1011,6 +1022,7 @@ ); const winningCards = new Set(winningLines.flat()); const lines = winningLines.length; + const previousLines = gameLineCounts.get(game); const count = Object.keys(state.practice).filter( (k) => k.startsWith(`w${week}-`) && state.practice[k], ).length; @@ -1033,6 +1045,60 @@ : "0 линий"; game.querySelector("[data-score]").textContent = `${count} применений за неделю`; + if (previousLines !== undefined && lines > previousLines) { + launchCelebration(); + } + gameLineCounts.set(game, lines); + } + function launchCelebration() { + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; + const canvas = document.createElement("canvas"); + canvas.className = "celebration-canvas"; + canvas.setAttribute("aria-hidden", "true"); + document.body.append(canvas); + const ctx = canvas.getContext("2d"); + const scale = Math.min(window.devicePixelRatio || 1, 2); + canvas.width = Math.round(innerWidth * scale); + canvas.height = Math.round(innerHeight * scale); + ctx.scale(scale, scale); + const colors = ["#ffd95a", "#ff8f70", "#4ba8e8", "#42b883", "#ffffff"]; + const particles = Array.from({ length: 110 }, (_, i) => { + const side = i % 2; + const angle = (side ? -Math.PI * 0.82 : -Math.PI * 0.18) + (Math.random() - 0.5) * 1.2; + const speed = 5 + Math.random() * 8; + return { + x: side ? innerWidth * 0.82 : innerWidth * 0.18, + y: innerHeight * 0.62, + vx: Math.cos(angle) * speed, + vy: Math.sin(angle) * speed, + size: 3 + Math.random() * 5, + color: colors[i % colors.length], + rotation: Math.random() * Math.PI, + spin: (Math.random() - 0.5) * 0.35, + }; + }); + const started = performance.now(); + function frame(now) { + const elapsed = now - started; + ctx.clearRect(0, 0, innerWidth, innerHeight); + particles.forEach((p) => { + p.x += p.vx; + p.y += p.vy; + p.vy += 0.16; + p.vx *= 0.992; + p.rotation += p.spin; + ctx.save(); + ctx.globalAlpha = Math.max(0, 1 - elapsed / 1500); + ctx.translate(p.x, p.y); + ctx.rotate(p.rotation); + ctx.fillStyle = p.color; + ctx.fillRect(-p.size / 2, -p.size / 2, p.size, p.size * 0.58); + ctx.restore(); + }); + if (elapsed < 1500) requestAnimationFrame(frame); + else canvas.remove(); + } + requestAnimationFrame(frame); } function updateProgress() { const checks = [...document.querySelectorAll(".check")],