fix: improve skeletons

This commit is contained in:
axolotle 2024-08-16 00:24:39 +02:00
parent fcfcd767f0
commit 42e97c749a
9 changed files with 215 additions and 129 deletions

View file

@ -3,37 +3,39 @@ import { randint } from '@/helpers/commons'
</script> </script>
<template> <template>
<BInputGroup class="w-100 mb-4"> <BSkeletonWrapper button search>
<BInputGroupText> <BInputGroup class="w-100 mb-4">
<YIcon iname="search" /> <BInputGroupText>
</BInputGroupText> <YIcon iname="search" />
</BInputGroupText>
<BFormInput :disabled="true" /> <BFormInput :disabled="true" />
</BInputGroup> </BInputGroup>
<BCardGroup deck> <BCardGroup deck>
<BCard v-for="i in 15" :key="i" no-body> <BCard v-for="i in 15" :key="i" no-body>
<div class="d-flex w-100 mt-auto"> <div class="d-flex w-100 mt-auto">
<BSkeleton width="30px" height="30px" class="me-2 ms-auto" /> <BSkeleton width="30px" height="30px" class="me-2 ms-auto" />
<BSkeleton
:width="randint(30, 70) + '%'"
height="30px"
class="me-auto"
/>
</div>
<BSkeleton <BSkeleton
:width="randint(30, 70) + '%'" v-if="randint(0, 1)"
height="30px" :width="randint(30, 85) + '%'"
class="me-auto" height="24px"
class="mx-auto"
/> />
</div> <BSkeleton
<BSkeleton :width="randint(30, 85) + '%'"
v-if="randint(0, 1)" height="24px"
:width="randint(30, 85) + '%'" class="mx-auto mb-auto"
height="24px" />
class="mx-auto" </BCard>
/> </BCardGroup>
<BSkeleton </BSkeletonWrapper>
:width="randint(30, 85) + '%'"
height="24px"
class="mx-auto mb-auto"
/>
</BCard>
</BCardGroup>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{ withDefaults(defineProps<{ height?: string; width?: string }>(), {
height: string height: '26px',
width: string width: '100%',
}>() })
</script> </script>
<template> <template>
@ -13,7 +13,7 @@ defineProps<{
.b-skeleton { .b-skeleton {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
background-color: $gray-200; background-color: var(--bs-secondary-bg);
cursor: wait; cursor: wait;
height: $font-size-base; height: $font-size-base;
@ -22,9 +22,5 @@ defineProps<{
@if $enable-rounded { @if $enable-rounded {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
[data-bs-theme='dark'] & {
background-color: $gray-800;
}
} }
</style> </style>

View file

@ -1,16 +1,96 @@
<script setup lang="ts"> <script setup lang="ts">
withDefaults(defineProps<{ loading?: boolean }>(), { loading: false }) withDefaults(defineProps<{ button: boolean; search: boolean }>(), {
button: false,
search: false,
})
const slots = defineSlots<{
default: any
}>()
</script> </script>
<template> <template>
<div v-if="loading" class="b-skeleton-wrapper"> <div class="y-skeleton-wrapper">
<slot name="loading" /> <div class="visually-hidden">
<!-- FIXME add `loading` translation -->
{{ $t('loading') }}
</div>
<div v-if="search || button" id="top-bar-skeleton" class="d-flex mb-3">
<div id="search-skeleton" class="top-bar-group-skeleton">
<BInputGroup v-if="search" class="pe-none" aria-hidden="true">
<BInputGroupText>
<YIcon iname="search" />
</BInputGroupText>
<BFormInput :disabled="true" tabindex="-1" />
</BInputGroup>
</div>
<div v-if="button" id="button-skeleton" class="top-bar-group-skeleton">
<BSkeleton height="36px" class="ms-3-md" />
</div>
</div>
<slot name="default" />
</div> </div>
<slot v-else name="default" />
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.b-skeleton-wrapper { .y-skeleton-wrapper {
cursor: wait; cursor: wait;
#top-bar-skeleton {
flex-wrap: wrap-reverse;
.top-bar-group-skeleton {
margin-bottom: 1rem;
}
#button-skeleton {
width: 170px;
}
@include media-breakpoint-down(sm) {
.top-bar-group-skeleton {
flex-direction: column-reverse;
}
#button-skeleton {
width: 100%;
}
}
@include media-breakpoint-down(md) {
flex-direction: column-reverse;
#button-skeleton {
margin-bottom: 0.75rem;
:deep(> *) {
margin-bottom: 0.25rem;
}
}
.top-bar-group-skeleton {
justify-content: space-between;
flex-wrap: wrap;
}
}
@include media-breakpoint-up(md) {
#search-skeleton {
flex-grow: 2;
max-width: 50%;
}
#button-skeleton {
margin-left: auto;
}
:deep(.btn) {
margin-left: 0.5rem;
}
}
}
} }
</style> </style>

