| 1 |
wp.domReady(function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var Fragment = wp.element.Fragment; |
| 4 |
var __ = wp.i18n.__; |
| 5 |
var useState = wp.element.useState; |
| 6 |
var useEffect = wp.element.useEffect; |
| 7 |
var registerBlockType = wp.blocks.registerBlockType; |
| 8 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 9 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 10 |
var PanelBody = wp.components.PanelBody; |
| 11 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 12 |
var ToggleControl = wp.components.ToggleControl; |
| 13 |
var RangeControl = wp.components.RangeControl; |
| 14 |
var SelectControl = wp.components.SelectControl; |
| 15 |
var TextControl = wp.components.TextControl; |
| 16 |
|
| 17 |
// Calculate time remaining |
| 18 |
function getTimeRemaining(targetDate, targetTime) { |
| 19 |
if (!targetDate) return { days: 0, hours: 0, minutes: 0, seconds: 0, total: 0 }; |
| 20 |
|
| 21 |
var target = new Date(targetDate + 'T' + (targetTime || '00:00') + ':00'); |
| 22 |
var now = new Date(); |
| 23 |
var total = target - now; |
| 24 |
|
| 25 |
if (total <= 0) { |
| 26 |
return { days: 0, hours: 0, minutes: 0, seconds: 0, total: 0 }; |
| 27 |
} |
| 28 |
|
| 29 |
return { |
| 30 |
days: Math.floor(total / (1000 * 60 * 60 * 24)), |
| 31 |
hours: Math.floor((total / (1000 * 60 * 60)) % 24), |
| 32 |
minutes: Math.floor((total / (1000 * 60)) % 60), |
| 33 |
seconds: Math.floor((total / 1000) % 60), |
| 34 |
total: total |
| 35 |
}; |
| 36 |
} |
| 37 |
|
| 38 |
// Pad number with leading zero |
| 39 |
function pad(num) { |
| 40 |
return num < 10 ? '0' + num : String(num); |
| 41 |
} |
| 42 |
|
| 43 |
// Get default date (7 days from now) |
| 44 |
function getDefaultDate() { |
| 45 |
var d = new Date(); |
| 46 |
d.setDate(d.getDate() + 7); |
| 47 |
return d.toISOString().split('T')[0]; |
| 48 |
} |
| 49 |
|
| 50 |
registerBlockType('blockenberg/countdown', { |
| 51 |
title: __('Countdown', 'blockenberg'), |
| 52 |
icon: 'clock', |
| 53 |
category: 'blockenberg', |
| 54 |
description: __('Display a countdown timer to a specific date and time.', 'blockenberg'), |
| 55 |
|
| 56 |
edit: function (props) { |
| 57 |
var attributes = props.attributes; |
| 58 |
var setAttributes = props.setAttributes; |
| 59 |
var a = attributes; |
| 60 |
|
| 61 |
// State for live countdown in editor |
| 62 |
var timeState = useState(function () { |
| 63 |
return getTimeRemaining(a.targetDate || getDefaultDate(), a.targetTime); |
| 64 |
}); |
| 65 |
var time = timeState[0]; |
| 66 |
var setTime = timeState[1]; |
| 67 |
|
| 68 |
// State for editing |
| 69 |
var editingState = useState(null); |
| 70 |
var editing = editingState[0]; |
| 71 |
var setEditing = editingState[1]; |
| 72 |
|
| 73 |
// Ref for evergreen simulation start time |
| 74 |
var evergreenStartRef = wp.element.useRef(null); |
| 75 |
|
| 76 |
// Update countdown every second in editor |
| 77 |
useEffect(function () { |
| 78 |
var targetDate = a.targetDate || getDefaultDate(); |
| 79 |
|
| 80 |
// Set default date if not set and not evergreen |
| 81 |
if (!a.targetDate && !a.evergreenMode) { |
| 82 |
setAttributes({ targetDate: targetDate }); |
| 83 |
} |
| 84 |
|
| 85 |
// For evergreen, set up simulation start time |
| 86 |
if (a.evergreenMode && !evergreenStartRef.current) { |
| 87 |
evergreenStartRef.current = Date.now(); |
| 88 |
} |
| 89 |
if (!a.evergreenMode) { |
| 90 |
evergreenStartRef.current = null; |
| 91 |
} |
| 92 |
|
| 93 |
// Calculate time remaining |
| 94 |
function updateTime() { |
| 95 |
if (a.evergreenMode) { |
| 96 |
// Calculate total duration in ms |
| 97 |
var totalDuration = (a.evergreenDays * 24 * 60 * 60 * 1000) + |
| 98 |
(a.evergreenHours * 60 * 60 * 1000) + |
| 99 |
(a.evergreenMinutes * 60 * 1000); |
| 100 |
|
| 101 |
// Calculate elapsed time since simulation started |
| 102 |
var elapsed = Date.now() - evergreenStartRef.current; |
| 103 |
var remaining = Math.max(0, totalDuration - elapsed); |
| 104 |
|
| 105 |
// If expired, restart simulation |
| 106 |
if (remaining <= 0) { |
| 107 |
evergreenStartRef.current = Date.now(); |
| 108 |
remaining = totalDuration; |
| 109 |
} |
| 110 |
|
| 111 |
var days = Math.floor(remaining / (1000 * 60 * 60 * 24)); |
| 112 |
var hours = Math.floor((remaining / (1000 * 60 * 60)) % 24); |
| 113 |
var minutes = Math.floor((remaining / (1000 * 60)) % 60); |
| 114 |
var seconds = Math.floor((remaining / 1000) % 60); |
| 115 |
setTime({ days: days, hours: hours, minutes: minutes, seconds: seconds, total: remaining }); |
| 116 |
} else { |
| 117 |
setTime(getTimeRemaining(targetDate, a.targetTime)); |
| 118 |
} |
| 119 |
} |
| 120 |
|
| 121 |
var interval = setInterval(updateTime, 1000); |
| 122 |
updateTime(); |
| 123 |
|
| 124 |
return function () { clearInterval(interval); }; |
| 125 |
}, [a.targetDate, a.targetTime, a.evergreenMode, a.evergreenDays, a.evergreenHours, a.evergreenMinutes]); |
| 126 |
|
| 127 |
var layoutOptions = [ |
| 128 |
{ label: __('Cards', 'blockenberg'), value: 'cards' }, |
| 129 |
{ label: __('Inline', 'blockenberg'), value: 'inline' }, |
| 130 |
{ label: __('Minimal', 'blockenberg'), value: 'minimal' }, |
| 131 |
{ label: __('Circle', 'blockenberg'), value: 'circle' } |
| 132 |
]; |
| 133 |
|
| 134 |
var expiredOptions = [ |
| 135 |
{ label: __('Show Message', 'blockenberg'), value: 'message' }, |
| 136 |
{ label: __('Hide Block', 'blockenberg'), value: 'hide' }, |
| 137 |
{ label: __('Redirect', 'blockenberg'), value: 'redirect' }, |
| 138 |
{ label: __('Keep Last State', 'blockenberg'), value: 'keep' } |
| 139 |
]; |
| 140 |
|
| 141 |
var fontWeightOptions = [ |
| 142 |
{ label: '400', value: 400 }, |
| 143 |
{ label: '500', value: 500 }, |
| 144 |
{ label: '600', value: 600 }, |
| 145 |
{ label: '700', value: 700 }, |
| 146 |
{ label: '800', value: 800 } |
| 147 |
]; |
| 148 |
|
| 149 |
// Inspector controls |
| 150 |
var inspector = el(InspectorControls, {}, |
| 151 |
el(PanelBody, { title: __('Date & Time', 'blockenberg'), initialOpen: true }, |
| 152 |
el(ToggleControl, { |
| 153 |
label: __('Evergreen Mode', 'blockenberg'), |
| 154 |
help: a.evergreenMode ? __('Countdown resets for each visitor', 'blockenberg') : __('Fixed date countdown', 'blockenberg'), |
| 155 |
checked: a.evergreenMode, |
| 156 |
__nextHasNoMarginBottom: true, |
| 157 |
onChange: function (v) { |
| 158 |
setAttributes({ evergreenMode: v }); |
| 159 |
// Generate unique ID for evergreen |
| 160 |
if (v && !a.evergreenId) { |
| 161 |
setAttributes({ evergreenId: 'eg_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9) }); |
| 162 |
} |
| 163 |
} |
| 164 |
}), |
| 165 |
!a.evergreenMode && el('div', { className: 'bkbg-cd-date-control' }, |
| 166 |
el('label', {}, __('Target Date', 'blockenberg')), |
| 167 |
el('input', { |
| 168 |
type: 'date', |
| 169 |
value: a.targetDate, |
| 170 |
onChange: function (e) { setAttributes({ targetDate: e.target.value }); }, |
| 171 |
className: 'components-text-control__input' |
| 172 |
}) |
| 173 |
), |
| 174 |
!a.evergreenMode && el('div', { className: 'bkbg-cd-date-control', style: { marginTop: '12px' } }, |
| 175 |
el('label', {}, __('Target Time', 'blockenberg')), |
| 176 |
el('input', { |
| 177 |
type: 'time', |
| 178 |
value: a.targetTime, |
| 179 |
onChange: function (e) { setAttributes({ targetTime: e.target.value }); }, |
| 180 |
className: 'components-text-control__input' |
| 181 |
}) |
| 182 |
), |
| 183 |
a.evergreenMode && el(RangeControl, { |
| 184 |
label: __('Days', 'blockenberg'), |
| 185 |
value: a.evergreenDays, |
| 186 |
min: 0, |
| 187 |
max: 30, |
| 188 |
onChange: function (v) { setAttributes({ evergreenDays: v }); } |
| 189 |
}), |
| 190 |
a.evergreenMode && el(RangeControl, { |
| 191 |
label: __('Hours', 'blockenberg'), |
| 192 |
value: a.evergreenHours, |
| 193 |
min: 0, |
| 194 |
max: 23, |
| 195 |
onChange: function (v) { setAttributes({ evergreenHours: v }); } |
| 196 |
}), |
| 197 |
a.evergreenMode && el(RangeControl, { |
| 198 |
label: __('Minutes', 'blockenberg'), |
| 199 |
value: a.evergreenMinutes, |
| 200 |
min: 0, |
| 201 |
max: 59, |
| 202 |
onChange: function (v) { setAttributes({ evergreenMinutes: v }); } |
| 203 |
}) |
| 204 |
), |
| 205 |
|
| 206 |
el(PanelBody, { title: __('Display Options', 'blockenberg'), initialOpen: true }, |
| 207 |
el(SelectControl, { |
| 208 |
label: __('Layout Style', 'blockenberg'), |
| 209 |
value: a.layoutStyle, |
| 210 |
options: layoutOptions, |
| 211 |
onChange: function (v) { setAttributes({ layoutStyle: v }); } |
| 212 |
}), |
| 213 |
el(ToggleControl, { |
| 214 |
label: __('Show Title', 'blockenberg'), |
| 215 |
checked: a.showTitle, |
| 216 |
__nextHasNoMarginBottom: true, |
| 217 |
onChange: function (v) { setAttributes({ showTitle: v }); } |
| 218 |
}), |
| 219 |
el(ToggleControl, { |
| 220 |
label: __('Show Days', 'blockenberg'), |
| 221 |
checked: a.showDays, |
| 222 |
__nextHasNoMarginBottom: true, |
| 223 |
onChange: function (v) { setAttributes({ showDays: v }); } |
| 224 |
}), |
| 225 |
el(ToggleControl, { |
| 226 |
label: __('Show Hours', 'blockenberg'), |
| 227 |
checked: a.showHours, |
| 228 |
__nextHasNoMarginBottom: true, |
| 229 |
onChange: function (v) { setAttributes({ showHours: v }); } |
| 230 |
}), |
| 231 |
el(ToggleControl, { |
| 232 |
label: __('Show Minutes', 'blockenberg'), |
| 233 |
checked: a.showMinutes, |
| 234 |
__nextHasNoMarginBottom: true, |
| 235 |
onChange: function (v) { setAttributes({ showMinutes: v }); } |
| 236 |
}), |
| 237 |
el(ToggleControl, { |
| 238 |
label: __('Show Seconds', 'blockenberg'), |
| 239 |
checked: a.showSeconds, |
| 240 |
__nextHasNoMarginBottom: true, |
| 241 |
onChange: function (v) { setAttributes({ showSeconds: v }); } |
| 242 |
}), |
| 243 |
el(ToggleControl, { |
| 244 |
label: __('Show Labels', 'blockenberg'), |
| 245 |
checked: a.showLabels, |
| 246 |
__nextHasNoMarginBottom: true, |
| 247 |
onChange: function (v) { setAttributes({ showLabels: v }); } |
| 248 |
}), |
| 249 |
el(ToggleControl, { |
| 250 |
label: __('Show Separators', 'blockenberg'), |
| 251 |
checked: a.showSeparators, |
| 252 |
__nextHasNoMarginBottom: true, |
| 253 |
onChange: function (v) { setAttributes({ showSeparators: v }); } |
| 254 |
}) |
| 255 |
), |
| 256 |
|
| 257 |
el(PanelBody, { title: __('Labels', 'blockenberg'), initialOpen: false }, |
| 258 |
el(TextControl, { |
| 259 |
label: __('Days Label', 'blockenberg'), |
| 260 |
value: a.labelDays, |
| 261 |
onChange: function (v) { setAttributes({ labelDays: v }); } |
| 262 |
}), |
| 263 |
el(TextControl, { |
| 264 |
label: __('Hours Label', 'blockenberg'), |
| 265 |
value: a.labelHours, |
| 266 |
onChange: function (v) { setAttributes({ labelHours: v }); } |
| 267 |
}), |
| 268 |
el(TextControl, { |
| 269 |
label: __('Minutes Label', 'blockenberg'), |
| 270 |
value: a.labelMinutes, |
| 271 |
onChange: function (v) { setAttributes({ labelMinutes: v }); } |
| 272 |
}), |
| 273 |
el(TextControl, { |
| 274 |
label: __('Seconds Label', 'blockenberg'), |
| 275 |
value: a.labelSeconds, |
| 276 |
onChange: function (v) { setAttributes({ labelSeconds: v }); } |
| 277 |
}) |
| 278 |
), |
| 279 |
|
| 280 |
el(PanelBody, { title: __('Expiration', 'blockenberg'), initialOpen: false }, |
| 281 |
el(SelectControl, { |
| 282 |
label: __('When Expired', 'blockenberg'), |
| 283 |
value: a.expiredAction, |
| 284 |
options: expiredOptions, |
| 285 |
onChange: function (v) { setAttributes({ expiredAction: v }); } |
| 286 |
}), |
| 287 |
a.expiredAction === 'message' && el(TextControl, { |
| 288 |
label: __('Expired Message', 'blockenberg'), |
| 289 |
value: a.expiredMessage, |
| 290 |
onChange: function (v) { setAttributes({ expiredMessage: v }); } |
| 291 |
}), |
| 292 |
a.expiredAction === 'redirect' && el(TextControl, { |
| 293 |
label: __('Redirect URL', 'blockenberg'), |
| 294 |
value: a.expiredRedirectUrl, |
| 295 |
onChange: function (v) { setAttributes({ expiredRedirectUrl: v }); } |
| 296 |
}) |
| 297 |
), |
| 298 |
|
| 299 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 300 |
el(RangeControl, { |
| 301 |
label: __('Digit Font Size', 'blockenberg'), |
| 302 |
value: a.digitFontSize, |
| 303 |
min: 24, |
| 304 |
max: 120, |
| 305 |
onChange: function (v) { setAttributes({ digitFontSize: v }); } |
| 306 |
}), |
| 307 |
el(SelectControl, { |
| 308 |
label: __('Digit Font Weight', 'blockenberg'), |
| 309 |
value: a.digitFontWeight, |
| 310 |
options: fontWeightOptions, |
| 311 |
onChange: function (v) { setAttributes({ digitFontWeight: parseInt(v, 10) }); } |
| 312 |
}), |
| 313 |
el(RangeControl, { |
| 314 |
label: __('Label Font Size', 'blockenberg'), |
| 315 |
value: a.labelFontSize, |
| 316 |
min: 10, |
| 317 |
max: 24, |
| 318 |
onChange: function (v) { setAttributes({ labelFontSize: v }); } |
| 319 |
}), |
| 320 |
el(SelectControl, { |
| 321 |
label: __('Label Font Weight', 'blockenberg'), |
| 322 |
value: a.labelFontWeight, |
| 323 |
options: fontWeightOptions, |
| 324 |
onChange: function (v) { setAttributes({ labelFontWeight: parseInt(v, 10) }); } |
| 325 |
}), |
| 326 |
el(RangeControl, { |
| 327 |
label: __('Title Font Size', 'blockenberg'), |
| 328 |
value: a.titleFontSize, |
| 329 |
min: 14, |
| 330 |
max: 48, |
| 331 |
onChange: function (v) { setAttributes({ titleFontSize: v }); } |
| 332 |
}) |
| 333 |
), |
| 334 |
|
| 335 |
el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false }, |
| 336 |
el(RangeControl, { |
| 337 |
label: __('Container Padding', 'blockenberg'), |
| 338 |
value: a.padding, |
| 339 |
min: 0, |
| 340 |
max: 60, |
| 341 |
onChange: function (v) { setAttributes({ padding: v }); } |
| 342 |
}), |
| 343 |
el(RangeControl, { |
| 344 |
label: __('Gap Between Units', 'blockenberg'), |
| 345 |
value: a.gap, |
| 346 |
min: 8, |
| 347 |
max: 48, |
| 348 |
onChange: function (v) { setAttributes({ gap: v }); } |
| 349 |
}), |
| 350 |
el(RangeControl, { |
| 351 |
label: __('Digit Box Padding', 'blockenberg'), |
| 352 |
value: a.digitPadding, |
| 353 |
min: 8, |
| 354 |
max: 40, |
| 355 |
onChange: function (v) { setAttributes({ digitPadding: v }); } |
| 356 |
}), |
| 357 |
el(RangeControl, { |
| 358 |
label: __('Container Radius', 'blockenberg'), |
| 359 |
value: a.borderRadius, |
| 360 |
min: 0, |
| 361 |
max: 30, |
| 362 |
onChange: function (v) { setAttributes({ borderRadius: v }); } |
| 363 |
}), |
| 364 |
el(RangeControl, { |
| 365 |
label: __('Digit Box Radius', 'blockenberg'), |
| 366 |
value: a.digitRadius, |
| 367 |
min: 0, |
| 368 |
max: 24, |
| 369 |
onChange: function (v) { setAttributes({ digitRadius: v }); } |
| 370 |
}) |
| 371 |
), |
| 372 |
|
| 373 |
el(PanelColorSettings, { |
| 374 |
title: __('Colors', 'blockenberg'), |
| 375 |
initialOpen: false, |
| 376 |
colorSettings: [ |
| 377 |
{ value: a.wrapBg, onChange: function (c) { setAttributes({ wrapBg: c }); }, label: __('Background', 'blockenberg') }, |
| 378 |
{ value: a.digitBg, onChange: function (c) { setAttributes({ digitBg: c }); }, label: __('Digit Background', 'blockenberg') }, |
| 379 |
{ value: a.digitColor, onChange: function (c) { setAttributes({ digitColor: c }); }, label: __('Digit Color', 'blockenberg') }, |
| 380 |
{ value: a.labelColor, onChange: function (c) { setAttributes({ labelColor: c }); }, label: __('Label Color', 'blockenberg') }, |
| 381 |
{ value: a.separatorColor, onChange: function (c) { setAttributes({ separatorColor: c }); }, label: __('Separator Color', 'blockenberg') }, |
| 382 |
{ value: a.titleColor, onChange: function (c) { setAttributes({ titleColor: c }); }, label: __('Title Color', 'blockenberg') } |
| 383 |
] |
| 384 |
}) |
| 385 |
); |
| 386 |
|
| 387 |
// CSS variables |
| 388 |
var wrapStyle = { |
| 389 |
'--bkbg-cd-wrap-bg': a.wrapBg, |
| 390 |
'--bkbg-cd-digit-bg': a.digitBg, |
| 391 |
'--bkbg-cd-digit-color': a.digitColor, |
| 392 |
'--bkbg-cd-label-color': a.labelColor, |
| 393 |
'--bkbg-cd-separator-color': a.separatorColor, |
| 394 |
'--bkbg-cd-title-color': a.titleColor, |
| 395 |
'--bkbg-cd-digit-size': a.digitFontSize + 'px', |
| 396 |
'--bkbg-cd-digit-weight': a.digitFontWeight, |
| 397 |
'--bkbg-cd-label-size': a.labelFontSize + 'px', |
| 398 |
'--bkbg-cd-label-weight': a.labelFontWeight, |
| 399 |
'--bkbg-cd-title-size': a.titleFontSize + 'px', |
| 400 |
'--bkbg-cd-padding': a.padding + 'px', |
| 401 |
'--bkbg-cd-gap': a.gap + 'px', |
| 402 |
'--bkbg-cd-radius': a.borderRadius + 'px', |
| 403 |
'--bkbg-cd-digit-padding': a.digitPadding + 'px', |
| 404 |
'--bkbg-cd-digit-radius': a.digitRadius + 'px' |
| 405 |
}; |
| 406 |
|
| 407 |
// Build time units |
| 408 |
var units = []; |
| 409 |
|
| 410 |
if (a.showDays) { |
| 411 |
units.push({ key: 'days', value: time.days, label: a.labelDays }); |
| 412 |
} |
| 413 |
if (a.showHours) { |
| 414 |
units.push({ key: 'hours', value: time.hours, label: a.labelHours }); |
| 415 |
} |
| 416 |
if (a.showMinutes) { |
| 417 |
units.push({ key: 'minutes', value: time.minutes, label: a.labelMinutes }); |
| 418 |
} |
| 419 |
if (a.showSeconds) { |
| 420 |
units.push({ key: 'seconds', value: time.seconds, label: a.labelSeconds }); |
| 421 |
} |
| 422 |
|
| 423 |
// Title element |
| 424 |
var titleEl = null; |
| 425 |
if (a.showTitle) { |
| 426 |
if (editing === 'title') { |
| 427 |
titleEl = el('input', { |
| 428 |
type: 'text', |
| 429 |
className: 'bkbg-cd-title bkbg-cd-input-active', |
| 430 |
value: a.title, |
| 431 |
autoFocus: true, |
| 432 |
placeholder: __('Countdown Title', 'blockenberg'), |
| 433 |
onChange: function (e) { setAttributes({ title: e.target.value }); }, |
| 434 |
onBlur: function () { setEditing(null); }, |
| 435 |
onKeyDown: function (e) { if (e.key === 'Enter') setEditing(null); } |
| 436 |
}); |
| 437 |
} else { |
| 438 |
titleEl = el('div', { |
| 439 |
className: 'bkbg-cd-title bkbg-cd-clickable', |
| 440 |
onClick: function () { setEditing('title'); } |
| 441 |
}, a.title || __('Countdown Title', 'blockenberg')); |
| 442 |
} |
| 443 |
} |
| 444 |
|
| 445 |
// Build countdown units |
| 446 |
var countdownUnits = units.map(function (unit, index) { |
| 447 |
var isLast = index === units.length - 1; |
| 448 |
var labelKey = 'label-' + unit.key; |
| 449 |
var valueStr = pad(unit.value); |
| 450 |
|
| 451 |
// Label element - click to edit |
| 452 |
var labelEl = null; |
| 453 |
if (a.showLabels) { |
| 454 |
if (editing === labelKey) { |
| 455 |
labelEl = el('input', { |
| 456 |
type: 'text', |
| 457 |
className: 'bkbg-cd-label bkbg-cd-input-active', |
| 458 |
value: unit.label, |
| 459 |
autoFocus: true, |
| 460 |
onChange: function (e) { |
| 461 |
var attr = 'label' + unit.key.charAt(0).toUpperCase() + unit.key.slice(1); |
| 462 |
var obj = {}; |
| 463 |
obj[attr] = e.target.value; |
| 464 |
setAttributes(obj); |
| 465 |
}, |
| 466 |
onBlur: function () { setEditing(null); }, |
| 467 |
onKeyDown: function (e) { if (e.key === 'Enter') setEditing(null); } |
| 468 |
}); |
| 469 |
} else { |
| 470 |
labelEl = el('span', { |
| 471 |
className: 'bkbg-cd-label bkbg-cd-clickable', |
| 472 |
onClick: function () { setEditing(labelKey); } |
| 473 |
}, unit.label); |
| 474 |
} |
| 475 |
} |
| 476 |
|
| 477 |
return el(Fragment, { key: unit.key }, |
| 478 |
el('div', { className: 'bkbg-cd-unit' }, |
| 479 |
el('div', { className: 'bkbg-cd-digit' }, |
| 480 |
el('span', { className: 'bkbg-cd-number' }, valueStr) |
| 481 |
), |
| 482 |
labelEl |
| 483 |
), |
| 484 |
a.showSeparators && !isLast && el('span', { className: 'bkbg-cd-separator' }, ':') |
| 485 |
); |
| 486 |
}); |
| 487 |
|
| 488 |
var blockProps = useBlockProps({ |
| 489 |
className: 'bkbg-editor-wrap', |
| 490 |
'data-block-label': 'Countdown' |
| 491 |
}); |
| 492 |
|
| 493 |
return el('div', blockProps, |
| 494 |
inspector, |
| 495 |
el('div', { |
| 496 |
className: 'bkbg-cd-wrap', |
| 497 |
style: wrapStyle, |
| 498 |
'data-layout': a.layoutStyle |
| 499 |
}, |
| 500 |
titleEl, |
| 501 |
el('div', { className: 'bkbg-cd-countdown' }, countdownUnits) |
| 502 |
) |
| 503 |
); |
| 504 |
}, |
| 505 |
|
| 506 |
save: function (props) { |
| 507 |
var a = props.attributes; |
| 508 |
|
| 509 |
var wrapStyle = { |
| 510 |
'--bkbg-cd-wrap-bg': a.wrapBg, |
| 511 |
'--bkbg-cd-digit-bg': a.digitBg, |
| 512 |
'--bkbg-cd-digit-color': a.digitColor, |
| 513 |
'--bkbg-cd-label-color': a.labelColor, |
| 514 |
'--bkbg-cd-separator-color': a.separatorColor, |
| 515 |
'--bkbg-cd-title-color': a.titleColor, |
| 516 |
'--bkbg-cd-digit-size': a.digitFontSize + 'px', |
| 517 |
'--bkbg-cd-digit-weight': a.digitFontWeight, |
| 518 |
'--bkbg-cd-label-size': a.labelFontSize + 'px', |
| 519 |
'--bkbg-cd-label-weight': a.labelFontWeight, |
| 520 |
'--bkbg-cd-title-size': a.titleFontSize + 'px', |
| 521 |
'--bkbg-cd-padding': a.padding + 'px', |
| 522 |
'--bkbg-cd-gap': a.gap + 'px', |
| 523 |
'--bkbg-cd-radius': a.borderRadius + 'px', |
| 524 |
'--bkbg-cd-digit-padding': a.digitPadding + 'px', |
| 525 |
'--bkbg-cd-digit-radius': a.digitRadius + 'px' |
| 526 |
}; |
| 527 |
|
| 528 |
// Build units config as data attributes |
| 529 |
var unitsConfig = []; |
| 530 |
if (a.showDays) unitsConfig.push('days:' + a.labelDays); |
| 531 |
if (a.showHours) unitsConfig.push('hours:' + a.labelHours); |
| 532 |
if (a.showMinutes) unitsConfig.push('minutes:' + a.labelMinutes); |
| 533 |
if (a.showSeconds) unitsConfig.push('seconds:' + a.labelSeconds); |
| 534 |
|
| 535 |
// Calculate evergreen duration in milliseconds |
| 536 |
var evergreenDuration = (a.evergreenDays * 24 * 60 * 60 * 1000) + |
| 537 |
(a.evergreenHours * 60 * 60 * 1000) + |
| 538 |
(a.evergreenMinutes * 60 * 1000); |
| 539 |
|
| 540 |
return el('div', { |
| 541 |
className: 'bkbg-cd-wrap', |
| 542 |
style: wrapStyle, |
| 543 |
'data-layout': a.layoutStyle, |
| 544 |
'data-target': a.evergreenMode ? '' : (a.targetDate + 'T' + a.targetTime), |
| 545 |
'data-units': unitsConfig.join('|'), |
| 546 |
'data-show-labels': a.showLabels ? '1' : '0', |
| 547 |
'data-show-separators': a.showSeparators ? '1' : '0', |
| 548 |
'data-expired-action': a.expiredAction, |
| 549 |
'data-expired-message': a.expiredMessage, |
| 550 |
'data-expired-redirect': a.expiredRedirectUrl, |
| 551 |
'data-evergreen': a.evergreenMode ? '1' : '0', |
| 552 |
'data-evergreen-duration': String(evergreenDuration), |
| 553 |
'data-evergreen-id': a.evergreenId |
| 554 |
}, |
| 555 |
a.showTitle && a.title && el('div', { className: 'bkbg-cd-title' }, a.title), |
| 556 |
el('div', { className: 'bkbg-cd-countdown' }) |
| 557 |
); |
| 558 |
} |
| 559 |
}); |
| 560 |
}); |
| 561 |
|