Switch to Svelte

This commit is contained in:
2026-06-11 14:39:41 -07:00
parent 29860061c4
commit 58a7e4d4f1
74 changed files with 7144 additions and 2379 deletions

View File

@@ -0,0 +1,131 @@
<script>
import { onMount } from 'svelte';
import { apiRequest } from '../lib/api';
export let state;
let settingRole = false;
let starting = false;
let error = '';
let allowedRoles = ['pirat', 'deep'];
onMount(async () => {
try {
const res = await apiRequest(`/game/${state.game.id}/player/${state.player.id}/allowed-roles`, 'GET');
allowedRoles = res.allowed_roles;
} catch(e) {
console.error("Failed to load allowed roles", e);
}
});
async function setRole(role) {
settingRole = true;
try {
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/set-role`, 'POST', { role });
} catch(e) {
console.error(e);
} finally {
settingRole = false;
}
}
async function startScene() {
starting = true;
error = '';
try {
await apiRequest(`/game/${state.game.id}/scene/start`, 'POST');
} catch(e) {
error = e.message;
starting = false;
}
}
$: allRolesAssigned = state.players.every(p => p.role !== null);
$: deepPlayer = state.players.find(p => p.role === 'deep');
$: piratPlayer = state.players.find(p => p.role === 'pirat');
$: canStart = allRolesAssigned && deepPlayer && piratPlayer && (state.player.is_creator || state.player.role === 'deep');
</script>
<div class="scene-setup-view text-center">
<h2>Scene Setup (Scene #{state.game.current_scene_number})</h2>
<p class="description">Select your role for the upcoming scene. There must be at least one Pi-Rat and one Deep player. If you played the Deep in the last scene, you must play a Pi-Rat this scene!</p>
<div class="setup-grid">
<!-- Role Selection Card -->
<div class="card glass-panel role-selection-card">
<h3>Select Your Role</h3>
<div class="role-buttons">
<button on:click={() => setRole('pirat')}
disabled={settingRole || !allowedRoles.includes('pirat')}
class="btn btn-large role-btn pirat-btn {state.player.role === 'pirat' ? 'active' : ''}">
🐀 Play Pi-Rat
</button>
<button on:click={() => setRole('deep')}
disabled={settingRole || !allowedRoles.includes('deep')}
class="btn btn-large role-btn deep-btn {state.player.role === 'deep' ? 'active' : ''}">
🌊 Play the Deep
</button>
</div>
<div class="role-restrictions mt-4">
{#if !allowedRoles.includes('pirat')}
{#if state.game.current_scene_number === 1}
<p class="text-red-400 text-sm italic">You are the highest ranked player, so you must play The Deep for the first scene!</p>
{:else}
<p class="text-red-400 text-sm italic">You are the only eligible player for The Deep this scene!</p>
{/if}
{/if}
{#if !allowedRoles.includes('deep')}
{#if state.game.current_scene_number === 1}
<p class="text-red-400 text-sm italic">Only the highest ranked player(s) can play The Deep in the first scene!</p>
{:else}
<p class="text-red-400 text-sm italic">You played The Deep last scene, so you must play a Pi-Rat!</p>
{/if}
{/if}
</div>
</div>
<!-- Live Roster Card -->
<div class="card glass-panel roster-card">
<h3>Live Roster Selection</h3>
<div class="roster-list" id="scene-roster-list">
{#each state.players as p}
<div class="roster-item">
<span class="player-name">{p.name} <span class="text-sm text-gray-400">(Rank {p.rank})</span></span>
{#if p.role === 'pirat'}
<span class="role-badge pirat">Pi-Rat</span>
{:else if p.role === 'deep'}
<span class="role-badge deep">The Deep</span>
{:else}
<span class="role-badge unassigned">Choosing...</span>
{/if}
</div>
{/each}
</div>
</div>
</div>
<div class="action-box margin-top">
{#if error}
<div class="alert alert-danger">{error}</div>
{/if}
{#if canStart}
<button on:click={startScene}
disabled={starting}
class="btn btn-primary btn-large glow-effect">
{starting ? 'Starting Scene...' : 'Confirm Roles & Shuffle Deck'}
</button>
{:else if !allRolesAssigned}
<p class="text-gray-400 italic mt-4">Waiting for all players to choose a role...</p>
{:else if !deepPlayer}
<p class="text-red-400 italic mt-4">Someone must play as The Deep!</p>
{:else if !piratPlayer}
<p class="text-red-400 italic mt-4">Someone must play as a Pi-Rat!</p>
{:else}
<p class="text-gray-400 italic mt-4">Waiting for The Deep or Creator to start the scene...</p>
{/if}
</div>
</div>