@designcrowd/library.brand-page 5.16.13-ast-bug-fix-9 → 5.16.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/{CreatedOnBrandCrowd-de-de-C-Kjk7Mf.js → CreatedOnBrandCrowd-de-de-CtO2RJXa.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-Da73K6iE.js → CreatedOnBrandCrowd-en-us-CZ3dIt1i.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-CqSmhjNh.js → CreatedOnBrandCrowd-es-es-9ScTkL0Q.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-TpguCMe4.js → CreatedOnBrandCrowd-fr-ca-BWrn1KZs.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-TpguCMe4.js → CreatedOnBrandCrowd-fr-fr-BWrn1KZs.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-Dv47A0wQ.js → CreatedOnBrandCrowd-pt-br-w9BZQE0-.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-Dv47A0wQ.js → CreatedOnBrandCrowd-pt-pt-w9BZQE0-.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-DNaAebBi.js → CreatedOnDcom-de-de-5MYEbeQk.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-qnXpTeaa.js → CreatedOnDcom-en-us-Btw0u0Ks.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-B2sQE-wp.js → CreatedOnDcom-es-es-4YwGIV-M.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BcyuEyOt.js → CreatedOnDcom-fr-ca-BpIS0iFt.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-FFt3_3mc.js → CreatedOnDcom-fr-fr-Bnk2A1-e.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DZit9sQw.js → CreatedOnDcom-pt-br-CCZRRMaR.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-CXuEvbvE.js → CreatedOnDcom-pt-pt-BG8aaK5S.js} +1 -1
- package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +69 -0
- package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.js +122 -0
- package/lib/src/css/library.brand-page-brandCrowd.min.css +10 -30
- package/lib/src/css/library.brand-page-brandPage.min.css +10 -33
- package/lib/src/css/library.brand-page-designCom.min.css +10 -42
- package/lib/src/css/library.brand-page-preview.min.css +10 -30
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-CgqwbARM.js → lib-GB7OrH7U.js} +11115 -11101
- package/package.json +2 -2
- package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +144 -0
- package/src/brand-page/components/image-gallery/masonry/MasonryGallery.vue +16 -135
- package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designcrowd/library.brand-page",
|
|
3
3
|
"description": "A collection of Maker/Designer applications",
|
|
4
|
-
"version": "5.16.13
|
|
4
|
+
"version": "5.16.13",
|
|
5
5
|
"author": "Design.com Eng",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@ckpack/vue-color": "1.4.1",
|
|
58
|
-
"@designcrowd/fe-shared-lib": "1.5.
|
|
58
|
+
"@designcrowd/fe-shared-lib": "1.5.2",
|
|
59
59
|
"@pinia/nuxt": "0.11.0",
|
|
60
60
|
"@storybook/react": "9.0.4",
|
|
61
61
|
"@tiptap/extension-bubble-menu": "^2.14.0",
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { defineComponent, ref } from 'vue';
|
|
2
|
+
import type { PropType } from 'vue';
|
|
3
|
+
import type { ImageGalleryViewModel } from '../../../view-models';
|
|
4
|
+
import type { DebounceHandle } from 'lodash.debounce';
|
|
5
|
+
import debounce from 'lodash.debounce';
|
|
6
|
+
import type { ImageGalleryImageClickPayload } from '../models';
|
|
7
|
+
import type { BrandPageContext, ImageGalleryItem } from '../../../models';
|
|
8
|
+
import { getImageAltText } from '../../../utils';
|
|
9
|
+
|
|
10
|
+
interface IndexedImageGalleryItem extends ImageGalleryItem {
|
|
11
|
+
id: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CONTAINER_WIDTH_MIN_THRESHOLD = 360;
|
|
15
|
+
const DEBOUNCE_WAIT_MS = 100;
|
|
16
|
+
const INIT_COLUMN_WIDTH = 140;
|
|
17
|
+
const MIN_COLUMNS = 2;
|
|
18
|
+
const MAX_COLUMNS = 3;
|
|
19
|
+
|
|
20
|
+
export default defineComponent({
|
|
21
|
+
props: {
|
|
22
|
+
gap: {
|
|
23
|
+
type: Number,
|
|
24
|
+
required: false,
|
|
25
|
+
default: 5,
|
|
26
|
+
},
|
|
27
|
+
viewModel: {
|
|
28
|
+
type: Object as PropType<ImageGalleryViewModel>,
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
context: {
|
|
32
|
+
type: Object as PropType<BrandPageContext>,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
contentIndex: {
|
|
36
|
+
type: Number,
|
|
37
|
+
required: false,
|
|
38
|
+
default: undefined,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
setup() {
|
|
42
|
+
const masonryRef = ref<InstanceType<any> | null>(null);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
masonryRef,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
emits: ['image-click'],
|
|
49
|
+
data() {
|
|
50
|
+
return {
|
|
51
|
+
columnWidth: INIT_COLUMN_WIDTH,
|
|
52
|
+
resizeDebounceHandler: undefined as DebounceHandle | undefined,
|
|
53
|
+
resizeObserver: undefined as ResizeObserver | undefined,
|
|
54
|
+
imagesBroken: {},
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
computed: {
|
|
58
|
+
items(): IndexedImageGalleryItem[] {
|
|
59
|
+
if (!this.viewModel || !Array.isArray(this.viewModel.images)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return this.viewModel.images.map((item, id) => {
|
|
64
|
+
return { ...item, id };
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
altText(): (item: ImageGalleryItem) => string {
|
|
69
|
+
return (item) => {
|
|
70
|
+
return getImageAltText(item, this.context);
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
created() {
|
|
75
|
+
if (!this.resizeDebounceHandler) {
|
|
76
|
+
this.resizeDebounceHandler = debounce(() => {
|
|
77
|
+
this.onResize();
|
|
78
|
+
}, DEBOUNCE_WAIT_MS);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
mounted() {
|
|
82
|
+
const $masonry = this.masonryRef;
|
|
83
|
+
|
|
84
|
+
if (this.resizeDebounceHandler && $masonry) {
|
|
85
|
+
this.resizeObserver?.disconnect();
|
|
86
|
+
this.resizeObserver = new ResizeObserver(this.resizeDebounceHandler);
|
|
87
|
+
this.resizeObserver.observe($masonry.$el);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.onResize();
|
|
91
|
+
},
|
|
92
|
+
beforeUnmount() {
|
|
93
|
+
this.resizeObserver?.disconnect();
|
|
94
|
+
this.resizeObserver = undefined;
|
|
95
|
+
},
|
|
96
|
+
watch: {
|
|
97
|
+
viewModel: {
|
|
98
|
+
handler(newVal, oldVal) {
|
|
99
|
+
if (newVal.images !== oldVal.images) {
|
|
100
|
+
this.resetImageBrokenList();
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
deep: true,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
methods: {
|
|
107
|
+
onImageClick(selectedIndex: number) {
|
|
108
|
+
const payload: ImageGalleryImageClickPayload = {
|
|
109
|
+
selectedIndex,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
this.$emit('image-click', payload);
|
|
113
|
+
},
|
|
114
|
+
onResize() {
|
|
115
|
+
const $masonry = this.masonryRef;
|
|
116
|
+
|
|
117
|
+
if (!$masonry) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const containerWidth = $masonry.$el.clientWidth;
|
|
122
|
+
const column =
|
|
123
|
+
containerWidth < CONTAINER_WIDTH_MIN_THRESHOLD
|
|
124
|
+
? MIN_COLUMNS
|
|
125
|
+
: MAX_COLUMNS;
|
|
126
|
+
|
|
127
|
+
this.columnWidth = containerWidth / column - this.gap;
|
|
128
|
+
|
|
129
|
+
// Force vue masonry wall to resize when container width changed but document width unchanged
|
|
130
|
+
if ($masonry.$el.$children && $masonry.$el.$children[0]) {
|
|
131
|
+
$masonry.$el.$children[0].$resize();
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
onImageError(index: number) {
|
|
135
|
+
this.imagesBroken[index] = true;
|
|
136
|
+
},
|
|
137
|
+
hasImageError(index: number) {
|
|
138
|
+
return this.imagesBroken[index] || false;
|
|
139
|
+
},
|
|
140
|
+
resetImageBrokenList() {
|
|
141
|
+
this.imagesBroken = {};
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
});
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
<Masonry
|
|
3
3
|
v-if="items.length > 0"
|
|
4
4
|
ref="masonryRef"
|
|
5
|
-
:gap="
|
|
5
|
+
:gap="5"
|
|
6
6
|
:column-width="columnWidth"
|
|
7
|
-
:max-columns="MAX_COLUMNS"
|
|
8
|
-
:min-columns="MIN_COLUMNS"
|
|
9
7
|
:items="items"
|
|
10
8
|
>
|
|
11
9
|
<template #item="{ item }">
|
|
@@ -31,148 +29,31 @@
|
|
|
31
29
|
</template>
|
|
32
30
|
</Masonry>
|
|
33
31
|
</template>
|
|
34
|
-
<script
|
|
35
|
-
import {
|
|
36
|
-
computed,
|
|
37
|
-
ref,
|
|
38
|
-
watch,
|
|
39
|
-
onMounted,
|
|
40
|
-
onBeforeUnmount,
|
|
41
|
-
nextTick,
|
|
42
|
-
} from 'vue';
|
|
32
|
+
<script>
|
|
43
33
|
import { Masonry } from '@designcrowd/fe-shared-lib';
|
|
44
|
-
import
|
|
45
|
-
import type { DebounceHandle } from 'lodash.debounce';
|
|
34
|
+
import MasonryGalleryMixin from './MasonryGallery.mixin.ts';
|
|
46
35
|
import Placeholder from '../../placeholder/Placeholder.vue';
|
|
47
36
|
import FallbackImage from '../../fallback-image/FallbackImage.vue';
|
|
48
37
|
import { imageGalleryTr } from '../../../../composables/useTranslate';
|
|
49
|
-
import type { ImageGalleryViewModel } from '../../../view-models';
|
|
50
|
-
import type { BrandPageContext, ImageGalleryItem } from '../../../models';
|
|
51
|
-
import type { ImageGalleryImageClickPayload } from '../models';
|
|
52
|
-
import { getImageAltText } from '../../../utils';
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
gap?: number;
|
|
60
|
-
viewModel: ImageGalleryViewModel;
|
|
61
|
-
context: BrandPageContext;
|
|
62
|
-
contentIndex?: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const CONTAINER_WIDTH_MIN_THRESHOLD = 360;
|
|
66
|
-
const DEBOUNCE_WAIT_MS = 100;
|
|
67
|
-
const INIT_COLUMN_WIDTH = 140;
|
|
68
|
-
const MIN_COLUMNS = 2;
|
|
69
|
-
const MAX_COLUMNS = 3;
|
|
70
|
-
|
|
71
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
72
|
-
gap: 5,
|
|
73
|
-
contentIndex: undefined,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const emit = defineEmits<{
|
|
77
|
-
'image-click': [payload: ImageGalleryImageClickPayload];
|
|
78
|
-
}>();
|
|
79
|
-
|
|
80
|
-
const masonryRef = ref<InstanceType<typeof Masonry> | null>(null);
|
|
81
|
-
const columnWidth = ref(INIT_COLUMN_WIDTH);
|
|
82
|
-
const imagesBroken = ref<Record<number, boolean>>({});
|
|
83
|
-
let resizeObserver: ResizeObserver | undefined;
|
|
84
|
-
let resizeDebounceHandler: DebounceHandle | undefined;
|
|
85
|
-
|
|
86
|
-
const items = computed((): IndexedImageGalleryItem[] => {
|
|
87
|
-
if (!props.viewModel || !Array.isArray(props.viewModel.images)) {
|
|
88
|
-
return [];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return props.viewModel.images.map((item, id) => {
|
|
92
|
-
return { ...item, id };
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const altText = (item: ImageGalleryItem): string => {
|
|
97
|
-
return getImageAltText(item, props.context);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const onImageClick = (selectedIndex: number) => {
|
|
101
|
-
const payload: ImageGalleryImageClickPayload = {
|
|
102
|
-
selectedIndex,
|
|
103
|
-
};
|
|
104
|
-
emit('image-click', payload);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const onResize = () => {
|
|
108
|
-
const $masonry = masonryRef.value;
|
|
109
|
-
|
|
110
|
-
if (!$masonry) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const containerWidth = $masonry.$el.clientWidth;
|
|
115
|
-
const column =
|
|
116
|
-
containerWidth < CONTAINER_WIDTH_MIN_THRESHOLD ? MIN_COLUMNS : MAX_COLUMNS;
|
|
117
|
-
|
|
118
|
-
columnWidth.value = containerWidth / column - props.gap;
|
|
119
|
-
|
|
120
|
-
// Force vue masonry wall to resize when container width changed but document width unchanged
|
|
121
|
-
if ($masonry.$el.$children && $masonry.$el.$children[0]) {
|
|
122
|
-
$masonry.$el.$children[0].$resize();
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const onImageError = (index: number) => {
|
|
127
|
-
imagesBroken.value[index] = true;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const hasImageError = (index: number): boolean => {
|
|
131
|
-
return imagesBroken.value[index] || false;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const resetImageBrokenList = () => {
|
|
135
|
-
imagesBroken.value = {};
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
// Watchers
|
|
139
|
-
watch(
|
|
140
|
-
() => props.viewModel.images,
|
|
141
|
-
() => {
|
|
142
|
-
resetImageBrokenList();
|
|
39
|
+
export default {
|
|
40
|
+
components: {
|
|
41
|
+
Masonry,
|
|
42
|
+
Placeholder,
|
|
43
|
+
FallbackImage,
|
|
143
44
|
},
|
|
144
|
-
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const $masonry = masonryRef.value;
|
|
154
|
-
|
|
155
|
-
if (resizeDebounceHandler && $masonry) {
|
|
156
|
-
resizeObserver?.disconnect();
|
|
157
|
-
resizeObserver = new ResizeObserver(resizeDebounceHandler);
|
|
158
|
-
resizeObserver.observe($masonry.$el);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Initial resize calculation
|
|
162
|
-
nextTick(() => {
|
|
163
|
-
onResize();
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
onBeforeUnmount(() => {
|
|
168
|
-
resizeObserver?.disconnect();
|
|
169
|
-
});
|
|
45
|
+
mixins: [MasonryGalleryMixin],
|
|
46
|
+
setup() {
|
|
47
|
+
return {
|
|
48
|
+
...MasonryGalleryMixin.setup(),
|
|
49
|
+
imageGalleryTr,
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
170
53
|
</script>
|
|
171
54
|
<style scoped>
|
|
172
55
|
.c-masonry-img {
|
|
173
56
|
@apply tw-w-full tw-cursor-pointer;
|
|
174
|
-
display: block;
|
|
175
|
-
height: auto;
|
|
176
57
|
}
|
|
177
58
|
</style>
|
|
178
59
|
<style>
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
ref="dropdown"
|
|
48
48
|
v-model:show="data.showMenu"
|
|
49
49
|
element-classes="tw-h-10 tw-w-full tw-text-grayscale-800"
|
|
50
|
-
menu-element-classes="tw-overflow-y-auto tw-max-h-72
|
|
50
|
+
menu-element-classes="tw-overflow-y-auto tw-max-h-72"
|
|
51
51
|
:title="data.selectedOption.option"
|
|
52
52
|
@update:show="onShowMenu"
|
|
53
53
|
>
|