Switch to Svelte
This commit is contained in:
527
frontend/src/components/CharacterCreationPhase.svelte
Normal file
527
frontend/src/components/CharacterCreationPhase.svelte
Normal file
@@ -0,0 +1,527 @@
|
||||
<script>
|
||||
import { apiRequest } from '../lib/api';
|
||||
import { getSuggestion } from '../lib/suggestions';
|
||||
|
||||
export let state;
|
||||
|
||||
// Form states
|
||||
let basicDetails = {
|
||||
avatar_look: state.player.avatar_look || '',
|
||||
avatar_smell: state.player.avatar_smell || '',
|
||||
first_words: state.player.first_words || '',
|
||||
good_at_math: state.player.good_at_math || ''
|
||||
};
|
||||
|
||||
let savingBasic = false;
|
||||
let delegating = false;
|
||||
|
||||
async function saveBasicDetails() {
|
||||
savingBasic = true;
|
||||
try {
|
||||
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/save-basic`, 'POST', basicDetails);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
savingBasic = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function autoDelegate() {
|
||||
delegating = true;
|
||||
try {
|
||||
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/delegate/auto`, 'POST');
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
delegating = false;
|
||||
}
|
||||
}
|
||||
|
||||
// A helper to get player name
|
||||
function getPlayerName(id) {
|
||||
if (!id) return "None";
|
||||
const p = state.players.find(x => x.id === id);
|
||||
return p ? p.name : "Unknown";
|
||||
}
|
||||
|
||||
// Techniques
|
||||
let tech1 = '', tech2 = '', tech3 = '';
|
||||
let savingTechs = false;
|
||||
|
||||
async function submitTechniques() {
|
||||
savingTechs = true;
|
||||
try {
|
||||
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/submit-techniques`, 'POST', {
|
||||
tech1, tech2, tech3
|
||||
});
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
savingTechs = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Face Techniques
|
||||
let jackTech = '', queenTech = '', kingTech = '';
|
||||
let assigningFace = false;
|
||||
let faceError = '';
|
||||
|
||||
async function assignFaceTechniques() {
|
||||
assigningFace = true;
|
||||
faceError = '';
|
||||
try {
|
||||
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/assign-face-techniques`, 'POST', {
|
||||
jack: jackTech,
|
||||
queen: queenTech,
|
||||
king: kingTech
|
||||
});
|
||||
} catch(e) {
|
||||
faceError = e.message;
|
||||
} finally {
|
||||
assigningFace = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Submit delegated answers
|
||||
let answerLike = '', answerHate = '';
|
||||
async function submitDelegatedAnswer(type, targetId, answer) {
|
||||
try {
|
||||
await apiRequest(`/game/${state.game.id}/player/${state.player.id}/submit-delegate/${targetId}/${type}`, 'POST', { answer });
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Check completion status
|
||||
$: createdTechniques = state.player.created_techniques ? JSON.parse(state.player.created_techniques) : [];
|
||||
$: swappedTechniques = state.player.swapped_techniques ? JSON.parse(state.player.swapped_techniques) : [];
|
||||
|
||||
$: basicComplete = !!(state.player.avatar_look && state.player.avatar_smell && state.player.first_words && state.player.good_at_math);
|
||||
$: delegateComplete = !!(state.player.other_like_from_player_id && state.player.other_hate_from_player_id);
|
||||
$: techniquesComplete = !!(state.player.tech_jack && state.player.tech_queen && state.player.tech_king);
|
||||
|
||||
// Dev Mode
|
||||
let devMode = false;
|
||||
let autoFilling = false;
|
||||
|
||||
async function autoFillAll() {
|
||||
autoFilling = true;
|
||||
try {
|
||||
// 1. Basic details
|
||||
if (!basicComplete) {
|
||||
basicDetails = {
|
||||
avatar_look: 'A scruffy rat',
|
||||
avatar_smell: 'Like old cheese',
|
||||
first_words: 'Give me the loot!',
|
||||
good_at_math: 'No'
|
||||
};
|
||||
await saveBasicDetails();
|
||||
}
|
||||
|
||||
// 2. Delegate
|
||||
if (!delegateComplete && state.players.length >= 2) {
|
||||
await autoDelegate();
|
||||
}
|
||||
|
||||
// 3. Answer questions (might need a quick refresh to get the questions, but we can do our best with current state)
|
||||
// Wait, state needs to be re-fetched to get the assigned questions. We can just fill what's currently in inbox.
|
||||
for (const p of state.players) {
|
||||
if (p.other_like_from_player_id === state.player.id && !p.other_like) {
|
||||
await submitDelegatedAnswer('like', p.id, 'They are sneaky');
|
||||
}
|
||||
if (p.other_hate_from_player_id === state.player.id && !p.other_hate) {
|
||||
await submitDelegatedAnswer('hate', p.id, 'They snore loud');
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Techniques
|
||||
if (createdTechniques.length === 0) {
|
||||
tech1 = 'Pocket Sand';
|
||||
tech2 = 'Tail Whip';
|
||||
tech3 = 'Cheese Decoy';
|
||||
await submitTechniques();
|
||||
}
|
||||
|
||||
// 5. Face Techniques - we need the swapped ones. We can't do this synchronously without waiting for the server
|
||||
// to process the state, because swapped_techniques comes from the server once everyone is done.
|
||||
if (!techniquesComplete && swappedTechniques.length === 3) {
|
||||
jackTech = swappedTechniques[0];
|
||||
queenTech = swappedTechniques[1];
|
||||
kingTech = swappedTechniques[2];
|
||||
await assignFaceTechniques();
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
autoFilling = false;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="character-creation-view">
|
||||
<div class="view-header text-center">
|
||||
<h2>Character Sheet Creation</h2>
|
||||
<p>Fill in your Rat Records, delegate questions to your crew, and prepare your Math Magic Techniques.</p>
|
||||
<div class="flex justify-center items-center gap-2 text-sm text-gray-500 mt-2">
|
||||
<input type="checkbox" id="devModeToggle" bind:checked={devMode} class="accent-gold"/>
|
||||
<label for="devModeToggle">Dev Mode</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if devMode}
|
||||
<div class="bg-dark-900 border border-gold p-4 rounded-lg flex justify-between items-center mb-6 max-w-4xl mx-auto">
|
||||
<span class="text-gold font-bold">🛠 Dev Mode Tools</span>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
on:click={autoFillAll}
|
||||
disabled={autoFilling}>
|
||||
{autoFilling ? 'Auto-Filling...' : 'Auto-Fill Available Fields'}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- MAIN PANEL: Grid for Layout -->
|
||||
<div class="creation-grid max-w-5xl mx-auto">
|
||||
|
||||
<!-- SECTION 1: Rat Records (Basic Info) -->
|
||||
<div class="card glass-panel section-basic">
|
||||
<h3>I. Basic Rat Records {basicComplete ? '✅' : '❌'}</h3>
|
||||
|
||||
{#if basicComplete}
|
||||
<!-- Saved View -->
|
||||
<div class="read-only-sheet">
|
||||
<div class="record-line"><strong>Look:</strong> {state.player.avatar_look}</div>
|
||||
<div class="record-line"><strong>Smell:</strong> {state.player.avatar_smell}</div>
|
||||
<div class="record-line"><strong>First Words:</strong> "{state.player.first_words}"</div>
|
||||
<div class="record-line"><strong>Good at Math?</strong> {state.player.good_at_math}</div>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Form View -->
|
||||
<form on:submit|preventDefault={saveBasicDetails} class="creation-form">
|
||||
<div class="form-group">
|
||||
<label for="avatar_look">What does your Pi-Rat look like?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="avatar_look" placeholder="e.g. A blue bandana, scarred snout" bind:value={basicDetails.avatar_look} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.avatar_look = getSuggestion('look')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="avatar_smell">What does your Pi-Rat smell like?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="avatar_smell" placeholder="e.g. Damp gunpowder, salty cheese" bind:value={basicDetails.avatar_smell} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.avatar_smell = getSuggestion('smell')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="first_words">What were your first words after transforming?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="first_words" placeholder="e.g. Where is my gat?!" bind:value={basicDetails.first_words} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.first_words = getSuggestion('first_words')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="good_at_math">Is your Pi-Rat good at Math?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="good_at_math" placeholder="e.g. Yes, but only geometry; No, thinks Pi is a dessert" bind:value={basicDetails.good_at_math} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => basicDetails.good_at_math = getSuggestion('good_at_math')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-full" disabled={savingBasic}>Save Records</button>
|
||||
</form>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- SECTION 2: Delegated Questions (Like/Hate) -->
|
||||
<div class="card glass-panel section-delegations">
|
||||
<div class="card-header-flex" style="display:flex; justify-content:space-between; align-items:center; margin-bottom:1rem; border-bottom:1px solid rgba(212,175,55,0.2); padding-bottom:0.5rem;">
|
||||
<h3 style="border:none; margin:0; padding:0; color:var(--gold); font-family:var(--font-heading);">II. Crew Delegations {delegateComplete ? '✅' : '❌'}</h3>
|
||||
{#if !delegateComplete}
|
||||
<button on:click={autoDelegate} disabled={delegating || state.players.length < 2} class="btn btn-secondary btn-small">
|
||||
🎲 Auto-Assign Tasks
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="section-desc">You must let other players decide what they like and hate about your character.</p>
|
||||
|
||||
<div class="delegation-list">
|
||||
{#if delegateComplete}
|
||||
<div class="delegation-box glass-panel">
|
||||
<h4>What does another rat LIKE about you?</h4>
|
||||
<div class="answer-box">
|
||||
{state.player.other_like ? `"${state.player.other_like}"` : '(Waiting for answer...)'}
|
||||
</div>
|
||||
<div class="author-label">— {getPlayerName(state.player.other_like_from_player_id)}</div>
|
||||
</div>
|
||||
<div class="delegation-box glass-panel">
|
||||
<h4>What does another rat HATE about you?</h4>
|
||||
<div class="answer-box">
|
||||
{state.player.other_hate ? `"${state.player.other_hate}"` : '(Waiting for answer...)'}
|
||||
</div>
|
||||
<div class="author-label">— {getPlayerName(state.player.other_hate_from_player_id)}</div>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="mb-4 text-sm text-gray-400">Randomly assign crewmates to write your relationships by clicking "Auto-Assign Tasks".</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SECTION 3: Answer Delegations for Others -->
|
||||
<div class="card glass-panel section-inbox" style="grid-column: span 2;">
|
||||
<h3>III. Your Inbox (Task List)</h3>
|
||||
<p class="section-desc">Answer these questions for your crewmates. Be creative and have fun with it!</p>
|
||||
<div class="inbox-list">
|
||||
{#each state.players as p}
|
||||
{#if p.other_like_from_player_id === state.player.id && !p.other_like}
|
||||
<div class="inbox-item">
|
||||
<label>What do you LIKE about {p.name}?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" class="input-field" bind:value={answerLike} placeholder="e.g. They always share their cheese"/>
|
||||
<button class="btn btn-primary" on:click={() => submitDelegatedAnswer('like', p.id, answerLike)}>Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if p.other_hate_from_player_id === state.player.id && !p.other_hate}
|
||||
<div class="inbox-item">
|
||||
<label>What do you HATE about {p.name}?</label>
|
||||
<div class="input-row">
|
||||
<input type="text" class="input-field" bind:value={answerHate} placeholder="e.g. They snore too loudly"/>
|
||||
<button class="btn btn-primary" on:click={() => submitDelegatedAnswer('hate', p.id, answerHate)}>Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if state.players.filter(p => (p.other_like_from_player_id === state.player.id && !p.other_like) || (p.other_hate_from_player_id === state.player.id && !p.other_hate)).length === 0}
|
||||
<p class="inbox-empty-message text-gray-400 italic">No pending tasks! Wait for other players to assign you tasks.</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SECTION 4: Techniques -->
|
||||
<div class="card glass-panel section-techniques" id="techniques-card" style="grid-column: span 2;">
|
||||
<h3>IV. Secret Techniques {techniquesComplete ? '✅' : '❌'}</h3>
|
||||
|
||||
{#if createdTechniques.length === 0}
|
||||
<p class="section-desc">Create 3 techniques that you will swap with other players. Make them cool or ridiculous!</p>
|
||||
<form on:submit|preventDefault={submitTechniques} id="tech-form">
|
||||
<div class="form-group">
|
||||
<label for="tech1">Technique #1:</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="tech1" placeholder="e.g. Carlo's cheese shield" bind:value={tech1} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => tech1 = getSuggestion('techniques')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tech2">Technique #2:</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="tech2" placeholder="e.g. Parabolic boarding bounce" bind:value={tech2} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => tech2 = getSuggestion('techniques')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tech3">Technique #3:</label>
|
||||
<div class="input-row">
|
||||
<input type="text" id="tech3" placeholder="e.g. Look, a three-headed gull!" bind:value={tech3} required class="input-field">
|
||||
<button type="button" class="btn btn-secondary btn-small" on:click={() => tech3 = getSuggestion('techniques')}>Suggest</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-full glow-effect" disabled={savingTechs}>Submit Techniques to Swap Pool</button>
|
||||
</form>
|
||||
{:else if createdTechniques.length === 3 && swappedTechniques.length < 3}
|
||||
<div class="submitted-techniques text-center mt-4">
|
||||
<div class="tech-chip">#1: {createdTechniques[0]}</div>
|
||||
<div class="tech-chip">#2: {createdTechniques[1]}</div>
|
||||
<div class="tech-chip">#3: {createdTechniques[2]}</div>
|
||||
<p class="waiting-box margin-top flex justify-center mt-4">
|
||||
<span class="spinner-small"></span>
|
||||
Techniques submitted! Waiting for other players to submit so we can shuffle and swap them.
|
||||
</p>
|
||||
</div>
|
||||
{:else if !techniquesComplete}
|
||||
{#if swappedTechniques.length === 3}
|
||||
<div class="max-w-4xl mx-auto space-y-6">
|
||||
<p class="text-gray-300">Drag and drop your assigned techniques onto your Face Cards:</p>
|
||||
|
||||
{#if faceError}
|
||||
<div class="alert alert-danger">{faceError}</div>
|
||||
{/if}
|
||||
|
||||
<div class="available-techniques-container">
|
||||
<h4>Available Swapped Techniques</h4>
|
||||
<p class="instruction-help">Drag a technique onto a card slot below to assign it.</p>
|
||||
<div class="techniques-drag-pool">
|
||||
{#each swappedTechniques as tech}
|
||||
<div
|
||||
draggable={tech !== jackTech && tech !== queenTech && tech !== kingTech}
|
||||
on:dragstart={(e) => e.dataTransfer.setData('text/plain', tech)}
|
||||
class="draggable-tech-chip {tech === jackTech || tech === queenTech || tech === kingTech ? 'assigned-hidden' : ''}"
|
||||
>
|
||||
<span class="drag-icon">⋮⋮</span> {tech}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Visual Card Slots Grid -->
|
||||
<div class="face-cards-slots-grid">
|
||||
|
||||
<!-- JACK SLOT -->
|
||||
<div class="face-card-slot-wrapper">
|
||||
<div class="face-card-slot {jackTech ? 'has-assignment' : ''}"
|
||||
on:dragover|preventDefault
|
||||
on:drop={(e) => {
|
||||
const tech = e.dataTransfer.getData('text/plain');
|
||||
if (tech) {
|
||||
if (queenTech === tech) queenTech = '';
|
||||
if (kingTech === tech) kingTech = '';
|
||||
jackTech = tech;
|
||||
}
|
||||
}}>
|
||||
<div class="card-bg-letter">J</div>
|
||||
<div class="card-slot-header">
|
||||
<span class="rank">J</span>
|
||||
</div>
|
||||
<div class="card-slot-body">
|
||||
<div class="card-title">Jack</div>
|
||||
<div class="drop-zone-placeholder">Drop Technique Here</div>
|
||||
<div class="assigned-tech-content">
|
||||
{#if jackTech}
|
||||
<div class="assigned-tech-chip">
|
||||
{jackTech}
|
||||
<span class="remove-tech-btn" on:click={() => jackTech = ''}>×</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-slot-footer">
|
||||
<span></span>
|
||||
<span class="rank">J</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- QUEEN SLOT -->
|
||||
<div class="face-card-slot-wrapper">
|
||||
<div class="face-card-slot {queenTech ? 'has-assignment' : ''}"
|
||||
on:dragover|preventDefault
|
||||
on:drop={(e) => {
|
||||
const tech = e.dataTransfer.getData('text/plain');
|
||||
if (tech) {
|
||||
if (jackTech === tech) jackTech = '';
|
||||
if (kingTech === tech) kingTech = '';
|
||||
queenTech = tech;
|
||||
}
|
||||
}}>
|
||||
<div class="card-bg-letter">Q</div>
|
||||
<div class="card-slot-header">
|
||||
<span class="rank">Q</span>
|
||||
</div>
|
||||
<div class="card-slot-body">
|
||||
<div class="card-title">Queen</div>
|
||||
<div class="drop-zone-placeholder">Drop Technique Here</div>
|
||||
<div class="assigned-tech-content">
|
||||
{#if queenTech}
|
||||
<div class="assigned-tech-chip">
|
||||
{queenTech}
|
||||
<span class="remove-tech-btn" on:click={() => queenTech = ''}>×</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-slot-footer">
|
||||
<span></span>
|
||||
<span class="rank">Q</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KING SLOT -->
|
||||
<div class="face-card-slot-wrapper">
|
||||
<div class="face-card-slot {kingTech ? 'has-assignment' : ''}"
|
||||
on:dragover|preventDefault
|
||||
on:drop={(e) => {
|
||||
const tech = e.dataTransfer.getData('text/plain');
|
||||
if (tech) {
|
||||
if (jackTech === tech) jackTech = '';
|
||||
if (queenTech === tech) queenTech = '';
|
||||
kingTech = tech;
|
||||
}
|
||||
}}>
|
||||
<div class="card-bg-letter">K</div>
|
||||
<div class="card-slot-header">
|
||||
<span class="rank">K</span>
|
||||
</div>
|
||||
<div class="card-slot-body">
|
||||
<div class="card-title">King</div>
|
||||
<div class="drop-zone-placeholder">Drop Technique Here</div>
|
||||
<div class="assigned-tech-content">
|
||||
{#if kingTech}
|
||||
<div class="assigned-tech-chip">
|
||||
{kingTech}
|
||||
<span class="remove-tech-btn" on:click={() => kingTech = ''}>×</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-slot-footer">
|
||||
<span></span>
|
||||
<span class="rank">K</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<button
|
||||
class="btn btn-primary btn-large w-full"
|
||||
disabled={assigningFace || !jackTech || !queenTech || !kingTech}
|
||||
on:click={assignFaceTechniques}
|
||||
>
|
||||
{assigningFace ? 'Assigning...' : 'Assign to Cards'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center italic text-gray-400">
|
||||
Waiting for all players to submit techniques so they can be shuffled...
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="assigned-techs text-center mt-4">
|
||||
<div class="tech-assignment-pill"><span class="card-rank">J</span> {state.player.tech_jack}</div>
|
||||
<div class="tech-assignment-pill"><span class="card-rank">Q</span> {state.player.tech_queen}</div>
|
||||
<div class="tech-assignment-pill"><span class="card-rank">K</span> {state.player.tech_king}</div>
|
||||
<p class="waiting-box margin-top flex justify-center mt-4">
|
||||
<span class="spinner-small"></span>
|
||||
Ready! Waiting for other players to finish J/Q/K assignment...
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- SECTION 5: Crew Creation Progress -->
|
||||
<div class="card glass-panel section-crew-status" style="grid-column: span 2;">
|
||||
<h3>V. Crew Creation Status</h3>
|
||||
<p class="section-desc">See the creation progress of the entire crew in real time.</p>
|
||||
<div class="crew-status-list">
|
||||
<ul class="space-y-2 mt-4">
|
||||
{#each state.players as p}
|
||||
<li class="p-3 bg-dark-800 rounded flex justify-between items-center border-l-4 {p.tech_jack ? 'border-green-500' : 'border-gray-500'}">
|
||||
<span>{p.name}</span>
|
||||
<span class="text-sm">
|
||||
{#if p.tech_jack}
|
||||
<span class="text-green-400">Ready</span>
|
||||
{:else if p.created_techniques && JSON.parse(p.created_techniques).length === 3}
|
||||
<span class="text-yellow-400">Assigning Face Cards</span>
|
||||
{:else}
|
||||
<span class="text-gray-400">Writing Sheet</span>
|
||||
{/if}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user