Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 101 102 103 104 105 106 107 108 109 110 | 29x 29x 118x 118x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 2x 27x 29x 29x 29x 2x 27x 28x 167x 168x 173x | <script setup lang="ts">
import { computed } from "vue";
import Skeleton from "../Skeleton.vue";
import type { SkeletonBaseProps } from "../types";
type GridOptions = {
rows?: number;
columns?: number;
minItemWidth?: number | string;
itemCount?: number;
gap?: number | string;
itemHeight?: number | string;
itemRadius?: number | string;
padding?: number | string;
};
const props = defineProps<SkeletonBaseProps>();
const options = computed(() => (props.options ?? {}) as GridOptions);
function toUnit(value?: number | string) {
Iif (value == null) return undefined;
return typeof value === "number" ? `${value}px` : value;
}
const rows = computed(() => Math.max(1, options.value.rows ?? 2));
const columns = computed(() => Math.max(1, options.value.columns ?? 3));
const gap = computed(() => toUnit(options.value.gap ?? "16px"));
const itemHeight = computed(() => toUnit(options.value.itemHeight ?? "140px"));
const itemRadius = computed(() => toUnit(options.value.itemRadius ?? "12px"));
const padding = computed(() => toUnit(options.value.padding ?? "0"));
const containerWidth = computed(() =>
typeof props.width === "number"
? `${props.width}px`
: props.width ?? "100%"
);
const forwardedProps = computed(() => {
const { width, options, ...rest } = props;
return rest;
});
const isAutoFit = computed(() => options.value.minItemWidth != null);
const totalItems = computed(() => {
if (options.value.itemCount != null) {
return Math.max(1, options.value.itemCount);
}
return rows.value * columns.value;
});
const gridStyle = computed(() => {
const base = {
width: containerWidth.value,
gap: gap.value,
padding: padding.value,
};
if (isAutoFit.value) {
return {
...base,
gridTemplateColumns: `repeat(auto-fit, minmax(${toUnit(
options.value.minItemWidth!
)}, 1fr))`,
};
}
return {
...base,
gridTemplateColumns: `repeat(${columns.value}, minmax(0, 1fr))`,
};
});
</script>
<template>
<div class="vslk-grid" :style="gridStyle">
<div
v-for="item in totalItems"
:key="item"
class="vslk-grid__item"
>
<Skeleton
v-bind="forwardedProps"
variant="block"
width="100%"
:height="itemHeight"
:radius="itemRadius"
/>
</div>
</div>
</template>
<style scoped>
.vslk-grid {
display: grid;
box-sizing: border-box;
min-width: 0;
}
.vslk-grid__item {
min-width: 0;
box-sizing: border-box;
}
</style> |