mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Save and clear collection from storage. Load from user storage into collection store on page load.
This commit is contained in:
parent
213cb8ed74
commit
470c0b051e
6 changed files with 189 additions and 16 deletions
|
|
@ -15,8 +15,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<div><Themes /></div>
|
<!-- <div><Themes /></div> -->
|
||||||
<!-- <div><Profile /></div> -->
|
<div><Profile /></div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
||||||
43
src/lib/components/preferences/gameCollection.svelte
Normal file
43
src/lib/components/preferences/gameCollection.svelte
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { browser } from '$app/env';
|
||||||
|
import { collectionStore } from '$root/lib/stores/collectionStore';
|
||||||
|
import { ToastType } from '$root/lib/types';
|
||||||
|
import { SaveIcon } from '@rgossiaux/svelte-heroicons/outline';
|
||||||
|
import { toast } from '../toast/toast';
|
||||||
|
|
||||||
|
function saveCollection() {
|
||||||
|
console.log('Saving collection');
|
||||||
|
console.log('collectionStore', $collectionStore);
|
||||||
|
if (!browser) return;
|
||||||
|
localStorage.collection = JSON.stringify($collectionStore);
|
||||||
|
toast.send("Saved collection", { duration: 3000, type: ToastType.INFO });
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCollection() {
|
||||||
|
if (!browser) return;
|
||||||
|
localStorage.collection = [];
|
||||||
|
toast.send("Cleared collection", { duration: 3000, type: ToastType.INFO });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="button" on:click={() => saveCollection()}><SaveIcon class="preferences-icon" /> Save Collection</button>
|
||||||
|
<button type="button" on:click={() => clearCollection()}><SaveIcon class="preferences-icon" /> Clear Collection</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(.preferences-icon) {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,25 +1,141 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
import { Popover, PopoverButton, PopoverPanel } from '@rgossiaux/svelte-headlessui';
|
import { Popover, PopoverButton, PopoverPanel } from '@rgossiaux/svelte-headlessui';
|
||||||
|
import { CogIcon } from '@rgossiaux/svelte-heroicons/outline'
|
||||||
|
import Themes from './themes.svelte';
|
||||||
|
import GameCollection from './gameCollection.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Popover style="position: relative;">
|
<div class="container">
|
||||||
<PopoverButton>Solutions</PopoverButton>
|
<Popover let:open class="popover">
|
||||||
|
<PopoverButton aria-label="Preferences">
|
||||||
|
<CogIcon width="24" height="24" />
|
||||||
|
</PopoverButton>
|
||||||
|
|
||||||
<PopoverPanel style="position: absolute; z-index: 10;">
|
{#if open}
|
||||||
<div class="panel-contents">
|
<div transition:fade={{ duration: 100 }}>
|
||||||
<a href="/analytics">Analytics</a>
|
<PopoverPanel class="popover-panel" static>
|
||||||
<a href="/engagement">Engagement</a>
|
<div class="preferences">
|
||||||
<a href="/security">Security</a>
|
<svg
|
||||||
<a href="/integrations">Integrations</a>
|
width="24"
|
||||||
</div>
|
height="24"
|
||||||
|
class="arrow"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
id="inside"
|
||||||
|
d="M23 24H1L11.0909 1.98341C11.4474 1.20562 12.5526 1.20562 12.9091 1.98341L23 24Z"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="outside"
|
||||||
|
d="M12.8944 1.78885L24 24H23L12.9021 2.88628C12.5396 2.12822 11.4604 2.12822 11.0979 2.88628L1 24H0L11.1056 1.78885C11.4741 1.05181 12.5259 1.0518 12.8944 1.78885Z"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
<img src="/solutions.jpg" alt="" />
|
<span class="title">Preferences</span>
|
||||||
</PopoverPanel>
|
|
||||||
</Popover>
|
<div class="options">
|
||||||
|
<Themes />
|
||||||
|
<GameCollection />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PopoverPanel>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.panel-contents {
|
.panel-contents {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container :global(.popover) {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container :global(.popover-panel) {
|
||||||
|
position: absolute;
|
||||||
|
top: 48px;
|
||||||
|
right: -22px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences {
|
||||||
|
background-image: var(--clr-menu-bg);
|
||||||
|
padding: var(--spacing-24);
|
||||||
|
border: 1px solid var(--clr-menu-border);
|
||||||
|
border-radius: var(--rounded-20);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: -23px;
|
||||||
|
right: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .arrow #inside {
|
||||||
|
fill: var(--clr-menu-arrow-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .arrow #outside {
|
||||||
|
fill: var(--clr-menu-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .title {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: var(--spacing-8);
|
||||||
|
font-size: var(--font-24);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 32px;
|
||||||
|
border-bottom: 1px solid var(--clr-menu-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--clr-menu-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options > :global(*) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-32);
|
||||||
|
padding: var(--spacing-24) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options > :global(*:not(:last-child)) {
|
||||||
|
border-bottom: 1px solid var(--clr-menu-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options > :global(*:last-child) {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options span {
|
||||||
|
max-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 480px) {
|
||||||
|
.preferences {
|
||||||
|
width: 420px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preferences .options > :global(*) {
|
||||||
|
gap: var(--spacing-64);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,12 @@ import type { GameType } from '$lib/types';
|
||||||
const state = () => {
|
const state = () => {
|
||||||
const { subscribe, set, update } = writable<GameType[]>([]);
|
const { subscribe, set, update } = writable<GameType[]>([]);
|
||||||
|
|
||||||
|
function addAll(games: GameType[]) {
|
||||||
|
for (const game of games) {
|
||||||
|
add(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function add(game: GameType) {
|
function add(game: GameType) {
|
||||||
update((store) => [...store, game]);
|
update((store) => [...store, game]);
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +28,7 @@ const state = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { subscribe, set, update, add, remove, removeAll };
|
return { subscribe, set, update, add, addAll, remove, removeAll };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const collectionStore = state();
|
export const collectionStore = state();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { browser } from '$app/env';
|
||||||
import { Toy } from '@leveluptuts/svelte-toy';
|
import { Toy } from '@leveluptuts/svelte-toy';
|
||||||
import Header from '$lib/components/header/Header.svelte';
|
import Header from '$lib/components/header/Header.svelte';
|
||||||
import Loading from '$lib/components/loading.svelte';
|
import Loading from '$lib/components/loading.svelte';
|
||||||
|
|
@ -11,6 +12,14 @@
|
||||||
import '$root/styles/styles.scss';
|
import '$root/styles/styles.scss';
|
||||||
import Toast from '$lib/components/toast/Toast.svelte';
|
import Toast from '$lib/components/toast/Toast.svelte';
|
||||||
|
|
||||||
|
if (browser) {
|
||||||
|
const collection = JSON.parse(localStorage.collection);
|
||||||
|
console.log('collection', collection);
|
||||||
|
if (collection) {
|
||||||
|
collectionStore.addAll(collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== 'production';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.game-search {
|
.game-search {
|
||||||
margin: 1rem;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: var(--level-2);
|
box-shadow: var(--level-2);
|
||||||
background: rgba(0, 0, 0, 0.02);
|
background: rgba(0, 0, 0, 0.02);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue