-
-
Notifications
You must be signed in to change notification settings - Fork 366
/
Copy pathSkeletonLoader.vue
100 lines (87 loc) · 2.24 KB
/
SkeletonLoader.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<template>
<div class="h-full relative">
<div
v-if="solid"
class="relative w-full h-full rounded-[1.25rem] bg-k-grey-light"
/>
<NeoSkeleton
v-else
id="skeleton-backdrop"
class="z-[2]"
rounded
border-radius="20px"
no-margin
full-size
variant="k-grey-light"
/>
<div
class="flex justify-center w-full absolute -translate-x-2/4 -translate-y-2/4 z-[3] left-2/4 top-2/4"
>
<slot>
<KIcon
name="i-mdi:loading"
class="spinner text-k-grey mr-6 animate-spin"
size="large"
/>
<div :style="{ width: textContainerWidth }">
<p
ref="titleRef"
class="capitalize font-bold text-base"
>
{{ title || $t('general.doingSomeMagic') }}
</p>
<p class="capitalize text-base text-k-grey">
<span
ref="subtitleRef"
class="inline-block"
>{{
subtitle || $t('general.pleaseWait')
}}</span>
<span
v-if="showDots"
class="dots ml-1"
/>
</p>
</div>
</slot>
</div>
<slot name="footer" />
</div>
</template>
<script setup lang="ts">
import { NeoSkeleton } from '@kodadot1/brick'
const DOTS_PLUS_MARGIN_WIDTH = 20 // px
const props = withDefaults(
defineProps<{
title?: string
subtitle?: string
withDots?: boolean
solid?: boolean
}>(),
{
withDots: false,
solid: false,
},
)
const titleRef = ref<HTMLElement>()
const subtitleRef = ref<HTMLElement>()
const textContainerWidth = ref()
const showDots = computed(() => props.withDots || !props.subtitle)
const calculateTextContainerWidth = () => {
if (!showDots.value) {
return
}
textContainerWidth.value = undefined
nextTick(() => {
const title = titleRef.value?.clientWidth || 0
const subtitle = subtitleRef.value?.clientWidth || 0
const subtitlePlusDots = subtitle + DOTS_PLUS_MARGIN_WIDTH
if (subtitle && subtitlePlusDots > title) {
textContainerWidth.value = `${subtitlePlusDots}px`
}
})
}
watch([() => props.title, () => props.subtitle], calculateTextContainerWidth, {
immediate: true,
})
</script>