@akinon/pz-theme 2.0.35-rc.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 +12 -28
- 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
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
} from '@akinon/next/data/client/account';
|
|
23
23
|
import { ContactFormType } from '@akinon/next/types';
|
|
24
24
|
|
|
25
|
+
import { postToEditor } from '../editor-bridge';
|
|
26
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
25
27
|
interface ContactFormSectionProps {
|
|
26
28
|
section: Section;
|
|
27
29
|
currentBreakpoint?: string;
|
|
@@ -71,7 +73,9 @@ const readProperty = (
|
|
|
71
73
|
if (typeof raw === 'object') {
|
|
72
74
|
const responsive = raw as Record<string, unknown>;
|
|
73
75
|
const picked =
|
|
74
|
-
responsive[breakpoint] ??
|
|
76
|
+
responsive[breakpoint] ??
|
|
77
|
+
responsive.desktop ??
|
|
78
|
+
Object.values(responsive)[0];
|
|
75
79
|
return picked == null ? fallback : String(picked);
|
|
76
80
|
}
|
|
77
81
|
return String(raw);
|
|
@@ -100,7 +104,15 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
100
104
|
|
|
101
105
|
// Build filtered subjects
|
|
102
106
|
const filteredSubjects: { label: string; value: string }[] = [
|
|
103
|
-
{
|
|
107
|
+
{
|
|
108
|
+
label: readProperty(
|
|
109
|
+
section.properties,
|
|
110
|
+
'subject-placeholder',
|
|
111
|
+
'Konu seçiniz',
|
|
112
|
+
currentBreakpoint
|
|
113
|
+
),
|
|
114
|
+
value: ''
|
|
115
|
+
}
|
|
104
116
|
];
|
|
105
117
|
|
|
106
118
|
if (subjectsSuccess && contactSubjects) {
|
|
@@ -124,21 +136,60 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
124
136
|
reset,
|
|
125
137
|
handleSubmit,
|
|
126
138
|
formState: { errors }
|
|
127
|
-
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
128
140
|
} = useForm<ContactFormType & Record<string, any>>({
|
|
129
141
|
resolver: yupResolver(contactFormSchema) as any
|
|
130
142
|
});
|
|
131
143
|
|
|
132
144
|
// Read section properties
|
|
133
145
|
const props = section.properties || {};
|
|
134
|
-
const fullNamePlaceholder = readProperty(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
146
|
+
const fullNamePlaceholder = readProperty(
|
|
147
|
+
props,
|
|
148
|
+
'full-name-placeholder',
|
|
149
|
+
'Adınız Soyadınız',
|
|
150
|
+
currentBreakpoint
|
|
151
|
+
);
|
|
152
|
+
const emailPlaceholder = readProperty(
|
|
153
|
+
props,
|
|
154
|
+
'email-placeholder',
|
|
155
|
+
'E-posta adresiniz',
|
|
156
|
+
currentBreakpoint
|
|
157
|
+
);
|
|
158
|
+
const phonePlaceholder = readProperty(
|
|
159
|
+
props,
|
|
160
|
+
'phone-placeholder',
|
|
161
|
+
'Telefon numaranız',
|
|
162
|
+
currentBreakpoint
|
|
163
|
+
);
|
|
164
|
+
const messagePlaceholder = readProperty(
|
|
165
|
+
props,
|
|
166
|
+
'message-placeholder',
|
|
167
|
+
'Mesajınızı yazın...',
|
|
168
|
+
currentBreakpoint
|
|
169
|
+
);
|
|
170
|
+
const buttonText = readProperty(
|
|
171
|
+
props,
|
|
172
|
+
'button-text',
|
|
173
|
+
'Gönder',
|
|
174
|
+
currentBreakpoint
|
|
175
|
+
);
|
|
176
|
+
const successMessage = readProperty(
|
|
177
|
+
props,
|
|
178
|
+
'success-message',
|
|
179
|
+
'Mesajınız başarıyla gönderildi!',
|
|
180
|
+
currentBreakpoint
|
|
181
|
+
);
|
|
182
|
+
const errorMessageText = readProperty(
|
|
183
|
+
props,
|
|
184
|
+
'error-message',
|
|
185
|
+
'Bir hata oluştu. Lütfen tekrar deneyin.',
|
|
186
|
+
currentBreakpoint
|
|
187
|
+
);
|
|
188
|
+
const showFileUploadRaw = getResponsiveValue(
|
|
189
|
+
props['show-file-upload'],
|
|
190
|
+
currentBreakpoint,
|
|
191
|
+
true
|
|
192
|
+
);
|
|
142
193
|
const showFileUpload =
|
|
143
194
|
showFileUploadRaw === false || showFileUploadRaw === 'false' ? false : true;
|
|
144
195
|
// Read section styles
|
|
@@ -155,43 +206,99 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
155
206
|
: '';
|
|
156
207
|
const hasMaxWidth = maxWidth !== 'none' && maxWidth !== 'full';
|
|
157
208
|
|
|
158
|
-
const formGap = getResponsiveValue(
|
|
209
|
+
const formGap = getResponsiveValue(
|
|
210
|
+
section.styles?.['form-gap'],
|
|
211
|
+
currentBreakpoint,
|
|
212
|
+
16
|
|
213
|
+
);
|
|
159
214
|
|
|
160
215
|
const inputBg = resolveThemeCssVariables(
|
|
161
|
-
String(
|
|
216
|
+
String(
|
|
217
|
+
getResponsiveValue(
|
|
218
|
+
section.styles?.['input-background-color'],
|
|
219
|
+
currentBreakpoint,
|
|
220
|
+
'#ffffff'
|
|
221
|
+
)
|
|
222
|
+
),
|
|
162
223
|
themeSettings
|
|
163
224
|
);
|
|
164
225
|
const inputTextColor = resolveThemeCssVariables(
|
|
165
|
-
String(
|
|
226
|
+
String(
|
|
227
|
+
getResponsiveValue(
|
|
228
|
+
section.styles?.['input-text-color'],
|
|
229
|
+
currentBreakpoint,
|
|
230
|
+
'#0f172a'
|
|
231
|
+
)
|
|
232
|
+
),
|
|
166
233
|
themeSettings
|
|
167
234
|
);
|
|
168
235
|
const inputBorderColor = resolveThemeCssVariables(
|
|
169
|
-
String(
|
|
236
|
+
String(
|
|
237
|
+
getResponsiveValue(
|
|
238
|
+
section.styles?.['input-border-color'],
|
|
239
|
+
currentBreakpoint,
|
|
240
|
+
'#cbd5e1'
|
|
241
|
+
)
|
|
242
|
+
),
|
|
170
243
|
themeSettings
|
|
171
244
|
);
|
|
172
245
|
const inputBorderRadius = String(
|
|
173
|
-
getResponsiveValue(
|
|
246
|
+
getResponsiveValue(
|
|
247
|
+
section.styles?.['input-border-radius'],
|
|
248
|
+
currentBreakpoint,
|
|
249
|
+
'8px'
|
|
250
|
+
)
|
|
174
251
|
);
|
|
175
252
|
const inputPadding = String(
|
|
176
|
-
getResponsiveValue(
|
|
253
|
+
getResponsiveValue(
|
|
254
|
+
section.styles?.['input-padding'],
|
|
255
|
+
currentBreakpoint,
|
|
256
|
+
'14px 16px'
|
|
257
|
+
)
|
|
177
258
|
);
|
|
178
259
|
const buttonBg = resolveThemeCssVariables(
|
|
179
|
-
String(
|
|
260
|
+
String(
|
|
261
|
+
getResponsiveValue(
|
|
262
|
+
section.styles?.['button-background-color'],
|
|
263
|
+
currentBreakpoint,
|
|
264
|
+
'#0f172a'
|
|
265
|
+
)
|
|
266
|
+
),
|
|
180
267
|
themeSettings
|
|
181
268
|
);
|
|
182
269
|
const buttonTextColor = resolveThemeCssVariables(
|
|
183
|
-
String(
|
|
270
|
+
String(
|
|
271
|
+
getResponsiveValue(
|
|
272
|
+
section.styles?.['button-text-color'],
|
|
273
|
+
currentBreakpoint,
|
|
274
|
+
'#ffffff'
|
|
275
|
+
)
|
|
276
|
+
),
|
|
184
277
|
themeSettings
|
|
185
278
|
);
|
|
186
279
|
const buttonHoverBg = resolveThemeCssVariables(
|
|
187
|
-
String(
|
|
280
|
+
String(
|
|
281
|
+
getResponsiveValue(
|
|
282
|
+
section.styles?.['button-hover-background-color'],
|
|
283
|
+
currentBreakpoint,
|
|
284
|
+
'#1e293b'
|
|
285
|
+
)
|
|
286
|
+
),
|
|
188
287
|
themeSettings
|
|
189
288
|
);
|
|
190
289
|
const buttonBorderRadius = String(
|
|
191
|
-
getResponsiveValue(
|
|
290
|
+
getResponsiveValue(
|
|
291
|
+
section.styles?.['button-border-radius'],
|
|
292
|
+
currentBreakpoint,
|
|
293
|
+
'8px'
|
|
294
|
+
)
|
|
192
295
|
);
|
|
193
296
|
const buttonPadding = String(
|
|
194
|
-
getResponsiveValue(
|
|
297
|
+
getResponsiveValue(
|
|
298
|
+
section.styles?.['button-padding'],
|
|
299
|
+
currentBreakpoint,
|
|
300
|
+
'14px 32px'
|
|
301
|
+
)
|
|
195
302
|
);
|
|
196
303
|
|
|
197
304
|
const filteredStyles = Object.fromEntries(
|
|
@@ -214,7 +321,11 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
214
321
|
)
|
|
215
322
|
);
|
|
216
323
|
|
|
217
|
-
const sectionStyles = getCSSStyles(
|
|
324
|
+
const sectionStyles = getCSSStyles(
|
|
325
|
+
filteredStyles,
|
|
326
|
+
themeSettings,
|
|
327
|
+
currentBreakpoint
|
|
328
|
+
);
|
|
218
329
|
|
|
219
330
|
const inputStyle: React.CSSProperties = {
|
|
220
331
|
backgroundColor: inputBg,
|
|
@@ -257,20 +368,21 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
257
368
|
.forEach((b) => textBlocks.push(b));
|
|
258
369
|
}
|
|
259
370
|
|
|
260
|
-
const postBlockAction = (
|
|
371
|
+
const postBlockAction = (
|
|
372
|
+
type: PreviewToEditorMessageType,
|
|
373
|
+
blockId: string,
|
|
374
|
+
label?: string
|
|
375
|
+
) => {
|
|
261
376
|
if (!window.parent) return;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
},
|
|
272
|
-
'*'
|
|
273
|
-
);
|
|
377
|
+
postToEditor({
|
|
378
|
+
type,
|
|
379
|
+
data: {
|
|
380
|
+
placeholderId,
|
|
381
|
+
sectionId: section.id,
|
|
382
|
+
blockId,
|
|
383
|
+
...(label ? { label } : {})
|
|
384
|
+
}
|
|
385
|
+
});
|
|
274
386
|
};
|
|
275
387
|
|
|
276
388
|
const renderBlock = (block: Block) => (
|
|
@@ -286,9 +398,13 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
286
398
|
onMoveUp={() => postBlockAction('MOVE_BLOCK_UP', block.id)}
|
|
287
399
|
onMoveDown={() => postBlockAction('MOVE_BLOCK_DOWN', block.id)}
|
|
288
400
|
onDuplicate={() => postBlockAction('DUPLICATE_BLOCK', block.id)}
|
|
289
|
-
onToggleVisibility={() =>
|
|
401
|
+
onToggleVisibility={() =>
|
|
402
|
+
postBlockAction('TOGGLE_BLOCK_VISIBILITY', block.id)
|
|
403
|
+
}
|
|
290
404
|
onDelete={() => postBlockAction('DELETE_BLOCK', block.id)}
|
|
291
|
-
onRename={(newLabel) =>
|
|
405
|
+
onRename={(newLabel) =>
|
|
406
|
+
postBlockAction('RENAME_BLOCK', block.id, newLabel)
|
|
407
|
+
}
|
|
292
408
|
/>
|
|
293
409
|
);
|
|
294
410
|
|
|
@@ -320,10 +436,9 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
320
436
|
.catch((err) => {
|
|
321
437
|
let msg = errorMessageText;
|
|
322
438
|
if (err?.data && typeof err.data === 'object') {
|
|
323
|
-
const entries = Object.entries(err.data)
|
|
324
|
-
.
|
|
325
|
-
|
|
326
|
-
);
|
|
439
|
+
const entries = Object.entries(err.data).map(([, msgs]) =>
|
|
440
|
+
Array.isArray(msgs) ? msgs.join(', ') : String(msgs)
|
|
441
|
+
);
|
|
327
442
|
if (entries.length > 0) msg = entries.join(' ');
|
|
328
443
|
}
|
|
329
444
|
setFeedbackModal({ open: true, title: 'Hata', message: msg });
|
|
@@ -342,7 +457,6 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
342
457
|
marginTop: '4px'
|
|
343
458
|
};
|
|
344
459
|
|
|
345
|
-
|
|
346
460
|
return (
|
|
347
461
|
<>
|
|
348
462
|
<div
|
|
@@ -371,7 +485,11 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
371
485
|
{/* Form */}
|
|
372
486
|
<form
|
|
373
487
|
onSubmit={handleSubmit(onSubmit)}
|
|
374
|
-
style={{
|
|
488
|
+
style={{
|
|
489
|
+
display: 'flex',
|
|
490
|
+
flexDirection: 'column',
|
|
491
|
+
gap: `${formGap}px`
|
|
492
|
+
}}
|
|
375
493
|
>
|
|
376
494
|
{/* Name + Email row */}
|
|
377
495
|
<div
|
|
@@ -430,7 +548,13 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
430
548
|
{/* Subject — select from API */}
|
|
431
549
|
<div style={{ position: 'relative' }}>
|
|
432
550
|
{subjectsLoading && (
|
|
433
|
-
<div
|
|
551
|
+
<div
|
|
552
|
+
style={{
|
|
553
|
+
padding: '10px',
|
|
554
|
+
fontSize: '13px',
|
|
555
|
+
color: '#94a3b8'
|
|
556
|
+
}}
|
|
557
|
+
>
|
|
434
558
|
Konular yükleniyor...
|
|
435
559
|
</div>
|
|
436
560
|
)}
|
|
@@ -508,8 +632,9 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
508
632
|
}}
|
|
509
633
|
onMouseEnter={(e) => {
|
|
510
634
|
if (!isSubmitting) {
|
|
511
|
-
(
|
|
512
|
-
|
|
635
|
+
(
|
|
636
|
+
e.currentTarget as HTMLButtonElement
|
|
637
|
+
).style.backgroundColor = buttonHoverBg;
|
|
513
638
|
}
|
|
514
639
|
}}
|
|
515
640
|
onMouseLeave={(e) => {
|
|
@@ -523,19 +648,21 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
523
648
|
|
|
524
649
|
{/* Server-side errors */}
|
|
525
650
|
{submitError && (
|
|
526
|
-
<div
|
|
651
|
+
<div
|
|
652
|
+
style={{ color: '#ef4444', fontSize: '13px', marginTop: '4px' }}
|
|
653
|
+
>
|
|
527
654
|
{'data' in submitError &&
|
|
528
655
|
submitError.data &&
|
|
529
656
|
typeof submitError.data === 'object'
|
|
530
|
-
? Object.entries(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
)
|
|
657
|
+
? Object.entries(
|
|
658
|
+
submitError.data as Record<string, unknown>
|
|
659
|
+
).map(([field, messages]) => (
|
|
660
|
+
<div key={field}>
|
|
661
|
+
{Array.isArray(messages)
|
|
662
|
+
? messages.join(', ')
|
|
663
|
+
: String(messages)}
|
|
664
|
+
</div>
|
|
665
|
+
))
|
|
539
666
|
: errorMessageText}
|
|
540
667
|
</div>
|
|
541
668
|
)}
|
|
@@ -546,9 +673,7 @@ const ContactFormSection: React.FC<ContactFormSectionProps> = ({
|
|
|
546
673
|
<Modal
|
|
547
674
|
portalId={`contact-form-feedback-${section.id}`}
|
|
548
675
|
open={feedbackModal.open}
|
|
549
|
-
setOpen={(open) =>
|
|
550
|
-
setFeedbackModal((prev) => ({ ...prev, open }))
|
|
551
|
-
}
|
|
676
|
+
setOpen={(open) => setFeedbackModal((prev) => ({ ...prev, open }))}
|
|
552
677
|
title={feedbackModal.title}
|
|
553
678
|
showCloseButton={true}
|
|
554
679
|
className="w-[92vw] max-w-[420px] rounded"
|
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
} from '../utils';
|
|
15
15
|
import { Section } from '../theme-section';
|
|
16
16
|
|
|
17
|
+
import { postToEditor } from '../editor-bridge';
|
|
18
|
+
import { PreviewToEditorMessageType } from '@akinon/theme-contract';
|
|
17
19
|
interface CountdownCampaignBannerSectionProps {
|
|
18
20
|
section: Section;
|
|
19
21
|
currentBreakpoint?: string;
|
|
@@ -87,7 +89,8 @@ const parseNumber = (value: unknown, fallback: number): number => {
|
|
|
87
89
|
const clampNumber = (value: number, min: number, max: number) =>
|
|
88
90
|
Math.min(Math.max(value, min), max);
|
|
89
91
|
|
|
90
|
-
const formatTwoDigits = (value: number) =>
|
|
92
|
+
const formatTwoDigits = (value: number) =>
|
|
93
|
+
String(Math.max(0, value)).padStart(2, '0');
|
|
91
94
|
|
|
92
95
|
const parseBoolean = (value: unknown, fallback: boolean): boolean => {
|
|
93
96
|
if (typeof value === 'boolean') return value;
|
|
@@ -166,7 +169,9 @@ const getRemainingTime = (
|
|
|
166
169
|
};
|
|
167
170
|
};
|
|
168
171
|
|
|
169
|
-
const CountdownCampaignBannerSection: React.FC<
|
|
172
|
+
const CountdownCampaignBannerSection: React.FC<
|
|
173
|
+
CountdownCampaignBannerSectionProps
|
|
174
|
+
> = ({
|
|
170
175
|
section,
|
|
171
176
|
currentBreakpoint = 'desktop',
|
|
172
177
|
placeholderId = '',
|
|
@@ -203,7 +208,11 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
203
208
|
const endDate = useMemo(() => parseEndDate(endDateRaw), [endDateRaw]);
|
|
204
209
|
|
|
205
210
|
const showSeconds = parseBoolean(
|
|
206
|
-
getResponsiveValue(
|
|
211
|
+
getResponsiveValue(
|
|
212
|
+
section.properties?.['show-seconds'],
|
|
213
|
+
currentBreakpoint,
|
|
214
|
+
true
|
|
215
|
+
),
|
|
207
216
|
true
|
|
208
217
|
);
|
|
209
218
|
|
|
@@ -256,7 +265,11 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
256
265
|
)
|
|
257
266
|
);
|
|
258
267
|
|
|
259
|
-
const sectionStyles = getCSSStyles(
|
|
268
|
+
const sectionStyles = getCSSStyles(
|
|
269
|
+
filteredStyles,
|
|
270
|
+
themeSettings,
|
|
271
|
+
currentBreakpoint
|
|
272
|
+
);
|
|
260
273
|
const backgroundImageSrc = useMemo(() => {
|
|
261
274
|
if (!backgroundBlock) return '';
|
|
262
275
|
const raw = pickImageSource(backgroundBlock.value, currentBreakpoint);
|
|
@@ -266,14 +279,22 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
266
279
|
|
|
267
280
|
const overlayColor = resolveThemeCssVariables(
|
|
268
281
|
String(
|
|
269
|
-
getResponsiveValue(
|
|
282
|
+
getResponsiveValue(
|
|
283
|
+
section.styles?.['overlay-color'],
|
|
284
|
+
currentBreakpoint,
|
|
285
|
+
'#0f172a'
|
|
286
|
+
)
|
|
270
287
|
),
|
|
271
288
|
themeSettings
|
|
272
289
|
);
|
|
273
290
|
const overlayOpacity =
|
|
274
291
|
clampNumber(
|
|
275
292
|
parseNumber(
|
|
276
|
-
getResponsiveValue(
|
|
293
|
+
getResponsiveValue(
|
|
294
|
+
section.styles?.['overlay-opacity'],
|
|
295
|
+
currentBreakpoint,
|
|
296
|
+
45
|
|
297
|
+
),
|
|
277
298
|
45
|
|
278
299
|
),
|
|
279
300
|
0,
|
|
@@ -293,39 +314,55 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
293
314
|
);
|
|
294
315
|
const timerTextColor = resolveThemeCssVariables(
|
|
295
316
|
String(
|
|
296
|
-
getResponsiveValue(
|
|
317
|
+
getResponsiveValue(
|
|
318
|
+
section.styles?.['timer-text-color'],
|
|
319
|
+
currentBreakpoint,
|
|
320
|
+
'#0f172a'
|
|
321
|
+
)
|
|
297
322
|
),
|
|
298
323
|
themeSettings
|
|
299
324
|
);
|
|
300
325
|
const timerLabelColor = resolveThemeCssVariables(
|
|
301
326
|
String(
|
|
302
|
-
getResponsiveValue(
|
|
327
|
+
getResponsiveValue(
|
|
328
|
+
section.styles?.['timer-label-color'],
|
|
329
|
+
currentBreakpoint,
|
|
330
|
+
'#64748b'
|
|
331
|
+
)
|
|
303
332
|
),
|
|
304
333
|
themeSettings
|
|
305
334
|
);
|
|
306
335
|
const timerBorderRadius = String(
|
|
307
|
-
getResponsiveValue(
|
|
336
|
+
getResponsiveValue(
|
|
337
|
+
section.styles?.['timer-border-radius'],
|
|
338
|
+
currentBreakpoint,
|
|
339
|
+
'10px'
|
|
340
|
+
)
|
|
308
341
|
);
|
|
309
342
|
const timerGap = clampNumber(
|
|
310
|
-
parseNumber(
|
|
343
|
+
parseNumber(
|
|
344
|
+
getResponsiveValue(section.styles?.['timer-gap'], currentBreakpoint, 10),
|
|
345
|
+
10
|
|
346
|
+
),
|
|
311
347
|
0,
|
|
312
348
|
32
|
|
313
349
|
);
|
|
314
350
|
|
|
315
|
-
const postBlockAction = (
|
|
351
|
+
const postBlockAction = (
|
|
352
|
+
type: PreviewToEditorMessageType,
|
|
353
|
+
blockId: string,
|
|
354
|
+
label?: string
|
|
355
|
+
) => {
|
|
316
356
|
if (!window.parent) return;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
},
|
|
327
|
-
'*'
|
|
328
|
-
);
|
|
357
|
+
postToEditor({
|
|
358
|
+
type,
|
|
359
|
+
data: {
|
|
360
|
+
placeholderId,
|
|
361
|
+
sectionId: section.id,
|
|
362
|
+
blockId,
|
|
363
|
+
...(label ? { label } : {})
|
|
364
|
+
}
|
|
365
|
+
});
|
|
329
366
|
};
|
|
330
367
|
|
|
331
368
|
const renderBlock = (block: Block) => (
|
|
@@ -341,9 +378,13 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
341
378
|
onMoveUp={() => postBlockAction('MOVE_BLOCK_UP', block.id)}
|
|
342
379
|
onMoveDown={() => postBlockAction('MOVE_BLOCK_DOWN', block.id)}
|
|
343
380
|
onDuplicate={() => postBlockAction('DUPLICATE_BLOCK', block.id)}
|
|
344
|
-
onToggleVisibility={() =>
|
|
381
|
+
onToggleVisibility={() =>
|
|
382
|
+
postBlockAction('TOGGLE_BLOCK_VISIBILITY', block.id)
|
|
383
|
+
}
|
|
345
384
|
onDelete={() => postBlockAction('DELETE_BLOCK', block.id)}
|
|
346
|
-
onRename={(newLabel) =>
|
|
385
|
+
onRename={(newLabel) =>
|
|
386
|
+
postBlockAction('RENAME_BLOCK', block.id, newLabel)
|
|
387
|
+
}
|
|
347
388
|
/>
|
|
348
389
|
);
|
|
349
390
|
|
|
@@ -372,7 +413,9 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
372
413
|
style={{ ...sectionStyles, position: 'relative' }}
|
|
373
414
|
>
|
|
374
415
|
{backgroundBlock && backgroundImageSrc ? (
|
|
375
|
-
<div className="absolute inset-0 z-0">
|
|
416
|
+
<div className="absolute inset-0 z-0">
|
|
417
|
+
{renderBlock(backgroundBlock)}
|
|
418
|
+
</div>
|
|
376
419
|
) : (
|
|
377
420
|
<div className="absolute inset-0 z-0 bg-slate-600" />
|
|
378
421
|
)}
|
|
@@ -397,7 +440,10 @@ const CountdownCampaignBannerSection: React.FC<CountdownCampaignBannerSectionPro
|
|
|
397
440
|
{expiredMessage}
|
|
398
441
|
</div>
|
|
399
442
|
) : (
|
|
400
|
-
<div
|
|
443
|
+
<div
|
|
444
|
+
className="flex flex-wrap items-stretch"
|
|
445
|
+
style={{ gap: `${timerGap}px` }}
|
|
446
|
+
>
|
|
401
447
|
{timerUnits.map((unit) => (
|
|
402
448
|
<div
|
|
403
449
|
key={unit.key}
|