add generic components for table sorting
This commit is contained in:
parent
9ababd4847
commit
9be57c1004
35
src/lib/components/Table/SortableTh.svelte
Normal file
35
src/lib/components/Table/SortableTh.svelte
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, getContext, onDestroy } from 'svelte';
|
||||||
|
import type { Writable } from 'svelte/store';
|
||||||
|
import { IconSolid } from 'svelte-heros-v2';
|
||||||
|
|
||||||
|
let id = crypto.randomUUID();
|
||||||
|
let asc = false;
|
||||||
|
let { ascHeader } = getContext('sortableTr') as { ascHeader: Writable<null | string> };
|
||||||
|
ascHeader.subscribe((v) => {
|
||||||
|
if (v !== id) asc = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
let dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if ($ascHeader === id) $ascHeader = null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<th>
|
||||||
|
<button
|
||||||
|
class="flex flex-center"
|
||||||
|
on:click={() => {
|
||||||
|
dispatch('sort', { asc: (asc = !asc) });
|
||||||
|
$ascHeader = id;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="mr-1"><slot /></span>
|
||||||
|
<IconSolid
|
||||||
|
name={$ascHeader === id && asc ? 'chevron-up-solid' : 'chevron-down-solid'}
|
||||||
|
width="12"
|
||||||
|
height="12"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</th>
|
12
src/lib/components/Table/SortableTr.svelte
Normal file
12
src/lib/components/Table/SortableTr.svelte
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { setContext } from 'svelte';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
setContext('sortableTr', {
|
||||||
|
ascHeader: writable(null)
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<tr {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</tr>
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { IconOutline, IconSolid } from 'svelte-heros-v2';
|
import { IconOutline } from 'svelte-heros-v2';
|
||||||
import Input from '$lib/components/Input/Input.svelte';
|
import Input from '$lib/components/Input/Input.svelte';
|
||||||
import Select from '$lib/components/Input/Select.svelte';
|
import Select from '$lib/components/Input/Select.svelte';
|
||||||
import { env } from '$env/dynamic/public';
|
import { env } from '$env/dynamic/public';
|
||||||
@ -8,41 +8,11 @@
|
|||||||
import { buttonTriggeredRequest } from '$lib/components/utils';
|
import { buttonTriggeredRequest } from '$lib/components/utils';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import HeaderBar from './HeaderBar.svelte';
|
import HeaderBar from './HeaderBar.svelte';
|
||||||
|
import SortableTr from '$lib/components/Table/SortableTr.svelte';
|
||||||
|
import SortableTh from '$lib/components/Table/SortableTh.svelte';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
let headers = [
|
|
||||||
{
|
|
||||||
name: 'Vorname',
|
|
||||||
key: 'firstname',
|
|
||||||
asc: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Nachname',
|
|
||||||
key: 'lastname',
|
|
||||||
asc: false
|
|
||||||
},
|
|
||||||
{ name: 'Geburtstag', key: 'birthday', asc: false, sort: (a, b) => a.birthday - b.birthday },
|
|
||||||
{ name: 'Telefon', key: 'telephone', asc: false, sort: (a, b) => a.telephone - b.telephone },
|
|
||||||
{
|
|
||||||
name: 'Username',
|
|
||||||
key: 'username',
|
|
||||||
asc: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Minecraft Edition',
|
|
||||||
key: 'playertype',
|
|
||||||
asc: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Passwort',
|
|
||||||
key: 'password',
|
|
||||||
asc: false
|
|
||||||
},
|
|
||||||
{ name: 'UUID', key: 'uuid', asc: false }
|
|
||||||
];
|
|
||||||
let ascHeader: (typeof headers)[0] | null = null;
|
|
||||||
|
|
||||||
let currentPageUsers: (typeof User.prototype.dataValues)[] = [];
|
let currentPageUsers: (typeof User.prototype.dataValues)[] = [];
|
||||||
let currentPageUsersRequest: Promise<void> = new Promise((resolve) => resolve());
|
let currentPageUsersRequest: Promise<void> = new Promise((resolve) => resolve());
|
||||||
let usersPerPage = 50;
|
let usersPerPage = 50;
|
||||||
@ -70,12 +40,19 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sortUsers(key: string, reverse: boolean) {
|
$: fetchPageUsers(userPage, userFilter);
|
||||||
const multiplyValue = reverse ? -1 : 1;
|
|
||||||
|
|
||||||
currentPageUsers.sort((entryA, entryB) => {
|
let sortKey: string | null = null;
|
||||||
const a = entryA[key];
|
let sortAsc = false;
|
||||||
const b = entryB[key];
|
$: if (sortKey != null)
|
||||||
|
currentPageUsers = currentPageUsers.sort((entryA, entryB) => {
|
||||||
|
const multiplyValue = sortAsc ? -1 : 1;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
const a = entryA[sortKey];
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
const b = entryB[sortKey];
|
||||||
|
|
||||||
switch (typeof a) {
|
switch (typeof a) {
|
||||||
case 'number':
|
case 'number':
|
||||||
@ -86,10 +63,6 @@
|
|||||||
return (a - b) * multiplyValue;
|
return (a - b) * multiplyValue;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
currentPageUsers = currentPageUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
$: fetchPageUsers(userPage, userFilter);
|
|
||||||
|
|
||||||
async function updateUser(user: typeof User.prototype.dataValues) {
|
async function updateUser(user: typeof User.prototype.dataValues) {
|
||||||
const response = await fetch(`${env.PUBLIC_BASE_PATH}/admin/users`, {
|
const response = await fetch(`${env.PUBLIC_BASE_PATH}/admin/users`, {
|
||||||
@ -126,29 +99,19 @@
|
|||||||
<div class="h-full overflow-scroll" bind:this={userTableContainerElement}>
|
<div class="h-full overflow-scroll" bind:this={userTableContainerElement}>
|
||||||
<table class="table table-auto">
|
<table class="table table-auto">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="[&>th]:bg-base-100 [&>th]:z-[1] [&>th]:sticky [&>th]:top-0">
|
<!-- prettier-ignore -->
|
||||||
|
<SortableTr class="[&>th]:bg-base-100 [&>th]:z-[1] [&>th]:sticky [&>th]:top-0">
|
||||||
<th />
|
<th />
|
||||||
{#each headers as header}
|
<SortableTh on:sort={(e) => { sortKey = 'firstname'; sortAsc = e.detail.asc }}>Vorname</SortableTh>
|
||||||
<th>
|
<SortableTh on:sort={(e) => { sortKey = 'lastname'; sortAsc = e.detail.asc }}>Nachname</SortableTh>
|
||||||
<button
|
<SortableTh on:sort={(e) => { sortKey = 'birthday'; sortAsc = e.detail.asc }}>Geburtstag</SortableTh>
|
||||||
class="flex items-center"
|
<SortableTh on:sort={(e) => { sortKey = 'telephone'; sortAsc = e.detail.asc }}>Telefon</SortableTh>
|
||||||
on:click={() => {
|
<SortableTh on:sort={(e) => { sortKey = 'username'; sortAsc = e.detail.asc }}>Username</SortableTh>
|
||||||
sortUsers(header.key, (ascHeader = ascHeader == header ? null : header));
|
<SortableTh on:sort={(e) => { sortKey = 'playertype'; sortAsc = e.detail.asc }}>Minecraft Edition</SortableTh>
|
||||||
}}
|
<SortableTh on:sort={(e) => { sortKey = 'password'; sortAsc = e.detail.asc }}>Passwort</SortableTh>
|
||||||
>
|
<SortableTh on:sort={(e) => { sortKey = 'uuid'; sortAsc = e.detail.asc }}>UUID</SortableTh>
|
||||||
{header.name}
|
|
||||||
<span class="ml-1">
|
|
||||||
<IconSolid
|
|
||||||
name={ascHeader === header ? 'chevron-up-solid' : 'chevron-down-solid'}
|
|
||||||
width="12"
|
|
||||||
height="12"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</th>
|
|
||||||
{/each}
|
|
||||||
<th />
|
<th />
|
||||||
</tr>
|
</SortableTr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#key currentPageUsersRequest}
|
{#key currentPageUsersRequest}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user