Skip to content

Commit 29b9b3c

Browse files
committed
feat(theme): add basic skeleton loader component
1 parent aac1472 commit 29b9b3c

File tree

4 files changed

+402
-306
lines changed

4 files changed

+402
-306
lines changed

packages/theme/components/Category/CategorySidebar.vue

Lines changed: 55 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,64 @@
11
<template>
2-
<div>
3-
<slot
4-
v-if="!$fetchState.pending"
5-
name="content"
6-
:category-tree="categoryTree"
7-
:active-category="activeCategory"
2+
<SfAccordion
3+
:open="activeCategory"
4+
:show-chevron="true"
5+
>
6+
<SfAccordionItem
7+
v-for="(cat, i) in categoryTree.items"
8+
:key="i"
9+
:header="cat.label"
810
>
9-
<SfAccordion
10-
:open="activeCategory"
11-
:show-chevron="true"
12-
>
13-
<SfAccordionItem
14-
v-for="(cat, i) in categoryTree.items"
15-
:key="i"
16-
:header="cat.label"
11+
<SfList class="list">
12+
<SfListItem
13+
v-for="(subCat, j) in cat.items"
14+
:key="j"
15+
class="list__item"
1716
>
18-
<SfList class="list">
19-
<SfListItem
20-
v-for="(subCat, j) in cat.items"
21-
:key="j"
22-
class="list__item"
23-
>
24-
<SfMenuItem
25-
:count="subCat.count || ''"
26-
:label="subCat.label"
17+
<SfMenuItem
18+
:count="subCat.count || ''"
19+
:label="subCat.label"
20+
>
21+
<template #label="{ label }">
22+
<nuxt-link
23+
:to="localePath(getAgnosticCatLink(subCat))"
24+
:class="subCat.isCurrent ? 'sidebar--cat-selected' : ''"
2725
>
28-
<template #label="{ label }">
29-
<nuxt-link
30-
:to="localePath(getAgnosticCatLink(subCat))"
31-
:class="subCat.isCurrent ? 'sidebar--cat-selected' : ''"
32-
>
33-
{{ label }}
34-
</nuxt-link>
35-
</template>
36-
</SfMenuItem>
37-
<SfMenuItem
38-
v-for="(subSubCat, z) in subCat.items && subCat.items"
39-
:key="z"
40-
:count="subSubCat.count || ''"
41-
:label="subSubCat.label"
42-
class="list__item__sub"
26+
{{ label }}
27+
</nuxt-link>
28+
</template>
29+
</SfMenuItem>
30+
<SfMenuItem
31+
v-for="(subSubCat, z) in subCat.items"
32+
:key="z"
33+
:count="subSubCat.count || ''"
34+
:label="subSubCat.label"
35+
class="list__item__sub"
36+
>
37+
<template #label="{ label }">
38+
<nuxt-link
39+
:to="localePath(getAgnosticCatLink(subSubCat))"
40+
:class="{'sidebar--cat-selected': subSubCat.isCurrent}"
4341
>
44-
<template #label="{ label }">
45-
<nuxt-link
46-
:to="localePath(getAgnosticCatLink(subSubCat))"
47-
:class="subSubCat.isCurrent ? 'sidebar--cat-selected' : ''"
48-
>
49-
{{ label }}
50-
</nuxt-link>
51-
</template>
52-
</SfMenuItem>
53-
</SfListItem>
54-
</SfList>
55-
</SfAccordionItem>
56-
</SfAccordion>
57-
</slot>
58-
</div>
42+
{{ label }}
43+
</nuxt-link>
44+
</template>
45+
</SfMenuItem>
46+
</SfListItem>
47+
</SfList>
48+
</SfAccordionItem>
49+
</SfAccordion>
5950
</template>
6051

