make sortable table sortable

This commit is contained in:
MiniDigger | Martin 2022-04-02 20:06:34 +02:00
parent 2821bbf612
commit a91af36ca8
2 changed files with 38 additions and 6 deletions

View File

@ -1,8 +1,7 @@
<script lang="ts" setup>
import { hasSlotContent } from "~/composables/useSlot";
import Table from "~/components/design/Table.vue";
import Button from "~/components/design/Button.vue";
import { ref } from "vue";
import { computed, reactive, ref } from "vue";
export interface Header {
name: string;
@ -18,20 +17,50 @@ const props = defineProps<{
}>();
const expanded = ref<Record<number, boolean>>({});
// TODO actually implement sorting
const sorter = reactive<Record<string, number>>({});
const sorted = ref<any[]>(props.items);
function sort() {
sorted.value = [...props.items].sort((a, b) => {
for (let field of Object.keys(sorter)) {
if (sorter[field] === 0) continue;
if (a[field] > b[field]) return sorter[field];
if (a[field] < b[field]) return -sorter[field];
}
return 0;
});
}
function click(header: Header) {
if (header.sortable) {
if (sorter[header.name] === 1) {
sorter[header.name] = -1;
} else if (sorter[header.name] === -1) {
sorter[header.name] = 0;
} else {
sorter[header.name] = 1;
}
sort();
}
}
</script>
<template>
<Table class="w-full">
<thead>
<tr>
<th v-for="header in headers" :key="header.name" :style="header.width ? 'width: ' + header.width : ''">
{{ header.title }}
<th v-for="header in headers" :key="header.name" :style="header.width ? 'width: ' + header.width : ''" @click="click(header)">
<div class="items-center inline-flex" :cursor="header.sortable ? 'pointer' : 'auto'">
<span class="mr-2"> {{ header.title }}</span>
<IconMdiSortAscending v-if="sorter[header.name] === 1" />
<IconMdiSortDescending v-else-if="sorter[header.name] === -1" />
<IconMdiSort v-else-if="header.sortable" class="text-gray-400" />
</div>
</th>
</tr>
</thead>
<tbody>
<template v-for="(item, idx) in items" :key="idx">
<template v-for="(item, idx) in sorted" :key="idx">
<tr>
<td v-for="header in headers" :key="header.name" :style="header.width ? 'width: ' + header.width : ''" @click="expanded[idx] = !expanded[idx]">
<template v-if="hasSlotContent($slots['item_' + header.name], { item: item })">

View File

@ -28,6 +28,9 @@ declare module "vue" {
IconMdiPlay: typeof import("~icons/mdi/play")["default"];
IconMdiPlus: typeof import("~icons/mdi/plus")["default"];
IconMdiRenameBox: typeof import("~icons/mdi/rename-box")["default"];
IconMdiSort: typeof import("~icons/mdi/sort")["default"];
IconMdiSortAscending: typeof import("~icons/mdi/sort-ascending")["default"];
IconMdiSortDescending: typeof import("~icons/mdi/sort-descending")["default"];
IconMdiSortVariant: typeof import("~icons/mdi/sort-variant")["default"];
IconMdiStar: typeof import("~icons/mdi/star")["default"];
IconMdiStarOutline: typeof import("~icons/mdi/star-outline")["default"];