ENH - adopt Konsta controls in game headers

This commit is contained in:
smx.pusha
2026-08-07 18:00:06 +02:00
parent 4e88b59413
commit ddfbfaf0a4
7 changed files with 90 additions and 38 deletions
+13 -6
View File
@@ -16,6 +16,7 @@ import {
VolumeX,
Zap,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import { computed, onBeforeUnmount, onMounted } from 'vue'
import { playMemorySound } from '@/features/games/memory/audio'
@@ -135,7 +136,10 @@ onBeforeUnmount(() => {
</div>
<div class="memory-header__actions">
<Sparkles :size="23" aria-hidden="true" />
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="phone.t(memory.soundEnabled ? 'Apps.memory.mute' : 'Apps.memory.unmute')"
:title="phone.t(memory.soundEnabled ? 'Apps.memory.mute' : 'Apps.memory.unmute')"
@@ -143,7 +147,7 @@ onBeforeUnmount(() => {
>
<Volume2 v-if="memory.soundEnabled" :size="18" aria-hidden="true" />
<VolumeX v-else :size="18" aria-hidden="true" />
</button>
</k-button>
</div>
</header>
@@ -182,7 +186,10 @@ onBeforeUnmount(() => {
<section v-else class="memory-game">
<div class="memory-stats">
<button
<k-button
component="button"
clear
rounded
type="button"
class="memory-menu-button"
:aria-label="phone.t('Apps.memory.backToMenu')"
@@ -190,7 +197,7 @@ onBeforeUnmount(() => {
@click="returnToMenu"
>
<ChevronLeft :size="18" :stroke-width="2.6" aria-hidden="true" />
</button>
</k-button>
<div>
<span>{{ phone.t('Apps.memory.time') }}</span>
<strong>{{ formatTime(memory.elapsedMs) }}</strong>
@@ -199,9 +206,9 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.memory.moves') }}</span>
<strong>{{ game.moves }}</strong>
</div>
<button type="button" @click="restart">
<k-button component="button" clear rounded type="button" @click="restart">
{{ phone.t('Apps.memory.restart') }}
</button>
</k-button>
</div>
<div
+16 -6
View File
@@ -7,6 +7,7 @@ import {
Volume2,
VolumeX,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import {
computed,
onBeforeUnmount,
@@ -208,7 +209,10 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.minesweeper.eyebrow') }}</span>
<h1>{{ phone.t('Apps.minesweeper.name') }}</h1>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="
phone.t(
@@ -221,7 +225,7 @@ onBeforeUnmount(() => {
>
<Volume2 v-if="minesweeper.soundEnabled" :size="18" aria-hidden="true" />
<VolumeX v-else :size="18" aria-hidden="true" />
</button>
</k-button>
</header>
<section v-if="minesweeper.menuOpen" class="minesweeper-menu">
@@ -275,7 +279,10 @@ onBeforeUnmount(() => {
}"
>
<div class="minesweeper-toolbar">
<button
<k-button
component="button"
clear
rounded
type="button"
class="minesweeper-toolbar__icon"
:aria-label="phone.t('Apps.minesweeper.backToMenu')"
@@ -283,7 +290,7 @@ onBeforeUnmount(() => {
@click.stop="minesweeper.showMenu()"
>
<ChevronLeft :size="19" :stroke-width="2.7" aria-hidden="true" />
</button>
</k-button>
<div>
<span>{{ phone.t('Apps.minesweeper.mines') }}</span>
<strong>{{ minesRemaining }}</strong>
@@ -292,14 +299,17 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.minesweeper.time') }}</span>
<strong>{{ formatTime(minesweeper.elapsedMs) }}</strong>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
class="minesweeper-toolbar__icon"
:aria-label="phone.t('Apps.minesweeper.restart')"
@click="restart"
>
<RotateCcw :size="17" :stroke-width="2.5" aria-hidden="true" />
</button>
</k-button>
</div>
<div
+16 -6
View File
@@ -9,6 +9,7 @@ import {
VolumeX,
Zap,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { playNeonDropSound } from '@/features/games/neon-drop/audio'
@@ -206,7 +207,10 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.neonDrop.eyebrow') }}</span>
<h1>{{ phone.t('Apps.neonDrop.name') }}</h1>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="
phone.t(
@@ -219,7 +223,7 @@ onBeforeUnmount(() => {
v-else
:size="18"
/>
</button>
</k-button>
</header>
<section v-if="neon.menuOpen" class="neon-menu">
@@ -274,13 +278,16 @@ onBeforeUnmount(() => {
<section v-else-if="game" class="neon-game">
<div class="neon-toolbar">
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="phone.t('Apps.neonDrop.backToMenu')"
@click="neon.showMenu()"
>
<ChevronLeft :size="19" />
</button>
</k-button>
<div>
<span>{{ phone.t('Apps.neonDrop.score') }}</span
><strong>{{ game.score }}</strong>
@@ -289,7 +296,10 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.neonDrop.lines') }}</span
><strong>{{ game.lines }}</strong>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="phone.t('Apps.neonDrop.pause')"
@click="togglePause"
@@ -299,7 +309,7 @@ onBeforeUnmount(() => {
:size="16"
fill="currentColor"
/><Play v-else :size="16" fill="currentColor" />
</button>
</k-button>
</div>
<div class="neon-play-area">
+16 -6
View File
@@ -5,6 +5,7 @@ import {
Volume2,
VolumeX,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import { computed, onBeforeUnmount, onMounted, ref, type CSSProperties } from 'vue'
import { playNumberMergeSound } from '@/features/games/number-merge/audio'
@@ -135,7 +136,10 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
<span>{{ phone.t('Apps.numberMerge.eyebrow') }}</span>
<h1>{{ phone.t('Apps.numberMerge.name') }}</h1>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="
phone.t(
@@ -155,7 +159,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
>
<Volume2 v-if="numberMerge.soundEnabled" :size="18" aria-hidden="true" />
<VolumeX v-else :size="18" aria-hidden="true" />
</button>
</k-button>
</header>
<section v-if="numberMerge.menuOpen" class="number-merge-menu">
@@ -210,7 +214,10 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
<section v-else-if="game" class="number-merge-game">
<div class="number-merge-toolbar">
<button
<k-button
component="button"
clear
rounded
type="button"
class="number-merge-toolbar__icon"
:aria-label="phone.t('Apps.numberMerge.backToMenu')"
@@ -218,7 +225,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
@click="numberMerge.showMenu"
>
<ChevronLeft :size="19" :stroke-width="2.7" aria-hidden="true" />
</button>
</k-button>
<div>
<span>{{ phone.t('Apps.numberMerge.score') }}</span>
<strong>{{ formatScore(game.score) }}</strong>
@@ -227,7 +234,10 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
<span>{{ phone.t('Apps.numberMerge.best') }}</span>
<strong>{{ formatScore(numberMerge.bestScore) }}</strong>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
class="number-merge-toolbar__icon number-merge-toolbar__restart"
:aria-label="phone.t('Apps.numberMerge.newGame')"
@@ -235,7 +245,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', handleKeydown))
@click="requestNewGame"
>
<RotateCcw :size="17" :stroke-width="2.5" aria-hidden="true" />
</button>
</k-button>
</div>
<div
+5 -4
View File
@@ -2,6 +2,7 @@
<script setup lang="ts">
import { ChevronLeft, Pause, Play, RotateCcw, Volume2, VolumeX, Wind } from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import { computed, onBeforeUnmount, ref, watch, type CSSProperties } from 'vue'
import { playSkyFlappySound } from '@/features/games/sky-flappy/audio'
@@ -116,9 +117,9 @@ onBeforeUnmount(() => {
>
<header v-if="flappy.menuOpen" class="flappy-header">
<div><span>{{ phone.t('Apps.skyFlappy.eyebrow') }}</span><h1>{{ phone.t('Apps.skyFlappy.name') }}</h1></div>
<button type="button" :aria-label="phone.t(flappy.soundEnabled ? 'Apps.skyFlappy.mute' : 'Apps.skyFlappy.unmute')" @click="toggleSound">
<k-button component="button" clear rounded type="button" :aria-label="phone.t(flappy.soundEnabled ? 'Apps.skyFlappy.mute' : 'Apps.skyFlappy.unmute')" @click="toggleSound">
<Volume2 v-if="flappy.soundEnabled" :size="18" /><VolumeX v-else :size="18" />
</button>
</k-button>
</header>
<section v-if="flappy.menuOpen" class="flappy-menu">
@@ -141,10 +142,10 @@ onBeforeUnmount(() => {
<section v-else-if="game" class="flappy-game">
<div class="flappy-toolbar">
<button type="button" :aria-label="phone.t('Apps.skyFlappy.backToMenu')" @pointerdown.stop="flappy.showMenu()" @click.stop="flappy.showMenu()"><ChevronLeft :size="19" /></button>
<k-button component="button" clear rounded type="button" :aria-label="phone.t('Apps.skyFlappy.backToMenu')" @pointerdown.stop="flappy.showMenu()" @click.stop="flappy.showMenu()"><ChevronLeft :size="19" /></k-button>
<div><span>{{ phone.t('Apps.skyFlappy.score') }}</span><strong>{{ game.score }}</strong></div>
<div><span>{{ phone.t('Apps.skyFlappy.best') }}</span><strong>{{ flappy.highScore }}</strong></div>
<button type="button" :aria-label="phone.t('Apps.skyFlappy.pause')" @click="togglePause"><Pause v-if="game.status === 'playing'" :size="16" fill="currentColor" /><Play v-else :size="16" fill="currentColor" /></button>
<k-button component="button" clear rounded type="button" :aria-label="phone.t('Apps.skyFlappy.pause')" @click="togglePause"><Pause v-if="game.status === 'playing'" :size="16" fill="currentColor" /><Play v-else :size="16" fill="currentColor" /></k-button>
</div>
<button type="button" class="flappy-stage" :class="{ 'flappy-stage--crashed': game.status === 'over' && !gameOverVisible }" :aria-label="phone.t('Apps.skyFlappy.flap')" @pointerdown.stop.prevent="flap">
+11 -4
View File
@@ -4,6 +4,7 @@ import {
Pause,
Play,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import { computed, onBeforeUnmount, onMounted, watch } from 'vue'
import {
@@ -205,7 +206,10 @@ onBeforeUnmount(() => {
<section v-else class="snake-game">
<div class="snake-game__meta">
<button
<k-button
component="button"
clear
rounded
type="button"
class="snake-game__back"
:aria-label="phone.t('Apps.snake.backToMenu')"
@@ -213,12 +217,15 @@ onBeforeUnmount(() => {
@click="returnToMenu"
>
<ChevronLeft :size="18" :stroke-width="2.7" aria-hidden="true" />
</button>
</k-button>
<div>
<span>{{ phone.t('Apps.snake.score') }}</span>
<strong>{{ game.score }}</strong>
</div>
<button
<k-button
component="button"
clear
rounded
v-if="game.status !== 'game-over'"
type="button"
class="snake-game__pause"
@@ -233,7 +240,7 @@ onBeforeUnmount(() => {
>
<Play v-if="game.status === 'paused'" :size="18" fill="currentColor" />
<Pause v-else :size="18" fill="currentColor" />
</button>
</k-button>
</div>
<div
+13 -6
View File
@@ -8,6 +8,7 @@ import {
Volume2,
VolumeX,
} from 'lucide-vue-next'
import { kButton } from 'konsta/vue'
import {
computed,
onBeforeUnmount,
@@ -185,14 +186,17 @@ onBeforeUnmount(() => {
<span>{{ phone.t('Apps.towerStack.eyebrow') }}</span>
<h1>{{ phone.t('Apps.towerStack.name') }}</h1>
</div>
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="phone.t(tower.soundEnabled ? 'Apps.towerStack.mute' : 'Apps.towerStack.unmute')"
@click="toggleSound"
>
<Volume2 v-if="tower.soundEnabled" :size="18" aria-hidden="true" />
<VolumeX v-else :size="18" aria-hidden="true" />
</button>
</k-button>
</header>
<section v-if="tower.menuOpen" class="tower-menu">
@@ -232,18 +236,21 @@ onBeforeUnmount(() => {
<section v-else-if="game" class="tower-game">
<div class="tower-toolbar">
<button
<k-button
component="button"
clear
rounded
type="button"
:aria-label="phone.t('Apps.towerStack.backToMenu')"
@pointerdown.stop="tower.showMenu()"
@click.stop="tower.showMenu()"
><ChevronLeft :size="19" /></button>
><ChevronLeft :size="19" /></k-button>
<div><span>{{ phone.t('Apps.towerStack.height') }}</span><strong>{{ game.blocks.length - 1 }}</strong></div>
<div><span>{{ phone.t('Apps.towerStack.score') }}</span><strong>{{ game.score }}</strong></div>
<button type="button" :aria-label="phone.t('Apps.towerStack.pause')" @click="togglePause">
<k-button component="button" clear rounded type="button" :aria-label="phone.t('Apps.towerStack.pause')" @click="togglePause">
<Pause v-if="game.status === 'playing'" :size="17" fill="currentColor" />
<Play v-else :size="17" fill="currentColor" />
</button>
</k-button>
</div>
<button