mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Adding collection store, adding buttons to add/remove from collection, toast on add/remove, random button for collection.
This commit is contained in:
parent
bb1f51dcfd
commit
7d775608cd
8 changed files with 99 additions and 6 deletions
|
|
@ -1,9 +1,22 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import type { GameType } from '$lib/types';
|
import { ToastType, type GameType } from '$lib/types';
|
||||||
|
import { collectionStore } from '$lib/stores/collectionStore';
|
||||||
|
import { toast } from '../toast/toast';
|
||||||
|
|
||||||
export let game: GameType;
|
export let game: GameType;
|
||||||
export let detailed: boolean = false;
|
export let detailed: boolean = false;
|
||||||
|
$: existsInCollection = $collectionStore.find((item: GameType) => item.id === game.id);
|
||||||
|
|
||||||
|
function addToCollection() {
|
||||||
|
collectionStore.add(game)
|
||||||
|
toast.send(`"${game.name}" added to collection!`, { duration: 3000, type: ToastType.INFO });
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFromCollection() {
|
||||||
|
collectionStore.remove(game.id)
|
||||||
|
toast.send(`Removed "${game.name}" from collection!`, { duration: 3000, type: ToastType.INFO });
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<article class="game-container" transition:fade>
|
<article class="game-container" transition:fade>
|
||||||
|
|
@ -24,6 +37,12 @@
|
||||||
<div class="description">{@html game.description}</div>
|
<div class="description">{@html game.description}</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if existsInCollection}
|
||||||
|
<button type="button" on:click={removeFromCollection}>Remove from collection -</button>
|
||||||
|
{:else}
|
||||||
|
<button type="button" on:click={addToCollection}>Add to collection +</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
@ -36,6 +55,13 @@
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: var(--color-btn-primary-active);
|
||||||
|
}
|
||||||
|
|
||||||
.game-container {
|
.game-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
||||||
26
src/lib/components/random/index.svelte
Normal file
26
src/lib/components/random/index.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<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 } from '$lib/types';
|
||||||
|
|
||||||
|
function getRandomCollectionGame() {
|
||||||
|
if ($collectionStore.length > 0) {
|
||||||
|
boredState.set({ loading: true });
|
||||||
|
let randomNumber: number = Math.round(Math.random() * $collectionStore.length - 1);
|
||||||
|
if ($collectionStore.at(randomNumber)) {
|
||||||
|
gameStore.removeAll();
|
||||||
|
gameStore.add($collectionStore.at(randomNumber));
|
||||||
|
boredState.set({ loading: false });
|
||||||
|
} else {
|
||||||
|
toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true });
|
||||||
|
}
|
||||||
|
boredState.set({ 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>
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
<form on:submit|preventDefault={handleSubmit} method="post">
|
<form on:submit|preventDefault={handleSubmit} method="post">
|
||||||
<fieldset aria-busy={submitting} disabled={submitting}>
|
<fieldset aria-busy={submitting} disabled={submitting}>
|
||||||
<input type="checkbox" id="random" name="random" hidden checked />
|
<input type="checkbox" id="random" name="random" hidden checked />
|
||||||
<button type="submit" disabled={submitting}>🎲</button>
|
<button type="submit" disabled={submitting}>Random Game 🎲</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
||||||
28
src/lib/stores/collectionStore.ts
Normal file
28
src/lib/stores/collectionStore.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import type { GameType } from '$lib/types';
|
||||||
|
|
||||||
|
// Custom store
|
||||||
|
const state = () => {
|
||||||
|
const { subscribe, set, update } = writable<GameType[]>([]);
|
||||||
|
|
||||||
|
function add(game: GameType) {
|
||||||
|
update((store) => [...store, game]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(id: string) {
|
||||||
|
update((store) => {
|
||||||
|
const newStore = store.filter((item: GameType) => item.id !== id);
|
||||||
|
return [...newStore];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeAll() {
|
||||||
|
update(() => {
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { subscribe, set, update, add, remove, removeAll };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collectionStore = state();
|
||||||
|
|
@ -3,14 +3,17 @@ export type BoredStore = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ToastType {
|
export enum ToastType {
|
||||||
INFO,
|
INFO = "INFO",
|
||||||
ERROR,
|
ERROR = "ERROR",
|
||||||
WARNING
|
WARNING = "WARNING"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToastData = {
|
export type ToastData = {
|
||||||
id: number;
|
id: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
|
dismissible: boolean;
|
||||||
|
showButton: boolean;
|
||||||
|
autoDismiss: boolean;
|
||||||
type: ToastType;
|
type: ToastType;
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@
|
||||||
import Transition from '$lib/components/transition/index.svelte';
|
import Transition from '$lib/components/transition/index.svelte';
|
||||||
import Portal from '$lib/Portal.svelte';
|
import Portal from '$lib/Portal.svelte';
|
||||||
import { boredState } from '$lib/stores/boredState';
|
import { boredState } from '$lib/stores/boredState';
|
||||||
|
import { collectionStore } from '$lib/stores/collectionStore';
|
||||||
|
import { toast } from '$lib/components/toast/toast';
|
||||||
// import 'carbon-components-svelte/css/all.css';
|
// import 'carbon-components-svelte/css/all.css';
|
||||||
import '$root/styles/styles.scss';
|
import '$root/styles/styles.scss';
|
||||||
|
import Toast from '$lib/components/toast/Toast.svelte';
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== 'production';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if dev}
|
{#if dev}
|
||||||
<Toy register={{ boredState }} />
|
<Toy register={{ boredState, collectionStore, toast }} />
|
||||||
{/if}
|
{/if}
|
||||||
<Transition transition={{ type: 'fade', duration: 250 }}>
|
<Transition transition={{ type: 'fade', duration: 250 }}>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
@ -44,6 +47,7 @@
|
||||||
<div class="background" />
|
<div class="background" />
|
||||||
</Portal>
|
</Portal>
|
||||||
{/if}
|
{/if}
|
||||||
|
<Toast duration={3000} />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
import TextSearch from '$lib/components/search/textSearch/index.svelte';
|
import TextSearch from '$lib/components/search/textSearch/index.svelte';
|
||||||
import AdvancedSearch from '$lib/components/search/advancedSearch/index.svelte';
|
import AdvancedSearch from '$lib/components/search/advancedSearch/index.svelte';
|
||||||
import RandomSearch from '$lib/components/search/random/index.svelte';
|
import RandomSearch from '$lib/components/search/random/index.svelte';
|
||||||
|
import Random from '$lib/components/random/index.svelte';
|
||||||
import { gameStore } from '$lib/stores/gameSearchStore';
|
import { gameStore } from '$lib/stores/gameSearchStore';
|
||||||
import { boredState } from '$lib/stores/boredState';
|
import { boredState } from '$lib/stores/boredState';
|
||||||
import { Checkbox } from 'carbon-components-svelte';
|
import { Checkbox } from 'carbon-components-svelte';
|
||||||
|
|
@ -27,6 +28,7 @@
|
||||||
<TextSearch />
|
<TextSearch />
|
||||||
<AdvancedSearch />
|
<AdvancedSearch />
|
||||||
<RandomSearch />
|
<RandomSearch />
|
||||||
|
<Random />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- {#if submitting}
|
<!-- {#if submitting}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
--clr-input-txt: hsl(177 100% 15%);
|
--clr-input-txt: hsl(177 100% 15%);
|
||||||
|
|
||||||
--red: #990000;
|
--red: #990000;
|
||||||
|
--tomatoOrange: #e54b4b;
|
||||||
--redBrown: #633539;
|
--redBrown: #633539;
|
||||||
--blue: #336699;
|
--blue: #336699;
|
||||||
--black: #1f273a;
|
--black: #1f273a;
|
||||||
|
|
@ -127,6 +128,9 @@
|
||||||
--rounded-4: 4px;
|
--rounded-4: 4px;
|
||||||
--rounded-20: 20px;
|
--rounded-20: 20px;
|
||||||
|
|
||||||
|
--toast-background: var(--color-brand);
|
||||||
|
--toast-error-background: var(--tomatoOrange);
|
||||||
|
|
||||||
/* Media Queryies - Not yet supported in CSS */
|
/* Media Queryies - Not yet supported in CSS */
|
||||||
/*
|
/*
|
||||||
--xsmall: 340px;
|
--xsmall: 340px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue