Add fade transition and game cycling to Steam component
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m43s

Matches the Listening component pattern with auto-rotating games every
5 seconds, click to advance, and crossfade transitions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 02:00:52 +00:00
parent 264df132df
commit d4a6343d5e

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, onUnmounted } from "vue"; import { ref, computed, onMounted, onUnmounted } from "vue";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import { useSteamStore } from "@/stores/steam"; import { useSteamStore } from "@/stores/steam";
import { useHomeDataStore } from "@/stores/homeData"; import { useHomeDataStore } from "@/stores/homeData";
@@ -10,11 +10,28 @@ const { steamStatus } = storeToRefs(steamStore);
const homeData = useHomeDataStore(); const homeData = useHomeDataStore();
const { loaded } = storeToRefs(homeData); const { loaded } = storeToRefs(homeData);
let refreshInterval; const idx = ref(0);
const game = computed(() => steamStatus.value.recentGames[idx.value]);
let nextId = null;
let refreshId = null;
function nextGame() {
clearTimeout(nextId);
nextId = setTimeout(nextGame, 5000);
if (steamStatus.value.recentGames.length) {
idx.value = (idx.value + 1) % steamStatus.value.recentGames.length;
}
}
onMounted(() => { onMounted(() => {
refreshInterval = setInterval(() => steamStore.fetchSteam(), 5 * 60 * 1000); nextId = setTimeout(nextGame, 5000);
refreshId = setInterval(() => steamStore.fetchSteam(), 5 * 60 * 1000);
});
onUnmounted(() => {
clearTimeout(nextId);
clearInterval(refreshId);
}); });
onUnmounted(() => clearInterval(refreshInterval));
function formatHours(minutes) { function formatHours(minutes) {
const hrs = (minutes / 60).toFixed(1); const hrs = (minutes / 60).toFixed(1);
@@ -23,7 +40,7 @@ function formatHours(minutes) {
</script> </script>
<template> <template>
<div class="flex flex-col min-h-0 overflow-hidden"> <div class="steam-wrapper">
<Header class="text-left"> <Header class="text-left">
<span class="flex items-center gap-2"> <span class="flex items-center gap-2">
Steam Steam
@@ -37,30 +54,54 @@ function formatHours(minutes) {
<div v-if="!loaded" class="p-2 text-sm">Loading...</div> <div v-if="!loaded" class="p-2 text-sm">Loading...</div>
<div <Transition name="fade" v-else-if="game">
v-else-if="steamStatus.recentGames.length" <div @click="nextGame" :key="game.appId" class="flex flex-col items-center">
class="flex-1 overflow-y-auto flex flex-col gap-2 p-1"
>
<div
v-for="game in steamStatus.recentGames"
:key="game.appId"
class="flex flex-col"
>
<img <img
:src="game.headerImageUrl" :src="game.headerImageUrl"
:alt="game.name" :alt="game.name"
class="w-full object-cover" class="game-img"
loading="lazy"
/> />
<div class="px-1 py-0.5 text-xs"> <p class="text-center">
<p class="font-bold truncate">{{ game.name }}</p> <strong>{{ game.name }}</strong>
<p class="text-tertiary"> </p>
<p class="text-center text-tertiary text-xs">
{{ formatHours(game.playtime2Weeks) }} last 2 weeks {{ formatHours(game.playtime2Weeks) }} last 2 weeks
</p> </p>
</div> </div>
</div> </Transition>
</div>
<div v-else class="p-2 text-sm">No recent games.</div> <div v-else class="p-2 text-sm">No recent games.</div>
</div> </div>
</template> </template>
<style scoped>
.steam-wrapper {
position: relative;
width: 100%;
height: 100%;
}
.game-img {
width: 90%;
}
p {
width: 100%;
margin: 0 auto;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-leave-active {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>