Implemented Mode Select and FIlters for Admin Page
This commit is contained in:
parent
4d6f3c23c3
commit
01e301eb60
1 changed files with 295 additions and 82 deletions
|
@ -7,27 +7,61 @@
|
||||||
import { CaretDown, CaretRight } from 'radix-icons-svelte';
|
import { CaretDown, CaretRight } from 'radix-icons-svelte';
|
||||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||||
import { Label } from '$lib/components/ui/label';
|
import { Label } from '$lib/components/ui/label';
|
||||||
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
|
import { range } from 'svelte-loading-spinners/utils';
|
||||||
|
import * as Select from '$lib/components/ui/select';
|
||||||
|
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
|
||||||
|
import AdminSelectedGroupStore from '$lib/stores/admin-page/GroupStore';
|
||||||
|
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
|
||||||
|
import {
|
||||||
|
type ChellarisEmpire,
|
||||||
|
type ChellarisGameGroup,
|
||||||
|
type ChellarisGameInfo,
|
||||||
|
createBlankEmpire
|
||||||
|
} from '$lib/types/chellaris';
|
||||||
|
import { apiBaseUrl } from '$lib/components_custom/consts';
|
||||||
|
|
||||||
// Dummy Data, Replace with API fetch
|
// Dummy Data, Replace with API fetch
|
||||||
|
function defaultEmpires() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
name: "Test Empire 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Test Empire 2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
function defaultGroups() {
|
function defaultGroups() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
checked: false,
|
checked: false,
|
||||||
name: "Test Group 1"
|
name: "Test Group 1",
|
||||||
|
empires: defaultEmpires()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
checked: false,
|
checked: false,
|
||||||
name: "Test Group 2"
|
name: "Test Group 2",
|
||||||
|
empires: defaultEmpires()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Empire = {
|
||||||
|
id: number,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
type Group = {
|
type Group = {
|
||||||
id: number,
|
id: number,
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
name: string
|
name: string,
|
||||||
|
empires: Array<Empire>
|
||||||
}
|
}
|
||||||
|
|
||||||
type Game = {
|
type Game = {
|
||||||
|
@ -64,96 +98,275 @@
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
let filteredGames = $derived(games.filter(game => game.checked))
|
||||||
|
let filteredGroups = $derived(filteredGames.flatMap(game => game.groups.filter(group => group.checked)))
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
console.log(games)
|
console.log(games)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const modes = [
|
||||||
|
{ value: "Game", label: "Games" },
|
||||||
|
{ value: "Group", label: "Groups" },
|
||||||
|
{ value: "Empire", label: "Empires" },
|
||||||
|
{ value: "Ethic", label: "Ethics" },
|
||||||
|
{ value: "Portrait", label: "Portraits" },
|
||||||
|
{ value: "User", label: "Users" }
|
||||||
|
];
|
||||||
|
|
||||||
function toggleGame(id: number) {
|
let modeSelect = $state(modes[0]);
|
||||||
games[id].checked = !games[id].checked;
|
|
||||||
games = games;
|
// Helper Function
|
||||||
|
|
||||||
|
function newGame() {
|
||||||
|
let newGame = {
|
||||||
|
id: games.length,
|
||||||
|
checked: false,
|
||||||
|
name: `Test ${games.length + 1}`,
|
||||||
|
groups: defaultGroups()
|
||||||
|
}
|
||||||
|
return newGame
|
||||||
}
|
}
|
||||||
|
|
||||||
let test = $state([
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true
|
|
||||||
])
|
|
||||||
|
|
||||||
let filterWidth = 90
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="h-full grid grid-cols-5">
|
<div class="h-full grid grid-cols-5">
|
||||||
<div class="p-2 flex flex-col items-center border-r-2 border-accent">
|
<div class="pt-4 px-2 flex flex-col items-center border-r-2 border-accent gap-2">
|
||||||
<h2 class="py-2">Editing Mode</h2>
|
<div class="flex flex-row gap-2">
|
||||||
<Separator orientation="horizontal" class="w-[{filterWidth}%]" />
|
<h2 class="self-center">
|
||||||
<h2 class="py-2">Filters</h2>
|
Editing
|
||||||
<Separator orientation="horizontal" class="w-[{filterWidth}%]" />
|
</h2>
|
||||||
<Collapsible.Root class="w-[{filterWidth}%] space-y-2 py-2">
|
<Select.Root bind:selected={modeSelect}>
|
||||||
<Collapsible.Trigger asChild let:builder>
|
<Select.Trigger class="w-28">
|
||||||
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
<Select.Value />
|
||||||
{#if builder["data-state"] == "open"}
|
</Select.Trigger>
|
||||||
<CaretDown />
|
<Select.Content>
|
||||||
{:else}
|
<Select.Group>
|
||||||
<CaretRight />
|
{#each modes as mode}
|
||||||
{/if}
|
<Select.Item value={mode.value} label={mode.label}>
|
||||||
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
{mode.label}
|
||||||
Games
|
</Select.Item>
|
||||||
</h4>
|
|
||||||
</Button>
|
|
||||||
</Collapsible.Trigger>
|
|
||||||
<Collapsible.Content class="space-y-2">
|
|
||||||
{#each games as game}
|
|
||||||
<div class="pl-4 flex items-center space-x-2">
|
|
||||||
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
|
||||||
<Label
|
|
||||||
for="{game.id.toString()}"
|
|
||||||
class=""
|
|
||||||
>
|
|
||||||
{game.name}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</Collapsible.Content>
|
|
||||||
</Collapsible.Root>
|
|
||||||
<Separator orientation="horizontal" class="w-[{filterWidth}%]" />
|
|
||||||
<Collapsible.Root class="w-[{filterWidth}%] space-y-2 py-2">
|
|
||||||
<Collapsible.Trigger asChild let:builder>
|
|
||||||
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
|
||||||
{#if builder["data-state"] == "open"}
|
|
||||||
<CaretDown />
|
|
||||||
{:else}
|
|
||||||
<CaretRight />
|
|
||||||
{/if}
|
|
||||||
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
|
||||||
Groups
|
|
||||||
</h4>
|
|
||||||
</Button>
|
|
||||||
</Collapsible.Trigger>
|
|
||||||
<Collapsible.Content class="space-y-2">
|
|
||||||
{#if games.filter(value => value.checked == true).length == 0}
|
|
||||||
<div class="pl-4 flex flex-col items-center space-x-2 text-muted-foreground">
|
|
||||||
<Label class="text-center" >No Games Selected</Label>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{#each games as game}
|
|
||||||
{#if game.checked}
|
|
||||||
{#each game.groups as group}
|
|
||||||
<div class="pl-4 flex items-center space-x-2">
|
|
||||||
<Checkbox id="{game.id}-{group.id}" checked={group.checked} on:click={() => {games[game.id].groups[group.id].checked = !group.checked}} />
|
|
||||||
<Label
|
|
||||||
for="{game.id}-{group.id}"
|
|
||||||
class=""
|
|
||||||
>
|
|
||||||
{game.name} {group.name}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
|
</Select.Group>
|
||||||
|
</Select.Content>
|
||||||
|
<Select.Input name="modeSelect" />
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<h2>{modeSelect.value} Filters</h2>
|
||||||
|
{#if modeSelect.value == modes[0].value}
|
||||||
|
|
||||||
|
{:else if modeSelect.value == modes[1].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[2].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Groups
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#if games.filter(value => value.checked == true).length == 0}
|
||||||
|
<div class="pl-4 flex flex-col items-center space-x-2 text-muted-foreground">
|
||||||
|
<Label class="text-center" >No Games Selected</Label>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{#each games as game}
|
||||||
</Collapsible.Content>
|
{#if game.checked}
|
||||||
</Collapsible.Root>
|
{#each game.groups as group}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id}-{group.id}" checked={group.checked} on:click={() => {games[game.id].groups[group.id].checked = !group.checked}} />
|
||||||
|
<Label
|
||||||
|
for="{game.id}-{group.id}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name} {group.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[3].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{:else if modeSelect.value == modes[4].value}
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
<Collapsible.Root class="w-[90%] space-y-2">
|
||||||
|
<Collapsible.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} variant="ghost" size="sm" class="w-full p-0 justify-start">
|
||||||
|
{#if builder["data-state"] == "open"}
|
||||||
|
<CaretDown />
|
||||||
|
{:else}
|
||||||
|
<CaretRight />
|
||||||
|
{/if}
|
||||||
|
<h4 class="rounded-md text-sm font-semibold text-left align-middle">
|
||||||
|
Games
|
||||||
|
</h4>
|
||||||
|
</Button>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content class="space-y-2">
|
||||||
|
{#each games as game}
|
||||||
|
<div class="pl-4 flex items-center space-x-2">
|
||||||
|
<Checkbox id="{game.id.toString()}" checked={game.checked} on:click={() => game.checked = !game.checked} />
|
||||||
|
<Label
|
||||||
|
for="{game.id.toString()}"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
|
{game.name}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Separator orientation="horizontal" class="w-[90%]" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="pt-6 px-3 flex flex-col col-span-2 items-center border-r-2 border-accent text-center text-muted-foreground gap-2 overflow-y-scroll">
|
||||||
|
{#if modeSelect.value == modes[0].value}
|
||||||
|
{#each games as game}
|
||||||
|
<!--<Skeleton class="h-12 w-[90%]" />-->
|
||||||
|
<div class="px-6 h-12 w-[90%] flex flex-row items-center border-2 rounded-md bg-primary/10">
|
||||||
|
<p class="text-primary">{game.name}</p>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button
|
||||||
|
class="px-6 h-12 w-[90%] flex flex-row items-center border-2 rounded-md bg-primary/10 text-primary hover:bg-primary/5"
|
||||||
|
on:click={() => {games.push(newGame())}}
|
||||||
|
>
|
||||||
|
Add Game
|
||||||
|
</Button>
|
||||||
|
{:else if modeSelect.value == modes[1].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
{#each game.groups as group}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Group</Button>
|
||||||
|
{:else if modeSelect.value == modes[2].value}
|
||||||
|
{console.log(filteredGroups)}
|
||||||
|
{#each filteredGroups as group}
|
||||||
|
{#each group.empires as empire}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Empire</Button>
|
||||||
|
{:else if modeSelect.value == modes[3].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Ethic</Button>
|
||||||
|
{:else if modeSelect.value == modes[4].value}
|
||||||
|
{#each filteredGames as game}
|
||||||
|
<Skeleton class="h-12 w-[90%]" />
|
||||||
|
{:else}
|
||||||
|
No Content
|
||||||
|
{/each}
|
||||||
|
<Button>Add Portrait</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="pt-6 px-3 flex flex-col col-span-2 text-center text-muted-foreground">
|
||||||
|
No Content
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-2 border-r-2 border-accent">B</div>
|
|
||||||
<div class=""></div>
|
|
||||||
</div>
|
</div>
|
Reference in a new issue