mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Creating Button and Link with Icon components, formatting error on advanced search, and adding more to the local storage saved Game.
This commit is contained in:
parent
c1d4e5a2d9
commit
06a7d342a3
9 changed files with 116 additions and 37 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -8,3 +8,4 @@ node_modules
|
||||||
!.env.example
|
!.env.example
|
||||||
.vercel
|
.vercel
|
||||||
.output
|
.output
|
||||||
|
.idea
|
||||||
25
src/lib/components/LinkWithIcon.svelte
Normal file
25
src/lib/components/LinkWithIcon.svelte
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { SvelteComponentTyped } from 'svelte';
|
||||||
|
|
||||||
|
export let url: string;
|
||||||
|
export let ariaLabel = `Link to ${url}`;
|
||||||
|
export let external = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={url}
|
||||||
|
target={external ? '_blank' : '_self'}
|
||||||
|
rel="noreferrer"
|
||||||
|
aria-label={`Board Game Atlas Link for ${ariaLabel}`}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, auto);
|
||||||
|
place-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
37
src/lib/components/button/index.svelte
Normal file
37
src/lib/components/button/index.svelte
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export let kind = 'primary';
|
||||||
|
export let size;
|
||||||
|
export let icon = false;
|
||||||
|
export let disabled = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class={`btn ${icon ? 'btn-icon' : ''} ${kind}`} type="button" {disabled} on:click>
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
max-width: 30rem;
|
||||||
|
background-color: var(--color-btn-primary-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger {
|
||||||
|
background-color: var(--warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger:hover {
|
||||||
|
background-color: var(--warning-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, auto);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -28,27 +28,22 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<article class="game-container" transition:fade>
|
<article class="game-container" transition:fade>
|
||||||
<!-- <div class="game-info"> -->
|
|
||||||
<h2>{game.name}</h2>
|
<h2>{game.name}</h2>
|
||||||
<a class="thumbnail" href={`/game/${game.id}`}>
|
<a class="thumbnail" href={`/game/${game.id}`}>
|
||||||
<img src={game.thumb_url} alt={`Image of ${game.name}`} />
|
<img src={game.thumb_url} alt={`Image of ${game.name}`} />
|
||||||
</a>
|
</a>
|
||||||
<!-- </div> -->
|
|
||||||
|
|
||||||
{#if !minimal && game?.players && game?.playtime}
|
<div class="game-details">
|
||||||
<div class="game-details">
|
<p>Players: {game.min_players} - {game.max_players}</p>
|
||||||
{#if game.year_published}
|
<p>Time: {game.playtime} minutes</p>
|
||||||
<p>{game.year_published}</p>
|
{#if game?.min_age}
|
||||||
{/if}
|
<p>Min Age: {game.min_age}</p>
|
||||||
<p>{game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
|
{/if}
|
||||||
<p>{game.playtime} minutes</p>
|
{#if detailed}
|
||||||
<p>Minimum Age: {game.min_age}</p>
|
<div class="description">{@html game.description}</div>
|
||||||
<!-- <a href={`/game/${game.id}`}>View Game</a> -->
|
{/if}
|
||||||
{#if detailed}
|
</div>
|
||||||
<div class="description">{@html game.description}</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div class="game-buttons">
|
<div class="game-buttons">
|
||||||
{#if existsInCollection}
|
{#if existsInCollection}
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{#if form?.error?.id === 'minPlayers'}
|
{#if form?.error?.id === 'minPlayers'}
|
||||||
{form.error.message}
|
<p aria-label={`Error: ${form.error.message}`} class="center error">
|
||||||
|
Error: {form.error.message}
|
||||||
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -65,6 +67,11 @@
|
||||||
bind:checked={exactMaxPlayers}
|
bind:checked={exactMaxPlayers}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
{#if form?.error?.id === 'maxPlayers'}
|
||||||
|
<p aria-label={`Error: ${form.error.message}`} class="center error">
|
||||||
|
Error: {form.error.message}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!-- <button type="submit" disabled={submitting}>Submit</button> -->
|
<!-- <button type="submit" disabled={submitting}>Submit</button> -->
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ export type SavedGameType = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
thumb_url: string;
|
thumb_url: string;
|
||||||
|
min_players: number;
|
||||||
|
max_players: number;
|
||||||
|
playtime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GameType = {
|
export type GameType = {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
import type { GameType, SavedGameType } from '$lib/types';
|
import type { GameType, SavedGameType } from '$lib/types';
|
||||||
|
|
||||||
export function mapSavedGameToGame(game: SavedGameType): GameType {
|
export function mapSavedGameToGame(game: SavedGameType): GameType {
|
||||||
const { id, name, thumb_url } = game;
|
const { id, name, thumb_url, min_players, max_players, playtime } = game;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
thumb_url
|
thumb_url,
|
||||||
|
min_players,
|
||||||
|
max_players,
|
||||||
|
playtime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@
|
||||||
} from '@rgossiaux/svelte-heroicons/outline';
|
} from '@rgossiaux/svelte-heroicons/outline';
|
||||||
import type { GameType, SavedGameType } from '$lib/types';
|
import type { GameType, SavedGameType } from '$lib/types';
|
||||||
import { collectionStore } from '$lib/stores/collectionStore';
|
import { collectionStore } from '$lib/stores/collectionStore';
|
||||||
|
import Button from '$lib/components/button/index.svelte';
|
||||||
import RemoveCollectionDialog from '$root/lib/components/dialog/RemoveCollectionDialog.svelte';
|
import RemoveCollectionDialog from '$root/lib/components/dialog/RemoveCollectionDialog.svelte';
|
||||||
import { addToCollection } from '$lib/util/manipulateCollection';
|
import { addToCollection } from '$lib/util/manipulateCollection';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { boredState } from '$root/lib/stores/boredState';
|
import { boredState } from '$root/lib/stores/boredState';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
|
import LinkWithIcon from '$root/lib/components/LinkWithIcon.svelte';
|
||||||
|
|
||||||
$: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id);
|
$: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id);
|
||||||
|
|
||||||
|
|
@ -55,38 +57,36 @@
|
||||||
</div>
|
</div>
|
||||||
<div style="display: grid; place-items: center;">
|
<div style="display: grid; place-items: center;">
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<p>Year Published: {game?.year_published}</p>
|
<p>Year: {game?.year_published}</p>
|
||||||
<p>Players: {game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
|
<p>Players: {game.players}</p>
|
||||||
<p>Playtime: {game.playtime} minutes</p>
|
<p>Playtime: {game.playtime} minutes</p>
|
||||||
<p>Minimum Age: {game.min_age}</p>
|
<p>Minimum Age: {game.min_age}</p>
|
||||||
{#if +game?.price !== 0.0}
|
{#if game?.price !== 0.0}
|
||||||
<p>Price: ${game?.price}</p>
|
<p>Price: ${game?.price}</p>
|
||||||
{/if}
|
{/if}
|
||||||
<a
|
<LinkWithIcon external ariaLabel={`Board Game Atlas Link for ${game.name}`} url={game.url}>
|
||||||
class="with-icon"
|
Board Game Atlas <ExternalLinkIcon width="24" height="24" />
|
||||||
href={game.url}
|
</LinkWithIcon>
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
aria-label={`Board Game Atlas Link for ${game.name}`}
|
|
||||||
>Board Game Atlas <ExternalLinkIcon width="24" height="24" /></a
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{#if existsInCollection}
|
{#if existsInCollection}
|
||||||
<button class="btn button-icon remove" type="button" on:click={() => removeGame()}
|
<Button size="md" kind="danger" icon on:click={() => removeGame()}>
|
||||||
>Remove from collection <MinusCircleIcon width="24" height="24" /></button
|
Remove from collection <MinusCircleIcon width="24" height="24" />
|
||||||
>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<Button
|
||||||
class="btn"
|
size="md"
|
||||||
type="button"
|
kind="primary"
|
||||||
|
icon
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
addToCollection(game);
|
addToCollection(game);
|
||||||
if (browser) {
|
if (browser) {
|
||||||
localStorage.collection = JSON.stringify($collectionStore);
|
localStorage.collection = JSON.stringify($collectionStore);
|
||||||
}
|
}
|
||||||
}}>Add to collection <PlusCircleIcon width="24" height="24" /></button
|
}}
|
||||||
>
|
>
|
||||||
|
Add to collection <PlusCircleIcon width="24" height="24" />
|
||||||
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -348,4 +348,12 @@ ol {
|
||||||
.icon {
|
.icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--tomatoOrange);
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue