ENH - restore pre-Konsta app overhaul

This commit is contained in:
smx.pusha
2026-08-08 17:57:19 +02:00
parent 857fa95e23
commit 79501781b6
11 changed files with 2550 additions and 936 deletions
+41 -29
View File
@@ -27,7 +27,7 @@ import { usePhoneStore } from '@/stores/phone'
const phone = usePhoneStore()
const tower = useTowerStackStore()
const game = computed(() => tower.game)
const visibleBlocks = computed(() => game.value?.blocks.slice(-9) ?? [])
const visibleBlocks = computed(() => game.value?.blocks.slice(-6) ?? [])
const placementEffect = ref<'missed' | 'perfect' | 'placed' | null>(null)
const fallingBlock = ref<TowerActiveBlock | null>(null)
const fallingStyle = ref<CSSProperties>({})
@@ -175,8 +175,12 @@ onBeforeUnmount(() => {
</script>
<template>
<main class="tower-app" :aria-label="phone.t('Apps.towerStack.name')">
<header class="tower-header">
<main
class="tower-app"
:class="{ 'tower-app--playing': !tower.menuOpen && game }"
:aria-label="phone.t('Apps.towerStack.name')"
>
<header v-if="tower.menuOpen" class="tower-header">
<div>
<span>{{ phone.t('Apps.towerStack.eyebrow') }}</span>
<h1>{{ phone.t('Apps.towerStack.name') }}</h1>
@@ -214,7 +218,13 @@ onBeforeUnmount(() => {
<Play :size="17" fill="currentColor" />
{{ phone.t('Apps.towerStack.resume') }}
</button>
<button type="button" class="tower-secondary" @click="startGame">
<button
type="button"
:class="game?.status === 'paused' ? 'tower-secondary' : 'tower-primary'"
@click="startGame"
>
<RotateCcw v-if="game" :size="16" aria-hidden="true" />
<Play v-else :size="16" fill="currentColor" aria-hidden="true" />
{{ phone.t(game ? 'Apps.towerStack.newGame' : 'Apps.towerStack.start') }}
</button>
<p class="tower-menu__hint">{{ phone.t('Apps.towerStack.tapHint') }}</p>
@@ -305,32 +315,34 @@ onBeforeUnmount(() => {
<style scoped>
.tower-app { position: absolute; inset: 0; overflow: hidden; padding: 52px 16px 27px; color: #eef5ff; background: radial-gradient(circle at 75% 8%, #7146c866, transparent 35%), linear-gradient(170deg, #161634, #242054 52%, #10132c); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; user-select: none; touch-action: manipulation; }
.tower-header { height: 55px; display: flex; align-items: center; justify-content: space-between; }
.tower-header span { display: block; color: #c1b8f1; font-size: 14px; font-weight: 850; letter-spacing: 1.1px; text-transform: uppercase; }
.tower-header h1 { margin: 1px 0 0; font-size: 32px; line-height: 1; letter-spacing: -0.8px; }
.tower-app--playing { padding: 0; }
.tower-header { height: 50px; display: flex; align-items: center; justify-content: space-between; }
.tower-header span { display: block; color: #c1b8f1; font-size: 10px; font-weight: 850; letter-spacing: 1.1px; text-transform: uppercase; }
.tower-header h1 { margin: 1px 0 0; font-size: 27px; line-height: 1; letter-spacing: -0.8px; }
.tower-header button, .tower-toolbar button { width: 36px; height: 36px; display: grid; place-items: center; padding: 0; border: 1px solid #ffffff14; border-radius: 12px; color: #f2edff; background: #ffffff0d; }
.tower-menu { height: calc(100% - 55px); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; text-align: center; }
.tower-menu__preview { position: relative; width: 190px; height: 210px; }
.tower-menu__preview i { position: absolute; right: 12px; bottom: calc(var(--preview-index) * 25px); left: 25px; height: 29px; border-radius: 7px; background: hsl(calc(var(--preview-index) * 49deg + 5deg) 82% 62%); box-shadow: inset 0 4px 0 #ffffff35, 0 8px 15px #08091c5c; transform: perspective(200px) rotateX(5deg); }
.tower-menu__preview i:nth-child(even) { right: 25px; left: 12px; }
.tower-menu__preview span { position: absolute; top: 4px; left: 2px; width: 120px; height: 29px; border-radius: 7px; background: #ff6b68; box-shadow: 0 0 24px #ff6b6877; animation: tower-preview-slide 1.5s ease-in-out infinite alternate; }
.tower-menu__copy > span { color: #ffcf59; font-size: 14px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; }
.tower-menu__copy h2 { margin: 4px 0 7px; font-size: 30px; }
.tower-menu__copy p { max-width: 295px; margin: 0; color: #e0dcf2; font-size: 18px; font-weight: 550; line-height: 1.4; }
.tower-menu { height: calc(100% - 50px); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; text-align: center; }
.tower-menu__preview { position: relative; flex: 0 0 124px; width: 158px; height: 124px; }
.tower-menu__preview i { position: absolute; right: 12px; bottom: calc((var(--preview-index) - 1) * 15px); left: 23px; height: 21px; border-radius: 6px; background: hsl(calc(var(--preview-index) * 49deg + 5deg) 82% 62%); box-shadow: inset 0 3px 0 #ffffff35, 0 5px 11px #08091c5c; transform: perspective(200px) rotateX(5deg); }
.tower-menu__preview i:nth-child(even) { right: 23px; left: 12px; }
.tower-menu__preview span { position: absolute; top: 0; left: 4px; width: 100px; height: 21px; border-radius: 6px; background: #ff6b68; box-shadow: 0 0 20px #ff6b6877; animation: tower-preview-slide 1.5s ease-in-out infinite alternate; }
.tower-menu__copy > span { color: #ffcf59; font-size: 10px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase; }
.tower-menu__copy h2 { max-width: 270px; margin: 3px auto 5px; font-size: 24px; line-height: 1.08; }
.tower-menu__copy p { max-width: 285px; margin: 0; color: #d8d3eb; font-size: 12px; font-weight: 550; line-height: 1.35; }
.tower-records { width: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.tower-records div { display: grid; gap: 3px; padding: 12px 9px; border: 1px solid #ffffff1f; border-radius: 13px; background: #ffffff0d; }
.tower-records span { color: #d1caea; font-size: 15px; font-weight: 850; text-transform: uppercase; }
.tower-records strong { font-size: 26px; }
.tower-primary, .tower-secondary { width: 100%; min-height: 50px; display: flex; align-items: center; justify-content: center; gap: 8px; border-radius: 14px; font-size: 18px; font-weight: 850; }
.tower-records div { display: grid; gap: 1px; padding: 8px 9px; border: 1px solid #ffffff1f; border-radius: 13px; background: #ffffff0d; backdrop-filter: blur(8px); }
.tower-records span { color: #d1caea; font-size: 9px; font-weight: 850; letter-spacing: .35px; text-transform: uppercase; }
.tower-records strong { font-size: 20px; }
.tower-primary, .tower-secondary { width: 100%; min-height: 42px; display: flex; align-items: center; justify-content: center; gap: 7px; border-radius: 14px; font-size: 13px; font-weight: 850; }
.tower-primary { border: 0; color: #1e1839; background: linear-gradient(135deg, #ffca4f, #ff8760); box-shadow: 0 8px 18px #ff895330; }
.tower-secondary { border: 1px solid #ffffff16; color: #eeeaff; background: #ffffff0a; }
.tower-menu__hint, .tower-game__hint { margin: 0; color: #e0daf0; font-size: 16px; font-weight: 700; line-height: 1.35; }
.tower-game { position: relative; height: calc(100% - 55px); }
.tower-toolbar { height: 47px; display: grid; grid-template-columns: 36px 1fr 1fr 36px; align-items: center; gap: 7px; }
.tower-toolbar div { display: grid; justify-items: center; line-height: 1.05; }
.tower-toolbar span { color: #c9c2e9; font-size: 12px; font-weight: 850; letter-spacing: .35px; text-transform: uppercase; }
.tower-toolbar strong { font-size: 21px; }
.tower-stage { position: relative; width: 100%; height: 500px; display: block; overflow: hidden; padding: 0; border: 1px solid #ffffff35; border-radius: 22px; background: linear-gradient(#1d1b52, #433078 60%, #8e4c78); box-shadow: inset 0 0 35px #08091d80, 0 16px 28px #08091c66; touch-action: manipulation; }
.tower-menu__hint, .tower-game__hint { margin: 0; color: #c9c2e0; font-size: 10px; font-weight: 700; line-height: 1.35; }
.tower-game { position: absolute; inset: 0; }
.tower-toolbar { position: absolute; z-index: 10; top: 66px; right: 18px; left: 18px; height: 42px; display: grid; grid-template-columns: 32px 1fr 1fr 32px; align-items: center; gap: 4px; padding: 4px; border: 1px solid #ffffff1a; border-radius: 21px; background: #292451a8; box-shadow: 0 8px 24px #08091c52; backdrop-filter: blur(14px); box-sizing: border-box; }
.tower-toolbar div { height: 32px; display: grid; grid-template-rows: 10px 20px; align-content: center; justify-items: center; }
.tower-toolbar span { color: #c9c2e9; font-size: 11px; font-weight: 850; line-height: 10px; letter-spacing: .35px; text-transform: uppercase; }
.tower-toolbar strong { display: block; font-size: 19px; line-height: 20px; }
.tower-toolbar button { width: 32px; height: 32px; border: 0; border-radius: 50%; box-shadow: none; }
.tower-stage { position: absolute; inset: 0; width: 100%; height: 100%; display: block; overflow: hidden; padding: 0; border: 0; border-radius: 0; background: linear-gradient(#1d1b52, #433078 60%, #8e4c78); box-shadow: inset 0 0 35px #08091d80; touch-action: manipulation; }
.tower-sky { position: absolute; inset: 0; pointer-events: none; }
.tower-sky i { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #fff; box-shadow: 0 0 7px #c5c2ff; opacity: .65; }
.tower-sky i:nth-child(1) { top: 8%; left: 12%; } .tower-sky i:nth-child(2) { top: 17%; left: 72%; } .tower-sky i:nth-child(3) { top: 28%; left: 42%; } .tower-sky i:nth-child(4) { top: 37%; left: 88%; } .tower-sky i:nth-child(5) { top: 46%; left: 18%; } .tower-sky i:nth-child(6) { top: 58%; left: 64%; } .tower-sky i:nth-child(7) { top: 70%; left: 31%; } .tower-sky i:nth-child(8) { top: 11%; left: 91%; } .tower-sky i:nth-child(9) { top: 22%; left: 25%; } .tower-sky i:nth-child(10) { top: 50%; left: 78%; } .tower-sky i:nth-child(11) { top: 64%; left: 8%; } .tower-sky i:nth-child(12) { top: 77%; left: 92%; } .tower-sky i:nth-child(13) { top: 33%; left: 58%; }
@@ -343,13 +355,13 @@ onBeforeUnmount(() => {
.tower-perfect { position: absolute; z-index: 8; top: 24%; left: 50%; padding: 8px 17px; border-radius: 18px; color: #332149; background: #ffdc65; box-shadow: 0 0 24px #ffcf64aa; font-size: 13px; font-weight: 950; letter-spacing: .8px; transform: translateX(-50%); animation: tower-perfect-pop 650ms ease-out forwards; }
.tower-stage--perfect { animation: tower-perfect-glow 500ms ease-out; }
.tower-stage--missed { animation: tower-stage-shake 500ms ease-out; }
.tower-game__hint { margin-top: 8px; text-align: center; }
.tower-overlay { position: absolute; z-index: 15; inset: 47px 0 25px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; padding: 28px; border-radius: 22px; color: #f7f2ff; background: #11122bd9; backdrop-filter: blur(7px); text-align: center; }
.tower-game__hint { position: absolute; z-index: 6; right: 45px; bottom: 27px; left: 45px; margin: 0; padding: 7px 10px; border-radius: 999px; color: #e0daf0; background: #29245191; backdrop-filter: blur(10px); text-align: center; pointer-events: none; }
.tower-overlay { position: absolute; z-index: 15; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; padding: 28px; color: #f7f2ff; background: #11122bd9; backdrop-filter: blur(7px); text-align: center; }
.tower-overlay > svg { color: #ffbd4d; }
.tower-overlay > span { color: #ffad78; font-size: 12px; font-weight: 900; letter-spacing: 1.2px; text-transform: uppercase; }
.tower-overlay h2 { margin: 0; font-size: 25px; }
.tower-overlay p { margin: -3px 0 5px; color: #c7c1e4; font-size: 14px; }
@keyframes tower-preview-slide { from { transform: translateX(0) rotate(-2deg); } to { transform: translateX(66px) rotate(2deg); } }
@keyframes tower-preview-slide { from { transform: translateX(0) rotate(-2deg); } to { transform: translateX(48px) rotate(2deg); } }
@keyframes tower-land { from { filter: brightness(1.8); transform: translateY(-8px) scaleY(.85); } to { filter: brightness(1); transform: translateY(0) scaleY(1); } }
@keyframes tower-active-pulse { from { filter: saturate(1.2) brightness(1.08); } to { filter: saturate(1.45) brightness(1.35); } }
@keyframes tower-fall { 0% { opacity: 1; transform: translate(0) rotate(0); } 100% { opacity: 0; transform: translate(45px, 390px) rotate(145deg); } }