@akinon/next 2.0.0-beta.20 → 2.0.0-beta.21
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 +23 -0
- package/api/auth.ts +292 -60
- package/bin/pz-install-plugins.js +1 -1
- package/package.json +3 -3
- package/types/index.ts +19 -6
- package/types/next-auth.d.ts +1 -1
- package/with-pz-config.js +8 -1
- package/components/theme-editor/blocks/accordion-block.tsx +0 -136
- package/components/theme-editor/blocks/block-renderer-registry.tsx +0 -77
- package/components/theme-editor/blocks/button-block.tsx +0 -593
- package/components/theme-editor/blocks/counter-block.tsx +0 -348
- package/components/theme-editor/blocks/divider-block.tsx +0 -20
- package/components/theme-editor/blocks/embed-block.tsx +0 -208
- package/components/theme-editor/blocks/group-block.tsx +0 -116
- package/components/theme-editor/blocks/hotspot-block.tsx +0 -147
- package/components/theme-editor/blocks/icon-block.tsx +0 -230
- package/components/theme-editor/blocks/image-block.tsx +0 -137
- package/components/theme-editor/blocks/image-gallery-block.tsx +0 -269
- package/components/theme-editor/blocks/input-block.tsx +0 -123
- package/components/theme-editor/blocks/link-block.tsx +0 -216
- package/components/theme-editor/blocks/lottie-block.tsx +0 -325
- package/components/theme-editor/blocks/map-block.tsx +0 -89
- package/components/theme-editor/blocks/slider-block.tsx +0 -595
- package/components/theme-editor/blocks/tab-block.tsx +0 -10
- package/components/theme-editor/blocks/text-block.tsx +0 -52
- package/components/theme-editor/blocks/video-block.tsx +0 -122
- package/components/theme-editor/components/action-toolbar.tsx +0 -305
- package/components/theme-editor/components/designer-overlay.tsx +0 -74
- package/components/theme-editor/components/with-designer-features.tsx +0 -142
- package/components/theme-editor/dynamic-font-loader.tsx +0 -79
- package/components/theme-editor/hooks/use-designer-features.tsx +0 -100
- package/components/theme-editor/hooks/use-external-designer.tsx +0 -95
- package/components/theme-editor/hooks/use-native-widget-data.ts +0 -188
- package/components/theme-editor/hooks/use-visibility-context.ts +0 -27
- package/components/theme-editor/placeholder-registry.ts +0 -31
- package/components/theme-editor/sections/before-after-section.tsx +0 -245
- package/components/theme-editor/sections/contact-form-section.tsx +0 -563
- package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +0 -433
- package/components/theme-editor/sections/coupon-banner-section.tsx +0 -710
- package/components/theme-editor/sections/divider-section.tsx +0 -62
- package/components/theme-editor/sections/featured-product-spotlight-section.tsx +0 -507
- package/components/theme-editor/sections/find-in-store-section.tsx +0 -1995
- package/components/theme-editor/sections/hover-showcase-section.tsx +0 -326
- package/components/theme-editor/sections/image-hotspot-section.tsx +0 -142
- package/components/theme-editor/sections/installment-options-section.tsx +0 -1065
- package/components/theme-editor/sections/notification-banner-section.tsx +0 -173
- package/components/theme-editor/sections/order-tracking-lookup-section.tsx +0 -1379
- package/components/theme-editor/sections/posts-slider-section.tsx +0 -472
- package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +0 -663
- package/components/theme-editor/sections/section-renderer-registry.tsx +0 -89
- package/components/theme-editor/sections/section-wrapper.tsx +0 -135
- package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +0 -586
- package/components/theme-editor/sections/stats-counter-section.tsx +0 -486
- package/components/theme-editor/sections/tabs-section.tsx +0 -578
- package/components/theme-editor/theme-block.tsx +0 -102
- package/components/theme-editor/theme-placeholder-client.tsx +0 -218
- package/components/theme-editor/theme-placeholder-wrapper.tsx +0 -732
- package/components/theme-editor/theme-placeholder.tsx +0 -288
- package/components/theme-editor/theme-section.tsx +0 -1224
- package/components/theme-editor/theme-settings-context.tsx +0 -13
- package/components/theme-editor/utils/index.ts +0 -792
- package/components/theme-editor/utils/iterator-utils.ts +0 -234
- package/components/theme-editor/utils/publish-window.ts +0 -86
- package/components/theme-editor/utils/visibility-rules.ts +0 -188
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import React, { useState, useEffect } from 'react';
|
|
4
|
-
import { useLocalization } from '@akinon/next/hooks';
|
|
5
|
-
import ThemeBlock, { Block } from '../theme-block';
|
|
6
|
-
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
7
|
-
import {
|
|
8
|
-
getCSSStyles,
|
|
9
|
-
getResponsiveValue,
|
|
10
|
-
resolveThemeCssVariables
|
|
11
|
-
} from '../utils';
|
|
12
|
-
|
|
13
|
-
import { Section } from '../theme-section';
|
|
14
|
-
import { WithDesignerFeatures } from '../components/with-designer-features';
|
|
15
|
-
|
|
16
|
-
interface HoverShowcaseSectionProps {
|
|
17
|
-
section: Section;
|
|
18
|
-
currentBreakpoint?: string;
|
|
19
|
-
placeholderId?: string;
|
|
20
|
-
isDesigner?: boolean;
|
|
21
|
-
selectedBlockId?: string | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
25
|
-
section,
|
|
26
|
-
currentBreakpoint = 'desktop',
|
|
27
|
-
placeholderId = '',
|
|
28
|
-
isDesigner = false,
|
|
29
|
-
selectedBlockId = null
|
|
30
|
-
}) => {
|
|
31
|
-
const { locale } = useLocalization();
|
|
32
|
-
const defaultLocale = process.env.NEXT_PUBLIC_DEFAULT_LOCALE || 'en';
|
|
33
|
-
const themeSettings = useThemeSettingsContext();
|
|
34
|
-
|
|
35
|
-
const [activeIndex, setActiveIndex] = useState(0);
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (isDesigner && selectedBlockId && section.blocks) {
|
|
39
|
-
const index = section.blocks.findIndex(
|
|
40
|
-
(b: Block) => b.id === selectedBlockId || b.blocks?.some((child: Block) => child.id === selectedBlockId)
|
|
41
|
-
);
|
|
42
|
-
if (index !== -1) {
|
|
43
|
-
setActiveIndex(index);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}, [isDesigner, selectedBlockId, section.blocks]);
|
|
47
|
-
|
|
48
|
-
const resolveLocalizedValue = (
|
|
49
|
-
value: unknown,
|
|
50
|
-
fallback: string
|
|
51
|
-
): string => {
|
|
52
|
-
if (value == null) return fallback;
|
|
53
|
-
|
|
54
|
-
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
55
|
-
const localized = value as Record<string, unknown>;
|
|
56
|
-
|
|
57
|
-
if (localized[locale] != null) return String(localized[locale]);
|
|
58
|
-
if (localized[defaultLocale] != null) return String(localized[defaultLocale]);
|
|
59
|
-
|
|
60
|
-
const responsive = getResponsiveValue(value, currentBreakpoint);
|
|
61
|
-
if (responsive != null && typeof responsive !== 'object') {
|
|
62
|
-
return String(responsive);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const firstValue = Object.values(localized).find((item) => item != null);
|
|
66
|
-
if (firstValue != null) return String(firstValue);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const responsive = getResponsiveValue(value, currentBreakpoint, fallback);
|
|
70
|
-
return String(responsive ?? fallback);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const getStyleEntry = (kebabKey: string) => {
|
|
74
|
-
if (!section.styles) return undefined;
|
|
75
|
-
const styles = section.styles as Record<string, unknown>;
|
|
76
|
-
const camelKey = kebabKey.replace(/-([a-z])/g, (_, letter) =>
|
|
77
|
-
letter.toUpperCase()
|
|
78
|
-
);
|
|
79
|
-
return styles[kebabKey] ?? styles[camelKey];
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const maxWidth = getResponsiveValue(getStyleEntry('max-width'), currentBreakpoint, 'normal');
|
|
83
|
-
const maxWidthClass =
|
|
84
|
-
maxWidth === 'narrow'
|
|
85
|
-
? 'max-w-4xl'
|
|
86
|
-
: maxWidth === 'normal'
|
|
87
|
-
? 'max-w-7xl'
|
|
88
|
-
: '';
|
|
89
|
-
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
90
|
-
|
|
91
|
-
const inactiveColor = resolveThemeCssVariables(
|
|
92
|
-
String(getResponsiveValue(getStyleEntry('inactive-color'), currentBreakpoint, '#9ca3af')),
|
|
93
|
-
themeSettings
|
|
94
|
-
);
|
|
95
|
-
const activeColor = resolveThemeCssVariables(
|
|
96
|
-
String(getResponsiveValue(getStyleEntry('active-color'), currentBreakpoint, '#111827')),
|
|
97
|
-
themeSettings
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const isMobile = currentBreakpoint === 'mobile';
|
|
101
|
-
|
|
102
|
-
const items = (section.blocks || []).filter((b: Block) => b.type === 'hover-showcase-item');
|
|
103
|
-
|
|
104
|
-
if (items.length === 0) {
|
|
105
|
-
if (isDesigner) {
|
|
106
|
-
return (
|
|
107
|
-
<div className="w-full flex items-center justify-center p-8 border border-dashed border-gray-300 rounded-lg">
|
|
108
|
-
<p className="text-gray-500">Add Hover Showcase Item blocks to see them here.</p>
|
|
109
|
-
</div>
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const sendDesignerMessage = (type: string, blockId: string, label?: string) => {
|
|
116
|
-
if (isDesigner && window.parent) {
|
|
117
|
-
window.parent.postMessage(
|
|
118
|
-
{
|
|
119
|
-
type,
|
|
120
|
-
data: {
|
|
121
|
-
placeholderId,
|
|
122
|
-
sectionId: section.id,
|
|
123
|
-
blockId,
|
|
124
|
-
...(label && { label })
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
'*'
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
const renderMobile = isDesigner ? isMobile : true;
|
|
132
|
-
const renderDesktop = isDesigner ? !isMobile : true;
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
<div
|
|
136
|
-
className={`w-full mx-auto ${hasMaxWidth ? maxWidthClass : ''}`}
|
|
137
|
-
style={getCSSStyles(section.styles as Record<string, unknown>, themeSettings as Record<string, unknown>, currentBreakpoint)}
|
|
138
|
-
>
|
|
139
|
-
{renderMobile && (
|
|
140
|
-
<div className={`flex flex-col gap-6 px-4 ${isDesigner ? '' : 'block md:hidden'}`}>
|
|
141
|
-
{items.map((item: Block, index: number) => {
|
|
142
|
-
const props = item.properties || {};
|
|
143
|
-
const itemStyles = item.styles || {};
|
|
144
|
-
const title = resolveLocalizedValue(props.title, `Item ${index + 1}`);
|
|
145
|
-
const subtitle = resolveLocalizedValue(props.subtitle, '');
|
|
146
|
-
const link = resolveLocalizedValue(props.link, '');
|
|
147
|
-
const isActive = index === activeIndex;
|
|
148
|
-
|
|
149
|
-
// Inside mobile render block, force evaluation of values for 'mobile' instead of the generic currentBreakpoint
|
|
150
|
-
const evalBreakpoint = isDesigner ? currentBreakpoint : 'mobile';
|
|
151
|
-
const mobileLayout = getResponsiveValue(getStyleEntry('mobile-layout'), evalBreakpoint, 'list');
|
|
152
|
-
const titleFontSize = getResponsiveValue(itemStyles['title-font-size'], evalBreakpoint, '24px');
|
|
153
|
-
const subtitleFontSize = getResponsiveValue(itemStyles['subtitle-font-size'], evalBreakpoint, '14px');
|
|
154
|
-
|
|
155
|
-
return (
|
|
156
|
-
<WithDesignerFeatures
|
|
157
|
-
key={item.id}
|
|
158
|
-
block={item}
|
|
159
|
-
placeholderId={placeholderId}
|
|
160
|
-
sectionId={section.id}
|
|
161
|
-
isDesigner={isDesigner}
|
|
162
|
-
isSelected={selectedBlockId === item.id}
|
|
163
|
-
currentBreakpoint={currentBreakpoint}
|
|
164
|
-
className="flex flex-col gap-3 cursor-pointer p-2 rounded relative"
|
|
165
|
-
onMoveUp={() => sendDesignerMessage('MOVE_BLOCK_UP', item.id)}
|
|
166
|
-
onMoveDown={() => sendDesignerMessage('MOVE_BLOCK_DOWN', item.id)}
|
|
167
|
-
onDuplicate={() => sendDesignerMessage('DUPLICATE_BLOCK', item.id)}
|
|
168
|
-
onToggleVisibility={() => sendDesignerMessage('TOGGLE_BLOCK_VISIBILITY', item.id)}
|
|
169
|
-
onDelete={() => sendDesignerMessage('DELETE_BLOCK', item.id)}
|
|
170
|
-
onRename={(newLabel) => sendDesignerMessage('RENAME_BLOCK', item.id, newLabel)}
|
|
171
|
-
>
|
|
172
|
-
<div className="flex flex-col" onClick={() => setActiveIndex(index)}>
|
|
173
|
-
{link ? (
|
|
174
|
-
<a href={link} className="decoration-none">
|
|
175
|
-
<h3 style={{ fontSize: String(titleFontSize), color: activeColor, transition: 'color 0.3s' }} className="font-semibold leading-tight m-0">{title}</h3>
|
|
176
|
-
</a>
|
|
177
|
-
) : (
|
|
178
|
-
<h3 style={{ fontSize: String(titleFontSize), color: activeColor, transition: 'color 0.3s' }} className="font-semibold leading-tight m-0">{title}</h3>
|
|
179
|
-
)}
|
|
180
|
-
{subtitle && (
|
|
181
|
-
<p style={{ fontSize: String(subtitleFontSize), color: inactiveColor }} className="mt-1 mb-0 opacity-80">{subtitle}</p>
|
|
182
|
-
)}
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
{mobileLayout === 'accordion' ? (
|
|
186
|
-
<div className={`overflow-hidden transition-all duration-300 ${isActive ? 'max-h-[600px] opacity-100 mt-2' : 'max-h-0 opacity-0'}`}>
|
|
187
|
-
{item.blocks?.map((block: Block) => (
|
|
188
|
-
<ThemeBlock
|
|
189
|
-
key={block.id}
|
|
190
|
-
block={block}
|
|
191
|
-
currentBreakpoint={currentBreakpoint}
|
|
192
|
-
isDesigner={isDesigner}
|
|
193
|
-
placeholderId={placeholderId}
|
|
194
|
-
sectionId={section.id}
|
|
195
|
-
selectedBlockId={selectedBlockId}
|
|
196
|
-
/>
|
|
197
|
-
))}
|
|
198
|
-
</div>
|
|
199
|
-
) : (
|
|
200
|
-
<div className="mt-2">
|
|
201
|
-
{item.blocks?.map((block: Block) => (
|
|
202
|
-
<ThemeBlock
|
|
203
|
-
key={block.id}
|
|
204
|
-
block={block}
|
|
205
|
-
currentBreakpoint={currentBreakpoint}
|
|
206
|
-
isDesigner={isDesigner}
|
|
207
|
-
placeholderId={placeholderId}
|
|
208
|
-
sectionId={section.id}
|
|
209
|
-
selectedBlockId={selectedBlockId}
|
|
210
|
-
/>
|
|
211
|
-
))}
|
|
212
|
-
</div>
|
|
213
|
-
)}
|
|
214
|
-
</WithDesignerFeatures>
|
|
215
|
-
);
|
|
216
|
-
})}
|
|
217
|
-
</div>
|
|
218
|
-
)}
|
|
219
|
-
|
|
220
|
-
{renderDesktop && (
|
|
221
|
-
<div className={`px-4 md:px-8 lg:px-12 items-center min-h-[500px] ${isDesigner ? 'flex' : 'hidden md:flex'}`}>
|
|
222
|
-
<div className="w-1/2 flex flex-col justify-center gap-1 relative z-10 pr-8">
|
|
223
|
-
{items.map((item: Block, index: number) => {
|
|
224
|
-
const props = item.properties || {};
|
|
225
|
-
const itemStyles = item.styles || {};
|
|
226
|
-
const title = resolveLocalizedValue(props.title, `Item ${index + 1}`);
|
|
227
|
-
const subtitle = resolveLocalizedValue(props.subtitle, '');
|
|
228
|
-
const link = resolveLocalizedValue(props.link, '');
|
|
229
|
-
const isActive = index === activeIndex;
|
|
230
|
-
|
|
231
|
-
const evalBreakpoint = isDesigner ? currentBreakpoint : 'desktop';
|
|
232
|
-
const titleFontSize = getResponsiveValue(itemStyles['title-font-size'], evalBreakpoint, '32px');
|
|
233
|
-
const subtitleFontSize = getResponsiveValue(itemStyles['subtitle-font-size'], evalBreakpoint, '16px');
|
|
234
|
-
const pt = getResponsiveValue(itemStyles['padding-top'], evalBreakpoint, 16);
|
|
235
|
-
const pb = getResponsiveValue(itemStyles['padding-bottom'], evalBreakpoint, 16);
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
<WithDesignerFeatures
|
|
239
|
-
key={item.id}
|
|
240
|
-
block={item}
|
|
241
|
-
placeholderId={placeholderId}
|
|
242
|
-
sectionId={section.id}
|
|
243
|
-
isDesigner={isDesigner}
|
|
244
|
-
isSelected={selectedBlockId === item.id}
|
|
245
|
-
currentBreakpoint={currentBreakpoint}
|
|
246
|
-
className="flex flex-col cursor-pointer group w-max rounded px-2 relative"
|
|
247
|
-
style={{ paddingTop: `${pt}px`, paddingBottom: `${pb}px` }}
|
|
248
|
-
onMoveUp={() => sendDesignerMessage('MOVE_BLOCK_UP', item.id)}
|
|
249
|
-
onMoveDown={() => sendDesignerMessage('MOVE_BLOCK_DOWN', item.id)}
|
|
250
|
-
onDuplicate={() => sendDesignerMessage('DUPLICATE_BLOCK', item.id)}
|
|
251
|
-
onToggleVisibility={() => sendDesignerMessage('TOGGLE_BLOCK_VISIBILITY', item.id)}
|
|
252
|
-
onDelete={() => sendDesignerMessage('DELETE_BLOCK', item.id)}
|
|
253
|
-
onRename={(newLabel) => sendDesignerMessage('RENAME_BLOCK', item.id, newLabel)}
|
|
254
|
-
>
|
|
255
|
-
<div
|
|
256
|
-
className="flex flex-col relative w-full"
|
|
257
|
-
onMouseEnter={() => setActiveIndex(index)}
|
|
258
|
-
>
|
|
259
|
-
{link ? (
|
|
260
|
-
<a href={link} className="decoration-none">
|
|
261
|
-
<h3
|
|
262
|
-
style={{ fontSize: String(titleFontSize), color: isActive ? activeColor : inactiveColor, transition: 'color 0.4s ease' }}
|
|
263
|
-
className="font-semibold leading-tight m-0 hover:opacity-80"
|
|
264
|
-
>
|
|
265
|
-
{title}
|
|
266
|
-
</h3>
|
|
267
|
-
</a>
|
|
268
|
-
) : (
|
|
269
|
-
<h3
|
|
270
|
-
style={{ fontSize: String(titleFontSize), color: isActive ? activeColor : inactiveColor, transition: 'color 0.4s ease' }}
|
|
271
|
-
className="font-semibold leading-tight m-0"
|
|
272
|
-
>
|
|
273
|
-
{title}
|
|
274
|
-
</h3>
|
|
275
|
-
)}
|
|
276
|
-
{subtitle && (
|
|
277
|
-
<p
|
|
278
|
-
style={{
|
|
279
|
-
fontSize: String(subtitleFontSize),
|
|
280
|
-
color: inactiveColor,
|
|
281
|
-
opacity: isActive ? 1 : 0,
|
|
282
|
-
maxHeight: isActive ? '40px' : '0px',
|
|
283
|
-
transform: isActive ? 'translateY(0)' : 'translateY(-10px)'
|
|
284
|
-
}}
|
|
285
|
-
className="mt-2 mb-0 overflow-hidden transition-all duration-400 ease-out"
|
|
286
|
-
>
|
|
287
|
-
{subtitle}
|
|
288
|
-
</p>
|
|
289
|
-
)}
|
|
290
|
-
</div>
|
|
291
|
-
</WithDesignerFeatures>
|
|
292
|
-
);
|
|
293
|
-
})}
|
|
294
|
-
</div>
|
|
295
|
-
|
|
296
|
-
<div className="w-1/2 relative h-full min-h-[400px] flex items-center justify-center">
|
|
297
|
-
{items.map((item: Block, index: number) => {
|
|
298
|
-
const isActive = index === activeIndex;
|
|
299
|
-
|
|
300
|
-
return (
|
|
301
|
-
<div
|
|
302
|
-
key={item.id}
|
|
303
|
-
className={`absolute inset-0 transition-opacity duration-500 ease-in-out flex items-center justify-center ${isActive ? 'opacity-100 z-10' : 'opacity-0 z-0'}`}
|
|
304
|
-
>
|
|
305
|
-
{item.blocks?.map((block: Block) => (
|
|
306
|
-
<ThemeBlock
|
|
307
|
-
key={block.id}
|
|
308
|
-
block={block}
|
|
309
|
-
currentBreakpoint={currentBreakpoint}
|
|
310
|
-
isDesigner={isDesigner}
|
|
311
|
-
placeholderId={placeholderId}
|
|
312
|
-
sectionId={section.id}
|
|
313
|
-
selectedBlockId={selectedBlockId}
|
|
314
|
-
/>
|
|
315
|
-
))}
|
|
316
|
-
</div>
|
|
317
|
-
);
|
|
318
|
-
})}
|
|
319
|
-
</div>
|
|
320
|
-
</div>
|
|
321
|
-
)}
|
|
322
|
-
</div>
|
|
323
|
-
);
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
export default HoverShowcaseSection;
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { getResponsiveValue } from '../utils';
|
|
5
|
-
import { Section } from '../theme-section';
|
|
6
|
-
import { useThemeSettingsContext } from '../theme-settings-context';
|
|
7
|
-
import { twMerge } from 'tailwind-merge';
|
|
8
|
-
import clsx from 'clsx';
|
|
9
|
-
import ThemeBlock from '../theme-block';
|
|
10
|
-
|
|
11
|
-
interface ImageHotspotSectionProps {
|
|
12
|
-
section: Section;
|
|
13
|
-
currentBreakpoint?: string;
|
|
14
|
-
isDesigner?: boolean;
|
|
15
|
-
placeholderId?: string;
|
|
16
|
-
selectedBlockId?: string | null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default function ImageHotspotSection({
|
|
20
|
-
section,
|
|
21
|
-
currentBreakpoint = 'desktop',
|
|
22
|
-
isDesigner = false,
|
|
23
|
-
placeholderId = '',
|
|
24
|
-
selectedBlockId = null
|
|
25
|
-
}: ImageHotspotSectionProps) {
|
|
26
|
-
const themeSettings = useThemeSettingsContext();
|
|
27
|
-
|
|
28
|
-
const styles = section.styles || {};
|
|
29
|
-
const properties = section.properties || {};
|
|
30
|
-
|
|
31
|
-
const imageBlock = section.blocks?.find(b => b.type === 'image');
|
|
32
|
-
|
|
33
|
-
const hotspotBlocks = section.blocks?.filter(b => b.type === 'hotspot') || [];
|
|
34
|
-
|
|
35
|
-
const height = getResponsiveValue(styles.height, currentBreakpoint, '600px') as string | number;
|
|
36
|
-
const width = getResponsiveValue(styles.width, currentBreakpoint, '100%') as string;
|
|
37
|
-
const maxWidth = getResponsiveValue(styles['max-width'], currentBreakpoint, 'normal') as string;
|
|
38
|
-
|
|
39
|
-
const maxWidthClass =
|
|
40
|
-
maxWidth === 'narrow'
|
|
41
|
-
? 'max-w-4xl'
|
|
42
|
-
: maxWidth === 'normal'
|
|
43
|
-
? 'max-w-7xl'
|
|
44
|
-
: maxWidth === 'full'
|
|
45
|
-
? 'w-full'
|
|
46
|
-
: '';
|
|
47
|
-
|
|
48
|
-
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
className={twMerge(
|
|
53
|
-
clsx(
|
|
54
|
-
'relative mx-auto overflow-hidden group/hotspot-section',
|
|
55
|
-
hasMaxWidth && 'mx-auto',
|
|
56
|
-
maxWidthClass
|
|
57
|
-
)
|
|
58
|
-
)}
|
|
59
|
-
style={{
|
|
60
|
-
height: typeof height === 'number' ? `${height}px` : height,
|
|
61
|
-
width: width === 'fill' ? '100%' : width,
|
|
62
|
-
maxWidth: maxWidth === 'none' ? 'none' : undefined,
|
|
63
|
-
position: 'relative'
|
|
64
|
-
}}
|
|
65
|
-
>
|
|
66
|
-
|
|
67
|
-
<div className="absolute inset-0 w-full h-full z-0">
|
|
68
|
-
{imageBlock ? (
|
|
69
|
-
<div className="w-full h-full">
|
|
70
|
-
<ThemeBlock
|
|
71
|
-
key={imageBlock.id}
|
|
72
|
-
block={imageBlock}
|
|
73
|
-
placeholderId={placeholderId}
|
|
74
|
-
sectionId={section.id}
|
|
75
|
-
isDesigner={isDesigner}
|
|
76
|
-
isSelected={selectedBlockId === imageBlock.id}
|
|
77
|
-
selectedBlockId={selectedBlockId}
|
|
78
|
-
currentBreakpoint={currentBreakpoint}
|
|
79
|
-
|
|
80
|
-
onMoveUp={() => {
|
|
81
|
-
if (window.parent) window.parent.postMessage({ type: 'MOVE_BLOCK_UP', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id } }, '*');
|
|
82
|
-
}}
|
|
83
|
-
onMoveDown={() => {
|
|
84
|
-
if (window.parent) window.parent.postMessage({ type: 'MOVE_BLOCK_DOWN', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id } }, '*');
|
|
85
|
-
}}
|
|
86
|
-
onDuplicate={() => {
|
|
87
|
-
if (window.parent) window.parent.postMessage({ type: 'DUPLICATE_BLOCK', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id } }, '*');
|
|
88
|
-
}}
|
|
89
|
-
onToggleVisibility={() => {
|
|
90
|
-
if (window.parent) window.parent.postMessage({ type: 'TOGGLE_BLOCK_VISIBILITY', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id } }, '*');
|
|
91
|
-
}}
|
|
92
|
-
onDelete={() => {
|
|
93
|
-
if (window.parent) window.parent.postMessage({ type: 'DELETE_BLOCK', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id } }, '*');
|
|
94
|
-
}}
|
|
95
|
-
onRename={(newLabel) => {
|
|
96
|
-
if (window.parent) window.parent.postMessage({ type: 'RENAME_BLOCK', data: { placeholderId, sectionId: section.id, blockId: imageBlock.id, label: newLabel } }, '*');
|
|
97
|
-
}}
|
|
98
|
-
/>
|
|
99
|
-
</div>
|
|
100
|
-
) : (
|
|
101
|
-
<div className="w-full h-full bg-gray-200 flex items-center justify-center text-gray-400 select-none">
|
|
102
|
-
No Image Selected
|
|
103
|
-
</div>
|
|
104
|
-
)}
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
<div className="absolute inset-0 w-full h-full z-10 pointer-events-none">
|
|
108
|
-
{hotspotBlocks.map(block => (
|
|
109
|
-
<div key={block.id} className="absolute pointer-events-none" style={{ top: 0, left: 0, width: '100%', height: '100%' }}>
|
|
110
|
-
<ThemeBlock
|
|
111
|
-
block={block}
|
|
112
|
-
placeholderId={placeholderId}
|
|
113
|
-
sectionId={section.id}
|
|
114
|
-
isDesigner={isDesigner}
|
|
115
|
-
isSelected={selectedBlockId === block.id}
|
|
116
|
-
selectedBlockId={selectedBlockId}
|
|
117
|
-
currentBreakpoint={currentBreakpoint}
|
|
118
|
-
onMoveUp={() => {
|
|
119
|
-
if (window.parent) window.parent.postMessage({ type: 'MOVE_BLOCK_UP', data: { placeholderId, sectionId: section.id, blockId: block.id } }, '*');
|
|
120
|
-
}}
|
|
121
|
-
onMoveDown={() => {
|
|
122
|
-
if (window.parent) window.parent.postMessage({ type: 'MOVE_BLOCK_DOWN', data: { placeholderId, sectionId: section.id, blockId: block.id } }, '*');
|
|
123
|
-
}}
|
|
124
|
-
onDuplicate={() => {
|
|
125
|
-
if (window.parent) window.parent.postMessage({ type: 'DUPLICATE_BLOCK', data: { placeholderId, sectionId: section.id, blockId: block.id } }, '*');
|
|
126
|
-
}}
|
|
127
|
-
onToggleVisibility={() => {
|
|
128
|
-
if (window.parent) window.parent.postMessage({ type: 'TOGGLE_BLOCK_VISIBILITY', data: { placeholderId, sectionId: section.id, blockId: block.id } }, '*');
|
|
129
|
-
}}
|
|
130
|
-
onDelete={() => {
|
|
131
|
-
if (window.parent) window.parent.postMessage({ type: 'DELETE_BLOCK', data: { placeholderId, sectionId: section.id, blockId: block.id } }, '*');
|
|
132
|
-
}}
|
|
133
|
-
onRename={(newLabel) => {
|
|
134
|
-
if (window.parent) window.parent.postMessage({ type: 'RENAME_BLOCK', data: { placeholderId, sectionId: section.id, blockId: block.id, label: newLabel } }, '*');
|
|
135
|
-
}}
|
|
136
|
-
/>
|
|
137
|
-
</div>
|
|
138
|
-
))}
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
);
|
|
142
|
-
}
|