Migration away from maps since they cannot be easily de-/serialized
This commit is contained in:
parent
ef7bb99f41
commit
40dee1e8f8
14 changed files with 321 additions and 372 deletions
|
@ -2,7 +2,7 @@
|
|||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"printWidth": 160,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"pluginSearchDirs": ["."],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
|
|
3
src/app.d.ts
vendored
3
src/app.d.ts
vendored
|
@ -6,6 +6,9 @@ declare global {
|
|||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
interface Locals {
|
||||
authenticated: boolean | null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
13
src/hooks.server.ts
Normal file
13
src/hooks.server.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { redirect } from "@sveltejs/kit";
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
event.locals.authenticated = true;
|
||||
|
||||
if (event.url.pathname.startsWith('/admin')) {
|
||||
if (!event.locals.authenticated) {
|
||||
throw redirect(303, '/401');
|
||||
}
|
||||
}
|
||||
|
||||
return await resolve(event);
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
import { writable, type Writable } from "svelte/store";
|
||||
|
||||
const SelectedGameGroupsStore: Writable<Map<number, Array<number>>> = writable(new Map());
|
||||
export type SelectedChellarisGroups = {
|
||||
gameId: number,
|
||||
selectedGroups: Array<number>,
|
||||
}
|
||||
|
||||
const SelectedGameGroupsStore: Writable<Array<SelectedChellarisGroups>> = writable([]); // Key should always be the same as gameId
|
||||
|
||||
export default SelectedGameGroupsStore;
|
|
@ -1,35 +1,38 @@
|
|||
import type { Ethic, Species } from './stellaris';
|
||||
export interface ChellarisInfo {
|
||||
games: Map<number, ChellarisGame>, // Key is Game Id
|
||||
ethics: Map<number, Ethic>, // Key is Ethic Id
|
||||
species: Map<number, Species>, // Key is Species Group Id
|
||||
games: Array<ChellarisGame>, // Key is Game Id
|
||||
ethics: Array<Ethic>, // Key is Ethic Id
|
||||
species: Array<Species>, // Key is Species Group Id
|
||||
}
|
||||
|
||||
export type ChellarisGame = {
|
||||
id: number,
|
||||
name: string,
|
||||
groups: Map<number, ChellarisGameGroup>, // Key is Group Id
|
||||
empires: Map<number, ChellarisEmpire>, // Key is Empire Id
|
||||
groups: Array<ChellarisGameGroup>, // Key is Group Id
|
||||
empires: Array<ChellarisEmpire>, // Key is Empire Id
|
||||
}
|
||||
|
||||
export type ChellarisGameGroup = {
|
||||
id: number,
|
||||
name: string,
|
||||
}
|
||||
|
||||
export type ChellarisEmpire = {
|
||||
id: number,
|
||||
gestalt: boolean,
|
||||
machine: boolean,
|
||||
group: number,
|
||||
empire_portrait: number, // TODO replace with Enum?
|
||||
empire_portrait_group: number, // TODO replace with Enum?
|
||||
discord_user?: string,
|
||||
ethics: Map<number, Ethic>,
|
||||
ethics: Array<Ethic>,
|
||||
}
|
||||
|
||||
export const createChellarisInfo = (): ChellarisInfo => {
|
||||
const newChellarisInfo = {
|
||||
games: new Map(),
|
||||
ethics: new Map(),
|
||||
species: new Map(),
|
||||
games: [],
|
||||
ethics: [],
|
||||
species: [],
|
||||
};
|
||||
|
||||
return newChellarisInfo;
|
||||
|
@ -37,9 +40,10 @@ export const createChellarisInfo = (): ChellarisInfo => {
|
|||
|
||||
export const createChellarisGame = (): ChellarisGame => {
|
||||
const newChellarisGame = {
|
||||
id: 0,
|
||||
name: "",
|
||||
groups: new Map(),
|
||||
empires: new Map(),
|
||||
groups: [],
|
||||
empires: [],
|
||||
};
|
||||
|
||||
return newChellarisGame;
|
||||
|
@ -47,6 +51,7 @@ export const createChellarisGame = (): ChellarisGame => {
|
|||
|
||||
export const createChellarisGameGroup = (): ChellarisGameGroup => {
|
||||
const newChellarisGameGroup = {
|
||||
id: 0,
|
||||
name: "",
|
||||
};
|
||||
|
||||
|
@ -55,8 +60,9 @@ export const createChellarisGameGroup = (): ChellarisGameGroup => {
|
|||
|
||||
export const createChellarisEmpire = (
|
||||
{
|
||||
discord_user, group_id, gestalt, empire_portrait_id, empire_portrait_group_id
|
||||
id, discord_user, group_id, gestalt, empire_portrait_id, empire_portrait_group_id
|
||||
}: {
|
||||
id: number,
|
||||
discord_user?: string,
|
||||
group_id: number,
|
||||
gestalt: boolean,
|
||||
|
@ -64,12 +70,13 @@ export const createChellarisEmpire = (
|
|||
empire_portrait_group_id: number,
|
||||
}): ChellarisEmpire => {
|
||||
const newChellarisEmpire = {
|
||||
id: id,
|
||||
gestalt: gestalt,
|
||||
machine: false,
|
||||
group: group_id,
|
||||
empire_portrait: empire_portrait_id,
|
||||
empire_portrait_group: empire_portrait_group_id,
|
||||
ethics: new Map(),
|
||||
ethics: [],
|
||||
discord_user: discord_user,
|
||||
};
|
||||
|
||||
|
|
|
@ -65,17 +65,20 @@ export class EthicsDataLegacy {
|
|||
}
|
||||
|
||||
export type Ethic = {
|
||||
id: number,
|
||||
displayName: string,
|
||||
machine: boolean,
|
||||
fanatic?: boolean,
|
||||
}
|
||||
|
||||
export type Species = {
|
||||
id: number,
|
||||
displayName: string,
|
||||
portraits: Map<number, Portrait>, // Key is Portrait Id
|
||||
portraits: Array<Portrait>, // Key is Portrait Id
|
||||
}
|
||||
|
||||
export type Portrait = {
|
||||
id: number,
|
||||
hires: string,
|
||||
lores: string,
|
||||
}
|
||||
|
|
12
src/routes/401/+page.svelte
Normal file
12
src/routes/401/+page.svelte
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svelte:head>
|
||||
<title>About</title>
|
||||
<meta name="description" content="401: Unauthorized" />
|
||||
</svelte:head>
|
||||
|
||||
<div class="text-column">
|
||||
<h1>Unauthorized</h1>
|
||||
|
||||
<p>
|
||||
Your request was denied, the authentication token in your settings seems to be invalid.
|
||||
</p>
|
||||
</div>
|
|
@ -21,9 +21,9 @@
|
|||
<li aria-current={$page.url.pathname === '/legacy-graphs' ? 'page' : undefined}>
|
||||
<a href="/legacy-graphs">Game 15 Graphs</a>
|
||||
</li>
|
||||
<li aria-current={$page.url.pathname.startsWith('/sign-up') ? 'page' : undefined}>
|
||||
<!--<li aria-current={$page.url.pathname.startsWith('/sign-up') ? 'page' : undefined}>
|
||||
<a href="/sign-up">Empire Sign-Up</a>
|
||||
</li>
|
||||
</li>-->
|
||||
<li aria-current={$page.url.pathname.startsWith('/admin') ? 'page' : undefined}>
|
||||
<a href="/admin">Admin Menu</a>
|
||||
</li>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import SelectedGameGroupsStore from "$lib/stores/GameGroupFilter";
|
||||
import SelectedGameGroupsStore, { type SelectedChellarisGroups } from "$lib/stores/GameGroupFilter";
|
||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||
import { createChellarisInfo, type ChellarisGame, createChellarisGame, createChellarisGameGroup, createChellarisEmpire } from "$lib/types/chellaris";
|
||||
import type { LayoutLoad } from "./$types";
|
||||
|
@ -13,26 +13,27 @@ export const load: LayoutLoad = async ({ fetch }) => {
|
|||
|
||||
|
||||
// Chellaris Data Code
|
||||
const games: {id: number, name: string}[] = await (await fetch(apiBaseUrl + '/games')).json();
|
||||
const games: { id: number, name: string }[] = await (await fetch(apiBaseUrl + '/games')).json();
|
||||
|
||||
games.sort((a, b) => (a.name < b.name ? -1 : 1));
|
||||
games.forEach(game => {
|
||||
const newGame: ChellarisGame = createChellarisGame();
|
||||
newGame.id = game.id;
|
||||
newGame.name = game.name;
|
||||
chellarisData.games.set(game.id, newGame);
|
||||
chellarisData.games[game.id] = newGame;
|
||||
});
|
||||
|
||||
const groups: {id: number, name: string, game_id: number}[] = await (await fetch(apiBaseUrl + '/game_groups')).json();
|
||||
const groups: { id: number, name: string, game_id: number }[] = await (await fetch(apiBaseUrl + '/game_groups')).json();
|
||||
|
||||
groups.sort((a, b) => (a.name < b.name ? -1 : 1));
|
||||
groups.forEach(group => {
|
||||
const gameData = chellarisData.games.get(group.game_id);
|
||||
const gameData = chellarisData.games[group.game_id];
|
||||
|
||||
if (typeof gameData !== "undefined") {
|
||||
const newGroup = createChellarisGameGroup();
|
||||
newGroup.id = group.id;
|
||||
newGroup.name = group.name;
|
||||
gameData.groups.set(group.id, newGroup)
|
||||
chellarisData.games.set(group.game_id, gameData);
|
||||
chellarisData.games[group.game_id].groups[group.id] = newGroup;
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -43,25 +44,26 @@ export const load: LayoutLoad = async ({ fetch }) => {
|
|||
gestalt: boolean,
|
||||
empire_portrait_id: number,
|
||||
empire_portrait_group_id: number,
|
||||
group_game_id: number}[] = await (await fetch(apiBaseUrl + '/empires')).json();
|
||||
group_game_id: number
|
||||
}[] = await (await fetch(apiBaseUrl + '/empires')).json();
|
||||
|
||||
empires.sort((a, b) => (a.id < b.id ? -1 : 1));
|
||||
empires.forEach(empire => {
|
||||
const gameData = chellarisData.games.get(empire.group_game_id);
|
||||
const gameData = chellarisData.games[empire.group_game_id];
|
||||
|
||||
if (typeof gameData !== "undefined") {
|
||||
const newEmpire = createChellarisEmpire(empire);
|
||||
gameData.empires.set(empire.id, newEmpire);
|
||||
chellarisData.games[empire.group_game_id].empires[empire.id] = newEmpire;
|
||||
}
|
||||
});
|
||||
|
||||
const ethics: {id: number, name: string, machine_ethic: boolean}[] = await (await fetch(apiBaseUrl + '/ethics')).json();
|
||||
const ethics: { id: number, name: string, machine_ethic: boolean }[] = await (await fetch(apiBaseUrl + '/ethics')).json();
|
||||
|
||||
ethics.sort((a, b) => (a.id < b.id ? -1 : 1));
|
||||
ethics.forEach(ethic => {
|
||||
const newEthic: Ethic = {displayName: ethic.name, machine: ethic.machine_ethic};
|
||||
const newEthic: Ethic = { id: ethic.id, displayName: ethic.name, machine: ethic.machine_ethic };
|
||||
|
||||
chellarisData.ethics.set(ethic.id, newEthic);
|
||||
chellarisData.ethics[ethic.id] = newEthic;
|
||||
});
|
||||
|
||||
const empireEthics: {
|
||||
|
@ -69,20 +71,21 @@ export const load: LayoutLoad = async ({ fetch }) => {
|
|||
empires_group_id: number,
|
||||
empires_group_game_id: number,
|
||||
ethics_id: number,
|
||||
ethics_fanatic: boolean}[] = await (await fetch(apiBaseUrl + '/empire_ethics')).json();
|
||||
ethics_fanatic: boolean
|
||||
}[] = await (await fetch(apiBaseUrl + '/empire_ethics')).json();
|
||||
|
||||
empireEthics.forEach(empireEthic => {
|
||||
const gameData = chellarisData.games.get(empireEthic.empires_group_game_id);
|
||||
const ethic = chellarisData.ethics.get(empireEthic.ethics_id);
|
||||
const gameData = chellarisData.games[empireEthic.empires_group_game_id];
|
||||
const ethic = chellarisData.ethics[empireEthic.ethics_id];
|
||||
|
||||
if (typeof gameData !== "undefined" && typeof ethic !== "undefined") {
|
||||
const empireData = gameData.empires.get(empireEthic.empires_id);
|
||||
const empireData = gameData.empires[empireEthic.empires_id];
|
||||
if (typeof empireData !== "undefined") {
|
||||
const tmpEthic: Ethic = {machine: ethic.machine, displayName: ethic.displayName, fanatic: empireEthic.ethics_fanatic};
|
||||
const tmpEthic: Ethic = { id: ethic.id, machine: ethic.machine, displayName: ethic.displayName, fanatic: empireEthic.ethics_fanatic };
|
||||
if (tmpEthic.machine) {
|
||||
empireData.machine = true;
|
||||
}
|
||||
empireData.ethics.set(empireEthic.ethics_id, tmpEthic);
|
||||
empireData.ethics[empireEthic.ethics_id] = tmpEthic;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -95,8 +98,8 @@ export const load: LayoutLoad = async ({ fetch }) => {
|
|||
portraitGroups.sort((a, b) => (a.id < b.id ? -1 : 1));
|
||||
|
||||
portraitGroups.forEach(portraitGroup => {
|
||||
const newPortraitGroup = { displayName: portraitGroup.name, portraits: new Map() };
|
||||
chellarisData.species.set(portraitGroup.id, newPortraitGroup);
|
||||
const newPortraitGroup = { id: portraitGroup.id, displayName: portraitGroup.name, portraits: [] };
|
||||
chellarisData.species[portraitGroup.id] = newPortraitGroup;
|
||||
});
|
||||
|
||||
const portraits: {
|
||||
|
@ -109,56 +112,81 @@ export const load: LayoutLoad = async ({ fetch }) => {
|
|||
portraits.sort((a, b) => (a.id < b.id ? -1 : 1));
|
||||
|
||||
portraits.forEach(portrait => {
|
||||
const portraitGroupData = chellarisData.species.get(portrait.group_id);
|
||||
const portraitGroupData = chellarisData.species[portrait.group_id];
|
||||
|
||||
if (typeof portraitGroupData !== "undefined") {
|
||||
const newPortraitData = { hires: portrait.hires, lores: portrait.lores };
|
||||
const newPortraitData = { id: portrait.id, hires: portrait.hires, lores: portrait.lores };
|
||||
|
||||
portraitGroupData.portraits.set(portrait.id, newPortraitData);
|
||||
portraitGroupData.portraits[portrait.id] = newPortraitData;
|
||||
}
|
||||
})
|
||||
|
||||
ChellarisDataStore.set(chellarisData);
|
||||
|
||||
// Local Storage Code
|
||||
let gameGroupSelections: Array<SelectedChellarisGroups> = [];
|
||||
let gameSelection: number | undefined;
|
||||
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
// Tab Selection
|
||||
store = localStorage.getItem('graphsTab');
|
||||
if (typeof store == 'string') {
|
||||
if (typeof store === 'string') {
|
||||
GraphsTabStore.set(store);
|
||||
}
|
||||
|
||||
// Game Selection
|
||||
store = localStorage.getItem('gameSelection');
|
||||
|
||||
let selectedGame = 1;
|
||||
if (typeof store == 'string' && store != "\"\"") {
|
||||
selectedGame = JSON.parse(store);
|
||||
if (typeof store === 'string' && store != "\"\"") {
|
||||
gameSelection = JSON.parse(store);
|
||||
}
|
||||
|
||||
if (typeof gameSelection === 'undefined') {
|
||||
gameSelection = chellarisData.games[0].id;
|
||||
}
|
||||
SelectedGameStore.set(selectedGame);
|
||||
|
||||
// Game Groups Selection
|
||||
store = localStorage.getItem('gameGroupSelection');
|
||||
|
||||
if (typeof store == 'string') {
|
||||
let selectedGameGroups: Array<number> = [];
|
||||
const gameGroupSelectionMap = new Map<number, Array<number>>(JSON.parse(store));
|
||||
const tmp = gameGroupSelectionMap.get(selectedGame);
|
||||
if (typeof store === 'string') {
|
||||
gameGroupSelections = JSON.parse(store);
|
||||
|
||||
if (typeof tmp !== 'undefined') {
|
||||
selectedGameGroups = tmp;
|
||||
} else {
|
||||
const tmpGameData = chellarisData.games.get(selectedGame);
|
||||
// If this fails an empty array is precisely what we want
|
||||
if (typeof tmpGameData !== "undefined") {
|
||||
if (typeof gameGroupSelections[gameSelection] === 'undefined') {
|
||||
// Default to all available groups
|
||||
selectedGameGroups = [...tmpGameData.groups.keys()];
|
||||
gameGroupSelections[gameSelection] = { gameId: gameSelection, selectedGroups: chellarisData.games[gameSelection].groups.map(group => group.id) };
|
||||
|
||||
// Set Local Storage to default Values if not previously defined
|
||||
localStorage.setItem('gameGroupSelection', JSON.stringify(Array.from(selectedGameGroups.entries())));
|
||||
localStorage.setItem('gameGroupSelection', JSON.stringify(gameGroupSelections));
|
||||
}
|
||||
else {
|
||||
Object.keys(gameGroupSelections).forEach(
|
||||
gKey => {
|
||||
if (gameGroupSelections[+gKey] == null) {
|
||||
delete gameGroupSelections[+gKey];
|
||||
}
|
||||
else {
|
||||
Object.keys(gameGroupSelections[+gKey].selectedGroups).forEach(
|
||||
key => gameGroupSelections[+gKey].selectedGroups[+key] != null || delete gameGroupSelections[+gKey].selectedGroups[+key]
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
gameGroupSelectionMap.set(selectedGame, selectedGameGroups);
|
||||
SelectedGameGroupsStore.set(gameGroupSelectionMap);
|
||||
}
|
||||
|
||||
if (typeof gameSelection === 'undefined') {
|
||||
gameSelection = chellarisData.games[0].id;
|
||||
}
|
||||
|
||||
SelectedGameStore.set(gameSelection);
|
||||
|
||||
if (typeof gameGroupSelections[gameSelection] === 'undefined') {
|
||||
// Default to all available groups
|
||||
gameGroupSelections[gameSelection] = { gameId: gameSelection, selectedGroups: chellarisData.games[gameSelection].groups.map(group => group.id) };
|
||||
}
|
||||
|
||||
SelectedGameGroupsStore.set(gameGroupSelections);
|
||||
|
||||
gameGroupSelections = []; // TODO: actually assing a value
|
||||
return { chellarisData }
|
||||
}
|
|
@ -4,88 +4,54 @@
|
|||
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
import { createChellarisInfo, type ChellarisGame, type ChellarisGameGroup, type ChellarisInfo } from '$lib/types/chellaris';
|
||||
|
||||
let selectedGame: number;
|
||||
let selectedGameGroups: Array<number> = [];
|
||||
let selectedGameGroupsMap: Map<number, Array<number>> = new Map();
|
||||
|
||||
let gameGroups: Map<number, ChellarisGameGroup> = new Map();
|
||||
let chellarisData: ChellarisInfo = createChellarisInfo();
|
||||
|
||||
// Chellaris Data Code
|
||||
const updateGameGroups = () => {
|
||||
let tmpData;
|
||||
if (!selectedGame) {
|
||||
tmpData = chellarisData.games.get(chellarisData.games.keys().next().value);
|
||||
}
|
||||
else {
|
||||
tmpData = chellarisData.games.get(selectedGame);
|
||||
}
|
||||
|
||||
if (typeof tmpData !== 'undefined') {
|
||||
gameGroups = tmpData.groups;
|
||||
}
|
||||
}
|
||||
|
||||
ChellarisDataStore.subscribe((data) => {
|
||||
chellarisData = data;
|
||||
|
||||
updateGameGroups();
|
||||
// TODO Update selection if Groups Differ? Does this value ever even update without a full page reload?
|
||||
});
|
||||
|
||||
// Group Selection Code
|
||||
const updateSelectedGroups = () => {
|
||||
const tmp = selectedGameGroupsMap.get(selectedGame);
|
||||
if (typeof tmp !== 'undefined') {
|
||||
selectedGameGroups = [...tmp.values()];
|
||||
} else {
|
||||
selectedGameGroups = [...gameGroups.keys()];
|
||||
selectedGameGroupsMap.set(selectedGame, selectedGameGroups);
|
||||
SelectedGameGroupsStore.set(selectedGameGroupsMap);
|
||||
}
|
||||
};
|
||||
|
||||
// Game Selection Code
|
||||
SelectedGameStore.subscribe((selection) => {
|
||||
selectedGame = selection;
|
||||
|
||||
updateGameGroups();
|
||||
|
||||
if (selectedGameGroupsMap.size != 0) {
|
||||
updateSelectedGroups();
|
||||
if (typeof $SelectedGameGroupsStore[selection] === 'undefined') {
|
||||
// Default to all available groups
|
||||
$SelectedGameGroupsStore[selection] = { gameId: $SelectedGameStore, selectedGroups: $ChellarisDataStore.games[$SelectedGameStore].groups.map((group) => group.id) };
|
||||
SelectedGameGroupsStore.update(() => $SelectedGameGroupsStore);
|
||||
}
|
||||
});
|
||||
|
||||
SelectedGameGroupsStore.subscribe((selection) => {
|
||||
selectedGameGroupsMap = selection;
|
||||
updateSelectedGroups();
|
||||
})
|
||||
|
||||
// Game Group Selection Code
|
||||
$: {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('gameGroupSelection', JSON.stringify(Array.from(selection.entries())));
|
||||
localStorage.setItem('gameGroupSelection', JSON.stringify($SelectedGameGroupsStore));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const updateGameGroupSelection = () => {
|
||||
SelectedGameGroupsStore.update((selection) => selection.set(selectedGame, selectedGameGroups));
|
||||
};
|
||||
$: selectedGameData = $SelectedGameGroupsStore[$SelectedGameStore];
|
||||
$: groupJoiner = selectedGameData.selectedGroups.length > 2 ? ', ' : ' & ';
|
||||
|
||||
const updateGroupStore = () => {
|
||||
SelectedGameGroupsStore.update(() => $SelectedGameGroupsStore);
|
||||
}
|
||||
|
||||
const dropdownId = crypto.randomUUID();
|
||||
</script>
|
||||
|
||||
<DropDown {dropdownId} dropdownTitle={(selectedGameGroups.length > 1 ? "Groups " : "Group ") + selectedGameGroups.map((selection) => gameGroups.get(selection)?.name).join(", ")}>
|
||||
{#each gameGroups as group}
|
||||
<DropDown
|
||||
{dropdownId}
|
||||
dropdownTitle={(selectedGameData.selectedGroups.length > 1 ? 'Groups ' : 'Group ') +
|
||||
selectedGameData.selectedGroups
|
||||
.map((selection) => $ChellarisDataStore.games[$SelectedGameStore].groups[selection]?.name)
|
||||
.join(groupJoiner)}
|
||||
>
|
||||
{#each $ChellarisDataStore.games[$SelectedGameStore].groups as group}
|
||||
{#if group}
|
||||
<DropDownElement {dropdownId}>
|
||||
<input
|
||||
id={'checkbox' + group[0]}
|
||||
id={'checkbox' + group.id}
|
||||
data-dropdown={dropdownId}
|
||||
type="checkbox"
|
||||
bind:group={selectedGameGroups}
|
||||
on:change={updateGameGroupSelection}
|
||||
value={group[0]}
|
||||
bind:group={selectedGameData.selectedGroups}
|
||||
on:change={updateGroupStore}
|
||||
value={group.id}
|
||||
/>
|
||||
<label for={'checkbox' + group[0]} data-dropdown={dropdownId}>{group[1].name}</label>
|
||||
<label for={'checkbox' + group.id} data-dropdown={dropdownId}>{group.name}</label>
|
||||
</DropDownElement>
|
||||
{/if}
|
||||
{/each}
|
||||
</DropDown>
|
||||
|
||||
|
|
|
@ -3,45 +3,29 @@
|
|||
import DropDownElement from '$lib/components/DropDownElement.svelte';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
import type { ChellarisGame } from '$lib/types/chellaris';
|
||||
|
||||
let selectedGame: number;
|
||||
let gameList: Map<number, ChellarisGame> = new Map();
|
||||
|
||||
// Chellaris Data Code
|
||||
ChellarisDataStore.subscribe((data) => {
|
||||
gameList = data.games;
|
||||
});
|
||||
|
||||
// Game Selection Code
|
||||
SelectedGameStore.subscribe((selection) => {
|
||||
selectedGame = selection;
|
||||
|
||||
$: {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('gameSelection', JSON.stringify(selectedGame));
|
||||
localStorage.setItem('gameSelection', JSON.stringify($SelectedGameStore));
|
||||
}
|
||||
});
|
||||
|
||||
const updateGameSelection = () => {
|
||||
SelectedGameStore.update(() => selectedGame);
|
||||
};
|
||||
|
||||
// Dropdown UUID to make the Click Event work properly
|
||||
const dropdownId = crypto.randomUUID();
|
||||
</script>
|
||||
|
||||
<DropDown {dropdownId} dropdownTitle={gameList.get(selectedGame)?.name}>
|
||||
{#each gameList as game}
|
||||
<DropDown {dropdownId} dropdownTitle={$ChellarisDataStore.games[$SelectedGameStore]?.name}>
|
||||
{#each $ChellarisDataStore.games as game}
|
||||
<DropDownElement {dropdownId}>
|
||||
<input
|
||||
id={'checkbox' + game[0]}
|
||||
id={'checkbox' + game.id}
|
||||
data-dropdown={dropdownId}
|
||||
type="radio"
|
||||
bind:group={selectedGame}
|
||||
on:change={updateGameSelection}
|
||||
value={game[0]}
|
||||
bind:group={$SelectedGameStore}
|
||||
value={game.id}
|
||||
/>
|
||||
<label for={'checkbox' + game[0]} data-dropdown={dropdownId}>{game[1].name}</label>
|
||||
<label for={'checkbox' + game.id} data-dropdown={dropdownId}>{game.name}</label>
|
||||
</DropDownElement>
|
||||
{/each}
|
||||
</DropDown>
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
<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/tab' ? 'page' : undefined}>
|
||||
<!--<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>-->
|
||||
<li aria-current={$page.url.pathname === '/graphs/excel-style' ? 'page' : undefined}>
|
||||
<a href="/graphs/excel-style">Excel Style</a>
|
||||
</li>
|
||||
|
|
|
@ -1,96 +1,88 @@
|
|||
<script lang="ts">
|
||||
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import {
|
||||
createChellarisInfo,
|
||||
type ChellarisGameGroup,
|
||||
type ChellarisInfo,
|
||||
type ChellarisGame,
|
||||
createChellarisGame,
|
||||
type ChellarisEmpire
|
||||
} from '$lib/types/chellaris';
|
||||
import type { ChellarisGameGroup, ChellarisInfo, ChellarisEmpire, ChellarisGame } from '$lib/types/chellaris';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||
import type { LayoutData } from '../$types';
|
||||
import type { Ethic } from '$lib/types/stellaris';
|
||||
import { page } from '$app/stores';
|
||||
import LoadingSpinner from '$lib/components/LoadingSpinner.svelte';
|
||||
|
||||
export let data: LayoutData;
|
||||
let selectedGameGroups: Array<number> = [];
|
||||
let selectedGameGroupsMap: Map<number, Array<number>> = new Map();
|
||||
let gameGroups: Map<number, ChellarisGameGroup> = new Map();
|
||||
let chellarisData: ChellarisInfo = data.chellarisData;
|
||||
let selectedGameIdx: number;
|
||||
let selectedGame: ChellarisGame = createChellarisGame();
|
||||
$: selectedGame = $ChellarisDataStore.games[$SelectedGameStore];
|
||||
$: selectedGameGroupData = $SelectedGameGroupsStore[$SelectedGameStore];
|
||||
$: groupNoun = selectedGameGroupData.selectedGroups.length > 1 ? 'Groups' : 'Group';
|
||||
$: groupJoiner = selectedGameGroupData.selectedGroups.length > 2 ? ', ' : ' & ';
|
||||
|
||||
let groupPortraitLimit: number;
|
||||
$: {
|
||||
let containsNA = false;
|
||||
selectedGameGroupData.selectedGroups.forEach((selection) => {
|
||||
if ($ChellarisDataStore.games[$SelectedGameStore].groups[selection]?.name == 'N/A') {
|
||||
containsNA = true;
|
||||
}
|
||||
});
|
||||
groupPortraitLimit = containsNA ? $ChellarisDataStore.games[$SelectedGameStore].groups.length - 1 : selectedGameGroupData.selectedGroups.length;
|
||||
}
|
||||
|
||||
let pageData: {
|
||||
init: boolean;
|
||||
empireCount: number;
|
||||
gestaltCount: { total: number; machines: number };
|
||||
ethicsData: Map<
|
||||
number,
|
||||
{
|
||||
ethicsData: Array<{
|
||||
id: number;
|
||||
machine: boolean;
|
||||
displayName: string;
|
||||
regular: number;
|
||||
fanatic: number;
|
||||
}
|
||||
>;
|
||||
takenPortraits: Map<number, Map<number, number>>;
|
||||
}>;
|
||||
takenPortraits: Array<Array<[number, Array<number>]>>; // <SpeciesGroup, <Portrait, <SumTaken, <GroupsTaken>>>>
|
||||
};
|
||||
$: {
|
||||
console.log('Reran'); // DEBUG
|
||||
|
||||
let newPageData: {
|
||||
init: boolean;
|
||||
empireCount: number;
|
||||
gestaltCount: { total: number; machines: number };
|
||||
ethicsData: Array<{
|
||||
id: number;
|
||||
machine: boolean;
|
||||
displayName: string;
|
||||
regular: number;
|
||||
fanatic: number;
|
||||
}>;
|
||||
takenPortraits: Array<Array<[number, Array<number>]>>; // <SpeciesGroup, <Portrait, <SumTaken, <GroupsTaken>>>>
|
||||
} = {
|
||||
init: false,
|
||||
empireCount: 0,
|
||||
gestaltCount: { total: 0, machines: 0 },
|
||||
ethicsData: new Map(),
|
||||
takenPortraits: new Map()
|
||||
ethicsData: [],
|
||||
takenPortraits: []
|
||||
};
|
||||
|
||||
// Save Tab to Store
|
||||
GraphsTabStore.update(() => 'excel-style');
|
||||
|
||||
const updateGameGroups = () => {
|
||||
let tmpData;
|
||||
if (!selectedGame) {
|
||||
tmpData = chellarisData.games.get(chellarisData.games.keys().next().value);
|
||||
} else {
|
||||
tmpData = chellarisData.games.get(selectedGameIdx);
|
||||
}
|
||||
|
||||
if (typeof tmpData !== 'undefined') {
|
||||
gameGroups = tmpData.groups;
|
||||
}
|
||||
};
|
||||
|
||||
const updatePageData = () => {
|
||||
const tmpGameData = chellarisData.games.get(selectedGameIdx);
|
||||
|
||||
if (typeof tmpGameData !== 'undefined') {
|
||||
const groupEmpires: Map<number, ChellarisEmpire> = new Map();
|
||||
pageData.ethicsData = new Map();
|
||||
pageData.takenPortraits = new Map();
|
||||
pageData.gestaltCount = { total: 0, machines: 0 };
|
||||
|
||||
chellarisData.ethics.forEach((ethic, id) => {
|
||||
if (selectedGame) {
|
||||
// Empty init of Ethics Data
|
||||
$ChellarisDataStore.ethics.forEach((ethic) => {
|
||||
const newEthicsData: {
|
||||
id: number;
|
||||
machine: boolean;
|
||||
displayName: string;
|
||||
regular: number;
|
||||
fanatic: number;
|
||||
} = {
|
||||
id: ethic.id,
|
||||
machine: ethic.machine,
|
||||
displayName: ethic.displayName,
|
||||
regular: 0,
|
||||
fanatic: 0
|
||||
};
|
||||
pageData.ethicsData.set(id, newEthicsData);
|
||||
newPageData.ethicsData[ethic.id] = newEthicsData;
|
||||
});
|
||||
|
||||
tmpGameData.empires.forEach((empire, index) => {
|
||||
if (selectedGameGroups.includes(empire.group)) {
|
||||
groupEmpires.set(index, empire);
|
||||
selectedGame.empires.forEach((empire, index) => {
|
||||
if (selectedGameGroupData.selectedGroups.includes(empire.group)) {
|
||||
newPageData.empireCount = newPageData.empireCount + 1;
|
||||
|
||||
if (empire.gestalt) {
|
||||
pageData.gestaltCount.total = pageData.gestaltCount.total + 1;
|
||||
newPageData.gestaltCount.total = newPageData.gestaltCount.total + 1;
|
||||
|
||||
let machine = false;
|
||||
empire.ethics.forEach((ethic) => {
|
||||
|
@ -100,12 +92,12 @@
|
|||
});
|
||||
|
||||
if (machine) {
|
||||
pageData.gestaltCount.machines = pageData.gestaltCount.machines + 1;
|
||||
newPageData.gestaltCount.machines = newPageData.gestaltCount.machines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
empire.ethics.forEach((ethic, id) => {
|
||||
const tmpEthicPageData = pageData.ethicsData.get(id);
|
||||
const tmpEthicPageData = newPageData.ethicsData[id];
|
||||
|
||||
if (typeof tmpEthicPageData !== 'undefined') {
|
||||
tmpEthicPageData.displayName = ethic.displayName;
|
||||
|
@ -115,14 +107,16 @@
|
|||
tmpEthicPageData.fanatic = tmpEthicPageData.fanatic + 1;
|
||||
}
|
||||
|
||||
pageData.ethicsData.set(id, tmpEthicPageData);
|
||||
newPageData.ethicsData[id] = tmpEthicPageData;
|
||||
} else {
|
||||
let newEthicsData: {
|
||||
id: number;
|
||||
machine: boolean;
|
||||
displayName: string;
|
||||
regular: number;
|
||||
fanatic: number;
|
||||
} = {
|
||||
id: ethic.id,
|
||||
machine: ethic.machine,
|
||||
displayName: ethic.displayName,
|
||||
regular: 0,
|
||||
|
@ -135,72 +129,53 @@
|
|||
newEthicsData.fanatic = 1;
|
||||
}
|
||||
|
||||
pageData.ethicsData.set(id, newEthicsData);
|
||||
newPageData.ethicsData[id] = newEthicsData;
|
||||
}
|
||||
});
|
||||
|
||||
if (!pageData.takenPortraits.has(empire.empire_portrait_group)) {
|
||||
pageData.takenPortraits.set(empire.empire_portrait_group, new Map());
|
||||
if (typeof newPageData.takenPortraits[empire.empire_portrait_group] === 'undefined') {
|
||||
newPageData.takenPortraits[empire.empire_portrait_group] = [];
|
||||
}
|
||||
const portraitGroupData = pageData.takenPortraits.get(empire.empire_portrait_group);
|
||||
const portraitGroupData = newPageData.takenPortraits[empire.empire_portrait_group];
|
||||
|
||||
if (typeof portraitGroupData !== 'undefined') {
|
||||
if (!portraitGroupData.has(empire.empire_portrait)) {
|
||||
portraitGroupData.set(empire.empire_portrait, 0);
|
||||
if (typeof portraitGroupData[empire.empire_portrait] === 'undefined') {
|
||||
portraitGroupData[empire.empire_portrait] = [0, []];
|
||||
}
|
||||
|
||||
let portraitData = portraitGroupData.get(empire.empire_portrait);
|
||||
let portraitData = portraitGroupData[empire.empire_portrait];
|
||||
|
||||
if (typeof portraitData !== 'undefined') {
|
||||
portraitData = portraitData + 1;
|
||||
portraitGroupData.set(empire.empire_portrait, portraitData);
|
||||
pageData.takenPortraits.set(empire.empire_portrait_group, portraitGroupData);
|
||||
portraitData[0] = portraitData[0] + 1;
|
||||
portraitData[1].push(empire.group);
|
||||
portraitGroupData[empire.empire_portrait] = portraitData;
|
||||
newPageData.takenPortraits[empire.empire_portrait_group] = portraitGroupData;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
pageData.empireCount = groupEmpires.size;
|
||||
pageData.init = true;
|
||||
}
|
||||
};
|
||||
|
||||
ChellarisDataStore.subscribe((data) => {
|
||||
chellarisData = data;
|
||||
|
||||
updateGameGroups();
|
||||
// TODO Update selection if Groups Differ? Does this value ever even update without a full page reload?
|
||||
});
|
||||
|
||||
SelectedGameStore.subscribe((selection) => {
|
||||
selectedGameIdx = selection;
|
||||
const tmpGameData = chellarisData.games.get(selectedGameIdx);
|
||||
if (typeof tmpGameData !== 'undefined') {
|
||||
selectedGame = tmpGameData;
|
||||
// Fill undefined Portrait Info with default information.
|
||||
for (let i = 0; i < $ChellarisDataStore.species.length; i++) {
|
||||
if (typeof newPageData.takenPortraits[i] === 'undefined') {
|
||||
newPageData.takenPortraits[i] = [];
|
||||
}
|
||||
|
||||
updateGameGroups();
|
||||
|
||||
if (selectedGameGroupsMap.size != 0) {
|
||||
const tmp = selectedGameGroupsMap.get(selectedGameIdx);
|
||||
if (typeof tmp !== 'undefined') {
|
||||
selectedGameGroups = [...tmp.values()];
|
||||
for (let ii = 0; ii < $ChellarisDataStore.species[i].portraits.length; ii++) {
|
||||
if (typeof newPageData.takenPortraits[i][ii] === 'undefined') {
|
||||
newPageData.takenPortraits[i][ii] = [0, []];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatePageData();
|
||||
});
|
||||
|
||||
SelectedGameGroupsStore.subscribe((selection) => {
|
||||
selectedGameGroupsMap = selection;
|
||||
const tmp = selection.get(selectedGameIdx);
|
||||
if (typeof tmp !== 'undefined') {
|
||||
selectedGameGroups = [...tmp.values()];
|
||||
newPageData.init = true;
|
||||
}
|
||||
updatePageData();
|
||||
});
|
||||
|
||||
const groupNoun = selectedGameGroups.length > 1 ? 'Groups' : 'Group';
|
||||
const groupJoiner = selectedGameGroups.length > 2 ? ', ' : ' & ';
|
||||
pageData = newPageData;
|
||||
}
|
||||
|
||||
// Save Tab to Store
|
||||
GraphsTabStore.update(() => 'excel-style');
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -211,7 +186,7 @@
|
|||
{#if pageData.init}
|
||||
<h1>
|
||||
{selectedGame.name} Sign-Up Info for {groupNoun}
|
||||
{selectedGameGroups.map((selection) => gameGroups.get(selection)?.name).join(groupJoiner)}
|
||||
{selectedGameGroupData.selectedGroups.map((selection) => $ChellarisDataStore.games[$SelectedGameStore].groups[selection]?.name).join(groupJoiner)}
|
||||
</h1>
|
||||
|
||||
<div class="text-column">
|
||||
|
@ -227,11 +202,11 @@
|
|||
<th># Fanatic</th>
|
||||
</tr>
|
||||
{#each pageData.ethicsData as ethicData}
|
||||
{#if !ethicData[1].machine}
|
||||
{#if ethicData && !ethicData.machine}
|
||||
<tr>
|
||||
<td class="table-label">{ethicData[1].displayName}</td>
|
||||
<td>{ethicData[1].regular}</td>
|
||||
<td>{ethicData[1].fanatic}</td>
|
||||
<td class="table-label">{ethicData.displayName}</td>
|
||||
<td>{ethicData.regular}</td>
|
||||
<td>{ethicData.fanatic}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -247,10 +222,10 @@
|
|||
<th>#</th>
|
||||
</tr>
|
||||
{#each pageData.ethicsData as ethicData}
|
||||
{#if ethicData[1].machine}
|
||||
{#if ethicData && ethicData.machine}
|
||||
<tr>
|
||||
<td class="table-label">{ethicData[1].displayName}</td>
|
||||
<td>{ethicData[1].regular}</td>
|
||||
<td class="table-label">{ethicData.displayName}</td>
|
||||
<td>{ethicData.regular}</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -266,37 +241,32 @@
|
|||
<th>{index + 1}</th>
|
||||
{/each}
|
||||
</tr>
|
||||
{#each chellarisData.species as portraitGroup}
|
||||
{#each $ChellarisDataStore.species ?? false as portraitGroup}
|
||||
{#if portraitGroup}
|
||||
<tr>
|
||||
<td>{portraitGroup[1].displayName}</td>
|
||||
{#each portraitGroup[1].portraits as portrait}
|
||||
<td>{portraitGroup.displayName}</td>
|
||||
{#each portraitGroup.portraits ?? false as portrait}
|
||||
{#if portrait}
|
||||
<td
|
||||
class="image-box"
|
||||
style="--color-hovered-portrait: {gameGroups.size -
|
||||
1 -
|
||||
(pageData.takenPortraits.get(portraitGroup[0])?.get(portrait[0]) || 0) ==
|
||||
0
|
||||
style="--color-hovered-portrait: {groupPortraitLimit - pageData.takenPortraits[portraitGroup.id][portrait.id][0] == 0
|
||||
? 'var(--color-warn-2)'
|
||||
: gameGroups.size -
|
||||
1 -
|
||||
(pageData.takenPortraits.get(portraitGroup[0])?.get(portrait[0]) || 0) !=
|
||||
gameGroups.size - 1
|
||||
: groupPortraitLimit - pageData.takenPortraits[portraitGroup.id][portrait.id][0] != groupPortraitLimit
|
||||
? 'var(--color-warn-1)'
|
||||
: 'var(--color-bg)'}"
|
||||
>
|
||||
<input
|
||||
id={portraitGroup[0] + '-' + portrait[0]}
|
||||
id={portraitGroup.id + '-' + portrait.id}
|
||||
type="image"
|
||||
src={"../"+ portrait[1].lores}
|
||||
alt={portraitGroup[1].displayName + '-' + portrait[0]}
|
||||
src={'../' + portrait.lores}
|
||||
alt={portraitGroup.displayName + '-' + portrait.id}
|
||||
/>
|
||||
<label for={portraitGroup[0] + '-' + portrait[0]}
|
||||
>{pageData.takenPortraits.get(portraitGroup[0])?.get(portrait[0]) ||
|
||||
0}/{gameGroups.size - 1}</label
|
||||
>
|
||||
<label for={portraitGroup.id + '-' + portrait.id}>{pageData.takenPortraits[portraitGroup.id][portrait.id][0]}/{groupPortraitLimit}</label>
|
||||
</td>
|
||||
{/if}
|
||||
{/each}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -1,56 +1,14 @@
|
|||
<script lang="ts">
|
||||
import SelectedGameGroupsStore from '$lib/stores/GameGroupFilter';
|
||||
import SelectedGameStore from '$lib/stores/GameFilter';
|
||||
import { createChellarisInfo, type ChellarisGameGroup, type ChellarisInfo } from '$lib/types/chellaris';
|
||||
import ChellarisDataStore from '$lib/stores/ChellarisData';
|
||||
import GraphsTabStore from '$lib/stores/GraphsTab';
|
||||
|
||||
let selectedGameGroups: Array<string> = [];
|
||||
let selectedGameGroupsMap: Map<string, Array<string>> = new Map();
|
||||
let gameGroups: Map<string, ChellarisGameGroup> = new Map();
|
||||
let chellarisData = createChellarisInfo();
|
||||
let selectedGame = '';
|
||||
|
||||
// Save Tab to Store
|
||||
GraphsTabStore.update(() => 'tab');
|
||||
|
||||
const updateGameGroups = () => {
|
||||
let tmpData;
|
||||
if (selectedGame == '') {
|
||||
tmpData = chellarisData.games.get(chellarisData.games.keys().next().value);
|
||||
} else {
|
||||
tmpData = chellarisData.games.get(selectedGame);
|
||||
}
|
||||
|
||||
if (typeof tmpData !== 'undefined') {
|
||||
gameGroups = tmpData.groups;
|
||||
}
|
||||
};
|
||||
|
||||
ChellarisDataStore.subscribe((data) => {
|
||||
chellarisData = data;
|
||||
|
||||
updateGameGroups();
|
||||
// TODO Update selection if Groups Differ? Does this value ever even update without a full page reload?
|
||||
});
|
||||
|
||||
SelectedGameStore.subscribe((selection) => {
|
||||
selectedGame = selection;
|
||||
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()];
|
||||
}
|
||||
});
|
||||
$: selectedGroups = $SelectedGameGroupsStore[$SelectedGameStore].selectedGroups;
|
||||
$: groupJoiner = selectedGroups.length > 2 ? ', ' : ' & ';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -61,7 +19,7 @@
|
|||
<h1>Example Tab</h1>
|
||||
|
||||
<p>
|
||||
{selectedGameGroups.length > 1 ? 'Groups' : 'Group'}
|
||||
{selectedGameGroups.map((selection) => gameGroups.get(selection)?.name).join(', ')}
|
||||
{selectedGameGroups.length > 1 ? 'are' : 'is'} selected
|
||||
{selectedGroups.length > 1 ? 'Groups' : 'Group'}
|
||||
{selectedGroups.map((selection) => $ChellarisDataStore.games[$SelectedGameStore].groups[selection]?.name).join(groupJoiner)}
|
||||
{selectedGroups.length > 1 ? 'are' : 'is'} selected
|
||||
</p>
|
||||
|
|
Reference in a new issue