Skip to content

Commit

Permalink
Merge pull request #1547 from EnergySage/CED-1851-create-es-skeleton
Browse files Browse the repository at this point in the history
CED-1851 Create esSkeleton, SkeletonWrapper, SkeletonImg
  • Loading branch information
lgeggleston authored Oct 8, 2024
2 parents 7cfb722 + fa786a7 commit 909ed20
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 0 deletions.
38 changes: 38 additions & 0 deletions es-ds-components/components/es-skeleton-img.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
const props = defineProps({
aspect: {
type: String,
default: '16:9',
},
noAspect: {
type: Boolean,
default: false,
},
});
const aspects = props.aspect.split(':');
const aspectRatio = computed(() => `${(parseFloat(aspects[1]) / parseFloat(aspects[0])) * 100}%`);
</script>

<template>
<!-- if noAspect is set, pass along to esSkeleton with all other props -->
<es-skeleton
v-if="noAspect"
v-bind="$attrs" />
<!-- if setting the aspect ratio, wrap skeleton in containers to determine responsive size -->
<!-- based on Bootstrap Aspect -->
<div
v-else
class="d-flex">
<div
class="flex-grow-1"
:style="{ 'padding-bottom': aspectRatio, height: '0px' }" />
<div
class="flex-grow-1 w-100 mw-100"
style="margin-left: -100%">
<es-skeleton
v-bind="$attrs"
class="h-100 w-100" />
</div>
</div>
</template>
17 changes: 17 additions & 0 deletions es-ds-components/components/es-skeleton-wrapper.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
defineProps({
loading: {
type: Boolean,
default: false,
},
});
</script>

<template>
<div>
<slot
v-if="loading"
name="loading" />
<slot v-else />
</div>
</template>
97 changes: 97 additions & 0 deletions es-ds-components/components/es-skeleton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script setup lang="ts">
import Skeleton from 'primevue/skeleton';
defineProps({
animation: {
type: String,
default: 'wave',
validator: (val: string) => ['wave', 'fade', 'none'].includes(val as string),
},
height: {
type: String,
default: '1rem',
},
width: {
type: String,
default: 'auto',
},
size: {
type: String,
default: null,
},
});
</script>

<template>
<skeleton
:height="size ? size : height"
:width="size ? size : width"
class="es-skeleton rounded-xs mb-25 bg-gray-200"
:class="{
'es-skeleton-wave': animation == 'wave',
'es-skeleton-fade': animation == 'fade',
}" />
</template>

