From 2bdab2972e4997abb77ada237d4a656d32772748 Mon Sep 17 00:00:00 2001 From: aevgarik Date: Sun, 22 Mar 2026 21:54:38 +0300 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=D0=BF=D0=BE=D0=BB=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B0=20-=20=D0=B0=D0=B4=D0=B0=D0=BF=D1=82?= =?UTF-8?q?=D0=B8=D0=B2=D0=BD=D1=8B=D0=B9=20=D0=B4=D0=B8=D0=B7=D0=B0=D0=B9?= =?UTF-8?q?=D0=BD,=20=D1=80=D0=B5=D0=BA=D0=BE=D1=80=D0=B4=D1=8B,=20touch?= =?UTF-8?q?=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Touch events для мобильных устройств - Таблица рекордов (localStorage, top-10) - Ввод имени при новом рекорде - Отображение рейтинга с датами - CSS-переходы и анимации: - fadeIn для overlays - slideIn для модальных окон - hover-эффекты для кнопок - Адаптивный дизайн: - Масштабирование canvas под экран - Media queries для мобильных - Оптимизация UI для touch Refs: [GAM-10](/GAM/issues/GAM-10) Co-Authored-By: Paperclip --- src/components/GameBoard.vue | 380 ++++++++++++++++++++++++++++++----- 1 file changed, 335 insertions(+), 45 deletions(-) diff --git a/src/components/GameBoard.vue b/src/components/GameBoard.vue index 80eb48d..7efd9eb 100644 --- a/src/components/GameBoard.vue +++ b/src/components/GameBoard.vue @@ -6,38 +6,45 @@ Canvas-компонент игрового поля ColorLine98 --> @@ -223,19 +287,63 @@ function startNewGame(): void { :width="getCanvasSize()" :height="getCanvasSize()" class="game-board" + :style="{ width: canvasDisplaySize + 'px', height: canvasDisplaySize + 'px' }" @click="handleClick" + @touchstart="handleTouch" /> -
+

Игра окончена!

Ваш счёт: {{ state.score }}

- +
+ + +
+
+
+ +
+
+

Новый рекорд!

+

Ваш счёт: {{ lastScore }}

+ +
+ + +
+
+
+ +
+
+

Таблица рекордов

+
+
Пока нет рекордов
+
+ {{ index + 1 }}. + {{ score.name }} + {{ score.score }} + {{ score.date }} +
+
+
+ + +
+
@@ -247,10 +355,13 @@ function startNewGame(): void { align-items: center; padding: 20px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + max-width: 100vw; + box-sizing: border-box; } .game-header { display: flex; + flex-wrap: wrap; justify-content: space-between; align-items: center; width: 100%; @@ -260,6 +371,7 @@ function startNewGame(): void { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; color: white; + box-sizing: border-box; } .score { @@ -269,6 +381,7 @@ function startNewGame(): void { .score-value { font-size: 24px; + transition: transform 0.2s; } .next-balls { @@ -284,6 +397,7 @@ function startNewGame(): void { border-radius: 50%; border: 2px solid rgba(255, 255, 255, 0.5); box-shadow: inset -2px -2px 4px rgba(0, 0, 0, 0.2); + transition: transform 0.2s; } .game-board { @@ -292,6 +406,7 @@ function startNewGame(): void { background: #ecf0f1; cursor: pointer; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + touch-action: none; } .game-over { @@ -305,6 +420,16 @@ function startNewGame(): void { align-items: center; justify-content: center; z-index: 100; + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } } .game-over-content { @@ -313,6 +438,20 @@ function startNewGame(): void { border-radius: 15px; text-align: center; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); + animation: slideIn 0.3s ease; + max-width: 90vw; + box-sizing: border-box; +} + +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } } .game-over-content h2 { @@ -323,12 +462,23 @@ function startNewGame(): void { .game-over-content p { font-size: 20px; - margin-bottom: 30px; + margin-bottom: 20px; color: #2c3e50; } +.game-over-buttons { + display: flex; + gap: 10px; + justify-content: center; + flex-wrap: wrap; +} + .game-controls { margin-top: 20px; + display: flex; + gap: 10px; + flex-wrap: wrap; + justify-content: center; } .btn { @@ -353,4 +503,144 @@ function startNewGame(): void { .btn:active { transform: translateY(0); } + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn-secondary { + background: linear-gradient(135deg, #95a5a6 0%, #7f8c8d 100%); +} + +.name-input-content { + min-width: 300px; +} + +.name-input { + width: 100%; + padding: 12px 20px; + font-size: 18px; + border: 2px solid #ddd; + border-radius: 25px; + margin-bottom: 20px; + text-align: center; + box-sizing: border-box; + transition: border-color 0.2s; +} + +.name-input:focus { + outline: none; + border-color: #667eea; +} + +.highscores-content { + min-width: 320px; + max-width: 400px; +} + +.highscores-list { + max-height: 300px; + overflow-y: auto; + margin-bottom: 20px; + text-align: left; +} + +.no-scores { + text-align: center; + color: #7f8c8d; + padding: 20px; +} + +.highscore-row { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 12px; + border-bottom: 1px solid #ecf0f1; + transition: background-color 0.2s; +} + +.highscore-row:hover { + background-color: #f8f9fa; +} + +.highscore-row .rank { + font-weight: bold; + color: #667eea; + min-width: 25px; +} + +.highscore-row .name { + flex: 1; + color: #2c3e50; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.highscore-row .score-value { + font-weight: bold; + color: #27ae60; + min-width: 50px; + text-align: right; +} + +.highscore-row .date { + font-size: 12px; + color: #95a5a6; + min-width: 80px; + text-align: right; +} + +@media (max-width: 500px) { + .game-container { + padding: 10px; + } + + .game-header { + padding: 8px 12px; + font-size: 14px; + } + + .score { + font-size: 14px; + } + + .score-value { + font-size: 18px; + } + + .next-balls { + font-size: 12px; + } + + .preview-ball { + width: 16px; + height: 16px; + } + + .game-over-content { + padding: 20px; + margin: 10px; + } + + .game-over-content h2 { + font-size: 22px; + } + + .game-over-content p { + font-size: 16px; + } + + .btn { + padding: 10px 20px; + font-size: 14px; + } + + .highscore-row .date { + display: none; + } +}