Files
Kotyata/apps/client/components/stripped-table.vue
2026-03-17 13:24:22 +03:00

141 lines
2.6 KiB
Vue

<template>
<UiPlainTable
class="stripped-table"
:class="{ 'is-loading': loading }"
:columns="columns"
:data="data"
>
<template v-if="loading" #default>
<tbody>
<tr v-for="i in 6" :key="i">
<td :colspan="columns.length">
<div class="stripped-table__skeleton">
<div
v-for="j in i % 2 === 0 ? 7 : 3"
:key="j"
class="stripped-table__skeleton-cell"
/>
</div>
</td>
</tr>
</tbody>
</template>
<template v-else-if="!data.length" #default>
<tbody>
<tr>
<td class="stripped-table__no-data" :colspan="columns.length">
<img src="/no-data.svg" alt="No Data">
<h4>No Data</h4>
</td>
</tr>
</tbody>
</template>
<template v-for="(_, slot) of $slots" #[slot]="scope">
<slot :name="slot" v-bind="scope" />
</template>
</UiPlainTable>
</template>
<script setup lang="ts">
import type { ColumnDef } from '@tanstack/vue-table'
export interface Props {
columns: ColumnDef<unknown>[]
data: unknown[]
loading?: boolean
}
withDefaults(defineProps<Props>(), {
loading: false,
})
</script>
<style lang="scss">
.stripped-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 4px;
text-align: left;
margin-block: -4px;
td,
th {
margin: 0;
padding: 16px 8px;
&:first-child {
border-top-left-radius: 12px;
border-bottom-left-radius: 12px;
padding-left: 24px;
}
&:last-child {
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
padding-right: 24px;
}
}
th {
@include h5;
background-color: $clr-grey-100;
color: $clr-grey-500;
}
&.is-loading {
td {
background-color: $clr-grey-100;
}
}
&:not(.is-loading) {
tbody {
tr:nth-child(even) {
td {
background-color: $clr-grey-100;
}
}
}
}
&__no-data {
height: 494px;
text-align: center;
h4 {
margin-top: 8px;
color: $clr-grey-400;
}
}
&__skeleton {
display: flex;
align-items: center;
gap: 16px;
}
&__skeleton-cell {
border-radius: 12px;
background-color: $clr-white;
background-image: linear-gradient(
110deg,
$clr-white 8%,
$clr-grey-100 18%,
$clr-white 33%
);
background-size: 200% 100%;
height: 36px;
animation: 1.5s shine linear infinite;
width: 100%;
}
}
@keyframes shine {
to {
background-position-x: -200%;
}
}
</style>