1<template>
2 <div class="space-y-11" aria-busy="true">
3 <!-- Real headings: only the rows wait for data. -->
4 <section v-for="section in sections" :key="section.title">
5 <h2 class="text-md-semibold text-ink-gray-8">{{ section.title }}</h2>
6 <div class="mt-2 divide-y divide-outline-gray-1">
7 <div
8 v-for="i in section.rows || 0"
9 :key="`row-${i}`"
10 class="flex items-center justify-between gap-8 py-3.5"
11 >
12 <div class="flex min-w-0 flex-1 flex-col gap-1">
13 <div class="flex h-[17px] items-center">
14 <Skeleton
15 :class="[BLOCK, 'h-2.5 rounded-full']"
16 :style="{ width: `${7 + (i % 3) * 2}rem` }"
17 />
18 </div>
19 <div class="flex h-5 items-center">
20 <Skeleton
21 :class="[BLOCK, 'h-2 w-full max-w-[22rem] rounded-full']"
22 />
23 </div>
24 </div>
25 <Skeleton :class="[BLOCK, 'h-4 w-[26px] shrink-0 rounded-full']" />
26 </div>
27 <!-- A titled block over a box, e.g. pinned categories or the banner. -->
28 <div
29 v-for="(height, i) in section.panels || []"
30 :key="`panel-${i}`"
31 class="flex flex-col gap-1 py-3.5"
32 >
33 <div class="flex h-[17px] items-center">
34 <Skeleton :class="[BLOCK, 'h-2.5 w-28 rounded-full']" />
35 </div>
36 <div class="flex h-5 items-center">
37 <Skeleton :class="[BLOCK, 'h-2 w-3/4 rounded-full']" />
38 </div>
39 <Skeleton
40 :class="[BLOCK, 'mt-2 w-full rounded-[10px]']"
41 :style="{ height: `${height}px` }"
42 />
43 </div>
44 </div>
45 </section>
46 <!-- Last: first, it would take the sections' top margin. -->
47 <span class="sr-only" role="status">{{ __("Loading") }}</span>
48 </div>
49</template>
50
51<script setup lang="ts">
52import { Skeleton } from "frappe-ui";
53import { __ } from "../translation";
54
55// panels: each panel's box height, in px.
56defineProps<{
57 sections: { title: string; rows?: number; panels?: number[] }[];
58}>();
59
60const BLOCK = "motion-reduce:animate-none";
61</script>
62