View file

@ -2,59 +2,55 @@
import { randint } from '@/helpers/commons' import { randint } from '@/helpers/commons'
import type { Cols } from '@/types/commons' import type { Cols } from '@/types/commons'
withDefaults( withDefaults(defineProps<{ itemCount?: number; cols: Cols }>(), {
defineProps<{ itemCount: 5,
itemCount?: number cols: () => ({ md: 4, lg: 2 }),
cols: Cols })
}>(),
{
itemCount: 5,
cols: () => ({ md: 4, lg: 2 }),
},
)
</script> </script>
<template> <template>
<BCard> <BSkeletonWrapper>
<template #header> <BCard>
<BSkeleton width="30%" height="36px" class="m-0" /> <template #header>
</template> <BSkeleton width="30%" height="26px" class="m-0" />
</template>
<template v-for="count in itemCount" :key="count"> <template v-for="count in itemCount" :key="count">
<BRow :class="{ 'd-block': cols === null }"> <BRow :class="{ 'd-block': cols === null }">
<BCol v-bind="cols"> <BCol v-bind="cols">
<div style="height: 38px" class="d-flex align-items-center"> <div style="height: 38px" class="d-flex align-items-center">
<BSkeleton <BSkeleton
class="m-0" class="m-0"
:width="randint(45, 100) + '%'" :width="randint(45, 100) + '%'"
height="24px" height="24px"
/> />
</div> </div>
</BCol> </BCol>
<BCol> <BCol>
<div <div
v-if="count % 2 === 0" v-if="count % 2 === 0"
class="w100 d-flex justify-content-between" class="w100 d-flex justify-content-between"
> >
<BSkeleton width="100%" height="38px" /> <BSkeleton width="100%" height="38px" />
<BSkeleton width="38px" height="38px" class="ms-2" /> <BSkeleton width="38px" height="38px" class="ms-2" />
</div> </div>
<BSkeleton v-else width="100%" height="38px" /> <BSkeleton v-else width="100%" height="38px" />
<BSkeleton :width="randint(15, 35) + '%'" height="19px" /> <BSkeleton :width="randint(15, 35) + '%'" height="19px" />
</BCol> </BCol>
</BRow> </BRow>
<hr /> <hr />
</template> </template>
<template #footer> <template #footer>
<div class="d-flex justify-content-end w-100"> <div class="d-flex justify-content-end w-100">
<BSkeleton width="100px" height="38px" /> <BSkeleton width="100px" height="36px" />
</div> </div>
</template> </template>
</BCard> </BCard>
</BSkeletonWrapper>
</template> </template>

View file

@ -5,18 +5,20 @@ withDefaults(defineProps<{ itemCount: number }>(), { itemCount: 5 })
</script> </script>
<template> <template>
<BCard> <BSkeletonWrapper>
<template #header> <BCard>
<BSkeleton width="30%" height="36px" class="m-0" /> <template #header>
</template> <BSkeleton width="30%" height="36px" class="m-0" />
</template>
<BRow v-for="i in itemCount" :key="i" no-gutters> <BRow v-for="i in itemCount" :key="i" no-gutters>
<BCol cols="5" md="3" xl="3"> <BCol cols="5" md="3" xl="3">
<BSkeleton :width="randint(45, 95) + '%'" height="19px" /> <BSkeleton :width="randint(45, 95) + '%'" height="19px" />
</BCol> </BCol>
<BCol> <BCol>
<BSkeleton :width="randint(10, 60) + '%'" height="19px" /> <BSkeleton :width="randint(10, 60) + '%'" height="19px" />
</BCol> </BCol>
</BRow> </BRow>
</BCard> </BCard>
</BSkeletonWrapper>
</template> </template>

View file

