floriferous: add basic score calculator component

This commit is contained in:
Thomas 2022-08-29 21:53:36 +01:00
parent 70e7e982e9
commit 579da441d1
3 changed files with 279 additions and 34 deletions

View file

@ -3,6 +3,7 @@
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
import type { PageData } from './$types.js'; import type { PageData } from './$types.js';
import Navbar from '$lib/components/Navbar.svelte'; import Navbar from '$lib/components/Navbar.svelte';
import FloriferousScoreCalculator from './FloriferousScoreCalculator.svelte';
import { FloriferousGame } from '../../../lib/floriferous/floriferous-game.js'; import { FloriferousGame } from '../../../lib/floriferous/floriferous-game.js';
import type { FloriferousPlayer } from '../../../lib/floriferous'; import type { FloriferousPlayer } from '../../../lib/floriferous';
@ -19,6 +20,8 @@
let previousGames: FloriferousGame[] = data.previousGames; let previousGames: FloriferousGame[] = data.previousGames;
let apiPassword = ''; let apiPassword = '';
let players: FloriferousPlayer[] = []; let players: FloriferousPlayer[] = [];
let isScoreCalculatorVisible = true;
let isPlayersVisible = false;
let isPreviousScoresVisible = false; let isPreviousScoresVisible = false;
let isWinnerVisible = false; let isWinnerVisible = false;
let isSaveSubmitting = false; let isSaveSubmitting = false;
@ -92,9 +95,30 @@
abundance of nature. abundance of nature.
</p> </p>
<section class="players"> <section class="score-calculator">
<h2>Players</h2> <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} {#if players.length > 0}
<ul> <ul>
{#each players as player} {#each players as player}
@ -129,6 +153,7 @@
<h3>Add a New Player</h3> <h3>Add a New Player</h3>
<FloriferousPlayerForm on:submit={onAddPlayer} /> <FloriferousPlayerForm on:submit={onAddPlayer} />
{/if} {/if}
{/if}
</section> </section>
{#if previousGames.length > 0} {#if previousGames.length > 0}
@ -147,6 +172,26 @@
max-width: 600px; 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 { .previous-games {
padding: var(--spacing-md) 0; padding: var(--spacing-md) 0;
width: 100%; width: 100%;

View 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>

View file

@ -131,3 +131,15 @@ ol {
text-decoration: none; text-decoration: none;
cursor: pointer; 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;
}