From 59a5d6953bcdd395c03e0df6606eb9cd3b35ece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D1=80=D0=BE=D1=88=D0=B8=D0=BD=20=D0=90=D0=BD=D1=82?= =?UTF-8?q?=D0=BE=D0=BD=20=D0=92=D0=B0=D0=BB=D0=B5=D1=80=D1=8C=D0=B5=D0=B2?= =?UTF-8?q?=D0=B8=D1=87?= Date: Sun, 12 Jul 2026 21:50:38 +0300 Subject: [PATCH] more cosmetic improvements --- app.js | 63 +++++++++++++++++++++++++++++++++++++++++++++++------- index.html | 6 +++--- styles.css | 24 ++++++++++++++++++++- sw.js | 2 +- 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/app.js b/app.js index c7a38a6..51fdb60 100644 --- a/app.js +++ b/app.js @@ -76,7 +76,7 @@ const STRINGS = { binary: '\u0414\u0432\u043E\u0438\u0447\u043D\u0430\u044F', octal: '\u0412\u043E\u0441\u044C\u043C\u0435\u0440\u0438\u0447\u043D\u0430\u044F', hex: '\u0428\u0435\u0441\u0442\u043D\u0430\u0434\u0446\u0430\u0442\u0435\u0440\u0438\u0447\u043D\u0430\u044F', - ternary: '\u0421\u0431\u0430\u043B\u0430\u043D\u0441\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u0430\u044F \u0442\u0440\u043E\u0438\u0447\u043D\u0430\u044F', + ternary: '\u0423\u0440\u0430\u0432\u043D\u043E\u0432\u0435\u0448\u0435\u043D\u043D\u0430\u044F \u0442\u0440\u043E\u0438\u0447\u043D\u0430\u044F', braille: '\u0414\u0435\u0441\u044F\u0442\u0438\u0447\u043D\u0430\u044F \u0411\u0440\u0430\u0439\u043B\u044F', roman: '\u0420\u0438\u043C\u0441\u043A\u0430\u044F', slavonic: '\u0426\u0435\u0440\u043A\u043E\u0432\u043D\u043E\u0441\u043B\u0430\u0432\u044F\u043D\u0441\u043A\u0430\u044F', @@ -145,18 +145,27 @@ const SYSTEM_RANGES = { ], greek: [ { label: '1 \u2013 9', min: 1, max: 9 }, + { label: '10 \u2013 19', min: 10, max: 19 }, + { label: '20 \u2013 99', min: 20, max: 99 }, + { label: '1 \u2013 99', min: 1, max: 99 }, { label: '10 \u2013 99', min: 10, max: 99 }, { label: '100 \u2013 999', min: 100, max: 999 }, { label: '1000 \u2013 9999', min: 1000, max: 9999 }, ], slavonic: [ { label: '1 \u2013 9', min: 1, max: 9 }, + { label: '10 \u2013 19', min: 10, max: 19 }, + { label: '20 \u2013 99', min: 20, max: 99 }, + { label: '1 \u2013 99', min: 1, max: 99 }, { label: '10 \u2013 99', min: 10, max: 99 }, { label: '100 \u2013 999', min: 100, max: 999 }, { label: '1000 \u2013 9999', min: 1000, max: 9999 }, ], hebrew: [ { label: '1 \u2013 9', min: 1, max: 9 }, + { label: '10 \u2013 19', min: 10, max: 19 }, + { label: '20 \u2013 99', min: 20, max: 99 }, + { label: '1 \u2013 99', min: 1, max: 99 }, { label: '10 \u2013 99', min: 10, max: 99 }, { label: '100 \u2013 499', min: 100, max: 499 }, ], @@ -173,10 +182,10 @@ const MODES = [ ]; const TIMINGS = [ - { value: 60 }, - { value: 40 }, - { value: 10 }, { value: 0 }, + { value: 30 }, + { value: 15 }, + { value: 5 }, ]; const ROUNDS = [10, 25, 50, 100]; @@ -272,7 +281,7 @@ function renderSetupRange() { function renderSetupOptions() { const defaultMode = 0; - const defaultTiming = 3; + const defaultTiming = 0; const defaultRounds = 0; setupState.mode = defaultMode; @@ -420,6 +429,8 @@ function handleChoice(idx, val, choices) { allBtns[idx].classList.add('correct-choice'); feedback.textContent = t('correct'); feedback.className = 'answer-feedback correct'; + const rect = allBtns[idx].getBoundingClientRect(); + spawnAnswerConfetti(rect.left + rect.width / 2, rect.top + rect.height / 2); } else { allBtns[idx].classList.add('incorrect-choice'); const correctIdx = choices.indexOf(game.correctAnswer); @@ -475,6 +486,8 @@ function renderNumpad() { document.getElementById('score-correct').textContent = MARK_CORRECT + game.correctCount; feedback.textContent = t('correct'); feedback.className = 'answer-feedback correct'; + const rect = inputEl.getBoundingClientRect(); + spawnAnswerConfetti(rect.left + rect.width / 2, rect.top + rect.height / 2); } else { feedback.textContent = t('incorrect', {n: game.correctAnswer}); feedback.className = 'answer-feedback incorrect'; @@ -611,11 +624,34 @@ function endGame() { } } +function spawnAnswerConfetti(x, y) { + const chars = ['🎉', '🎊', '✨', '🎈', '🥳', '💫']; + const burst = document.createElement('div'); + burst.className = 'answer-confetti-burst'; + burst.style.left = x + 'px'; + burst.style.top = y + 'px'; + + for (let j = 0; j < 8; j++) { + const particle = document.createElement('span'); + particle.className = 'confetti-particle'; + particle.textContent = chars[Math.floor(Math.random() * chars.length)]; + particle.style.setProperty('--dx', (Math.random() - 0.5) * 80 + 'px'); + particle.style.setProperty('--dy', -(30 + Math.random() * 60) + 'px'); + particle.style.setProperty('--rot', Math.random() * 360 + 'deg'); + particle.style.animationDuration = (0.5 + Math.random() * 0.3) + 's'; + burst.appendChild(particle); + } + + document.body.appendChild(burst); + setTimeout(() => burst.remove(), 1000); +} + function spawnConfetti() { const chars = ['🎉', '🎊', '✨', '🎈', '🥳', '💫']; const container = document.getElementById('results-congrats'); - for (let i = 0; i < 3; i++) { + const bursts = Math.round(game.rounds / 3); + for (let i = 0; i < bursts; i++) { setTimeout(() => { const burst = document.createElement('div'); burst.className = 'confetti-burst'; @@ -666,8 +702,20 @@ const TICKER_SYSTEMS = [ function generateTickerText() { const pairs = []; + let lastKey = null; + let lastColor = null; for (let i = 0; i < 20; i++) { - const sys = TICKER_SYSTEMS[Math.floor(Math.random() * TICKER_SYSTEMS.length)]; + let sys; + do { + sys = TICKER_SYSTEMS[Math.floor(Math.random() * TICKER_SYSTEMS.length)]; + } while (sys.key === lastKey); + lastKey = sys.key; + + let color; + do { + color = TICKER_COLORS[Math.floor(Math.random() * TICKER_COLORS.length)]; + } while (color === lastColor); + lastColor = color; const num = sys.min + Math.floor(Math.random() * (sys.max - sys.min + 1)); const display = SYSTEMS[sys.key].toDisplay(num); let labelled = display; @@ -676,7 +724,6 @@ function generateTickerText() { const wrapped = sys.key === 'slavonic' ? '' + labelled + '' : labelled; - const color = TICKER_COLORS[Math.floor(Math.random() * TICKER_COLORS.length)]; pairs.push('' + wrapped + ' = ' + num + ''); } return pairs.join('\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0'); diff --git a/index.html b/index.html index d20b196..860f71a 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ - +
@@ -158,10 +158,10 @@
- + diff --git a/styles.css b/styles.css index 393b53e..f7a2b72 100644 --- a/styles.css +++ b/styles.css @@ -10,6 +10,7 @@ --bg-card: #0f3460; --accent: #e94560; --accent-hover: #ff6b81; + --accent-secondary: #ff9a56; --text: #eaeaea; --text-dim: #a0a0b0; --correct: #2ecc71; @@ -19,6 +20,21 @@ --safe-bottom: env(safe-area-inset-bottom); } +@media (prefers-color-scheme: light) { + :root { + --bg: #f5f5f5; + --bg-light: #ffffff; + --bg-card: #ffffff; + --accent: #e94560; + --accent-hover: #d63851; + --accent-secondary: #f09040; + --text: #1a1a2e; + --text-dim: #555566; + --correct: #27ae60; + --incorrect: #c0392b; + } +} + @font-face { font-family: 'Ponomar'; src: url('Ponomar-Regular.woff') format('woff'); @@ -72,7 +88,7 @@ body { .logo { font-size: 3.5rem; font-weight: 800; - background: linear-gradient(135deg, var(--accent), #ff9a56); + background: linear-gradient(135deg, var(--accent), var(--accent-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -626,6 +642,12 @@ body { pointer-events: none; } +.answer-confetti-burst { + position: fixed; + pointer-events: none; + z-index: 1000; +} + .confetti-particle { position: absolute; font-size: 1.4rem; diff --git a/sw.js b/sw.js index ba2eb3a..70aaa97 100644 --- a/sw.js +++ b/sw.js @@ -1,4 +1,4 @@ -const CACHE_NAME = 'numnum-v46'; +const CACHE_NAME = 'numnum-v8'; const ASSETS = [ '/', '/index.html',