<style lang="scss" scoped>
@use '@energysage/es-ds-styles/scss/variables' as variables;
@keyframes skeleton-animate-wave {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes skeleton-animate-fade {
0% {
opacity: 1;
}
100% {
opacity: 0.4;
}
}
.es-skeleton {
overflow: hidden;
&-wave:after {
content: '';
height: 100%;
position: absolute;
left: 0;
right: 0;
top: 0;
z-index: 1;
// wave animation from PrimeVue Skeleton
background-image: linear-gradient(
90deg,
rgba(variables.$white, 0),
rgba(variables.$white, 0.4),
rgba(variables.$white, 0)
);
animation-name: skeleton-animate-wave;
animation-duration: 1.2s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: infinite;
animation-direction: normal;
animation-fill-mode: none;
animation-play-state: running;
}
&-fade {
// fade animation from Bootstrap Skeleton
animation-name: skeleton-animate-fade;
animation-duration: 0.875s;
animation-timing-function: ease-in-out;
animation-delay: 0s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-fill-mode: none;
animation-play-state: running;
}
}
</style>
1 change: 1 addition & 0 deletions es-ds-components/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export default defineNuxtConfig({
'primevue/progressbar',
'primevue/radiobutton',
'primevue/rating',
'primevue/skeleton',
'primevue/slider',
'primevue/tabpanel',
'primevue/tabview',
Expand Down
3 changes: 3 additions & 0 deletions es-ds-docs/components/ds-molecules-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
<li>
<ds-link to="/molecules/rating"> Rating </ds-link>
</li>
<li>
<ds-link to="/molecules/skeleton"> Skeleton </ds-link>
</li>
<li>
<ds-link to="/molecules/slider"> Slider </ds-link>
</li>
Expand Down
167 changes: 167 additions & 0 deletions es-ds-docs/pages/molecules/skeleton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<script setup lang="ts">
const loading = ref(true);
const asyncTimeout = async (seconds = 3) => {
const millisecondTimeout = seconds * 1000;
return new Promise((resolve) => {
setTimeout(resolve, millisecondTimeout);
});
};
const startLoading = async () => {
loading.value = true;
await asyncTimeout();
loading.value = false;
};
const esSkeletonProps = [
['animation', 'String', 'wave', `Options are 'wave', 'fade', or 'none'`],
['height', 'String', '1rem', `Manually set height`],
['width', 'String', 'auto', `Manually set width`],
['size', 'String', 'null', `Manually set width and height, overriding 'height' and 'width' props`],
];
const esSkeletonImgProps = [
['aspect', 'String', '16:9', `Adds a container around the skeleton image with given aspect ratio`],
['noAspect', 'Boolean', 'false', `Override the default aspect ratio and height, width, or size`],
...esSkeletonProps,
].sort((a, b) => a[0].localeCompare(b[0]));
const esSkeletonWrapperProps = [
['loading', 'Boolean', 'false', `Determines whether to show loading template or default content`],
];
const { $prism } = useNuxtApp();
const compCode = ref('');
const docCode = ref('');
onMounted(async () => {
if ($prism) {
const compSource = await import('@energysage/es-ds-components/components/es-skeleton.vue?raw');
// eslint-disable-next-line import/no-self-import
const docSource = await import('./skeleton.vue?raw');
compCode.value = $prism.normalizeCode(compSource.default);
docCode.value = $prism.normalizeCode(docSource.default);
$prism.highlight();
}
startLoading();
});
</script>

<template>
<div>
<h1>Skeleton</h1>
<p>
Extended from
<nuxt-link
href="https://v3.primevue.org/skeleton/"
target="_blank">
PrimeVue Skeleton
</nuxt-link>
and
<nuxt-link
href="https://bootstrap-vue.org/docs/components/skeleton/"
target="_blank">
Bootstrap Skeleton
</nuxt-link>
styles
</p>

<h2>Basic examples</h2>
<p>Wave animation:</p>
<es-row class="mb-200">
<es-col lg="6">
<es-skeleton />
<es-skeleton width="75%" />
<es-skeleton height="3rem" />
</es-col>
<es-col
lg="6"
class="d-flex">
<es-skeleton size="5rem" />
<es-skeleton
size="4rem"
class="rounded-circle ml-100" />
</es-col>
</es-row>

<p>Fade animation:</p>
<es-row class="mb-500">
<es-col lg="6">
<es-skeleton
animation="fade"
height="33px"
width="100%" />
<es-skeleton
animation="fade"
height="25px"
width="100%" />
</es-col>
</es-row>

<h2>Helper components</h2>

<h3>Skeleton image</h3>
<es-row class="mb-500 d-flex">
<es-col lg="6">
<es-skeleton-img />
</es-col>
<es-col lg="6">
<es-skeleton-img aspect="3:1" />
</es-col>
<es-col
cols="12"
class="mt-100">
<es-skeleton-img
no-aspect
height="5rem" />
</es-col>
</es-row>

<h3>Skeleton wrapper</h3>
<es-row class="mb-500 d-flex">
<es-col
cols="12"
lg="3"
class="mb-100 mb-lg-0">
<es-button @click="startLoading()">Reload content</es-button>
</es-col>
<es-col
lg="7"
class="ml-lg-100">
<es-skeleton-wrapper :loading="loading">
<template #loading>
<es-skeleton width="85%"></es-skeleton>
<es-skeleton width="55%"></es-skeleton>
</template>

<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas viverra nunc sapien, non
rhoncus elit tincidunt vitae.
</p>
</es-skeleton-wrapper>
</es-col>
</es-row>

<div class="my-500">
<h2>EsSkeleton props</h2>
<ds-prop-table :rows="esSkeletonProps" />
</div>

<div class="my-500">
<h2>EsSkeletonImg props</h2>
<ds-prop-table :rows="esSkeletonImgProps" />
</div>

<div class="my-500">
<h2>EsSkeletonWrapper props</h2>
<ds-prop-table :rows="esSkeletonWrapperProps" />
</div>

<ds-doc-source
:comp-code="compCode"
comp-source="es-ds-components/components/es-skeleton.vue"
:doc-code="docCode"
doc-source="es-ds-docs/pages/molecules/skeleton.vue" />
</div>
</template>

0 comments on commit 909ed20

Please sign in to comment.