floriferous: add basic score calculator component
This commit is contained in:
parent
70e7e982e9
commit
579da441d1
3 changed files with 279 additions and 34 deletions
|
|
@ -3,6 +3,7 @@
|
|||
import { slide } from 'svelte/transition';
|
||||
import type { PageData } from './$types.js';
|
||||
import Navbar from '$lib/components/Navbar.svelte';
|
||||
import FloriferousScoreCalculator from './FloriferousScoreCalculator.svelte';
|
||||
|
||||
import { FloriferousGame } from '../../../lib/floriferous/floriferous-game.js';
|
||||
import type { FloriferousPlayer } from '../../../lib/floriferous';
|
||||
|
|
@ -19,6 +20,8 @@
|
|||
let previousGames: FloriferousGame[] = data.previousGames;
|
||||
let apiPassword = '';
|
||||
let players: FloriferousPlayer[] = [];
|
||||
let isScoreCalculatorVisible = true;
|
||||
let isPlayersVisible = false;
|
||||
let isPreviousScoresVisible = false;
|
||||
let isWinnerVisible = false;
|
||||
let isSaveSubmitting = false;
|
||||
|
|
@ -92,9 +95,30 @@
|
|||
abundance of nature.
|
||||
</p>
|
||||
|
||||
<section class="players">
|
||||
<h2>Players</h2>
|
||||
<section class="score-calculator">
|
||||
<div class="score-calculator__header">
|
||||
<h2>Score Calculator</h2>
|
||||
{#if isScoreCalculatorVisible}
|
||||
<button on:click={() => (isScoreCalculatorVisible = false)}>Hide</button>
|
||||
{:else}
|
||||
<button on:click={() => (isScoreCalculatorVisible = true)}>Show</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<FloriferousScoreCalculator isVisible={isScoreCalculatorVisible} />
|
||||
</section>
|
||||
|
||||
<section class="players">
|
||||
<div class="players__header">
|
||||
<h2>Players</h2>
|
||||
{#if isPlayersVisible}
|
||||
<button on:click={() => (isPlayersVisible = false)}>Hide</button>
|
||||
{:else}
|
||||
<button on:click={() => (isPlayersVisible = true)}>Show</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if isPlayersVisible}
|
||||
{#if players.length > 0}
|
||||
<ul>
|
||||
{#each players as player}
|
||||
|
|
@ -129,6 +153,7 @@
|
|||
<h3>Add a New Player</h3>
|
||||
<FloriferousPlayerForm on:submit={onAddPlayer} />
|
||||
{/if}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{#if previousGames.length > 0}
|
||||
|
|
@ -147,6 +172,26 @@
|
|||
max-width: 600px;
|
||||
}
|
||||
|
||||
.players {
|
||||
padding: var(--spacing-md) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.players__header {
|
||||
display: grid;
|
||||
grid-template-columns: auto min-content;
|
||||
}
|
||||
|
||||
.score-calculator {
|
||||
padding: var(--spacing-md) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.score-calculator__header {
|
||||
display: grid;
|
||||
grid-template-columns: auto min-content;
|
||||
}
|
||||
|
||||
.previous-games {
|
||||
padding: var(--spacing-md) 0;
|
||||
width: 100%;
|
||||
|
|
|
|||
188
src/routes/games/floriferous/FloriferousScoreCalculator.svelte
Normal file
188
src/routes/games/floriferous/FloriferousScoreCalculator.svelte
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
export let isVisible: boolean;
|
||||
|
||||
let currentScore = 0;
|
||||
let actions = [];
|
||||
|
||||
let newActionScore = 0;
|
||||
let newActionName = '';
|
||||
let newActionNameInput;
|
||||
let isNewActionNameVisible = false;
|
||||
|
||||
function incrementNewActionScore() {
|
||||
newActionScore += 1;
|
||||
}
|
||||
|
||||
function decrementNewActionScore() {
|
||||
newActionScore -= 1;
|
||||
}
|
||||
|
||||
function onNewActionSubmit(score: number, name = '') {
|
||||
actions = [...actions, { score, name }];
|
||||
currentScore += score;
|
||||
newActionScore = 0;
|
||||
newActionName = '';
|
||||
}
|
||||
|
||||
function toggleIsNewActionNameVisible() {
|
||||
isNewActionNameVisible = true;
|
||||
newActionNameInput.focus();
|
||||
newActionName = '';
|
||||
}
|
||||
|
||||
const suggestedDescriptions = [
|
||||
'Arrangement Card',
|
||||
'Desire Card',
|
||||
'Bounty',
|
||||
'Stones',
|
||||
'Cup of Tea'
|
||||
];
|
||||
</script>
|
||||
|
||||
{#if isVisible}
|
||||
<div transition:slide>
|
||||
<div>
|
||||
<p>Your score is {currentScore}</p>
|
||||
|
||||
<ul class="actions-list">
|
||||
{#each actions as action}
|
||||
<li class="actions-list__item">
|
||||
+{action.score}
|
||||
{#if action.name.length > 0} ({action.name}) {/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form
|
||||
class="form"
|
||||
on:submit|preventDefault={() => onNewActionSubmit(newActionScore, newActionName)}
|
||||
>
|
||||
<div class="form-field">
|
||||
<label class="form__label" for="points">Points*</label>
|
||||
<input required name="points" type="number" bind:value={newActionScore} step="1" />
|
||||
</div>
|
||||
|
||||
<div class="increment-decrement">
|
||||
<button type="button" on:click={decrementNewActionScore}>-</button>
|
||||
<button type="button" on:click={incrementNewActionScore}>+</button>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<fieldset class="suggested-descriptions">
|
||||
<legend>Reason for Points</legend>
|
||||
{#each suggestedDescriptions as suggestion}
|
||||
<label
|
||||
class="suggested-descriptions__label"
|
||||
class:selected={newActionName === suggestion}
|
||||
for={`suggestion-${suggestion}`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name="suggestion"
|
||||
id={`suggestion-${suggestion}`}
|
||||
value={suggestion}
|
||||
class="suggested-descriptions__item"
|
||||
on:click={() => (newActionName = suggestion)}
|
||||
checked={newActionName === suggestion}
|
||||
/>
|
||||
{suggestion}</label
|
||||
>
|
||||
{/each}
|
||||
<label class="suggested-descriptions__item">
|
||||
<button
|
||||
type="button"
|
||||
class="suggested-descriptions__button"
|
||||
on:click={toggleIsNewActionNameVisible}
|
||||
>
|
||||
Other
|
||||
</button>
|
||||
</label>
|
||||
<input
|
||||
transition:slide
|
||||
name="action-name"
|
||||
type="text"
|
||||
step="1"
|
||||
class:sr-only={!isNewActionNameVisible}
|
||||
bind:value={newActionName}
|
||||
bind:this={newActionNameInput}
|
||||
/>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="submit">
|
||||
<input type="submit" value="Add Points" class="thomaswilson-button form__submit" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.actions-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.actions-list__item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
gap: var(--spacing-md);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form__label {
|
||||
font-size: var(--font-size-md);
|
||||
}
|
||||
|
||||
.form-field {
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
}
|
||||
|
||||
.increment-decrement {
|
||||
padding: var(--spacing-md) 0;
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.suggested-descriptions {
|
||||
padding: var(--spacing-sm);
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
}
|
||||
|
||||
.suggested-descriptions__item {
|
||||
padding: var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.suggested-descriptions__label {
|
||||
border: none;
|
||||
background: transparent;
|
||||
text-decoration: underline;
|
||||
transition: all 0.15s;
|
||||
padding: var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.suggested-descriptions__label.selected {
|
||||
color: var(--brand-blue);
|
||||
}
|
||||
|
||||
.submit {
|
||||
padding-top: var(--spacing-lg);
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form__submit {
|
||||
background: var(--brand-blue);
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -131,3 +131,15 @@ ol {
|
|||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue