add good looking lobby ui with websocket support with claude sonnet 3.7

This commit is contained in:
Pablu23
2025-10-07 14:55:30 +02:00
parent 81ad47960a
commit eb6e85a099
19 changed files with 1477 additions and 86 deletions

View File

@@ -0,0 +1,168 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { createWebSocketClient } from '$lib/websocketClient';
import type { Settings, GameMode, Playlist } from '$lib/types';
import PlayerList from '$lib/components/PlayerList.svelte';
import GameSettings from '$lib/components/GameSettings.svelte';
// Create WebSocket client
let wsClient = $state(createWebSocketClient());
// Current user state
let isHost = $state(true); // Assume current user is host for this example
let lobbyCode = $state('GAME123');
// Available options for settings
let gameModes = $state<GameMode[]>([
{ id: 'classic', name: 'Classic Mode' },
{ id: 'team', name: 'Team Battle' },
{ id: 'speed', name: 'Speed Round' }
]);
let playlists = $state<Playlist[]>([
{ id: 1, name: 'Pop Hits 2023', imageUrl: 'https://example.com/images/pop2023.jpg', songCount: 25 },
{ id: 2, name: 'Rock Classics', imageUrl: 'https://example.com/images/rock.jpg', songCount: 30 },
{ id: 3, name: '80s Mixtape', imageUrl: 'https://example.com/images/80s.jpg', songCount: 20 },
{ id: 4, name: 'Movie Soundtracks', imageUrl: 'https://example.com/images/movies.jpg', songCount: 15 },
{ id: 5, name: 'Hip Hop Essentials', imageUrl: 'https://example.com/images/hiphop.jpg', songCount: 40 },
{ id: 6, name: 'Indie Discoveries', imageUrl: 'https://example.com/images/indie.jpg', songCount: 35 }
]);
function handleSettingsUpdate(settings: Settings) {
// Send updated settings to other players via websocket
wsClient.sendMessage({
type: 'settingsUpdate',
settings: settings
});
}
function startGame() {
wsClient.sendMessage({
type: 'startGame',
settings: wsClient.gameSettings
});
// In a real app, this would navigate to the game screen
}
function copyLobbyCode() {
navigator.clipboard.writeText(lobbyCode);
// Would show a toast notification in a real app
}
function leaveLobby() {
wsClient.disconnect();
// In a real app, you'd likely redirect to another page here
}
// Initialize mock data for demo
function initializeMockData() {
// Simulate WebSocket connection and receiving initial player data
setTimeout(() => {
console.log("Init mock data");
wsClient.players = [
{ id: 1, name: 'YourName', isHost: true },
{ id: 2, name: 'Player2', isHost: false },
{ id: 3, name: 'GamerX', isHost: false }
];
wsClient.connected = true;
}, 500);
}
onMount(() => {
// In a real app, connect to WebSocket server
// wsClient.connect('ws://example.com/game-lobby');
// For demo purposes, we'll simulate a connection
initializeMockData();
});
onDestroy(() => {
// Clean up WebSocket connection when component is destroyed
wsClient.disconnect();
});
</script>
<div class="min-h-screen bg-gray-50 py-8 px-4 sm:px-6 lg:px-8">
<div class="max-w-5xl mx-auto">
<!-- Header -->
<div class="mb-8 text-center">
<h1 class="text-3xl font-bold text-gray-900">Game Lobby</h1>
<div class="mt-3 flex items-center justify-center">
<span class="text-gray-600 mr-2">Invite your friends using code:</span>
<span class="font-mono bg-white px-3 py-1.5 rounded-md border border-gray-200 text-blue-600 font-semibold">{lobbyCode}</span>
<button
class="ml-2 p-1.5 text-gray-500 hover:text-blue-600 transition-colors"
title="Copy to clipboard"
on:click={copyLobbyCode}
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" />
<path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z" />
</svg>
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Left column: Player list -->
<div class="md:col-span-1">
{#if wsClient.connected}
<PlayerList
players={wsClient.players}
maxPlayers={wsClient.gameSettings.maxPlayers}
/>
{:else}
<div class="bg-white rounded-lg shadow-sm p-5 flex items-center justify-center">
<div class="flex items-center text-amber-600">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Connecting to lobby...
</div>
</div>
{/if}
</div>
<!-- Right column: Game settings and controls -->
<div class="md:col-span-2 space-y-6">
<GameSettings
settings={wsClient.gameSettings}
gameModes={gameModes}
playlists={playlists}
isHost={isHost}
onUpdate={handleSettingsUpdate}
/>
<!-- Action buttons -->
<div class="flex justify-between">
<button
class="px-4 py-2.5 bg-white border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
on:click={leaveLobby}
>
Leave Lobby
</button>
{#if isHost}
<button
class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 flex items-center"
on:click={startGame}
>
<span>Start Game</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 ml-1.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
{:else}
<div class="text-gray-500 italic self-center flex items-center">
<svg class="animate-pulse h-5 w-5 mr-2 text-blue-400" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="12" r="10" />
</svg>
Waiting for host to start...
</div>
{/if}
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,15 +1,18 @@
<script lang="ts">
import type { PageProps } from './$types';
import { onDestroy } from 'svelte';
let { data }: PageProps = $props();
onDestroy(() => console.log('left site'));
</script>
<h1>You are in lobby with ID: {data.lobby?.id}</h1>
<h2>Youre username is: {data.username}</h2>
<h2>Your username is: {data.username}</h2>
<h2>Players in Lobby: </h2>
<h2>Players in Lobby:</h2>
<ul>
{#each data.lobby.usersInLobby as player (player.userEmail)}
<li>{player.user.username}</li>
{/each}
</ul>
{#each data.lobby.usersInLobby as player (player.userEmail)}
<li>{player.user.username}</li>
{/each}
</ul>