49 lines
1.1 KiB
Svelte
49 lines
1.1 KiB
Svelte
<script lang="ts">
|
|
import { getContext, type Snippet } from 'svelte';
|
|
import type { Writable } from 'svelte/store';
|
|
import Icon from '@iconify/svelte';
|
|
|
|
// types
|
|
interface Props {
|
|
key?: string;
|
|
|
|
children?: Snippet;
|
|
}
|
|
|
|
interface SortableHeaderContext {
|
|
headerKey: Writable<string>;
|
|
onSort: (key: string, order: 'asc' | 'desc') => void;
|
|
}
|
|
|
|
// inputs
|
|
const { key, children, ...restProps }: Props & Record<string, any> = $props();
|
|
|
|
let { headerKey, onSort }: SortableHeaderContext = getContext('sortableHeader');
|
|
|
|
let asc = $state(false);
|
|
|
|
// callbacks
|
|
function onButtonClick() {
|
|
if (key == undefined) return;
|
|
|
|
$headerKey = key;
|
|
asc = !asc;
|
|
onSort(key, asc ? 'asc' : 'desc');
|
|
}
|
|
</script>
|
|
|
|
<th {...restProps}>
|
|
{#if key}
|
|
<button class="flex items-center gap-1" onclick={() => onButtonClick()}>
|
|
<span>{@render children?.()}</span>
|
|
{#if $headerKey === key && asc}
|
|
<Icon icon="heroicons:chevron-up-16-solid" />
|
|
{:else}
|
|
<Icon icon="heroicons:chevron-down-16-solid" />
|
|
{/if}
|
|
</button>
|
|
{:else}
|
|
{@render children?.()}
|
|
{/if}
|
|
</th>
|