@akinon/next 2.0.0-beta.19 → 2.0.0-beta.20
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/CHANGELOG.md +20 -13
- package/assets/styles/index.scss +84 -0
- package/components/client-root.tsx +107 -1
- package/components/link.tsx +46 -16
- package/components/theme-editor/blocks/accordion-block.tsx +136 -0
- package/components/theme-editor/blocks/block-renderer-registry.tsx +77 -0
- package/components/theme-editor/blocks/button-block.tsx +593 -0
- package/components/theme-editor/blocks/counter-block.tsx +348 -0
- package/components/theme-editor/blocks/divider-block.tsx +20 -0
- package/components/theme-editor/blocks/embed-block.tsx +208 -0
- package/components/theme-editor/blocks/group-block.tsx +116 -0
- package/components/theme-editor/blocks/hotspot-block.tsx +147 -0
- package/components/theme-editor/blocks/icon-block.tsx +230 -0
- package/components/theme-editor/blocks/image-block.tsx +137 -0
- package/components/theme-editor/blocks/image-gallery-block.tsx +269 -0
- package/components/theme-editor/blocks/input-block.tsx +123 -0
- package/components/theme-editor/blocks/link-block.tsx +216 -0
- package/components/theme-editor/blocks/lottie-block.tsx +325 -0
- package/components/theme-editor/blocks/map-block.tsx +89 -0
- package/components/theme-editor/blocks/slider-block.tsx +595 -0
- package/components/theme-editor/blocks/tab-block.tsx +10 -0
- package/components/theme-editor/blocks/text-block.tsx +52 -0
- package/components/theme-editor/blocks/video-block.tsx +122 -0
- package/components/theme-editor/components/action-toolbar.tsx +305 -0
- package/components/theme-editor/components/designer-overlay.tsx +74 -0
- package/components/theme-editor/components/with-designer-features.tsx +142 -0
- package/components/theme-editor/dynamic-font-loader.tsx +79 -0
- package/components/theme-editor/hooks/use-designer-features.tsx +100 -0
- package/components/theme-editor/hooks/use-external-designer.tsx +95 -0
- package/components/theme-editor/hooks/use-native-widget-data.ts +188 -0
- package/components/theme-editor/hooks/use-visibility-context.ts +27 -0
- package/components/theme-editor/placeholder-registry.ts +31 -0
- package/components/theme-editor/sections/before-after-section.tsx +245 -0
- package/components/theme-editor/sections/contact-form-section.tsx +563 -0
- package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +433 -0
- package/components/theme-editor/sections/coupon-banner-section.tsx +710 -0
- package/components/theme-editor/sections/divider-section.tsx +62 -0
- package/components/theme-editor/sections/featured-product-spotlight-section.tsx +507 -0
- package/components/theme-editor/sections/find-in-store-section.tsx +1995 -0
- package/components/theme-editor/sections/hover-showcase-section.tsx +326 -0
- package/components/theme-editor/sections/image-hotspot-section.tsx +142 -0
- package/components/theme-editor/sections/installment-options-section.tsx +1065 -0
- package/components/theme-editor/sections/notification-banner-section.tsx +173 -0
- package/components/theme-editor/sections/order-tracking-lookup-section.tsx +1379 -0
- package/components/theme-editor/sections/posts-slider-section.tsx +472 -0
- package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +663 -0
- package/components/theme-editor/sections/section-renderer-registry.tsx +89 -0
- package/components/theme-editor/sections/section-wrapper.tsx +135 -0
- package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +586 -0
- package/components/theme-editor/sections/stats-counter-section.tsx +486 -0
- package/components/theme-editor/sections/tabs-section.tsx +578 -0
- package/components/theme-editor/theme-block.tsx +102 -0
- package/components/theme-editor/theme-placeholder-client.tsx +218 -0
- package/components/theme-editor/theme-placeholder-wrapper.tsx +732 -0
- package/components/theme-editor/theme-placeholder.tsx +288 -0
- package/components/theme-editor/theme-section.tsx +1224 -0
- package/components/theme-editor/theme-settings-context.tsx +13 -0
- package/components/theme-editor/utils/index.ts +792 -0
- package/components/theme-editor/utils/iterator-utils.ts +234 -0
- package/components/theme-editor/utils/publish-window.ts +86 -0
- package/components/theme-editor/utils/visibility-rules.ts +188 -0
- package/data/client/misc.ts +13 -1
- package/data/server/widget.ts +68 -1
- package/data/urls.ts +3 -1
- package/hooks/use-router.ts +53 -19
- package/lib/cache.ts +1 -0
- package/package.json +4 -2
- package/redux/reducers/index.ts +2 -0
- package/redux/reducers/widget.ts +80 -0
- package/types/commerce/widget.ts +33 -0
- package/types/widget.ts +80 -0
- package/utils/widget-styles.ts +107 -0
- package/with-pz-config.js +1 -1
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Carousel from 'react-multi-carousel';
|
|
3
|
+
import 'react-multi-carousel/lib/styles.css';
|
|
4
|
+
import clsx from 'clsx';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
|
|
7
|
+
import ThemeBlock from '../theme-block';
|
|
8
|
+
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
9
|
+
import { getCSSStyles, getResponsiveValue } from '../utils';
|
|
10
|
+
|
|
11
|
+
interface PostsSliderSectionProps {
|
|
12
|
+
section: any;
|
|
13
|
+
currentBreakpoint?: string;
|
|
14
|
+
placeholderId?: string;
|
|
15
|
+
isDesigner?: boolean;
|
|
16
|
+
selectedBlockId?: string | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const parseNumber = (value: unknown, fallback: number) => {
|
|
20
|
+
if (value === undefined || value === null || value === '') return fallback;
|
|
21
|
+
const parsed = typeof value === 'string' ? Number(value) : Number(value);
|
|
22
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const clampNumber = (value: number, min: number, max: number) =>
|
|
26
|
+
Math.min(Math.max(value, min), max);
|
|
27
|
+
|
|
28
|
+
const getNestedValue = (source: unknown, path: string): unknown => {
|
|
29
|
+
if (!path) return source;
|
|
30
|
+
const parts = path.split('.');
|
|
31
|
+
let current: unknown = source;
|
|
32
|
+
|
|
33
|
+
for (const part of parts) {
|
|
34
|
+
const arrayMatch = part.match(/^(.+)\[(\d+)\]$/);
|
|
35
|
+
if (arrayMatch) {
|
|
36
|
+
const [, arrayName, indexStr] = arrayMatch;
|
|
37
|
+
const arrayValue = (current as Record<string, unknown>)?.[arrayName];
|
|
38
|
+
if (!Array.isArray(arrayValue)) return undefined;
|
|
39
|
+
current = arrayValue[parseInt(indexStr, 10)];
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
current = (current as Record<string, unknown>)?.[part];
|
|
44
|
+
if (current === undefined) return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return current;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const cloneBlock = (block: any): any => ({
|
|
51
|
+
...block,
|
|
52
|
+
properties: block.properties ? { ...block.properties } : block.properties,
|
|
53
|
+
styles: block.styles
|
|
54
|
+
? JSON.parse(JSON.stringify(block.styles))
|
|
55
|
+
: block.styles,
|
|
56
|
+
blocks: block.blocks
|
|
57
|
+
? block.blocks.map((child: any) => cloneBlock(child))
|
|
58
|
+
: undefined
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const replaceBlockValues = (
|
|
62
|
+
blockToReplace: any,
|
|
63
|
+
productData: Record<string, unknown>,
|
|
64
|
+
productIndex: number
|
|
65
|
+
) => {
|
|
66
|
+
const newBlock = cloneBlock(blockToReplace);
|
|
67
|
+
const isPlaceholderMode =
|
|
68
|
+
!productData || Object.keys(productData).length === 0;
|
|
69
|
+
|
|
70
|
+
if (newBlock.properties?.dataBinding && !isPlaceholderMode) {
|
|
71
|
+
const bindingPath = String(newBlock.properties.dataBinding).replace(
|
|
72
|
+
'item.',
|
|
73
|
+
''
|
|
74
|
+
);
|
|
75
|
+
const resolvedValue = getNestedValue(productData, bindingPath);
|
|
76
|
+
|
|
77
|
+
if (resolvedValue !== undefined) {
|
|
78
|
+
if (newBlock.properties?.tag === 'a') {
|
|
79
|
+
newBlock.properties = {
|
|
80
|
+
...newBlock.properties,
|
|
81
|
+
href: String(resolvedValue)
|
|
82
|
+
};
|
|
83
|
+
} else {
|
|
84
|
+
newBlock.value =
|
|
85
|
+
typeof resolvedValue === 'string' || typeof resolvedValue === 'number'
|
|
86
|
+
? String(resolvedValue)
|
|
87
|
+
: resolvedValue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else if (isPlaceholderMode && newBlock.type === 'image') {
|
|
91
|
+
const placeholderImages = [
|
|
92
|
+
'/assets/images/product-placeholder-1.jpg',
|
|
93
|
+
'/assets/images/product-placeholder-2.jpg',
|
|
94
|
+
'/assets/images/product-placeholder-3.jpg',
|
|
95
|
+
'/assets/images/product-placeholder-4.jpg'
|
|
96
|
+
];
|
|
97
|
+
const placeholderIndex = productIndex % placeholderImages.length;
|
|
98
|
+
|
|
99
|
+
if (
|
|
100
|
+
newBlock.value &&
|
|
101
|
+
typeof newBlock.value === 'string' &&
|
|
102
|
+
newBlock.value.includes('product-placeholder')
|
|
103
|
+
) {
|
|
104
|
+
newBlock.value = placeholderImages[placeholderIndex];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (newBlock.blocks && newBlock.blocks.length > 0) {
|
|
109
|
+
newBlock.blocks = newBlock.blocks.map((childBlock: any) =>
|
|
110
|
+
replaceBlockValues(childBlock, productData, productIndex)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return newBlock;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const getIteratorProducts = (
|
|
118
|
+
section: any,
|
|
119
|
+
iteratorBlock: any,
|
|
120
|
+
isDesigner: boolean
|
|
121
|
+
): Record<string, unknown>[] => {
|
|
122
|
+
if (!section?.dataSource?.details) return [];
|
|
123
|
+
|
|
124
|
+
const dataPath =
|
|
125
|
+
iteratorBlock.iteratorDataPath ||
|
|
126
|
+
iteratorBlock.properties?.iteratorDataPath;
|
|
127
|
+
|
|
128
|
+
const details = section.dataSource.details;
|
|
129
|
+
const inEditor =
|
|
130
|
+
isDesigner && typeof window !== 'undefined' && window.parent !== window;
|
|
131
|
+
|
|
132
|
+
const candidates: unknown[] = inEditor
|
|
133
|
+
? [
|
|
134
|
+
details.collection?.products,
|
|
135
|
+
details.static?.data,
|
|
136
|
+
details.collection?.data,
|
|
137
|
+
details
|
|
138
|
+
]
|
|
139
|
+
: [
|
|
140
|
+
details.collection?.data?.products,
|
|
141
|
+
details.collection?.data,
|
|
142
|
+
details.collection?.products,
|
|
143
|
+
details.static?.data,
|
|
144
|
+
details
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
for (const candidate of candidates) {
|
|
148
|
+
if (Array.isArray(candidate)) {
|
|
149
|
+
return candidate as Record<string, unknown>[];
|
|
150
|
+
}
|
|
151
|
+
if (candidate && dataPath) {
|
|
152
|
+
const pathValue = getNestedValue(candidate, dataPath);
|
|
153
|
+
if (Array.isArray(pathValue)) {
|
|
154
|
+
return pathValue as Record<string, unknown>[];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return [];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const PostsSliderSection: React.FC<PostsSliderSectionProps> = ({
|
|
163
|
+
section,
|
|
164
|
+
currentBreakpoint = 'desktop',
|
|
165
|
+
placeholderId = '',
|
|
166
|
+
isDesigner = false,
|
|
167
|
+
selectedBlockId = null
|
|
168
|
+
}) => {
|
|
169
|
+
const themeSettings = useThemeSettingsContext();
|
|
170
|
+
|
|
171
|
+
const getConfigEntry = (key: string) =>
|
|
172
|
+
section.properties?.[key] ?? section.styles?.[key];
|
|
173
|
+
|
|
174
|
+
const normalizeResponsiveNumber = (
|
|
175
|
+
value: unknown,
|
|
176
|
+
fallback: { desktop: number; tablet: number; mobile: number }
|
|
177
|
+
) => {
|
|
178
|
+
if (value === undefined || value === null || value === '') {
|
|
179
|
+
return { ...fallback };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (typeof value === 'number' || typeof value === 'string') {
|
|
183
|
+
const parsed = parseNumber(value, fallback.desktop);
|
|
184
|
+
return { desktop: parsed, tablet: parsed, mobile: parsed };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (typeof value === 'object') {
|
|
188
|
+
const responsiveValue = value as Record<string, unknown>;
|
|
189
|
+
const candidate =
|
|
190
|
+
typeof responsiveValue.desktop === 'object' &&
|
|
191
|
+
responsiveValue.desktop !== null
|
|
192
|
+
? (responsiveValue.desktop as Record<string, unknown>)
|
|
193
|
+
: responsiveValue;
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
desktop: parseNumber(candidate.desktop, fallback.desktop),
|
|
197
|
+
tablet: parseNumber(candidate.tablet, fallback.tablet),
|
|
198
|
+
mobile: parseNumber(candidate.mobile, fallback.mobile)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { ...fallback };
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const itemsConfig = normalizeResponsiveNumber(
|
|
206
|
+
getConfigEntry('items-per-slide'),
|
|
207
|
+
{ desktop: 4, tablet: 3, mobile: 1 }
|
|
208
|
+
);
|
|
209
|
+
const slidesConfig = normalizeResponsiveNumber(
|
|
210
|
+
getConfigEntry('slides-to-slide'),
|
|
211
|
+
{ desktop: 1, tablet: 1, mobile: 1 }
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const sortedBlocks = [...(section.blocks || [])]
|
|
215
|
+
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
216
|
+
.filter((block) => (isDesigner ? true : !block.hidden));
|
|
217
|
+
|
|
218
|
+
const expandedBlocks = sortedBlocks.flatMap((block) => {
|
|
219
|
+
if (!block.isIterator || !block.blocks || block.blocks.length === 0) {
|
|
220
|
+
return [block];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const template = block.blocks[0];
|
|
224
|
+
const products = getIteratorProducts(section, block, isDesigner);
|
|
225
|
+
const fallbackCount = clampNumber(
|
|
226
|
+
parseNumber(block.properties?.iteratorCount, 1),
|
|
227
|
+
1,
|
|
228
|
+
50
|
|
229
|
+
);
|
|
230
|
+
const actualCount = products.length > 0 ? products.length : fallbackCount;
|
|
231
|
+
|
|
232
|
+
return Array.from({ length: actualCount }, (_, index) => {
|
|
233
|
+
const product = products[index] || {};
|
|
234
|
+
const cloned = replaceBlockValues(template, product, index);
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
...cloned,
|
|
238
|
+
id: `${template.id || block.id}-iter-${index}`,
|
|
239
|
+
__iteratorParentId: block.id,
|
|
240
|
+
__fromIterator: true
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const visibleCount = expandedBlocks.length;
|
|
246
|
+
|
|
247
|
+
const desktopItems = clampNumber(itemsConfig.desktop, 1, 8);
|
|
248
|
+
const tabletItems = clampNumber(itemsConfig.tablet, 1, 6);
|
|
249
|
+
const mobileItems = clampNumber(itemsConfig.mobile, 1, 4);
|
|
250
|
+
const desktopSlides = clampNumber(
|
|
251
|
+
slidesConfig.desktop,
|
|
252
|
+
1,
|
|
253
|
+
Math.max(1, visibleCount)
|
|
254
|
+
);
|
|
255
|
+
const tabletSlides = clampNumber(
|
|
256
|
+
slidesConfig.tablet,
|
|
257
|
+
1,
|
|
258
|
+
Math.max(1, visibleCount)
|
|
259
|
+
);
|
|
260
|
+
const mobileSlides = clampNumber(
|
|
261
|
+
slidesConfig.mobile,
|
|
262
|
+
1,
|
|
263
|
+
Math.max(1, visibleCount)
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const itemsPerView =
|
|
267
|
+
currentBreakpoint === 'mobile'
|
|
268
|
+
? mobileItems
|
|
269
|
+
: currentBreakpoint === 'tablet'
|
|
270
|
+
? tabletItems
|
|
271
|
+
: desktopItems;
|
|
272
|
+
|
|
273
|
+
const responsive = {
|
|
274
|
+
desktop: {
|
|
275
|
+
breakpoint: { max: 3000, min: 1024 },
|
|
276
|
+
items: desktopItems,
|
|
277
|
+
slidesToSlide: desktopSlides
|
|
278
|
+
},
|
|
279
|
+
tablet: {
|
|
280
|
+
breakpoint: { max: 1023, min: 768 },
|
|
281
|
+
items: tabletItems,
|
|
282
|
+
slidesToSlide: tabletSlides
|
|
283
|
+
},
|
|
284
|
+
mobile: {
|
|
285
|
+
breakpoint: { max: 767, min: 0 },
|
|
286
|
+
items: mobileItems,
|
|
287
|
+
slidesToSlide: mobileSlides
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const currentSlidesToSlide =
|
|
292
|
+
currentBreakpoint === 'mobile'
|
|
293
|
+
? mobileSlides
|
|
294
|
+
: currentBreakpoint === 'tablet'
|
|
295
|
+
? tabletSlides
|
|
296
|
+
: desktopSlides;
|
|
297
|
+
|
|
298
|
+
const carouselResponsive = isDesigner
|
|
299
|
+
? {
|
|
300
|
+
desktop: {
|
|
301
|
+
breakpoint: { max: 3000, min: 0 },
|
|
302
|
+
items: itemsPerView,
|
|
303
|
+
slidesToSlide: currentSlidesToSlide
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
: responsive;
|
|
307
|
+
|
|
308
|
+
const maxWidth = getResponsiveValue(
|
|
309
|
+
section.styles?.['max-width'],
|
|
310
|
+
currentBreakpoint,
|
|
311
|
+
'normal'
|
|
312
|
+
);
|
|
313
|
+
const maxWidthClass =
|
|
314
|
+
maxWidth === 'narrow'
|
|
315
|
+
? 'max-w-4xl'
|
|
316
|
+
: maxWidth === 'normal'
|
|
317
|
+
? 'max-w-7xl'
|
|
318
|
+
: '';
|
|
319
|
+
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
320
|
+
|
|
321
|
+
const styleEntries = section.styles || {};
|
|
322
|
+
const filteredStyles = Object.fromEntries(
|
|
323
|
+
Object.entries(styleEntries).filter(
|
|
324
|
+
([key]) =>
|
|
325
|
+
![
|
|
326
|
+
'items-per-slide',
|
|
327
|
+
'slides-to-slide',
|
|
328
|
+
'show-arrows',
|
|
329
|
+
'show-dots',
|
|
330
|
+
'max-width'
|
|
331
|
+
].includes(key)
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
const sectionStyles = getCSSStyles(
|
|
336
|
+
filteredStyles,
|
|
337
|
+
themeSettings,
|
|
338
|
+
currentBreakpoint
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const gapValue = getResponsiveValue(
|
|
342
|
+
section.styles?.gap,
|
|
343
|
+
currentBreakpoint,
|
|
344
|
+
16
|
|
345
|
+
);
|
|
346
|
+
const gap = parseNumber(gapValue, 16);
|
|
347
|
+
const slidePadding = gap > 0 ? gap / 2 : 0;
|
|
348
|
+
|
|
349
|
+
const showArrows =
|
|
350
|
+
getResponsiveValue(
|
|
351
|
+
getConfigEntry('show-arrows'),
|
|
352
|
+
currentBreakpoint,
|
|
353
|
+
true
|
|
354
|
+
) === true && visibleCount > itemsPerView;
|
|
355
|
+
const showDots =
|
|
356
|
+
getResponsiveValue(
|
|
357
|
+
getConfigEntry('show-dots'),
|
|
358
|
+
currentBreakpoint,
|
|
359
|
+
false
|
|
360
|
+
) === true && visibleCount > itemsPerView;
|
|
361
|
+
const autoPlay =
|
|
362
|
+
getResponsiveValue(getConfigEntry('autoplay'), currentBreakpoint, false) ===
|
|
363
|
+
true;
|
|
364
|
+
const autoPlaySpeed = clampNumber(
|
|
365
|
+
parseNumber(getConfigEntry('autoplay-speed'), 3000),
|
|
366
|
+
1000,
|
|
367
|
+
10000
|
|
368
|
+
);
|
|
369
|
+
const infinite =
|
|
370
|
+
getResponsiveValue(getConfigEntry('infinite'), currentBreakpoint, false) ===
|
|
371
|
+
true;
|
|
372
|
+
const hasMultipleSlides = visibleCount > itemsPerView;
|
|
373
|
+
const useInfinite = infinite && hasMultipleSlides;
|
|
374
|
+
const useAutoPlay = autoPlay && hasMultipleSlides;
|
|
375
|
+
|
|
376
|
+
const postBlockAction = (type: string, blockId: string, label?: string) => {
|
|
377
|
+
if (!window.parent) return;
|
|
378
|
+
window.parent.postMessage(
|
|
379
|
+
{
|
|
380
|
+
type,
|
|
381
|
+
data: {
|
|
382
|
+
placeholderId,
|
|
383
|
+
sectionId: section.id,
|
|
384
|
+
blockId,
|
|
385
|
+
...(label ? { label } : {})
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
'*'
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
if (expandedBlocks.length === 0) {
|
|
393
|
+
return (
|
|
394
|
+
<div
|
|
395
|
+
className="p-4 text-gray-400 border border-dashed border-gray-300 rounded"
|
|
396
|
+
style={sectionStyles}
|
|
397
|
+
>
|
|
398
|
+
No posts available
|
|
399
|
+
</div>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return (
|
|
404
|
+
<div
|
|
405
|
+
className={twMerge(
|
|
406
|
+
clsx('relative z-10 w-full', hasMaxWidth && 'mx-auto', maxWidthClass)
|
|
407
|
+
)}
|
|
408
|
+
style={sectionStyles}
|
|
409
|
+
>
|
|
410
|
+
<Carousel
|
|
411
|
+
key={`${desktopItems}-${tabletItems}-${mobileItems}-${desktopSlides}-${tabletSlides}-${mobileSlides}-${visibleCount}-${currentBreakpoint}-${useInfinite}-${useAutoPlay}-${autoPlaySpeed}`}
|
|
412
|
+
responsive={carouselResponsive}
|
|
413
|
+
{...(isDesigner ? { slidesToSlide: currentSlidesToSlide } : {})}
|
|
414
|
+
swipeable={true}
|
|
415
|
+
draggable={true}
|
|
416
|
+
arrows={showArrows}
|
|
417
|
+
showDots={showDots}
|
|
418
|
+
renderDotsOutside={showDots}
|
|
419
|
+
infinite={useInfinite}
|
|
420
|
+
rewind={useInfinite}
|
|
421
|
+
rewindWithAnimation={useInfinite}
|
|
422
|
+
autoPlay={useAutoPlay}
|
|
423
|
+
autoPlaySpeed={autoPlaySpeed}
|
|
424
|
+
containerClass="posts-slider-carousel"
|
|
425
|
+
dotListClass="posts-slider-dots"
|
|
426
|
+
>
|
|
427
|
+
{expandedBlocks.map((block) => {
|
|
428
|
+
const controlBlockId = block.__iteratorParentId || block.id;
|
|
429
|
+
const isIteratorClone = Boolean(block.__fromIterator);
|
|
430
|
+
|
|
431
|
+
return (
|
|
432
|
+
<div
|
|
433
|
+
key={block.id}
|
|
434
|
+
style={{
|
|
435
|
+
paddingLeft: slidePadding,
|
|
436
|
+
paddingRight: slidePadding
|
|
437
|
+
}}
|
|
438
|
+
>
|
|
439
|
+
<ThemeBlock
|
|
440
|
+
block={block}
|
|
441
|
+
placeholderId={placeholderId}
|
|
442
|
+
sectionId={section.id}
|
|
443
|
+
isDesigner={isDesigner && !isIteratorClone}
|
|
444
|
+
isSelected={selectedBlockId === controlBlockId}
|
|
445
|
+
selectedBlockId={selectedBlockId}
|
|
446
|
+
currentBreakpoint={currentBreakpoint}
|
|
447
|
+
onMoveUp={() =>
|
|
448
|
+
postBlockAction('MOVE_BLOCK_UP', controlBlockId)
|
|
449
|
+
}
|
|
450
|
+
onMoveDown={() =>
|
|
451
|
+
postBlockAction('MOVE_BLOCK_DOWN', controlBlockId)
|
|
452
|
+
}
|
|
453
|
+
onDuplicate={() =>
|
|
454
|
+
postBlockAction('DUPLICATE_BLOCK', controlBlockId)
|
|
455
|
+
}
|
|
456
|
+
onToggleVisibility={() =>
|
|
457
|
+
postBlockAction('TOGGLE_BLOCK_VISIBILITY', controlBlockId)
|
|
458
|
+
}
|
|
459
|
+
onDelete={() => postBlockAction('DELETE_BLOCK', controlBlockId)}
|
|
460
|
+
onRename={(newLabel) =>
|
|
461
|
+
postBlockAction('RENAME_BLOCK', controlBlockId, newLabel)
|
|
462
|
+
}
|
|
463
|
+
/>
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
})}
|
|
467
|
+
</Carousel>
|
|
468
|
+
</div>
|
|
469
|
+
);
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
export default PostsSliderSection;
|