@ -1,26 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import { randint } from '@/helpers/commons' import { randint } from '@/helpers/commons'
withDefaults(defineProps<{ itemCount: number }>(), { itemCount: 5 }) withDefaults(defineProps<{ itemCount: number; search: boolean }>(), {
itemCount: 5,
search: false,
})
</script> </script>
<template> <template>
<BCard no-body> <BSkeletonWrapper :search="search">
<template #header> <BCard no-body>
<BSkeleton width="30%" height="36px" class="m-0" /> <template #header>
</template> <BSkeleton width="30%" height="36px" class="m-0" />
</template>
<BListGroup flush> <BListGroup flush>
<BListGroupItem v-for="count in itemCount" :key="count" class="d-flex"> <BListGroupItem v-for="count in itemCount" :key="count" class="d-flex">
<div style="width: 20%"> <div style="width: 20%">
<BSkeleton <BSkeleton
:width="randint(50, 100) + '%'" :width="randint(50, 100) + '%'"
height="24px" height="24px"
class="me-3" class="me-3"
/> />
</div> </div>
<BSkeleton :width="randint(30, 80) + '%'" height="24px" class="m-0" /> <BSkeleton :width="randint(30, 80) + '%'" height="24px" class="m-0" />
</BListGroupItem> </BListGroupItem>
</BListGroup> </BListGroup>
</BCard> </BCard>
</BSkeletonWrapper>
</template> </template>

View file

@ -1,14 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { randint } from '@/helpers/commons' import { randint } from '@/helpers/commons'
withDefaults(defineProps<{ itemCount: number }>(), { itemCount: 5 }) withDefaults(
defineProps<{ itemCount: number; button: boolean; search: boolean }>(),
{ itemCount: 5, button: true, search: true },
)
</script> </script>
<template> <template>
<BListGroup> <BSkeletonWrapper :button="button" :search="search">
<BListGroupItem v-for="count in itemCount" :key="count"> <BListGroup>
<BSkeleton :width="randint(15, 25) + '%'" height="24px" class="mb-2" /> <BListGroupItem v-for="count in itemCount" :key="count">
<BSkeleton :width="randint(25, 50) + '%'" height="24px" class="m-0" /> <BSkeleton :width="randint(15, 25) + '%'" height="24px" class="mb-2" />
</BListGroupItem> <BSkeleton :width="randint(25, 50) + '%'" height="24px" class="m-0" />
</BListGroup> </BListGroupItem>
</BListGroup>
</BSkeletonWrapper>
</template> </template>

View file

@ -77,7 +77,7 @@ const modalComponent = computed(() => {
<Component :is="Component" :class="classes" /> <Component :is="Component" :class="classes" />
<template #fallback> <template #fallback>
<template v-for="({ is, ...props }, i) in skeletons" :key="i"> <template v-for="({ is, ...props }, i) in skeletons" :key="i">
<Component :is="is" v-bind="props" /> <Component :is="is" v-bind="props" :class="{ 'mt-3': i !== 0 }" />
</template> </template>
</template> </template>
</Suspense> </Suspense>

View file

@ -239,7 +239,7 @@ const routes: RouteRecordRaw[] = [
meta: { meta: {
args: { trad: 'services' }, args: { trad: 'services' },
breadcrumb: ['tool-list', 'service-list'], breadcrumb: ['tool-list', 'service-list'],
skeleton: 'ListGroupSkeleton', skeleton: { is: 'ListGroupSkeleton', button: false },
}, },
}, },
{ {
@ -250,7 +250,7 @@ const routes: RouteRecordRaw[] = [
meta: { meta: {
args: { param: 'name' }, args: { param: 'name' },
breadcrumb: ['tool-list', 'service-list', 'service-info'], breadcrumb: ['tool-list', 'service-list', 'service-info'],
skeleton: 'CardInfoSkeleton', skeleton: ['CardInfoSkeleton', 'CardInfoSkeleton'],
}, },
}, },
@ -273,7 +273,7 @@ const routes: RouteRecordRaw[] = [
meta: { meta: {
args: { trad: 'logs' }, args: { trad: 'logs' },
breadcrumb: ['tool-list', 'tool-logs'], breadcrumb: ['tool-list', 'tool-logs'],
skeleton: 'CardListSkeleton', skeleton: { is: 'CardListSkeleton', search: true },
}, },
}, },
{ {
@ -284,7 +284,7 @@ const routes: RouteRecordRaw[] = [
meta: { meta: {
args: { param: 'name' }, args: { param: 'name' },
breadcrumb: ['tool-list', 'tool-logs', 'tool-log'], breadcrumb: ['tool-list', 'tool-logs', 'tool-log'],
skeleton: 'CardInfoSkeleton', skeleton: ['CardInfoSkeleton', 'CardInfoSkeleton'],
}, },
}, },
{ {