Skip to content

Commit a56410d

Browse files
committed
perf: category page CLS improvement
- improve title loading - improve filters cls and content jumps
1 parent 0a8e3f4 commit a56410d

File tree

9 files changed

+120
-75
lines changed

9 files changed

+120
-75
lines changed

packages/theme/components/SkeletonLoader/index.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</template>
1010

1111
<script lang="ts">
12-
import { computed, defineComponent } from '@nuxtjs/composition-api';
12+
import { computed, defineComponent, ref } from '@nuxtjs/composition-api';
1313
1414
type ComponentStyles = { width?: string, height?: string, borderRadius: string, margin: string };
1515
@@ -26,9 +26,11 @@ export default defineComponent({
2626
},
2727
width: {
2828
type: String,
29+
default: '',
2930
},
3031
height: {
3132
type: String,
33+
default: '',
3234
},
3335
margin: {
3436
type: String,
@@ -50,10 +52,10 @@ export default defineComponent({
5052
props.animation ? `skeleton--${props.animation}` : null,
5153
]);
5254
53-
const componentStyle = computed<ComponentStyles>(() => ({
55+
const componentStyle = ref<ComponentStyles>({
5456
borderRadius: props.radius,
5557
margin: props.margin,
56-
}));
58+
});
5759
5860
if (props.width) {
5961
componentStyle.value.width = props.width;

packages/theme/modules/catalog/category/components/filters/CategoryFilters.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.filters {
22
position: relative;
3-
&__title {
3+
::v-deep &__title {
44
--heading-title-font-size: var(--font-size--xl);
55
margin: var(--spacer-xl) 0 var(--spacer-base) 0;
66

packages/theme/modules/catalog/category/components/filters/CategoryFilters.vue

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@
4141
:key="i"
4242
data-testid="category-filter"
4343
>
44-
<SfHeading
45-
:key="`filter-title-${filter.attribute_code}`"
46-
:level="4"
47-
:title="filter.label"
48-
class="filters__title sf-heading--left"
49-
/>
5044
<component
5145
:is="getFilterConfig(filter.attribute_code).component"
5246
:filter="filter"

packages/theme/modules/catalog/category/components/filters/renderer/CheckboxType.vue

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,50 @@
11
<template>
2-
<component
3-
:is="filter.options.length > 4 ? 'SfScrollable' : 'div' "
4-
max-content-height="6.875rem"
5-
:show-text="$t('Show more')"
6-
:hide-text="$t('Show less')"
7-
>
8-
<SfCheckbox
9-
v-for="option in filter.options"
10-
:key="`${filter.attribute_code}-${option.value}`"
11-
:label="option.label"
12-
:selected="Boolean(selected(filter.attribute_code, option.value))"
13-
class="filters__item"
14-
data-testid="category-filter"
15-
@change="$emit('selectFilter', option)"
2+
<div>
3+
<SfHeading
4+
:key="`filter-title-${filter.attribute_code}`"
5+
:level="4"
6+
:title="filter.label"
7+
class="filters__title sf-heading--left"
8+
/>
9+
<component
10+
:is="filter.options.length > 4 ? 'SfScrollable' : 'div' "
11+
max-content-height="6.875rem"
12+
:show-text="$t('Show more')"
13+
:hide-text="$t('Show less')"
1614
>
17-
<template #label="{ label }">
18-
<!-- eslint-disable-next-line vue/no-v-html -->
19-
<span
20-
:class="{ 'display-none': !label }"
21-
class="sf-checkbox__label"
22-
v-html="$dompurify(label)"
23-
/>
24-
</template>
25-
</SfCheckbox>
26-
</component>
15+
<SfCheckbox
16+
v-for="option in filter.options"
17+
:key="`${filter.attribute_code}-${option.value}`"
18+
:label="option.label"
19+
:selected="Boolean(selected(filter.attribute_code, option.value))"
20+
class="filters__item"
21+
data-testid="category-filter"
22+
@change="$emit('selectFilter', option)"
23+
>
24+
<template #label="{ label }">
25+
<!-- eslint-disable-next-line vue/no-v-html -->
26+
<span
27+
:class="{ 'display-none': !label }"
28+
class="sf-checkbox__label"
29+
v-html="$dompurify(label)"
30+
/>
31+
</template>
32+
</SfCheckbox>
33+
</component>
34+
</div>
2735
</template>
2836
<script lang="ts">
2937
import {
3038
computed, defineComponent, inject, PropType,
3139
} from '@nuxtjs/composition-api';
32-
import { SfCheckbox, SfScrollable } from '@storefront-ui/vue';
40+
import { SfCheckbox, SfScrollable, SfHeading } from '@storefront-ui/vue';
3341
import type { Aggregation } from '~/modules/GraphQL/types';
3442
3543
export default defineComponent({
3644
components: {
3745
SfCheckbox,
3846
SfScrollable,
47+
SfHeading,
3948
},
4049
props: {
4150
filter: {

packages/theme/modules/catalog/category/components/filters/renderer/RadioType.vue

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,53 @@
11
<template>
2-
<component
3-
:is="filter.options.length > 4 ? 'SfScrollable' : 'div' "
4-
max-content-height="6.875rem"
5-
:show-text="$t('Show more')"
6-
:hide-text="$t('Show less')"
7-
>
8-
<SfRadio
9-
v-for="option in filter.options"
10-
:key="`${filter.attribute_code}-${option.value}`"
11-
class="radio-filter"
12-
:label="`${option.label}`"
13-
:selected="selected(filter.attribute_code, option.value)"
14-
:value="option.value"
15-
name="filter__price"
16-
data-testid="category-filter"
17-
@change="$emit('selectFilter', option)"
2+
<div>
3+
<SfHeading
4+
:key="`filter-title-${filter.attribute_code}`"
5+
:level="4"
6+
:title="filter.label"
7+
class="filters__title sf-heading--left"
8+
/>
9+
<component
10+
:is="filter.options.length > 4 ? 'SfScrollable' : 'div' "
11+
max-content-height="6.875rem"
12+
:show-text="$t('Show more')"
13+
:hide-text="$t('Show less')"
1814
>
19-
<template #label="{ label }">
20-
<!-- eslint-disable-next-line vue/no-v-html -->
21-
<span
22-
:class="{ 'display-none': !label }"
23-
class="sf-radio__label"
24-
v-html="$dompurify(label)"
25-
/>
26-
</template>
27-
</SfRadio>
28-
</component>
15+
<SfRadio
16+
v-for="option in filter.options"
17+
:key="`${filter.attribute_code}-${option.value}`"
18+
class="radio-filter"
19+
:label="`${option.label}`"
20+
:selected="selected(filter.attribute_code, option.value)"
21+
:value="option.value"
22+
name="filter__price"
23+
data-testid="category-filter"
24+
@change="$emit('selectFilter', option)"
25+
>
26+
<template #label="{ label }">
27+
<!-- eslint-disable-next-line vue/no-v-html -->
28+
<span
29+
:class="{ 'display-none': !label }"
30+
class="sf-radio__label"
31+
v-html="$dompurify(label)"
32+
/>
33+
</template>
34+
</SfRadio>
35+
</component>
36+
</div>
2937
</template>
3038
<script lang="ts">
3139
import {
3240
computed,
3341
defineComponent, inject, PropType,
3442
} from '@nuxtjs/composition-api';
35-
import { SfRadio, SfScrollable } from '@storefront-ui/vue';
43+
import { SfRadio, SfScrollable, SfHeading } from '@storefront-ui/vue';
3644
import type { Aggregation } from '~/modules/GraphQL/types';
3745
3846
export default defineComponent({
3947
components: {
4048
SfRadio,
4149
SfScrollable,
50+
SfHeading,
4251
},
4352
props: {
4453
filter: {

packages/theme/modules/catalog/category/components/filters/renderer/SwatchColorType.vue

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
<template>
2-
<div class="swatch_color_wrapper">
3-
<SfColor
4-
v-for="option in filter.options"
5-
:key="`${filter.attribute_code}-${option.value}`"
6-
:color="option.label"
7-
:selected="Boolean(selected(filter.attribute_code, option.value))"
8-
class="swatch_color"
9-
role="button"
10-
@click="$emit('selectFilter', option)"
2+
<div>
3+
<SfHeading
4+
:key="`filter-title-${filter.attribute_code}`"
5+
:level="4"
6+
:title="filter.label"
7+
class="filters__title sf-heading--left"
118
/>
9+
<div class="swatch_color_wrapper">
10+
<SfColor
11+
v-for="option in filter.options"
12+
:key="`${filter.attribute_code}-${option.value}`"
13+
:color="option.label"
14+
:selected="Boolean(selected(filter.attribute_code, option.value))"
15+
class="swatch_color"
16+
role="button"
17+
@click="$emit('selectFilter', option)"
18+
/>
19+
</div>
1220
</div>
1321
</template>
1422
<script lang="ts">
1523
import {
1624
computed, defineComponent, inject, PropType,
1725
} from '@nuxtjs/composition-api';
18-
import { SfColor } from '@storefront-ui/vue';
26+
import { SfColor, SfHeading } from '@storefront-ui/vue';
1927
import type { Aggregation } from '~/modules/GraphQL/types';
2028
2129
export default defineComponent({
2230
components: {
2331
SfColor,
32+
SfHeading,
2433
},
2534
props: {
2635
filter: {

packages/theme/modules/catalog/category/components/filters/renderer/YesNoType.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<template>
22
<div>
3+
<SfHeading
4+
:key="`filter-title-${filter.attribute_code}`"
5+
:level="4"
6+
:title="filter.label"
7+
class="filters__title sf-heading--left"
8+
/>
39
<SfRadio
410
v-for="option in filter.options"
511
:key="`${filter.attribute_code}-${option.value}`"
@@ -18,12 +24,13 @@ import {
1824
computed,
1925
defineComponent, inject, PropType, useContext,
2026
} from '@nuxtjs/composition-api';
21-
import { SfRadio } from '@storefront-ui/vue';
27+
import { SfRadio, SfHeading } from '@storefront-ui/vue';
2228
import type { Aggregation, AggregationOption } from '~/modules/GraphQL/types';
2329
2430
export default defineComponent({
2531
components: {
2632
SfRadio,
33+
SfHeading,
2734
},
2835
props: {
2936
filter: {

packages/theme/modules/catalog/category/components/views/CategoryProductGrid.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ export default defineComponent({
103103
}
104104
105105
::v-deep .sf-product-card {
106+
.card {
107+
will-change: transform, opacity;
108+
}
109+
106110
&__image-wrapper {
107111
height: 257px;
108112
}

packages/theme/modules/catalog/pages/category.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
:content="cmsContent"
66
/>
77
<CategoryBreadcrumbs />
8+
<SkeletonLoader
9+
v-if="!activeCategoryName"
10+
height="57px"
11+
width="200px"
12+
margin="0"
13+
/>
814
<SfHeading
9-
v-if="isShowProducts"
15+
v-else
1016
:level="2"
1117
:title="activeCategoryName"
1218
class="category-title"
@@ -110,6 +116,7 @@ import {
110116
defineComponent, onMounted, ref, ssrRef, useFetch,
111117
} from '@nuxtjs/composition-api';
112118
import { CacheTagPrefix, useCache } from '@vue-storefront/cache';
119+
import SkeletonLoader from '~/components/SkeletonLoader/index.vue';
113120
import CategoryPagination from '~/modules/catalog/category/components/pagination/CategoryPagination.vue';
114121
import {
115122
useFacet,
@@ -148,6 +155,7 @@ export default defineComponent({
148155
SfSelect,
149156
LazyHydrate,
150157
SfHeading,
158+
SkeletonLoader,
151159
},
152160
transition: 'fade',
153161
setup() {
@@ -185,11 +193,14 @@ export default defineComponent({
185193
: addItemToWishlistBase({ product }));
186194
};
187195
188-
const { activeCategory } = useTraverseCategory();
196+
const { activeCategory, loadCategoryTree } = useTraverseCategory();
189197
const activeCategoryName = computed(() => activeCategory.value?.name ?? '');
190198
const routeData = ref<CategoryTree | null>(null);
191199
192200
const { fetch } = useFetch(async () => {
201+
if (!activeCategory.value) {
202+
loadCategoryTree();
203+
}
193204
const resolvedUrl = await resolveUrl();
194205
if (isCategoryTreeRoute(resolvedUrl)) routeData.value = resolvedUrl;
195206

0 commit comments

Comments
 (0)