79 lines
2.4 KiB
Vue
79 lines
2.4 KiB
Vue
<template>
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-10">
|
|
<Icon @click="router.push('/')" name="gg:arrow-left-o" size="44" class="cursor-pointer text-primary-500"/>
|
|
<h1 class="text-3xl font-bold uppercase text-primary-500">{{ title }}</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="px-[86px]">
|
|
<div class="mt-6 border border-slate-200 mb-16">
|
|
<div
|
|
class="grid gap-4 bg-slate-100 px-4 py-3 text-sm font-semibold uppercase tracking-wide"
|
|
:style="{ gridTemplateColumns: gridCols }"
|
|
>
|
|
<div v-for="col in columns" :key="col.key">{{ col.label }}</div>
|
|
<div v-if="showActions">Actions</div>
|
|
</div>
|
|
<div
|
|
v-for="item in items"
|
|
:key="item.id"
|
|
class="grid gap-4 px-4 py-3 text-sm border-t border-slate-200"
|
|
:class="canOpenItems ? 'hover:bg-slate-50 cursor-pointer' : ''"
|
|
:style="{ gridTemplateColumns: gridCols }"
|
|
role="button"
|
|
tabindex="0"
|
|
@click="goToItem(item.id)"
|
|
@keydown.enter="goToItem(item.id)"
|
|
>
|
|
<div v-for="col in columns" :key="col.key">
|
|
<slot :name="`cell-${col.key}`" :item="item">
|
|
{{ getNestedValue(item, col.key) }}
|
|
</slot>
|
|
</div>
|
|
<div v-if="showActions" @click.stop>
|
|
<slot name="actions" :item="item" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
interface Column {
|
|
key: string
|
|
label: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<{
|
|
title: string
|
|
columns: Column[]
|
|
items: any[]
|
|
routePrefix: string
|
|
showActions?: boolean
|
|
canOpenItems?: boolean
|
|
}>(), {
|
|
showActions: false,
|
|
canOpenItems: true
|
|
})
|
|
|
|
const router = useRouter()
|
|
|
|
const gridCols = computed(() => {
|
|
const dataCols = props.columns.map(() => '1fr').join(' ')
|
|
return props.showActions ? `${dataCols} 60px` : dataCols
|
|
})
|
|
|
|
const goToItem = (id: number) => {
|
|
if (!props.canOpenItems) {
|
|
return
|
|
}
|
|
router.push(`${props.routePrefix}/${id}`)
|
|
}
|
|
|
|
const getNestedValue = (obj: any, path: string): string => {
|
|
const value = path.split('.').reduce((acc, key) => acc?.[key], obj)
|
|
return value || '—'
|
|
}
|
|
</script>
|