49 lines
1.4 KiB
Vue
49 lines
1.4 KiB
Vue
<script setup lang="ts">
|
|
import { ArrowDown, ArrowUp, ChevronsUpDown } from '@lucide/vue';
|
|
import { inject } from 'vue';
|
|
import { Button } from '@/components/ui/button';
|
|
import { cn } from '@/lib/utils';
|
|
import type { DataTableSort } from '@/types/data-table';
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
title: string;
|
|
column: string;
|
|
class?: string;
|
|
}>(),
|
|
{},
|
|
);
|
|
|
|
type DataTableSortContext = {
|
|
sort: () => DataTableSort | null | undefined;
|
|
onSort: (column: string) => void;
|
|
};
|
|
|
|
const sortContext = inject<DataTableSortContext>('data-table-sort');
|
|
|
|
function isSorted(): boolean {
|
|
return sortContext?.sort()?.column === props.column;
|
|
}
|
|
|
|
function sortDirection(): 'asc' | 'desc' | null {
|
|
if (!isSorted()) {
|
|
return null;
|
|
}
|
|
|
|
return sortContext?.sort()?.direction ?? null;
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="cn('flex items-center gap-2', props.class)">
|
|
<Button variant="ghost" size="sm"
|
|
:class="cn('-ml-3 h-8 data-[state=open]:bg-accent', props.class?.includes('justify-end') && 'ml-auto')"
|
|
@click="sortContext?.onSort(column)">
|
|
<span>{{ title }}</span>
|
|
<ArrowDown v-if="sortDirection() === 'desc'" class="size-4" />
|
|
<ArrowUp v-else-if="sortDirection() === 'asc'" class="size-4" />
|
|
<ChevronsUpDown v-else class="size-4" />
|
|
</Button>
|
|
</div>
|
|
</template>
|