122 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
| 	<v-app :theme="theme">
 | |
| 		<v-app-bar :elevation="2">
 | |
| 			<v-app-bar-title>SHOTGUN</v-app-bar-title>
 | |
| 			<template #append>
 | |
| 				<v-btn :icon="themeIcon" @click="toggleDark()"></v-btn>
 | |
| 			</template>
 | |
| 		</v-app-bar>
 | |
| 		<v-main>
 | |
| 			<Game v-if="playing" :game="game" :dealer="dealer" @action="(evt: Action) => action(evt)" />
 | |
| 			<v-container v-else-if="loading" class="fill-height">
 | |
| 				<v-row class="d-flex justify-center">
 | |
| 					<v-progress-circular class="pa-8" indeterminate size="128"></v-progress-circular>
 | |
| 				</v-row>
 | |
| 			</v-container>
 | |
| 			<v-container v-else>
 | |
| 				<TheLanding />
 | |
| 				<v-row v-if="!loadingMe && !me" class="d-flex justify-center">
 | |
| 					<TheLogin />
 | |
| 				</v-row>
 | |
| 				<v-row v-else-if="!loadingMe" class="d-flex justify-center">
 | |
| 					<v-btn @click="clickPlay" class="mx-4" color="primary">Play</v-btn>
 | |
| 					<v-btn class="mx-4">Log Out</v-btn>
 | |
| 				</v-row>
 | |
| 			</v-container>
 | |
| 		</v-main>
 | |
| 	</v-app>
 | |
| </template>
 | |
| 
 | |
| <script setup lang="ts">
 | |
| import { useDark, useToggle, useWebSocket } from '@vueuse/core';
 | |
| import { computed, onMounted, ref, watchEffect } from 'vue';
 | |
| import type { Action, Game, GameStart } from '@/lib/game';
 | |
| 
 | |
| const dark = useDark();
 | |
| const toggleDark = useToggle(dark);
 | |
| const theme = computed(() => dark.value ? 'dark' : 'light');
 | |
| const themeIcon = computed(() => dark.value ? 'mdi-moon-waxing-crescent' : 'mdi-white-balance-sunny');
 | |
| 
 | |
| const { status, data, send, open } = useWebSocket<string>(`wss://${window.location.host}/queue`, {
 | |
| 	immediate: false,
 | |
| 	heartbeat: {
 | |
| 		interval: 1000,
 | |
| 		message: '{"action":"ping"}',
 | |
| 	},
 | |
| 	onDisconnected: (ws, evt) => {
 | |
| 		console.warn('lost connection', {evt});
 | |
| 		game.value = null;
 | |
| 		dealer.value = null;
 | |
| 	}
 | |
| });
 | |
| const game = ref<Game | null>(null);
 | |
| const dealer = ref<boolean | null>(null);
 | |
| watchEffect(() => {
 | |
| 	console.log('data', data.value);
 | |
| 	if (data.value == null) {
 | |
| 		game.value = null;
 | |
| 		dealer.value = null;
 | |
| 		if (window.location.pathname.includes('game/')) {
 | |
| 			history.replaceState(null, '', window.origin);
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	const m = JSON.parse(data.value) as Game | GameStart;
 | |
| 	if ('id' in m) {
 | |
| 		// Game start.
 | |
| 		dealer.value = m.dealer;
 | |
| 		history.replaceState(null, '', `${window.origin}/game/${m.id}`);
 | |
| 		return;
 | |
| 	}
 | |
| 	// Game state update.
 | |
| 	game.value = m as Game;
 | |
| });
 | |
| 
 | |
| const playing = computed(() => game.value != null);
 | |
| const loading = computed(() => status.value === 'CONNECTING' || status.value === 'OPEN' && !playing.value);
 | |
| 
 | |
| function clickPlay() {
 | |
| 	open();
 | |
| }
 | |
| 
 | |
| const testGame = ref<Game>({
 | |
| 	players: [
 | |
| 		{ hp: 4, items: ['🔍', '🔪', '', '', '', '', '', ''] },
 | |
| 		{ hp: 3, items: ['👮', '🚬', '', '', '', '', '', ''] },
 | |
| 	],
 | |
| 	round: 1,
 | |
| 	dealer: true,
 | |
| 	damage: 1,
 | |
| 	previous: null,
 | |
| 	live: 3,
 | |
| 	blank: 4,
 | |
| });
 | |
| 
 | |
| function action(evt: Action) {
 | |
| 	console.log('send action', evt);
 | |
| 	send(JSON.stringify(action));
 | |
| }
 | |
| 
 | |
| const loadingMe = ref(true);
 | |
| const me = ref<string | null>(null);
 | |
| onMounted(async () => {
 | |
| 	loadingMe.value = true;
 | |
| 	try {
 | |
| 		const resp = await fetch('/user/me', {
 | |
| 			method: 'GET',
 | |
| 			mode: 'same-origin',
 | |
| 			credentials: 'same-origin',
 | |
| 		})
 | |
| 		loadingMe.value = false;
 | |
| 		if (!resp.ok) {
 | |
| 			me.value = null;
 | |
| 			return;
 | |
| 		}
 | |
| 		const { id } = await resp.json();
 | |
| 		me.value = id as string;
 | |
| 	} catch {
 | |
| 		me.value = null;
 | |
| 	}
 | |
| });
 | |
| </script>
 |