Files
Lesstime/frontend/components/ui/DataTable.vue
2026-03-12 18:06:28 +01:00

82 lines
2.9 KiB
Vue

<template>
<div class="mt-6 overflow-x-auto rounded-lg border border-neutral-200">
<table class="w-full text-left text-sm">
<thead class="border-b border-neutral-200 bg-neutral-50">
<tr>
<th
v-for="col in columns"
:key="col.key"
class="px-4 py-3 font-semibold text-neutral-700"
>
{{ col.label }}
</th>
<th v-if="deletable || $slots.actions" class="px-4 py-3 font-semibold text-neutral-700">
Actions
</th>
</tr>
</thead>
<tbody>
<tr
v-for="item in items"
:key="item.id"
class="cursor-pointer border-b border-neutral-100 hover:bg-neutral-50"
@click="$emit('row-click', item)"
>
<td
v-for="col in columns"
:key="col.key"
class="px-4 py-3"
:class="[col.class, { 'font-semibold text-primary-500': col.primary }]"
>
<slot :name="`cell-${col.key}`" :item="item" :value="item[col.key]">
{{ item[col.key] }}
</slot>
</td>
<td v-if="deletable || $slots.actions" class="px-4 py-3">
<div class="flex items-center gap-2">
<slot name="actions" :item="item" />
<button
v-if="deletable"
class="text-[red-500] hover:text-[red-700]"
@click.stop="$emit('delete', item)"
>
<Icon name="mdi:delete-outline" size="20" />
</button>
</div>
</td>
</tr>
<tr v-if="items.length === 0 && !loading">
<td
:colspan="columns.length + (deletable || $slots.actions ? 1 : 0)"
class="px-4 py-8 text-center text-neutral-400"
>
{{ emptyMessage }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup lang="ts">
export interface DataTableColumn {
key: string
label: string
primary?: boolean
class?: string
}
defineProps<{
columns: DataTableColumn[]
items: Record<string, any>[]
loading?: boolean
emptyMessage?: string
deletable?: boolean
}>()
defineEmits<{
(e: 'row-click', item: any): void
(e: 'delete', item: any): void
}>()
</script>