SyntaxSquad/DADProject#16 feat: Can now start matches, just missing the actuall gameplay
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="relative min-h-screen bg-slate-950 text-white">
|
||||
|
||||
<div class="fixed top-0 left-0 right-0 z-40 bg-slate-900/90 backdrop-blur border-b border-slate-700 p-2 shadow-lg">
|
||||
<div class="max-w-4xl mx-auto flex items-center justify-between">
|
||||
|
||||
<div class="flex flex-col items-start">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold text-lg text-blue-400">{{ myName }}</span>
|
||||
<span v-if="matchState.wager > 0" class="flex items-center text-xs text-yellow-400 bg-yellow-400/10 px-2 rounded">
|
||||
<Coins class="w-3 h-3 mr-1" /> {{ matchState.wager }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex gap-1 mt-1">
|
||||
<div class="w-3 h-3 rounded-full border border-blue-500"
|
||||
:class="{ 'bg-blue-500': matchState.myWins >= 1 }"></div>
|
||||
<div class="w-3 h-3 rounded-full border border-blue-500"
|
||||
:class="{ 'bg-blue-500': matchState.myWins >= 2 }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-xs uppercase tracking-widest text-slate-400">Match {{ matchState.id }}</span>
|
||||
<span class="text-xl font-black font-mono">
|
||||
{{ matchState.myWins }} - {{ matchState.oppWins }}
|
||||
</span>
|
||||
<span class="text-[10px] text-slate-500">Best of 3</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-end">
|
||||
<span class="font-bold text-lg text-red-400">{{ opponentName }}</span>
|
||||
<div class="flex gap-1 mt-1">
|
||||
<div class="w-3 h-3 rounded-full border border-red-500"
|
||||
:class="{ 'bg-red-500': matchState.oppWins >= 1 }"></div>
|
||||
<div class="w-3 h-3 rounded-full border border-red-500"
|
||||
:class="{ 'bg-red-500': matchState.oppWins >= 2 }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-20 h-screen">
|
||||
<GameBoard
|
||||
v-if="matchState.currentGameId && !matchOver"
|
||||
:game-id="matchState.currentGameId"
|
||||
@game-end="handleGameEnd"
|
||||
/>
|
||||
|
||||
<div v-else-if="!matchOver" class="flex h-full items-center justify-center flex-col gap-4">
|
||||
<div class="text-2xl font-bold animate-pulse">Preparing next round...</div>
|
||||
<p class="text-slate-400">Switching sides and shuffling deck</p>
|
||||
</div>
|
||||
|
||||
<div v-if="matchOver" class="absolute inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-md">
|
||||
<div class="text-center space-y-6 p-8 bg-slate-900 border-2 border-purple-500 rounded-2xl shadow-2xl max-w-md w-full">
|
||||
<Trophy v-if="iWonMatch" class="w-20 h-20 text-yellow-400 mx-auto animate-bounce" />
|
||||
<Frown v-else class="w-20 h-20 text-slate-500 mx-auto" />
|
||||
|
||||
<div>
|
||||
<h1 class="text-4xl font-black uppercase mb-2"
|
||||
:class="iWonMatch ? 'text-yellow-400' : 'text-slate-400'">
|
||||
{{ iWonMatch ? 'Victory!' : 'Defeat' }}
|
||||
</h1>
|
||||
<p class="text-slate-300">Final Score: {{ matchState.myWins }} - {{ matchState.oppWins }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="matchState.wager > 0" class="bg-yellow-500/10 p-4 rounded-xl border border-yellow-500/20">
|
||||
<p class="text-xs uppercase text-yellow-600 font-bold mb-1">Total Reward</p>
|
||||
<div class="flex items-center justify-center gap-2 text-2xl font-bold text-yellow-400">
|
||||
<Coins class="w-6 h-6" />
|
||||
<span>{{ iWonMatch ? '+' + (matchState.wager * 2) : '-' + matchState.wager }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button @click="leaveMatch" class="w-full bg-purple-600 hover:bg-purple-700">
|
||||
Return to Lobby
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// Imports and setup similar to GamePage, but tracking Match State
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { Coins, Trophy, Frown } from 'lucide-vue-next'
|
||||
import GameBoard from '@/components/game/GameBoard.vue' // Reuse your existing board logic
|
||||
import axios from 'axios'
|
||||
// ... socket logic for match_updates ...
|
||||
|
||||
const matchState = ref({
|
||||
id: null,
|
||||
wager: 0,
|
||||
myWins: 0,
|
||||
oppWins: 0,
|
||||
currentGameId: null,
|
||||
players: {}
|
||||
})
|
||||
|
||||
const matchOver = computed(() => matchState.value.myWins >= 2 || matchState.value.oppWins >= 2)
|
||||
const iWonMatch = computed(() => matchState.value.myWins > matchState.value.oppWins)
|
||||
|
||||
// This function listens for Socket events on the "Match Channel"
|
||||
// e.g., channel: `match.{id}` event: `RoundEnded`
|
||||
const listenToMatch = () => {
|
||||
// When a game ends, the server should send:
|
||||
// { nextGameId: 123, scores: { p1: 1, p2: 0 } }
|
||||
// Update matchState.currentGameId to trigger the GameBoard to reload
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user