115 lines
2.2 KiB
Vue
115 lines
2.2 KiB
Vue
<script setup lang="ts">
|
|
import { PropType } from "vue";
|
|
|
|
interface TableColumn {
|
|
key: string;
|
|
title: string;
|
|
}
|
|
|
|
defineProps({
|
|
cyTest: { type: String, default: "base" },
|
|
loading: Boolean,
|
|
columns: {
|
|
type: Array as PropType<TableColumn[]>,
|
|
required: true,
|
|
},
|
|
dataItems: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="wrapper" :class="{ '--loading': loading }">
|
|
<table :cy-test="`${cyTest}-table`">
|
|
<thead>
|
|
<tr>
|
|
<th v-for="column in columns" :key="column.key">
|
|
{{ column.title }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="(dataItem, index) in dataItems"
|
|
:key="dataItem.id || index"
|
|
:cy-test="`${cyTest}-table-row`"
|
|
>
|
|
<td
|
|
v-for="column in columns"
|
|
:key="column.key"
|
|
:cy-test="`${cyTest}-table-col-${column.key}`"
|
|
>
|
|
<slot :name="column.key" :dataItem="dataItem">{{
|
|
dataItem[column.key]
|
|
}}</slot>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="postcss">
|
|
.wrapper {
|
|
width: 100%;
|
|
min-height: 200px;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
}
|
|
|
|
td,
|
|
th {
|
|
text-align: left;
|
|
padding: 0.5rem 1rem;
|
|
border-bottom: 1px solid var(--color-table-border);
|
|
}
|
|
|
|
th {
|
|
background: var(--color-table-background);
|
|
font-weight: bold;
|
|
|
|
&:not(:last-child) {
|
|
border-right: 1px solid var(--color-table-border);
|
|
}
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background: var(--color-table-background);
|
|
}
|
|
|
|
.--loading {
|
|
pointer-events: none;
|
|
|
|
tbody,
|
|
thead {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
&::after {
|
|
position: absolute;
|
|
left: calc(50% - (1em * 0.5));
|
|
top: 100px;
|
|
position: absolute !important;
|
|
animation: spinAround 0.5s infinite linear;
|
|
border: 2px solid var(--color-spinner);
|
|
border-top-color: rgb(219, 219, 219);
|
|
border-right-color: rgb(219, 219, 219);
|
|
border-radius: 9999px;
|
|
border-right-color: transparent;
|
|
border-top-color: transparent;
|
|
content: "";
|
|
display: block;
|
|
height: 2em;
|
|
position: relative;
|
|
width: 2em;
|
|
z-index: 2;
|
|
}
|
|
}
|
|
</style>
|