mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
feat(table): add loading state (#259)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
committed by
GitHub
parent
d20983d355
commit
47415322ea
86
docs/components/content/examples/TableExampleLoadingSlot.vue
Normal file
86
docs/components/content/examples/TableExampleLoadingSlot.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<script setup>
|
||||
const columns = [{
|
||||
key: 'name',
|
||||
label: 'Name'
|
||||
}, {
|
||||
key: 'title',
|
||||
label: 'Title'
|
||||
}, {
|
||||
key: 'email',
|
||||
label: 'Email'
|
||||
}, {
|
||||
key: 'role',
|
||||
label: 'Role'
|
||||
}, {
|
||||
key: 'actions'
|
||||
}]
|
||||
|
||||
const people = []
|
||||
|
||||
const pending = ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable :rows="people" :columns="columns" :loading="pending">
|
||||
<template #loading-state>
|
||||
<div class="flex items-center justify-center h-32">
|
||||
<i class="loader --6" />
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* https://codepen.io/jenning/pen/YzNmzaV */
|
||||
|
||||
.loader {
|
||||
--color: rgb(var(--color-primary-400));
|
||||
--size-mid: 6vmin;
|
||||
--size-dot: 1.5vmin;
|
||||
--size-bar: 0.4vmin;
|
||||
--size-square: 3vmin;
|
||||
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 50%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.loader::before,
|
||||
.loader::after {
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/**
|
||||
loader --6
|
||||
**/
|
||||
.loader.--6::before {
|
||||
width: var(--size-square);
|
||||
height: var(--size-square);
|
||||
background-color: var(--color);
|
||||
top: calc(50% - var(--size-square));
|
||||
left: calc(50% - var(--size-square));
|
||||
animation: loader-6 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite;
|
||||
}
|
||||
|
||||
@keyframes loader-6 {
|
||||
0%, 100% {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(100%) translateY(100%);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -401,11 +401,60 @@ const rows = computed(() => {
|
||||
```
|
||||
::
|
||||
|
||||
### Loading :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full"}
|
||||
|
||||
Use the `loading` prop to display a loading state.
|
||||
|
||||
Use the `loading-state` prop to customize the `icon` and `label` or change them globally in `ui.table.default.loadingState`.
|
||||
|
||||
You can also set it to `null` to hide the loading state.
|
||||
|
||||
::component-card
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
baseProps:
|
||||
class: 'w-full'
|
||||
columns:
|
||||
- key: 'id'
|
||||
label: 'ID'
|
||||
- key: 'name'
|
||||
label: 'Name'
|
||||
- key: 'title'
|
||||
label: 'Title'
|
||||
- key: 'email'
|
||||
label: 'Email'
|
||||
- key: 'role'
|
||||
label: 'Role'
|
||||
props:
|
||||
loading: true
|
||||
loadingState:
|
||||
icon: 'i-heroicons-arrow-path-20-solid'
|
||||
label: "Loading..."
|
||||
excludedProps:
|
||||
- loadingState
|
||||
---
|
||||
::
|
||||
|
||||
This can be easily used with Nuxt `useAsyncData` composable.
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
const columns = [...]
|
||||
|
||||
const { pending, data: people } = await useLazyAsyncData('people', () => $fetch('/api/people'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable :rows="people" :columns="columns" :loading="pending" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Empty
|
||||
|
||||
Use the `empty-state` prop to display a message when there are no results.
|
||||
An empty state will be displayed when there are no results.
|
||||
|
||||
You can pass an `object` through the `empty-state` prop or globally through `ui.table.default.emptyState`.
|
||||
Use the `empty-state` prop to customize the `icon` and `label` or change them globally in `ui.table.default.emptyState`.
|
||||
|
||||
You can also set it to `null` to hide the empty state.
|
||||
|
||||
@@ -517,7 +566,46 @@ const selected = ref([people[1]])
|
||||
```
|
||||
::
|
||||
|
||||
### `empty-state` :u-badge{label="Edge" class="ml-2 align-text-bottom"}
|
||||
### `loading-state` :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full"}
|
||||
|
||||
Use the `#loading-state` slot to customize the loading state.
|
||||
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
padding: false
|
||||
overflowClass: 'overflow-x-auto'
|
||||
---
|
||||
|
||||
#default
|
||||
:table-example-loading-slot{class="flex-1"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const columns = [...]
|
||||
|
||||
const people = []
|
||||
|
||||
const pending = ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable :rows="people" :columns="columns" :loading="pending">
|
||||
<template #loading-state>
|
||||
<div class="flex items-center justify-center h-32">
|
||||
<i class="loader --6" />
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* https://codepen.io/jenning/pen/YzNmzaV */
|
||||
</style>
|
||||
```
|
||||
::
|
||||
|
||||
### `empty-state` :u-badge{label="Edge" class="ml-2 align-text-bottom !rounded-full"}
|
||||
|
||||
Use the `#empty-state` slot to customize the empty state.
|
||||
|
||||
|
||||
@@ -232,9 +232,9 @@ excludedProps:
|
||||
|
||||
### Empty
|
||||
|
||||
Use the `empty-state` prop to display a message when there are no results.
|
||||
An empty state will be displayed when there are no results.
|
||||
|
||||
You can pass an `object` through the `empty-state` prop or globally through `ui.commandPalette.default.emptyState`.
|
||||
Use the `empty-state` prop to customize the `icon` and `label` or change them globally in `ui.commandPalette.default.emptyState`.
|
||||
|
||||
You can also set it to `null` to hide the empty state.
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ const table = {
|
||||
font: '',
|
||||
size: 'text-sm'
|
||||
},
|
||||
loadingState: {
|
||||
wrapper: 'flex flex-col items-center justify-center flex-1 px-6 py-14 sm:px-14',
|
||||
label: 'text-sm text-center text-gray-900 dark:text-white',
|
||||
icon: 'w-6 h-6 mx-auto text-gray-400 dark:text-gray-500 mb-4 animate-spin'
|
||||
},
|
||||
emptyState: {
|
||||
wrapper: 'flex flex-col items-center justify-center flex-1 px-6 py-14 sm:px-14',
|
||||
label: 'text-sm text-center text-gray-900 dark:text-white',
|
||||
@@ -40,6 +45,10 @@ const table = {
|
||||
variant: 'ghost',
|
||||
class: '-m-1.5'
|
||||
},
|
||||
loadingState: {
|
||||
icon: 'i-heroicons-arrow-path-20-solid',
|
||||
label: 'Loading...'
|
||||
},
|
||||
emptyState: {
|
||||
icon: 'i-heroicons-circle-stack-20-solid',
|
||||
label: 'No items.'
|
||||
|
||||
@@ -34,7 +34,20 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr v-if="emptyState && !rows.length">
|
||||
<tr v-if="loadingState && loading">
|
||||
<td :colspan="columns.length">
|
||||
<slot name="loading-state">
|
||||
<div :class="ui.loadingState.wrapper">
|
||||
<UIcon v-if="loadingState.icon" :name="loadingState.icon" :class="ui.loadingState.icon" aria-hidden="true" />
|
||||
<p :class="ui.loadingState.label">
|
||||
{{ loadingState.label }}
|
||||
</p>
|
||||
</div>
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr v-else-if="emptyState && !rows.length">
|
||||
<td :colspan="columns.length">
|
||||
<slot name="empty-state">
|
||||
<div :class="ui.emptyState.wrapper">
|
||||
@@ -106,6 +119,14 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: () => appConfig.ui.table.default.sortDescIcon
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loadingState: {
|
||||
type: Object as PropType<{ icon: string, label: string }>,
|
||||
default: () => appConfig.ui.table.default.loadingState
|
||||
},
|
||||
emptyState: {
|
||||
type: Object as PropType<{ icon: string, label: string }>,
|
||||
default: () => appConfig.ui.table.default.emptyState
|
||||
|
||||
Reference in New Issue
Block a user