From 4de50184098fcaa03f99f100a59c8399d936b09e Mon Sep 17 00:00:00 2001 From: team3 Date: Tue, 8 Sep 2026 14:49:14 +0200 Subject: [PATCH] =?UTF-8?q?Klebende=20Reiterleiste=20und=20Zur=C3=BCck-nac?= =?UTF-8?q?h-oben?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bei 2500 Karten scrollt man sonst lange, bis die Reiter wieder auftauchen. Die Leiste bleibt jetzt oben stehen, der Knopf unten rechts bringt einen zurück. Er animiert selbst statt mit behavior: 'smooth'. Das rechnet mit fester Geschwindigkeit und bräuchte über 300.000 Pixel Seitenhöhe Minuten; hier sind es immer 450 ms. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013XVnRop5c3or3B8xE2hpgZ --- frontend/src/App.vue | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6c5b9ae..60774fa 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -225,6 +225,32 @@ const tabs = computed(() => [ const rad = ref(null) +// Bei 2500 Karten kommt man sonst nicht mehr nach oben +const obenKnopf = ref(false) + +function beimScrollen() { + obenKnopf.value = window.scrollY > 800 +} + +// Eigene Animation statt behavior: 'smooth'. Das rechnet mit fester +// Geschwindigkeit und bräuchte über 300.000 Pixel Seitenhöhe Minuten. +const OBEN_DAUER = 450 + +function nachOben() { + const start = window.scrollY + const beginn = performance.now() + + function schritt(jetzt) { + const t = Math.min(1, (jetzt - beginn) / OBEN_DAUER) + // Sanft an- und auslaufend + const p = t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2 + window.scrollTo(0, start * (1 - p)) + if (t < 1) requestAnimationFrame(schritt) + } + + requestAnimationFrame(schritt) +} + // Die movie_ids der geschauten Filme — die Detailansicht zeigt damit an, // ob der Film schon lief const gesehen = ref([]) @@ -476,10 +502,12 @@ onMounted(() => { else if (nachricht.type === 'features') ladeWuensche() }) window.addEventListener('keydown', tastatur) + window.addEventListener('scroll', beimScrollen, { passive: true }) }) onUnmounted(() => { window.removeEventListener('keydown', tastatur) + window.removeEventListener('scroll', beimScrollen) abbestellen?.() }) @@ -594,6 +622,10 @@ onUnmounted(() => { /> + + { } .tabs { + position: sticky; + top: 0; + z-index: 10; display: flex; gap: 0.35rem; - margin-bottom: 1.25rem; + /* Der negative Rand deckt das Polster der Seite ab, sonst scrollen + Karten oberhalb der Leiste durchs Bild */ + margin: -1.5rem -1.25rem 1.25rem; + padding: 0.7rem 1.25rem 0; + background: var(--bg); border-bottom: 1px solid var(--line); } +.nach-oben { + position: fixed; + right: calc(var(--sidebar) + 1.25rem); + bottom: 1.5rem; + z-index: 15; + width: 3rem; + height: 3rem; + color: #fff; + font-size: 1.35rem; + line-height: 1; + background: var(--accent); + border: 0; + border-radius: 50%; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6); +} + +.nach-oben:hover { + filter: brightness(1.15); +} + .tabs button { display: flex; align-items: center;