53 lines
1.6 KiB
Svelte
53 lines
1.6 KiB
Svelte
<!-- Table header for sorting by column -->
|
|
<script lang="ts">
|
|
import { mdiChevronDown, mdiChevronUp } from "@mdi/js";
|
|
|
|
import { Direction, type Sorting } from "$lib/util/types";
|
|
|
|
import Icon from "$lib/components/ui/Icon.svelte";
|
|
|
|
// Props
|
|
/** Sorting object (shared across all columns) */
|
|
export let sorting: Sorting | null = null;
|
|
/** Column identifier */
|
|
export let col: string;
|
|
/** Second column identifier (second title is placed in the `t2` slot) */
|
|
export let col2: string | undefined = undefined;
|
|
/** Disable ascending sorting */
|
|
export let noasc = false;
|
|
export let end = false;
|
|
export let ariaLabel: string | undefined = undefined;
|
|
|
|
$: value = sorting?.col === col || sorting?.col === col2 ? sorting?.dir : null;
|
|
|
|
function onClick(): void {
|
|
if (value === Direction.Forward) sorting!.dir = Direction.Backward;
|
|
else if (value === Direction.Backward) {
|
|
if (col2 && sorting!.col === col) {
|
|
sorting = { col: col2, dir: Direction.Forward };
|
|
} else sorting = null;
|
|
} else if (noasc && sorting) {
|
|
sorting = null;
|
|
} else {
|
|
sorting = { col, dir: noasc ? Direction.Backward : Direction.Forward };
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<button
|
|
class="w-full flex {end ? 'justify-end' : ''}"
|
|
class:text-primary={value}
|
|
aria-pressed={Boolean(value)}
|
|
aria-label={ariaLabel}
|
|
on:click={onClick}
|
|
>
|
|
{#if sorting && sorting.col === col2}
|
|
<slot name="t2" />
|
|
{:else}
|
|
<slot />
|
|
{/if}
|
|
<Icon
|
|
cls={value ? "" : "opacity-0"}
|
|
path={value === Direction.Backward ? mdiChevronDown : mdiChevronUp}
|
|
/>
|
|
</button>
|