Functioning Game and Group Dropdowns with svelte storage

This commit is contained in:
Neshura 2023-08-12 19:58:23 +02:00
parent f5a2d32adf
commit 1c92cb8418
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
8 changed files with 314 additions and 16 deletions

View file

@ -0,0 +1,66 @@
<script lang="ts">
export let showDropdown = false;
export let dropdownTitle = 'Dropdown';
export let dropdownId: string;
const toggleDropdown = () => {
showDropdown = !showDropdown;
document.body.addEventListener('click', handleMenuClose);
};
const handleMenuClose = (e: MouseEvent) => {
let self = false;
if (e) {
const target = e.target as HTMLElement;
if (target.dataset.dropdown == dropdownId) {
self = true;
}
}
if (!self) {
showDropdown = false;
document.body.removeEventListener('click', handleMenuClose);
}
};
</script>
<div data-dropdown={dropdownId} class="dropdown">
<button data-dropdown={dropdownId} class="dropdown-button" on:click|self={toggleDropdown}>{dropdownTitle}</button>
{#if showDropdown}
<ul data-dropdown={dropdownId} class="dropdown-container">
<slot />
</ul>
{/if}
</div>
<style>
.dropdown {
position: relative;
display: grid;
justify-items: center;
}
.dropdown-button {
background-color: var(--background);
color: var(--color-text);
border: none;
height: var(--height-m);
}
.dropdown-button:hover {
cursor: pointer;
color: var(--color-active-1);
}
.dropdown-container {
list-style-type: none;
width: max-content;
height: fit-content;
position: absolute;
top: 100%;
background: rgba(0, 0, 0, 0.8);
border-radius: 10px;
margin: 0;
padding: 0.5rem;
}
</style>

View file

@ -0,0 +1,19 @@
<script lang="ts">
export let dropdownId: string;
</script>
<li class="dropdown-element" data-dropdown={dropdownId}>
<slot />
</li>
<style>
.dropdown-element {
padding: 10px;
border-radius: 10px;
max-width: 100%;
min-width: fit-content;
margin: 10% auto;
margin-left: 0;
background: #3f3f3f;
}
</style>

View file

@ -0,0 +1,5 @@
import { writable, type Writable } from "svelte/store";
const SelectedGameStore: Writable<string> = writable("");
export default SelectedGameStore;

View file

@ -0,0 +1,5 @@
import { writable, type Writable } from "svelte/store";
const SelectedGameGroupsStore: Writable<Map<string, Array<string>>> = writable(new Map());
export default SelectedGameGroupsStore;

View file

@ -0,0 +1,99 @@
<script lang="ts">
import DropDown from '$lib/components/DropDown.svelte';
import DropDownElement from '$lib/components/DropDownElement.svelte';
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
import SelectedGameStore from '$lib/stores/GameFilter';
let selectedGame: string = "";
let selectedGameGroups: Array<string> = [];
let selectedGameGroupsMap: Map<string, Array<string>> = new Map();
let store: string | null;
SelectedGameStore.subscribe((selection) => {
selectedGame = selection;
if (selectedGameGroupsMap.size != 0) {
const tmp = selectedGameGroupsMap.get(selectedGame);
if (typeof tmp !== "undefined") {
selectedGameGroups = [...tmp.values()];
}
}
})
if (typeof localStorage !== 'undefined') {
store = localStorage.getItem('gameGroupSelection');
if (typeof store == 'string') {
let selectedGameGroupsMap = new Map<string, Array<string>>(JSON.parse(store));
const tmp = selectedGameGroupsMap.get(selectedGame);
if (typeof tmp !== "undefined") {
selectedGameGroups = [...tmp.values()];
}
SelectedGameGroupsStore.set(selectedGameGroupsMap);
}
}
SelectedGameGroupsStore.subscribe((selection) => {
selectedGameGroupsMap = selection;
const tmp = selection.get(selectedGame);
if (typeof tmp !== "undefined") {
selectedGameGroups = [...tmp.values()];
}
if (typeof localStorage !== 'undefined') {
localStorage.setItem('gameGroupSelection', JSON.stringify(Array.from(selection.entries())));
}
});
const updateGameGroupSelection = () => {
SelectedGameGroupsStore.update((selection) => selection.set(selectedGame, selectedGameGroups));
};
const dropdownId = crypto.randomUUID();
</script>
<DropDown dropdownId={dropdownId} dropdownTitle="Group Selection">
<DropDownElement dropdownId={dropdownId}>
<input
id="checkboxGameGroupA"
data-dropdown={dropdownId}
type="checkbox"
bind:group={selectedGameGroups}
on:change={updateGameGroupSelection}
value="A"
/>
<label for="checkboxGameGroupA" data-dropdown={dropdownId}>Group A</label>
</DropDownElement>
<DropDownElement dropdownId={dropdownId}>
<input
id="checkboxGameGroupB"
data-dropdown={dropdownId}
type="checkbox"
bind:group={selectedGameGroups}
on:change={updateGameGroupSelection}
value="B"
/>
<label for="checkboxGameGroupB" data-dropdown={dropdownId}>Group B</label>
</DropDownElement>
<DropDownElement dropdownId={dropdownId}>
<input
id="checkboxGameGroupNA"
data-dropdown={dropdownId}
type="checkbox"
bind:group={selectedGameGroups}
on:change={updateGameGroupSelection}
value="N/A"
/>
<label for="checkboxGameGroupNA" data-dropdown={dropdownId}>Ungrouped</label>
</DropDownElement>
</DropDown>
<style>
:checked + label {
color: var(--color-active-2);
}
:hover {
color: var(--color-active-1) !important;
}
</style>

View file

@ -0,0 +1,63 @@
<script lang="ts">
import DropDown from '$lib/components/DropDown.svelte';
import DropDownElement from '$lib/components/DropDownElement.svelte';
import SelectedGameStore from '$lib/stores/GameFilter';
let selectedGame: string = "";
let store: string | null;
if (typeof localStorage !== 'undefined') {
store = localStorage.getItem('gameSelection');
if (typeof store == 'string') {
selectedGame = JSON.parse(store);
SelectedGameStore.set(selectedGame);
}
}
SelectedGameStore.subscribe((selection) => {
selectedGame = selection;
if (typeof localStorage !== 'undefined') {
localStorage.setItem('gameSelection', JSON.stringify(selectedGame));
}
});
const updateGameSelection = () => {
SelectedGameStore.update(() => selectedGame);
};
const dropdownId = crypto.randomUUID();
</script>
<DropDown dropdownId={dropdownId} dropdownTitle="Game Selection">
<DropDownElement dropdownId={dropdownId}>
<input
id="checkboxGameGroupA"
data-dropdown={dropdownId}
type="radio"
bind:group={selectedGame}
on:change={updateGameSelection}
value="16"
/>
<label for="checkboxGameGroupA" data-dropdown={dropdownId}>Game 16</label>
</DropDownElement>
<DropDownElement dropdownId={dropdownId}>
<input
id="checkboxGameGroupB"
data-dropdown={dropdownId}
type="radio"
bind:group={selectedGame}
on:change={updateGameSelection}
value="17"
/>
<label for="checkboxGameGroupB" data-dropdown={dropdownId}>Game 17</label>
</DropDownElement>
</DropDown>
<style>
label:hover {
color: var(--color-active-1);
}
</style>

View file

@ -1,34 +1,35 @@
<script>
<script lang="ts">
import { page } from '$app/stores';
import discord from '$lib/images/discord.svg';
import GameGroupSelection from './GameGroupSelection.svelte';
import GameSelection from './GameSelection.svelte';
</script>
<header>
<div class="corner">
</div>
<div class="corner" />
<nav>
<svg viewBox="0 0 2 3" aria-hidden="true">
<path d="M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z" />
</svg>
<ul>
<li aria-current={$page.url.pathname === '/graphs' ? 'page' : undefined}>
<a href="/graphs">Home</a>
</li>
<li aria-current={$page.url.pathname === '/graphs/tab' ? 'page' : undefined}>
<a href="/graphs/tab">Tab 1</a>
</li>
<li aria-current={$page.url.pathname === '/graphs/tab2' ? 'page' : undefined}>
<a href="/graphs/tab2">Tab 2</a>
</li>
<li aria-current={$page.url.pathname === '/graphs/tab3' ? 'page' : undefined}>
<a href="/graphs/tab3">Tab 3</a>
</li>
</ul>
<GameSelection />
<GameGroupSelection />
<svg viewBox="0 0 2 3" aria-hidden="true">
<path d="M0,0 L0,3 C0.5,3 0.5,3 1,2 L2,0 Z" />
</svg>
</nav>
<div class="corner">
</div>
<div class="corner" />
</header>
<style>
@ -38,8 +39,8 @@
}
.corner {
width: 3em;
height: 3em;
width: var(--height-m);
height: var(--height-m);
}
.corner a {
@ -64,7 +65,7 @@
svg {
width: 2em;
height: 3em;
height: var(--height-m);
display: block;
}
@ -76,7 +77,7 @@
position: relative;
padding: 0;
margin: 0;
height: 3em;
height: var(--height-m);
display: flex;
justify-content: center;
align-items: center;
@ -99,7 +100,7 @@
top: 0;
left: calc(50% - var(--size));
border: var(--size) solid transparent;
border-top: var(--size) solid var(--color-theme-1);
border-top: var(--size) solid var(--color-active-1);
}
nav a {
@ -116,7 +117,11 @@
transition: color 0.2s linear;
}
nav button {
height: var(--height-m);
}
a:hover {
color: var(--color-theme-1);
color: var(--color-active-1);
}
</style>