6152
<script>
62-
import findDeep from 'deepdash/findDeep';
6353
import {
6454
SfList,
6555
SfMenuItem,
6656
SfAccordion,
67-
SfDivider,
6857
} from '@storefront-ui/vue';
6958
import {
70-
computed,
7159
defineComponent,
72-
ref,
73-
useFetch,
7460
} from '@nuxtjs/composition-api';
75-
import {
76-
categoryGetters,
77-
useCategory,
78-
} from '@vue-storefront/magento';
79-
import { CacheTagPrefix, useCache } from '@vue-storefront/cache';
80-
import { useUrlResolver } from '~/composables/useUrlResolver.ts';
61+
8162
import { useUiHelpers } from '~/composables';
8263
8364
export default defineComponent({
@@ -86,57 +67,22 @@ export default defineComponent({
8667
SfList,
8768
SfMenuItem,
8869
SfAccordion,
89-
SfDivider,
70+
},
71+
props: {
72+
categoryTree: {
73+
type: Object,
74+
default: () => {},
75+
},
76+
activeCategory: {
77+
type: String,
78+
default: '',
79+
},
9080
},
9181
setup() {
9282
const uiHelpers = useUiHelpers();
93-
const { addTags } = useCache();
94-
95-
const {
96-
result: urlData,
97-
search: resolveUrl,
98-
} = useUrlResolver();
99-
100-
const {
101-
categories,
102-
search,
103-
} = useCategory('categoryList-sidebar');
104-
105-
const categoryTree = ref([]);
106-
const activeCategory = computed(() => {
107-
const items = categoryTree.value?.items;
108-
if (!items) {
109-
return '';
110-
}
111-
const categoryLabel = ref();
112-
const parent = findDeep(items, (value, key, parentValue, _deepCtx) => {
113-
if (key === 'isCurrent' && value) {
114-
// eslint-disable-next-line no-underscore-dangle
115-
categoryLabel.value = _deepCtx.obj[_deepCtx._item.path[0]].label;
116-
}
117-
return key === 'isCurrent' && value;
118-
});
119-
120-
return categoryLabel.value || parent?.category?.label || items[0]?.label;
121-
});
122-
123-
useFetch(async () => {
124-
await Promise.all([resolveUrl(), search({ pageSize: 20 })]);
125-
categoryTree.value = categoryGetters.getCategoryTree(
126-
categories.value?.[0],
127-
urlData.value?.entity_uid,
128-
false,
129-
);
130-
131-
const categoriesTags = categoryTree?.value?.items?.map((category) => ({ prefix: CacheTagPrefix.Category, value: category.uid }));
132-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
133-
addTags(categoriesTags);
134-
});
13583
13684
return {
13785
...uiHelpers,
138-
categoryTree,
139-
activeCategory,
14086
};
14187
},
14288
});

packages/theme/components/Header/SearchBar/SearchBar.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@
5050

5151
<script>
5252
import { SfButton, SfSearchBar } from '@storefront-ui/vue';
53-
import { defineComponent, ref } from '@nuxtjs/composition-api';
54-
import { clickOutside } from '~/utilities/directives/click-outside/click-outside-directive.js';
55-
import SvgImage from '~/components/General/SvgImage.vue';
56-
53+
import {
54+
defineComponent, ref, watch, useRoute,
55+
} from '@nuxtjs/composition-api';
5756
import debounce from 'lodash.debounce';
5857
import {
5958
categoryGetters,
6059
useCategorySearch,
6160
useFacet,
6261
} from '@vue-storefront/magento';
63-
import { watch, useRoute } from '@nuxtjs/composition-api';
62+
import { clickOutside } from '~/utilities/directives/click-outside/click-outside-directive.js';
63+
import SvgImage from '~/components/General/SvgImage.vue';
6464
6565
export default defineComponent({
6666
name: 'SearchBar',
@@ -85,7 +85,7 @@ export default defineComponent({
8585
const isSearchOpen = ref(false);
8686
const result = ref(null);
8787
88-
const route = useRoute()
88+
const route = useRoute();
8989
9090
const {
9191
result: searchResult,
@@ -128,8 +128,8 @@ export default defineComponent({
128128
129129
const closeSearch = (event) => {
130130
if (document) {
131-
const searchResultsEl = document.getElementsByClassName('search');
132-
if (!searchResultsEl[0].contains(event.target)) {
131+
const searchResultsEl = document.querySelectorAll('.search');
132+
if (!searchResultsEl[0]?.contains(event.target)) {
133133
hideSearch();
134134
term.value = '';
135135
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<template>
2+
<div>
3+
<slot v-if="isLoaded" />
4+
<span
5+
v-else
6+
:class="componentClass"
7+
:style="componentStyle"
8+
/>
9+
</div>
10+
</template>
11+
12+
<script>
13+
import { computed, defineComponent } from '@nuxtjs/composition-api';
14+
15+
export default defineComponent({
16+
name: 'SkeletonLoader',
17+
props: {
18+
isLoaded: {
19+
type: Boolean,
20+
default: false,
21+
},
22+
animation: {
23+
type: [String, Boolean],
24+
default: 'shimmer',
25+
},
26+
width: {
27+
type: String,
28+
default: '100%',
29+
},
30+
height: {
31+
type: String,
32+
default: '1em',
33+
},
34+
margin: {
35+
type: String,
36+
default: '0 0 1em 0',
37+
},
38+
radius: {
39+
type: String,
40+
default: '4px',
41+
},
42+
skeletonClass: {
43+
type: String,
44+
default: '',
45+
},
46+
},
47+
setup(props) {
48+
const componentClass = computed(() => [
49+
'skeleton',
50+
props.skeletonClass,
51+
props.animation ? `skeleton--${props.animation}` : null,
52+
]);
53+
54+
const componentStyle = computed(() => ({
55+
width: props.width,
56+
height: props.height,
57+
borderRadius: props.radius,
58+
margin: props.margin,
59+
}));
60+
61+
return {
62+
componentClass,
63+
componentStyle,
64+
};
65+
},
66+
});
67+
68+
</script>
69+
70+
<style lang="scss">
71+
.skeleton {
72+
display: inline-block;
73+
vertical-align: middle;
74+
background-color: #f1f2f3;
75+
user-select: none;
76+
77+
&--shimmer {
78+
position: relative;
79+
overflow: hidden;
80+
81+
&::after {
82+
position: absolute;
83+
top: 0;
84+
right: 0;
85+
bottom: 0;
86+
left: 0;
87+
transform: translateX(-100%);
88+
background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(255,255,255,1) 40%, rgba(255,255,255,1) 60%, rgba(0,0,0,0) 100%);
89+
animation: shimmer 1.5s infinite;
90+
content: '';
91+
}
92+
}
93+
94+
@keyframes shimmer {
95+
100% {
96+
transform: translateX(100%);
97+
}
98+
}
99+
}
100+
</style>

0 commit comments

Comments
 (0)