mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Update toast to be in the bottom middle, error for fetching game data, fixing random from collection.
This commit is contained in:
parent
226c9454c7
commit
49464d3fba
10 changed files with 174 additions and 127 deletions
|
|
@ -14,6 +14,8 @@
|
|||
--background-without-opacity: rgba(255, 255, 255, 0.7);
|
||||
--column-width: 42rem;
|
||||
--column-margin-top: 4rem;
|
||||
--z-highest: 100;
|
||||
--cardBorderRadius: 12px;
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@
|
|||
<div class="game-info">
|
||||
<h2>{game.name}</h2>
|
||||
<a class="thumbnail" href={`/game/${game.id}`}>
|
||||
<img width="140" height="140" src={game.thumb_url} alt={`Image of ${game.name}`} />
|
||||
<img src={game.thumb_url} alt={`Image of ${game.name}`} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{#if !minimal}
|
||||
{#if !minimal && game?.players && game?.playtime}
|
||||
<div class="game-details">
|
||||
{#if game.year_published}
|
||||
<p>{game.year_published}</p>
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<p>{game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
|
||||
<p>{game.playtime} minutes</p>
|
||||
<p>Minimum Age: {game.min_age}</p>
|
||||
<a href={`/game/${game.id}`}>View Game</a>
|
||||
<!-- <a href={`/game/${game.id}`}>View Game</a> -->
|
||||
{#if detailed}
|
||||
<div class="description">{@html game.description}</div>
|
||||
{/if}
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
|
||||
<style lang="scss">
|
||||
img {
|
||||
border-radius: 10px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
button {
|
||||
|
|
@ -84,6 +84,7 @@
|
|||
|
||||
.game-container {
|
||||
display: flex;
|
||||
place-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (max-width: 650px) {
|
||||
|
|
@ -101,7 +102,8 @@
|
|||
|
||||
.game-info {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
place-items: center;
|
||||
gap: 0.75rem;
|
||||
margin: 0.2rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +1,48 @@
|
|||
<script lang="ts">
|
||||
import { boredState } from '$lib/stores/boredState';
|
||||
import { gameStore } from '$lib/stores/gameSearchStore';
|
||||
import { collectionStore } from '$lib/stores/collectionStore';
|
||||
import { toast } from '$lib/components/toast/toast';
|
||||
import { ToastType, type SavedGameType } from '$lib/types';
|
||||
import { boredState } from '$lib/stores/boredState';
|
||||
import { gameStore } from '$lib/stores/gameSearchStore';
|
||||
import { collectionStore } from '$lib/stores/collectionStore';
|
||||
import { toast } from '$lib/components/toast/toast';
|
||||
import { ToastType, type SavedGameType } from '$lib/types';
|
||||
import { mapSavedGameToGame } from '$root/lib/util/gameMapper';
|
||||
|
||||
async function getRandomCollectionGame() {
|
||||
if ($collectionStore.length > 0) {
|
||||
boredState.update((n) => ({ ...n, loading: true }));
|
||||
let randomNumber: number = Math.round(Math.random() * $collectionStore.length - 1);
|
||||
if ($collectionStore.at(randomNumber)) {
|
||||
gameStore.removeAll();
|
||||
const randomGame: SavedGameType = $collectionStore.at(randomNumber)!;
|
||||
const response = await fetch(`/api/game/${randomGame?.id}`, {
|
||||
method: 'GET',
|
||||
headers: { accept: 'application/json' }
|
||||
});
|
||||
const responseData = await response.json();
|
||||
console.log('responseData', responseData);
|
||||
gameStore.add(responseData?.game);
|
||||
boredState.update((n) => ({ ...n, loading: false }));
|
||||
} else {
|
||||
toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true });
|
||||
}
|
||||
boredState.update((n) => ({ ...n, loading: false }));
|
||||
} else {
|
||||
toast.send('No items in your collection!', {
|
||||
duration: 3000,
|
||||
type: ToastType.ERROR,
|
||||
dismissible: true
|
||||
});
|
||||
}
|
||||
}
|
||||
async function getRandomCollectionGame() {
|
||||
if ($collectionStore.length > 0) {
|
||||
boredState.update((n) => ({ ...n, loading: true }));
|
||||
let randomNumber: number = Math.round(Math.random() * $collectionStore.length - 1);
|
||||
if ($collectionStore.at(randomNumber)) {
|
||||
gameStore.removeAll();
|
||||
const randomGame: SavedGameType = $collectionStore.at(randomNumber)!;
|
||||
// const response = await fetch(`/api/game/${randomGame?.id}`, {
|
||||
// method: 'GET',
|
||||
// headers: { accept: 'application/json' }
|
||||
// });
|
||||
// const responseData = await response.json();
|
||||
// console.log('responseData', responseData);
|
||||
// gameStore.add(responseData?.game);
|
||||
const game = gameStore.add(mapSavedGameToGame(randomGame));
|
||||
boredState.update((n) => ({ ...n, loading: false }));
|
||||
} else {
|
||||
toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true });
|
||||
}
|
||||
boredState.update((n) => ({ ...n, loading: false }));
|
||||
} else {
|
||||
toast.send('No items in your collection!', {
|
||||
duration: 3000,
|
||||
type: ToastType.ERROR,
|
||||
dismissible: true
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="btn" type="button" on:click={() => getRandomCollectionGame()}
|
||||
>Random from collection 🎲</button
|
||||
>Random from collection 🎲</button
|
||||
>
|
||||
|
||||
<style lang="scss">
|
||||
button {
|
||||
max-width: 450px;
|
||||
padding: var(--spacing-8) var(--spacing-16);
|
||||
}
|
||||
button {
|
||||
max-width: 450px;
|
||||
padding: var(--spacing-8) var(--spacing-16);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,11 @@
|
|||
console.log('In success');
|
||||
const resultGames = result?.data?.games;
|
||||
if (resultGames?.length <= 0) {
|
||||
toast.send('No results!', { duration: 3000, type: ToastType.INFO, dismissible: true });
|
||||
toast.send('No results found 😿', {
|
||||
duration: 3000,
|
||||
type: ToastType.INFO,
|
||||
dismissible: true
|
||||
});
|
||||
}
|
||||
gameStore.addAll(resultGames);
|
||||
console.log(`Frontend result: ${JSON.stringify(result)}`);
|
||||
|
|
|
|||
|
|
@ -1,87 +1,94 @@
|
|||
<script lang="ts">
|
||||
import { fly, fade } from 'svelte/transition';
|
||||
import { flip } from 'svelte/animate';
|
||||
import Portal from '../../Portal.svelte';
|
||||
import ToastMessage from './ToastMessage.svelte';
|
||||
import { toast } from './toast';
|
||||
import { fly, fade } from 'svelte/transition';
|
||||
import { flip } from 'svelte/animate';
|
||||
import Portal from '../../Portal.svelte';
|
||||
import ToastMessage from './ToastMessage.svelte';
|
||||
import { toast } from './toast';
|
||||
</script>
|
||||
|
||||
<Portal>
|
||||
<div class="toast-wrapper">
|
||||
{#each $toast as toastData (toastData.id)}
|
||||
<div
|
||||
aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`}
|
||||
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
|
||||
in:fly={{ opacity: 0, x: 100 }}
|
||||
out:fade
|
||||
animate:flip
|
||||
class={`toast ${toastData.type.toLowerCase()}`}
|
||||
>
|
||||
<ToastMessage {toastData} />
|
||||
{#if toastData.dismissible && toastData.showButton}
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Click to dismiss"
|
||||
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
|
||||
class="close"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
><path
|
||||
d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z"
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="toast-wrapper">
|
||||
{#each $toast as toastData (toastData.id)}
|
||||
<div
|
||||
aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`}
|
||||
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
|
||||
on:keydown={() => toastData.dismissible && toast.remove(toastData.id)}
|
||||
in:fly={{ opacity: 0, x: 100 }}
|
||||
out:fade
|
||||
animate:flip
|
||||
class={`toast ${toastData.type.toLowerCase()}`}
|
||||
>
|
||||
<ToastMessage {toastData} />
|
||||
{#if toastData.dismissible && toastData.showButton}
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Click to dismiss"
|
||||
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
|
||||
class="close"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
><path
|
||||
d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z"
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
/></svg
|
||||
>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Portal>
|
||||
|
||||
<style lang="scss">
|
||||
.toast-wrapper {
|
||||
position: fixed;
|
||||
bottom: 5px;
|
||||
right: 25px;
|
||||
}
|
||||
.toast-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
bottom: 5vh;
|
||||
width: 100vw;
|
||||
z-index: calc(var(--z-highest) + 10);
|
||||
}
|
||||
|
||||
.toast {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
place-items: center;
|
||||
.toast {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin: 1rem 1rem 0;
|
||||
min-width: 460px;
|
||||
color: white;
|
||||
background: var(--toast-background, #625df5);
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
|
||||
width: 30rem;
|
||||
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin-bottom: 1rem;
|
||||
color: white;
|
||||
background: var(--toast-background, #625df5);
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
|
||||
.close {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
opacity: 1;
|
||||
transition: ease 0.3s;
|
||||
|
||||
.close {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
opacity: 1;
|
||||
transition: ease 0.3s;
|
||||
&:hover,
|
||||
&:focus {
|
||||
transition: ease 0.3s;
|
||||
background-color: #625df5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
transition: ease 0.3s;
|
||||
background-color: #625df5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
background: var(--toast-error-background, #e54b4b);
|
||||
color: black;
|
||||
}
|
||||
.toast.error {
|
||||
background: var(--toast-error-background, #e54b4b);
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
import type { GameType } from '$lib/types';
|
||||
import type { GameType, SavedGameType } from '$lib/types';
|
||||
|
||||
export function mapSavedGameToGame(game: SavedGameType): GameType {
|
||||
const { id, name, thumb_url } = game;
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
thumb_url
|
||||
};
|
||||
}
|
||||
|
||||
export function mapAPIGameToBoredGame(game): GameType {
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<h1>The page you requested doesn't exist!</h1>
|
||||
<h1>The page you requested doesn't exist! 🤷♂️</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
margin-top: var(--spacing-64);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-32);
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
margin-top: var(--spacing-64);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-32);
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -90,7 +90,11 @@
|
|||
console.log('In success');
|
||||
const resultGames = result?.data?.games;
|
||||
if (resultGames?.length <= 0) {
|
||||
toast.send('No results!', { duration: 3000, type: ToastType.INFO, dismissible: true });
|
||||
toast.send('No results found 😿', {
|
||||
duration: 3000,
|
||||
type: ToastType.ERROR,
|
||||
dismissible: true
|
||||
});
|
||||
}
|
||||
gameStore.addAll(resultGames);
|
||||
totalItems = result?.data?.totalCount;
|
||||
|
|
|
|||
12
src/routes/game/[id]/+error.svelte
Normal file
12
src/routes/game/[id]/+error.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<h1>Unable to load board game info! 🤦♂️</h1>
|
||||
<h2>Please try again later. 🙇🏼</h2>
|
||||
|
||||
<style>
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: var(--spacing-64);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--font-32);
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -127,6 +127,10 @@
|
|||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
|
|||
Loading…
Reference in a new issue