121 lines
4.3 KiB
Vue
121 lines
4.3 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted } from "vue";
|
|
import { gamesApiListGames } from "./api";
|
|
import type { GamesApiListGamesResponse } from "./api/types.gen";
|
|
|
|
interface Props {
|
|
marketEnabled?: string | boolean;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
marketEnabled: true,
|
|
});
|
|
|
|
const games = ref<GamesApiListGamesResponse | undefined>();
|
|
const loading = ref(true);
|
|
const imageErrors = ref<Set<number>>(new Set());
|
|
|
|
const getHeaderImage = (game: GamesApiListGamesResponse[number]) => {
|
|
if (game.image) {
|
|
return game.image;
|
|
}
|
|
if (game.steam_app_id) {
|
|
return `https://cdn.akamai.steamstatic.com/steam/apps/${game.steam_app_id}/header.jpg`;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const onImageError = (gameId: number) => {
|
|
imageErrors.value.add(gameId);
|
|
};
|
|
|
|
const navigate = (path: string) => {
|
|
window.location.href = path;
|
|
};
|
|
|
|
const isMarketEnabled = () => {
|
|
if (typeof props.marketEnabled === 'string') {
|
|
return props.marketEnabled === 'true';
|
|
}
|
|
return Boolean(props.marketEnabled);
|
|
};
|
|
|
|
onMounted(async () => {
|
|
// Fetch games list
|
|
const response = await gamesApiListGames();
|
|
if (response.data) {
|
|
games.value = response.data;
|
|
}
|
|
loading.value = false;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="min-h-screen bg-base-300 flex items-center justify-center px-4">
|
|
<div class="w-full max-w-6xl">
|
|
<!-- Header -->
|
|
<div class="text-center mb-12">
|
|
<h1 class="text-5xl font-bold mb-4">PolyLAN Submitter</h1>
|
|
<p class="text-xl text-base-content/70">
|
|
Choose a game and submit your best solutions
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Loading -->
|
|
<div v-if="loading" class="flex justify-center py-20">
|
|
<span class="loading loading-spinner loading-lg"></span>
|
|
</div>
|
|
|
|
<!-- Cards Grid -->
|
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
<!-- Market Card -->
|
|
<div v-if="isMarketEnabled()" @click="navigate('/market')"
|
|
class="card card-xl bg-base-200 shadow-xl hover:shadow-2xl transition-all cursor-pointer transform hover:-translate-y-2 hover:scale-[1.05] hover:bg-base-100 overflow-hidden">
|
|
<figure class="relative h-60 bg-gradient-to-br from-purple-600 to-blue-600 flex items-center justify-center">
|
|
<i class="mdi mdi-chart-box text-6xl text-white opacity-80"></i>
|
|
<div class="absolute inset-0 bg-black/30 group-hover:bg-black/20 transition-colors"></div>
|
|
</figure>
|
|
<div class="card-body">
|
|
<h2 class="card-title text-2xl">Market</h2>
|
|
<p class="text-base-content/70">Place your bets and compete</p>
|
|
<div class="card-actions justify-end mt-4">
|
|
<button class="btn btn-primary">
|
|
<i class="mdi mdi-arrow-right mr-2"></i>
|
|
Place bets
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Game Cards -->
|
|
<div v-for="game in games" :key="game.id" @click="navigate(game.path)"
|
|
class="card card-xl bg-base-200 shadow-xl hover:shadow-2xl transition-all cursor-pointer transform hover:-translate-y-2 hover:scale-[1.05] hover:bg-base-100 overflow-hidden">
|
|
<figure class="relative h-60 bg-base-300 overflow-hidden">
|
|
<img v-if="getHeaderImage(game) && !imageErrors.has(game.id)" :src="getHeaderImage(game)" :alt="game.name"
|
|
@error="onImageError(game.id)" class="w-full h-full object-cover" />
|
|
<div v-else
|
|
class="w-full h-full bg-gradient-to-br from-blue-600 to-blue-400 flex items-center justify-center text-white">
|
|
<i class="mdi mdi-gamepad-variant text-5xl"></i>
|
|
</div>
|
|
<div class="absolute inset-0 bg-black/30 group-hover:bg-black/20 transition-colors"></div>
|
|
</figure>
|
|
<div class="card-body">
|
|
<h2 class="card-title text-2xl">{{ game.name }}</h2>
|
|
<div class="card-actions justify-end mt-4">
|
|
<button class="btn btn-primary">
|
|
<i class="mdi mdi-arrow-right mr-2"></i>
|
|
Submit results
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="text-center mt-12 text-base-content/50">
|
|
<p>Select a game above to begin submitting</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|