Functioning Game and Group Dropdowns with svelte storage
This commit is contained in:
parent
f5a2d32adf
commit
1c92cb8418
8 changed files with 314 additions and 16 deletions
66
src/lib/components/DropDown.svelte
Normal file
66
src/lib/components/DropDown.svelte
Normal 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>
|
19
src/lib/components/DropDownElement.svelte
Normal file
19
src/lib/components/DropDownElement.svelte
Normal 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>
|
5
src/lib/stores/GameFilter.ts
Normal file
5
src/lib/stores/GameFilter.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { writable, type Writable } from "svelte/store";
|
||||
|
||||
const SelectedGameStore: Writable<string> = writable("");
|
||||
|
||||
export default SelectedGameStore;
|
5
src/lib/stores/GameGroupFilter.ts
Normal file
5
src/lib/stores/GameGroupFilter.ts
Normal 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;
|
99
src/routes/graphs/GameGroupSelection.svelte
Normal file
99
src/routes/graphs/GameGroupSelection.svelte
Normal 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>
|
63
src/routes/graphs/GameSelection.svelte
Normal file
63
src/routes/graphs/GameSelection.svelte
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Reference in a new issue