View file

@ -1 +1,37 @@
<h1>Example Tab</h1>
<script lang="ts">
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
import SelectedGameStore from '$lib/stores/GameFilter';
let selectedGameGroups: Array<string> = [];
let selectedGameGroupsMap: Map<string, Array<string>> = new Map();
let selectedGame: string = "";
SelectedGameStore.subscribe((selection) => {
selectedGame = selection;
console.log(selectedGameGroupsMap.size);
if (selectedGameGroupsMap.size != 0) {
const tmp = selectedGameGroupsMap.get(selectedGame);
if (typeof tmp !== "undefined") {
selectedGameGroups = [...tmp.values()];
}
}
});
SelectedGameGroupsStore.subscribe((selection) => {
selectedGameGroupsMap = selection;
const tmp = selection.get(selectedGame);
if (typeof tmp !== 'undefined') {
selectedGameGroups = [...tmp.values()];
}
});
</script>
<svelte:head>
<title>Graphs</title>
<meta name="description" content="Chellaris Sign-Up Graphs" />
</svelte:head>
<h1>Example Tab</h1>
<p>{selectedGameGroups.length > 1 ? "Groups" : "Group"} {selectedGameGroups.join(", ")} {selectedGameGroups.length > 1 ? "are" : "is"} selected</p>