@akinon/pz-theme 2.0.35-beta.0 → 2.0.35
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 +9 -3
- package/package.json +4 -3
- package/src/__tests__/theme-contract.test.ts +130 -0
- package/src/blocks/__tests__/text-block.test.tsx +8 -1
- package/src/blocks/__tests__/video-block.test.tsx +14 -7
- package/src/blocks/counter-block.tsx +44 -56
- package/src/blocks/group-block.tsx +23 -22
- package/src/blocks/hotspot-block.tsx +171 -80
- package/src/blocks/input-block.tsx +15 -17
- package/src/blocks/link-block.tsx +18 -21
- package/src/blocks/slider-block.tsx +15 -12
- package/src/components/with-designer-features.tsx +2 -0
- package/src/editor-bridge.ts +160 -0
- package/src/hooks/use-designer-features.tsx +30 -37
- package/src/placeholder-registry.ts +5 -7
- package/src/sections/__tests__/countdown-campaign-banner-section.test.tsx +8 -4
- package/src/sections/__tests__/coupon-banner-section.test.tsx +4 -2
- package/src/sections/before-after-section.tsx +189 -134
- package/src/sections/contact-form-section.tsx +185 -60
- package/src/sections/countdown-campaign-banner-section.tsx +73 -27
- package/src/sections/coupon-banner-section.tsx +152 -48
- package/src/sections/featured-product-spotlight-section.tsx +67 -66
- package/src/sections/find-in-store-section.tsx +37 -25
- package/src/sections/hover-showcase-section.tsx +221 -89
- package/src/sections/image-hotspot-section.tsx +208 -94
- package/src/sections/installment-options-section.tsx +268 -259
- package/src/sections/notification-banner-section.tsx +111 -25
- package/src/sections/order-tracking-lookup-section.tsx +272 -247
- package/src/sections/posts-slider-section.tsx +17 -16
- package/src/sections/pre-order-launch-banner-section.tsx +31 -50
- package/src/sections/section-wrapper.tsx +9 -10
- package/src/sections/shipping-threshold-progress-section.tsx +72 -29
- package/src/sections/stats-counter-section.tsx +68 -30
- package/src/sections/tabs-section.tsx +124 -147
- package/src/theme-placeholder-client.tsx +11 -14
- package/src/theme-placeholder-wrapper.tsx +42 -51
- package/src/theme-section.tsx +27 -34
- package/src/utils/__tests__/transform-styles.test.ts +97 -0
- package/src/utils/index.ts +9 -0
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
resolveThemeCssVariables
|
|
29
29
|
} from '../utils';
|
|
30
30
|
|
|
31
|
+
import { postToEditor } from '../editor-bridge';
|
|
32
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
31
33
|
interface FindInStoreSectionProps {
|
|
32
34
|
section: Section;
|
|
33
35
|
currentBreakpoint?: string;
|
|
@@ -649,11 +651,15 @@ export default function FindInStoreSection({
|
|
|
649
651
|
const trimmedInitialProduct = initialProductInput.trim();
|
|
650
652
|
if (!trimmedInitialProduct) return;
|
|
651
653
|
|
|
652
|
-
setProductUrlInput(
|
|
654
|
+
setProductUrlInput(
|
|
655
|
+
(currentValue) => currentValue || trimmedInitialProduct
|
|
656
|
+
);
|
|
653
657
|
setIsResolvingProduct(true);
|
|
654
658
|
|
|
655
659
|
try {
|
|
656
|
-
const resolvedPk = await resolveProductPkFromInput(
|
|
660
|
+
const resolvedPk = await resolveProductPkFromInput(
|
|
661
|
+
trimmedInitialProduct
|
|
662
|
+
);
|
|
657
663
|
if (!cancelled && resolvedPk) {
|
|
658
664
|
setResolvedProductPk(resolvedPk);
|
|
659
665
|
setSearchError('');
|
|
@@ -710,10 +716,10 @@ export default function FindInStoreSection({
|
|
|
710
716
|
maxWidth === 'narrow'
|
|
711
717
|
? 'max-w-4xl'
|
|
712
718
|
: maxWidth === 'normal'
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
719
|
+
? 'max-w-7xl'
|
|
720
|
+
: maxWidth === 'full'
|
|
721
|
+
? 'w-full'
|
|
722
|
+
: '';
|
|
717
723
|
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
718
724
|
|
|
719
725
|
const filteredStyles = Object.fromEntries(
|
|
@@ -1045,20 +1051,21 @@ export default function FindInStoreSection({
|
|
|
1045
1051
|
currentBreakpoint
|
|
1046
1052
|
);
|
|
1047
1053
|
|
|
1048
|
-
const postBlockAction = (
|
|
1054
|
+
const postBlockAction = (
|
|
1055
|
+
type: PreviewToEditorMessageType,
|
|
1056
|
+
blockId: string,
|
|
1057
|
+
label?: string
|
|
1058
|
+
) => {
|
|
1049
1059
|
if (!window.parent) return;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
},
|
|
1060
|
-
'*'
|
|
1061
|
-
);
|
|
1060
|
+
postToEditor({
|
|
1061
|
+
type,
|
|
1062
|
+
data: {
|
|
1063
|
+
placeholderId,
|
|
1064
|
+
sectionId: section.id,
|
|
1065
|
+
blockId,
|
|
1066
|
+
...(label ? { label } : {})
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1062
1069
|
};
|
|
1063
1070
|
|
|
1064
1071
|
const renderBlock = (block: Block, keyOverride?: string) => {
|
|
@@ -1376,7 +1383,10 @@ export default function FindInStoreSection({
|
|
|
1376
1383
|
const searchInputStyle = mergeControlStyles(inputStyle, searchInputBlock);
|
|
1377
1384
|
const citySelectStyle = mergeControlStyles(inputStyle, citySelectBlock);
|
|
1378
1385
|
const sizeSelectStyle = mergeControlStyles(inputStyle, sizeSelectBlock);
|
|
1379
|
-
const searchButtonControlStyle = mergeControlStyles(
|
|
1386
|
+
const searchButtonControlStyle = mergeControlStyles(
|
|
1387
|
+
buttonStyle,
|
|
1388
|
+
searchButtonBlock
|
|
1389
|
+
);
|
|
1380
1390
|
const availabilityButtonControlStyle = mergeControlStyles(
|
|
1381
1391
|
buttonStyle,
|
|
1382
1392
|
availabilityButtonBlock
|
|
@@ -1608,7 +1618,9 @@ export default function FindInStoreSection({
|
|
|
1608
1618
|
<input
|
|
1609
1619
|
type="text"
|
|
1610
1620
|
value={productUrlInput}
|
|
1611
|
-
onChange={(event) =>
|
|
1621
|
+
onChange={(event) =>
|
|
1622
|
+
setProductUrlInput(event.target.value)
|
|
1623
|
+
}
|
|
1612
1624
|
placeholder={urlPlaceholder}
|
|
1613
1625
|
inputMode="text"
|
|
1614
1626
|
style={searchInputStyle}
|
|
@@ -1732,7 +1744,7 @@ export default function FindInStoreSection({
|
|
|
1732
1744
|
}
|
|
1733
1745
|
)}
|
|
1734
1746
|
|
|
1735
|
-
{sizeOptions.length > 0 &&
|
|
1747
|
+
{sizeOptions.length > 0 &&
|
|
1736
1748
|
renderSelectableElement(
|
|
1737
1749
|
sizeSelectBlock,
|
|
1738
1750
|
<select
|
|
@@ -1756,8 +1768,7 @@ export default function FindInStoreSection({
|
|
|
1756
1768
|
{
|
|
1757
1769
|
keyOverride: 'size-select'
|
|
1758
1770
|
}
|
|
1759
|
-
)
|
|
1760
|
-
)}
|
|
1771
|
+
)}
|
|
1761
1772
|
</div>
|
|
1762
1773
|
|
|
1763
1774
|
{renderSelectableElement(
|
|
@@ -1769,7 +1780,8 @@ export default function FindInStoreSection({
|
|
|
1769
1780
|
onClick={handleSubmit}
|
|
1770
1781
|
onMouseEnter={(event) => {
|
|
1771
1782
|
if (!stockLoading && isProductResolved) {
|
|
1772
|
-
event.currentTarget.style.backgroundColor =
|
|
1783
|
+
event.currentTarget.style.backgroundColor =
|
|
1784
|
+
buttonHoverBg;
|
|
1773
1785
|
}
|
|
1774
1786
|
}}
|
|
1775
1787
|
onMouseLeave={(event) => {
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
import { Section } from '../theme-section';
|
|
14
14
|
import { WithDesignerFeatures } from '../components/with-designer-features';
|
|
15
15
|
|
|
16
|
+
import { postToEditor } from '../editor-bridge';
|
|
17
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
16
18
|
interface HoverShowcaseSectionProps {
|
|
17
19
|
section: Section;
|
|
18
20
|
currentBreakpoint?: string;
|
|
@@ -33,11 +35,13 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
33
35
|
const themeSettings = useThemeSettingsContext();
|
|
34
36
|
|
|
35
37
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
36
|
-
|
|
38
|
+
|
|
37
39
|
useEffect(() => {
|
|
38
40
|
if (isDesigner && selectedBlockId && section.blocks) {
|
|
39
41
|
const index = section.blocks.findIndex(
|
|
40
|
-
(b: Block) =>
|
|
42
|
+
(b: Block) =>
|
|
43
|
+
b.id === selectedBlockId ||
|
|
44
|
+
b.blocks?.some((child: Block) => child.id === selectedBlockId)
|
|
41
45
|
);
|
|
42
46
|
if (index !== -1) {
|
|
43
47
|
setActiveIndex(index);
|
|
@@ -45,17 +49,15 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
45
49
|
}
|
|
46
50
|
}, [isDesigner, selectedBlockId, section.blocks]);
|
|
47
51
|
|
|
48
|
-
const resolveLocalizedValue = (
|
|
49
|
-
value: unknown,
|
|
50
|
-
fallback: string
|
|
51
|
-
): string => {
|
|
52
|
+
const resolveLocalizedValue = (value: unknown, fallback: string): string => {
|
|
52
53
|
if (value == null) return fallback;
|
|
53
54
|
|
|
54
55
|
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
55
56
|
const localized = value as Record<string, unknown>;
|
|
56
57
|
|
|
57
58
|
if (localized[locale] != null) return String(localized[locale]);
|
|
58
|
-
if (localized[defaultLocale] != null)
|
|
59
|
+
if (localized[defaultLocale] != null)
|
|
60
|
+
return String(localized[defaultLocale]);
|
|
59
61
|
|
|
60
62
|
const responsive = getResponsiveValue(value, currentBreakpoint);
|
|
61
63
|
if (responsive != null && typeof responsive !== 'object') {
|
|
@@ -79,7 +81,11 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
79
81
|
return styles[kebabKey] ?? styles[camelKey];
|
|
80
82
|
};
|
|
81
83
|
|
|
82
|
-
const maxWidth = getResponsiveValue(
|
|
84
|
+
const maxWidth = getResponsiveValue(
|
|
85
|
+
getStyleEntry('max-width'),
|
|
86
|
+
currentBreakpoint,
|
|
87
|
+
'normal'
|
|
88
|
+
);
|
|
83
89
|
const maxWidthClass =
|
|
84
90
|
maxWidth === 'narrow'
|
|
85
91
|
? 'max-w-4xl'
|
|
@@ -89,43 +95,60 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
89
95
|
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
90
96
|
|
|
91
97
|
const inactiveColor = resolveThemeCssVariables(
|
|
92
|
-
String(
|
|
98
|
+
String(
|
|
99
|
+
getResponsiveValue(
|
|
100
|
+
getStyleEntry('inactive-color'),
|
|
101
|
+
currentBreakpoint,
|
|
102
|
+
'#9ca3af'
|
|
103
|
+
)
|
|
104
|
+
),
|
|
93
105
|
themeSettings
|
|
94
106
|
);
|
|
95
107
|
const activeColor = resolveThemeCssVariables(
|
|
96
|
-
String(
|
|
108
|
+
String(
|
|
109
|
+
getResponsiveValue(
|
|
110
|
+
getStyleEntry('active-color'),
|
|
111
|
+
currentBreakpoint,
|
|
112
|
+
'#111827'
|
|
113
|
+
)
|
|
114
|
+
),
|
|
97
115
|
themeSettings
|
|
98
116
|
);
|
|
99
|
-
|
|
117
|
+
|
|
100
118
|
const isMobile = currentBreakpoint === 'mobile';
|
|
101
119
|
|
|
102
|
-
const items = (section.blocks || []).filter(
|
|
120
|
+
const items = (section.blocks || []).filter(
|
|
121
|
+
(b: Block) => b.type === 'hover-showcase-item'
|
|
122
|
+
);
|
|
103
123
|
|
|
104
124
|
if (items.length === 0) {
|
|
105
125
|
if (isDesigner) {
|
|
106
126
|
return (
|
|
107
127
|
<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">
|
|
128
|
+
<p className="text-gray-500">
|
|
129
|
+
Add Hover Showcase Item blocks to see them here.
|
|
130
|
+
</p>
|
|
109
131
|
</div>
|
|
110
132
|
);
|
|
111
133
|
}
|
|
112
134
|
return null;
|
|
113
135
|
}
|
|
114
136
|
|
|
115
|
-
const sendDesignerMessage = (
|
|
137
|
+
const sendDesignerMessage = (
|
|
138
|
+
type: PreviewToEditorMessageType,
|
|
139
|
+
blockId: string,
|
|
140
|
+
label?: string
|
|
141
|
+
) => {
|
|
116
142
|
if (isDesigner && window.parent) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
},
|
|
127
|
-
'*'
|
|
128
|
-
);
|
|
143
|
+
postToEditor({
|
|
144
|
+
type,
|
|
145
|
+
data: {
|
|
146
|
+
placeholderId,
|
|
147
|
+
sectionId: section.id,
|
|
148
|
+
blockId,
|
|
149
|
+
...(label && { label })
|
|
150
|
+
}
|
|
151
|
+
});
|
|
129
152
|
}
|
|
130
153
|
};
|
|
131
154
|
const renderMobile = isDesigner ? isMobile : true;
|
|
@@ -134,23 +157,46 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
134
157
|
return (
|
|
135
158
|
<div
|
|
136
159
|
className={`w-full mx-auto ${hasMaxWidth ? maxWidthClass : ''}`}
|
|
137
|
-
style={getCSSStyles(
|
|
160
|
+
style={getCSSStyles(
|
|
161
|
+
section.styles as Record<string, unknown>,
|
|
162
|
+
themeSettings as Record<string, unknown>,
|
|
163
|
+
currentBreakpoint
|
|
164
|
+
)}
|
|
138
165
|
>
|
|
139
166
|
{renderMobile && (
|
|
140
|
-
<div
|
|
167
|
+
<div
|
|
168
|
+
className={`flex flex-col gap-6 px-4 ${
|
|
169
|
+
isDesigner ? '' : 'block md:hidden'
|
|
170
|
+
}`}
|
|
171
|
+
>
|
|
141
172
|
{items.map((item: Block, index: number) => {
|
|
142
173
|
const props = item.properties || {};
|
|
143
174
|
const itemStyles = item.styles || {};
|
|
144
|
-
const title = resolveLocalizedValue(
|
|
175
|
+
const title = resolveLocalizedValue(
|
|
176
|
+
props.title,
|
|
177
|
+
`Item ${index + 1}`
|
|
178
|
+
);
|
|
145
179
|
const subtitle = resolveLocalizedValue(props.subtitle, '');
|
|
146
180
|
const link = resolveLocalizedValue(props.link, '');
|
|
147
181
|
const isActive = index === activeIndex;
|
|
148
182
|
|
|
149
183
|
// Inside mobile render block, force evaluation of values for 'mobile' instead of the generic currentBreakpoint
|
|
150
184
|
const evalBreakpoint = isDesigner ? currentBreakpoint : 'mobile';
|
|
151
|
-
const mobileLayout = getResponsiveValue(
|
|
152
|
-
|
|
153
|
-
|
|
185
|
+
const mobileLayout = getResponsiveValue(
|
|
186
|
+
getStyleEntry('mobile-layout'),
|
|
187
|
+
evalBreakpoint,
|
|
188
|
+
'list'
|
|
189
|
+
);
|
|
190
|
+
const titleFontSize = getResponsiveValue(
|
|
191
|
+
itemStyles['title-font-size'],
|
|
192
|
+
evalBreakpoint,
|
|
193
|
+
'24px'
|
|
194
|
+
);
|
|
195
|
+
const subtitleFontSize = getResponsiveValue(
|
|
196
|
+
itemStyles['subtitle-font-size'],
|
|
197
|
+
evalBreakpoint,
|
|
198
|
+
'14px'
|
|
199
|
+
);
|
|
154
200
|
|
|
155
201
|
return (
|
|
156
202
|
<WithDesignerFeatures
|
|
@@ -163,27 +209,70 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
163
209
|
currentBreakpoint={currentBreakpoint}
|
|
164
210
|
className="flex flex-col gap-3 cursor-pointer p-2 rounded relative"
|
|
165
211
|
onMoveUp={() => sendDesignerMessage('MOVE_BLOCK_UP', item.id)}
|
|
166
|
-
onMoveDown={() =>
|
|
167
|
-
|
|
168
|
-
|
|
212
|
+
onMoveDown={() =>
|
|
213
|
+
sendDesignerMessage('MOVE_BLOCK_DOWN', item.id)
|
|
214
|
+
}
|
|
215
|
+
onDuplicate={() =>
|
|
216
|
+
sendDesignerMessage('DUPLICATE_BLOCK', item.id)
|
|
217
|
+
}
|
|
218
|
+
onToggleVisibility={() =>
|
|
219
|
+
sendDesignerMessage('TOGGLE_BLOCK_VISIBILITY', item.id)
|
|
220
|
+
}
|
|
169
221
|
onDelete={() => sendDesignerMessage('DELETE_BLOCK', item.id)}
|
|
170
|
-
onRename={(newLabel) =>
|
|
222
|
+
onRename={(newLabel) =>
|
|
223
|
+
sendDesignerMessage('RENAME_BLOCK', item.id, newLabel)
|
|
224
|
+
}
|
|
171
225
|
>
|
|
172
|
-
<div
|
|
226
|
+
<div
|
|
227
|
+
className="flex flex-col"
|
|
228
|
+
onClick={() => setActiveIndex(index)}
|
|
229
|
+
>
|
|
173
230
|
{link ? (
|
|
174
231
|
<a href={link} className="decoration-none">
|
|
175
|
-
<h3
|
|
232
|
+
<h3
|
|
233
|
+
style={{
|
|
234
|
+
fontSize: String(titleFontSize),
|
|
235
|
+
color: activeColor,
|
|
236
|
+
transition: 'color 0.3s'
|
|
237
|
+
}}
|
|
238
|
+
className="font-semibold leading-tight m-0"
|
|
239
|
+
>
|
|
240
|
+
{title}
|
|
241
|
+
</h3>
|
|
176
242
|
</a>
|
|
177
243
|
) : (
|
|
178
|
-
<h3
|
|
244
|
+
<h3
|
|
245
|
+
style={{
|
|
246
|
+
fontSize: String(titleFontSize),
|
|
247
|
+
color: activeColor,
|
|
248
|
+
transition: 'color 0.3s'
|
|
249
|
+
}}
|
|
250
|
+
className="font-semibold leading-tight m-0"
|
|
251
|
+
>
|
|
252
|
+
{title}
|
|
253
|
+
</h3>
|
|
179
254
|
)}
|
|
180
255
|
{subtitle && (
|
|
181
|
-
<p
|
|
256
|
+
<p
|
|
257
|
+
style={{
|
|
258
|
+
fontSize: String(subtitleFontSize),
|
|
259
|
+
color: inactiveColor
|
|
260
|
+
}}
|
|
261
|
+
className="mt-1 mb-0 opacity-80"
|
|
262
|
+
>
|
|
263
|
+
{subtitle}
|
|
264
|
+
</p>
|
|
182
265
|
)}
|
|
183
266
|
</div>
|
|
184
|
-
|
|
267
|
+
|
|
185
268
|
{mobileLayout === 'accordion' ? (
|
|
186
|
-
<div
|
|
269
|
+
<div
|
|
270
|
+
className={`overflow-hidden transition-all duration-300 ${
|
|
271
|
+
isActive
|
|
272
|
+
? 'max-h-[600px] opacity-100 mt-2'
|
|
273
|
+
: 'max-h-0 opacity-0'
|
|
274
|
+
}`}
|
|
275
|
+
>
|
|
187
276
|
{item.blocks?.map((block: Block) => (
|
|
188
277
|
<ThemeBlock
|
|
189
278
|
key={block.id}
|
|
@@ -197,7 +286,7 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
197
286
|
))}
|
|
198
287
|
</div>
|
|
199
288
|
) : (
|
|
200
|
-
|
|
289
|
+
<div className="mt-2">
|
|
201
290
|
{item.blocks?.map((block: Block) => (
|
|
202
291
|
<ThemeBlock
|
|
203
292
|
key={block.id}
|
|
@@ -218,21 +307,44 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
218
307
|
)}
|
|
219
308
|
|
|
220
309
|
{renderDesktop && (
|
|
221
|
-
<div
|
|
222
|
-
|
|
310
|
+
<div
|
|
311
|
+
className={`px-4 md:px-8 lg:px-12 items-center min-h-[500px] ${
|
|
312
|
+
isDesigner ? 'flex' : 'hidden md:flex'
|
|
313
|
+
}`}
|
|
314
|
+
>
|
|
315
|
+
<div className="w-1/2 flex flex-col justify-center gap-1 relative z-10 pr-8">
|
|
223
316
|
{items.map((item: Block, index: number) => {
|
|
224
317
|
const props = item.properties || {};
|
|
225
318
|
const itemStyles = item.styles || {};
|
|
226
|
-
const title = resolveLocalizedValue(
|
|
319
|
+
const title = resolveLocalizedValue(
|
|
320
|
+
props.title,
|
|
321
|
+
`Item ${index + 1}`
|
|
322
|
+
);
|
|
227
323
|
const subtitle = resolveLocalizedValue(props.subtitle, '');
|
|
228
324
|
const link = resolveLocalizedValue(props.link, '');
|
|
229
325
|
const isActive = index === activeIndex;
|
|
230
326
|
|
|
231
327
|
const evalBreakpoint = isDesigner ? currentBreakpoint : 'desktop';
|
|
232
|
-
const titleFontSize = getResponsiveValue(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
328
|
+
const titleFontSize = getResponsiveValue(
|
|
329
|
+
itemStyles['title-font-size'],
|
|
330
|
+
evalBreakpoint,
|
|
331
|
+
'32px'
|
|
332
|
+
);
|
|
333
|
+
const subtitleFontSize = getResponsiveValue(
|
|
334
|
+
itemStyles['subtitle-font-size'],
|
|
335
|
+
evalBreakpoint,
|
|
336
|
+
'16px'
|
|
337
|
+
);
|
|
338
|
+
const pt = getResponsiveValue(
|
|
339
|
+
itemStyles['padding-top'],
|
|
340
|
+
evalBreakpoint,
|
|
341
|
+
16
|
|
342
|
+
);
|
|
343
|
+
const pb = getResponsiveValue(
|
|
344
|
+
itemStyles['padding-bottom'],
|
|
345
|
+
evalBreakpoint,
|
|
346
|
+
16
|
|
347
|
+
);
|
|
236
348
|
|
|
237
349
|
return (
|
|
238
350
|
<WithDesignerFeatures
|
|
@@ -246,42 +358,60 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
246
358
|
className="flex flex-col cursor-pointer group w-max rounded px-2 relative"
|
|
247
359
|
style={{ paddingTop: `${pt}px`, paddingBottom: `${pb}px` }}
|
|
248
360
|
onMoveUp={() => sendDesignerMessage('MOVE_BLOCK_UP', item.id)}
|
|
249
|
-
onMoveDown={() =>
|
|
250
|
-
|
|
251
|
-
|
|
361
|
+
onMoveDown={() =>
|
|
362
|
+
sendDesignerMessage('MOVE_BLOCK_DOWN', item.id)
|
|
363
|
+
}
|
|
364
|
+
onDuplicate={() =>
|
|
365
|
+
sendDesignerMessage('DUPLICATE_BLOCK', item.id)
|
|
366
|
+
}
|
|
367
|
+
onToggleVisibility={() =>
|
|
368
|
+
sendDesignerMessage('TOGGLE_BLOCK_VISIBILITY', item.id)
|
|
369
|
+
}
|
|
252
370
|
onDelete={() => sendDesignerMessage('DELETE_BLOCK', item.id)}
|
|
253
|
-
onRename={(newLabel) =>
|
|
371
|
+
onRename={(newLabel) =>
|
|
372
|
+
sendDesignerMessage('RENAME_BLOCK', item.id, newLabel)
|
|
373
|
+
}
|
|
254
374
|
>
|
|
255
|
-
<div
|
|
375
|
+
<div
|
|
256
376
|
className="flex flex-col relative w-full"
|
|
257
377
|
onMouseEnter={() => setActiveIndex(index)}
|
|
258
378
|
>
|
|
259
379
|
{link ? (
|
|
260
380
|
<a href={link} className="decoration-none">
|
|
261
|
-
<h3
|
|
262
|
-
style={{
|
|
381
|
+
<h3
|
|
382
|
+
style={{
|
|
383
|
+
fontSize: String(titleFontSize),
|
|
384
|
+
color: isActive ? activeColor : inactiveColor,
|
|
385
|
+
transition: 'color 0.4s ease'
|
|
386
|
+
}}
|
|
263
387
|
className="font-semibold leading-tight m-0 hover:opacity-80"
|
|
264
388
|
>
|
|
265
389
|
{title}
|
|
266
390
|
</h3>
|
|
267
391
|
</a>
|
|
268
392
|
) : (
|
|
269
|
-
|
|
270
|
-
style={{
|
|
393
|
+
<h3
|
|
394
|
+
style={{
|
|
395
|
+
fontSize: String(titleFontSize),
|
|
396
|
+
color: isActive ? activeColor : inactiveColor,
|
|
397
|
+
transition: 'color 0.4s ease'
|
|
398
|
+
}}
|
|
271
399
|
className="font-semibold leading-tight m-0"
|
|
272
400
|
>
|
|
273
401
|
{title}
|
|
274
402
|
</h3>
|
|
275
403
|
)}
|
|
276
404
|
{subtitle && (
|
|
277
|
-
<p
|
|
278
|
-
style={{
|
|
279
|
-
fontSize: String(subtitleFontSize),
|
|
280
|
-
color: inactiveColor,
|
|
281
|
-
opacity: isActive ? 1 : 0,
|
|
405
|
+
<p
|
|
406
|
+
style={{
|
|
407
|
+
fontSize: String(subtitleFontSize),
|
|
408
|
+
color: inactiveColor,
|
|
409
|
+
opacity: isActive ? 1 : 0,
|
|
282
410
|
maxHeight: isActive ? '40px' : '0px',
|
|
283
|
-
transform: isActive
|
|
284
|
-
|
|
411
|
+
transform: isActive
|
|
412
|
+
? 'translateY(0)'
|
|
413
|
+
: 'translateY(-10px)'
|
|
414
|
+
}}
|
|
285
415
|
className="mt-2 mb-0 overflow-hidden transition-all duration-400 ease-out"
|
|
286
416
|
>
|
|
287
417
|
{subtitle}
|
|
@@ -291,32 +421,34 @@ const HoverShowcaseSection: React.FC<HoverShowcaseSectionProps> = ({
|
|
|
291
421
|
</WithDesignerFeatures>
|
|
292
422
|
);
|
|
293
423
|
})}
|
|
294
|
-
|
|
424
|
+
</div>
|
|
295
425
|
|
|
296
|
-
|
|
426
|
+
<div className="w-1/2 relative h-full min-h-[400px] flex items-center justify-center">
|
|
297
427
|
{items.map((item: Block, index: number) => {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
428
|
+
const isActive = index === activeIndex;
|
|
429
|
+
|
|
430
|
+
return (
|
|
431
|
+
<div
|
|
432
|
+
key={item.id}
|
|
433
|
+
className={`absolute inset-0 transition-opacity duration-500 ease-in-out flex items-center justify-center ${
|
|
434
|
+
isActive ? 'opacity-100 z-10' : 'opacity-0 z-0'
|
|
435
|
+
}`}
|
|
436
|
+
>
|
|
437
|
+
{item.blocks?.map((block: Block) => (
|
|
438
|
+
<ThemeBlock
|
|
439
|
+
key={block.id}
|
|
440
|
+
block={block}
|
|
441
|
+
currentBreakpoint={currentBreakpoint}
|
|
442
|
+
isDesigner={isDesigner}
|
|
443
|
+
placeholderId={placeholderId}
|
|
444
|
+
sectionId={section.id}
|
|
445
|
+
selectedBlockId={selectedBlockId}
|
|
446
|
+
/>
|
|
447
|
+
))}
|
|
448
|
+
</div>
|
|
449
|
+
);
|
|
318
450
|
})}
|
|
319
|
-
|
|
451
|
+
</div>
|
|
320
452
|
</div>
|
|
321
453
|
)}
|
|
322
454
|
</div>
|