| 1 |
( function () { |
| 2 |
var el = wp.element.createElement; |
| 3 |
var __ = wp.i18n.__; |
| 4 |
var useState = wp.element.useState; |
| 5 |
var registerBlockType = wp.blocks.registerBlockType; |
| 6 |
var InspectorControls = wp.blockEditor.InspectorControls; |
| 7 |
var useBlockProps = wp.blockEditor.useBlockProps; |
| 8 |
var PanelColorSettings = wp.blockEditor.PanelColorSettings; |
| 9 |
var PanelBody = wp.components.PanelBody; |
| 10 |
var ToggleControl = wp.components.ToggleControl; |
| 11 |
var RangeControl = wp.components.RangeControl; |
| 12 |
var SelectControl = wp.components.SelectControl; |
| 13 |
var TextControl = wp.components.TextControl; |
| 14 |
|
| 15 |
var _dmTC, _dmTV; |
| 16 |
function _tc() { return _dmTC || (_dmTC = window.bkbgTypographyControl); } |
| 17 |
function _tv(obj, prefix) { var fn = _dmTV || (_dmTV = window.bkbgTypoCssVars); return fn ? fn(obj, prefix) : {}; } |
| 18 |
|
| 19 |
/* ── Preview component ─────────────────────────────────────────────────── */ |
| 20 |
function TogglePreview(props) { |
| 21 |
var a = props.attrs; |
| 22 |
var isDark = props.isDark; |
| 23 |
|
| 24 |
var wrapStyle = { |
| 25 |
display: 'flex', |
| 26 |
alignItems: 'center', |
| 27 |
justifyContent: |
| 28 |
props.align === 'right' ? 'flex-end' : |
| 29 |
props.align === 'center' ? 'center' : 'flex-start', |
| 30 |
}; |
| 31 |
|
| 32 |
var btnStyle = { |
| 33 |
display: 'inline-flex', |
| 34 |
alignItems: 'center', |
| 35 |
gap: '8px', |
| 36 |
minWidth: a.buttonSize + 'px', |
| 37 |
height: a.buttonSize + 'px', |
| 38 |
padding: '0 12px', |
| 39 |
borderRadius: a.borderRadius + 'px', |
| 40 |
border: 'none', |
| 41 |
cursor: 'pointer', |
| 42 |
fontSize: Math.round(a.buttonSize * 0.4) + 'px', |
| 43 |
background: isDark ? a.darkBg : a.lightBg, |
| 44 |
color: isDark ? a.darkColor : a.lightColor, |
| 45 |
boxShadow: a.shadow ? '0 2px 8px rgba(0,0,0,0.18)' : 'none', |
| 46 |
transition: 'transform ' + a.transitionDuration + 'ms ease', |
| 47 |
transform: 'scale(1)', |
| 48 |
}; |
| 49 |
|
| 50 |
if (a.toggleStyle === 'switch') { |
| 51 |
var trackStyle = { |
| 52 |
display: 'inline-flex', |
| 53 |
alignItems: 'center', |
| 54 |
width: '48px', |
| 55 |
height: '26px', |
| 56 |
borderRadius: '13px', |
| 57 |
background: isDark ? a.switchTrackDark : a.switchTrackLight, |
| 58 |
padding: '2px', |
| 59 |
boxSizing: 'border-box', |
| 60 |
transition: 'background ' + a.transitionDuration + 'ms ease', |
| 61 |
flexShrink: 0, |
| 62 |
}; |
| 63 |
var thumbStyle = { |
| 64 |
width: '22px', |
| 65 |
height: '22px', |
| 66 |
borderRadius: '50%', |
| 67 |
background: a.switchThumbColor, |
| 68 |
boxShadow: '0 1px 4px rgba(0,0,0,0.25)', |
| 69 |
transition: 'transform ' + a.transitionDuration + 'ms ease', |
| 70 |
transform: isDark ? 'translateX(22px)' : 'translateX(0)', |
| 71 |
}; |
| 72 |
return el('div', { style: wrapStyle }, |
| 73 |
el('button', { |
| 74 |
'aria-label': 'Toggle dark mode', |
| 75 |
style: { |
| 76 |
display: 'inline-flex', |
| 77 |
alignItems: 'center', |
| 78 |
gap: '8px', |
| 79 |
background: 'none', |
| 80 |
border: 'none', |
| 81 |
cursor: 'pointer', |
| 82 |
padding: '0', |
| 83 |
fontSize: '18px', |
| 84 |
} |
| 85 |
}, |
| 86 |
a.showIcon ? el('span', null, isDark ? a.darkIcon : a.lightIcon) : null, |
| 87 |
el('div', { style: trackStyle }, |
| 88 |
el('div', { style: thumbStyle }) |
| 89 |
), |
| 90 |
a.showLabel ? el('span', { |
| 91 |
className: 'bkdm-label', style: { color: '#374151' } |
| 92 |
}, isDark ? a.darkLabel : a.lightLabel) : null |
| 93 |
) |
| 94 |
); |
| 95 |
} |
| 96 |
|
| 97 |
// icon or button style |
| 98 |
return el('div', { style: wrapStyle }, |
| 99 |
el('button', { 'aria-label': 'Toggle dark mode', style: btnStyle }, |
| 100 |
a.showIcon ? el('span', null, isDark ? a.darkIcon : a.lightIcon) : null, |
| 101 |
a.showLabel ? el('span', { |
| 102 |
className: 'bkdm-label' |
| 103 |
}, isDark ? a.darkLabel : a.lightLabel) : null |
| 104 |
) |
| 105 |
); |
| 106 |
} |
| 107 |
|
| 108 |
/* ── Register ──────────────────────────────────────────────────────────── */ |
| 109 |
registerBlockType('blockenberg/dark-mode-toggle', { |
| 110 |
edit: function (props) { |
| 111 |
var a = props.attributes; |
| 112 |
var set = props.setAttributes; |
| 113 |
var align = props.attributes.align; |
| 114 |
|
| 115 |
var isDark = useState(false); |
| 116 |
var previewDark = isDark[0]; |
| 117 |
var setPreviewDark = isDark[1]; |
| 118 |
|
| 119 |
var blockProps = useBlockProps({ |
| 120 |
className: 'bkdm-wrap', |
| 121 |
style: Object.assign( |
| 122 |
{ '--bkdm-lbl-fs': (a.labelFontSize || 14) + 'px' }, |
| 123 |
_tv(a.typoLabel || {}, '--bkdm-lbl-') |
| 124 |
) |
| 125 |
}); |
| 126 |
|
| 127 |
return el(wp.element.Fragment, null, |
| 128 |
|
| 129 |
/* Inspector */ |
| 130 |
el(InspectorControls, null, |
| 131 |
|
| 132 |
/* Appearance */ |
| 133 |
el(PanelBody, { title: __('Appearance', 'blockenberg'), initialOpen: true }, |
| 134 |
el(SelectControl, { |
| 135 |
label: __('Toggle Style', 'blockenberg'), |
| 136 |
value: a.toggleStyle, |
| 137 |
options: [ |
| 138 |
{ label: __('Switch (track + thumb)', 'blockenberg'), value: 'switch' }, |
| 139 |
{ label: __('Icon Button', 'blockenberg'), value: 'icon' }, |
| 140 |
], |
| 141 |
onChange: function (v) { set({ toggleStyle: v }); } |
| 142 |
}), |
| 143 |
el(SelectControl, { |
| 144 |
label: __('Position', 'blockenberg'), |
| 145 |
value: a.position, |
| 146 |
options: [ |
| 147 |
{ label: __('Inline (in flow)', 'blockenberg'), value: 'inline' }, |
| 148 |
{ label: __('Floating (fixed corner)', 'blockenberg'), value: 'floating' }, |
| 149 |
], |
| 150 |
onChange: function (v) { set({ position: v }); } |
| 151 |
}), |
| 152 |
a.position === 'floating' ? el(SelectControl, { |
| 153 |
label: __('Corner', 'blockenberg'), |
| 154 |
value: a.floatCorner, |
| 155 |
options: [ |
| 156 |
{ label: __('Bottom Right', 'blockenberg'), value: 'bottom-right' }, |
| 157 |
{ label: __('Bottom Left', 'blockenberg'), value: 'bottom-left' }, |
| 158 |
{ label: __('Top Right', 'blockenberg'), value: 'top-right' }, |
| 159 |
{ label: __('Top Left', 'blockenberg'), value: 'top-left' }, |
| 160 |
], |
| 161 |
onChange: function (v) { set({ floatCorner: v }); } |
| 162 |
}) : null, |
| 163 |
a.position === 'floating' ? el(RangeControl, { |
| 164 |
label: __('Offset X (px)', 'blockenberg'), |
| 165 |
value: a.floatOffsetX, |
| 166 |
min: 0, max: 120, |
| 167 |
onChange: function (v) { set({ floatOffsetX: v }); } |
| 168 |
}) : null, |
| 169 |
a.position === 'floating' ? el(RangeControl, { |
| 170 |
label: __('Offset Y (px)', 'blockenberg'), |
| 171 |
value: a.floatOffsetY, |
| 172 |
min: 0, max: 120, |
| 173 |
onChange: function (v) { set({ floatOffsetY: v }); } |
| 174 |
}) : null, |
| 175 |
el(RangeControl, { |
| 176 |
label: __('Button Size (px)', 'blockenberg'), |
| 177 |
value: a.buttonSize, |
| 178 |
min: 28, max: 80, |
| 179 |
onChange: function (v) { set({ buttonSize: v }); } |
| 180 |
}), |
| 181 |
el(RangeControl, { |
| 182 |
label: __('Border Radius (px)', 'blockenberg'), |
| 183 |
value: a.borderRadius, |
| 184 |
min: 0, max: 50, |
| 185 |
onChange: function (v) { set({ borderRadius: v }); } |
| 186 |
}), |
| 187 |
el(RangeControl, { |
| 188 |
label: __('Transition Duration (ms)', 'blockenberg'), |
| 189 |
value: a.transitionDuration, |
| 190 |
min: 0, max: 1000, step: 50, |
| 191 |
onChange: function (v) { set({ transitionDuration: v }); } |
| 192 |
}), |
| 193 |
el(ToggleControl, { |
| 194 |
label: __('Show Icon', 'blockenberg'), |
| 195 |
checked: a.showIcon, |
| 196 |
onChange: function (v) { set({ showIcon: v }); }, |
| 197 |
__nextHasNoMarginBottom: true |
| 198 |
}), |
| 199 |
el(ToggleControl, { |
| 200 |
label: __('Show Label', 'blockenberg'), |
| 201 |
checked: a.showLabel, |
| 202 |
onChange: function (v) { set({ showLabel: v }); }, |
| 203 |
__nextHasNoMarginBottom: true |
| 204 |
}), |
| 205 |
el(ToggleControl, { |
| 206 |
label: __('Hover Scale', 'blockenberg'), |
| 207 |
checked: a.hoverScale, |
| 208 |
onChange: function (v) { set({ hoverScale: v }); }, |
| 209 |
__nextHasNoMarginBottom: true |
| 210 |
}), |
| 211 |
el(ToggleControl, { |
| 212 |
label: __('Drop Shadow', 'blockenberg'), |
| 213 |
checked: a.shadow, |
| 214 |
onChange: function (v) { set({ shadow: v }); }, |
| 215 |
__nextHasNoMarginBottom: true |
| 216 |
}) |
| 217 |
), |
| 218 |
|
| 219 |
/* Icons & Labels */ |
| 220 |
el(PanelBody, { title: __('Icons & Labels', 'blockenberg'), initialOpen: false }, |
| 221 |
el(TextControl, { |
| 222 |
label: __('Light Mode Icon', 'blockenberg'), |
| 223 |
value: a.lightIcon, |
| 224 |
onChange: function (v) { set({ lightIcon: v }); } |
| 225 |
}), |
| 226 |
el(TextControl, { |
| 227 |
label: __('Dark Mode Icon', 'blockenberg'), |
| 228 |
value: a.darkIcon, |
| 229 |
onChange: function (v) { set({ darkIcon: v }); } |
| 230 |
}), |
| 231 |
el(TextControl, { |
| 232 |
label: __('Light Label Text', 'blockenberg'), |
| 233 |
value: a.lightLabel, |
| 234 |
onChange: function (v) { set({ lightLabel: v }); } |
| 235 |
}), |
| 236 |
el(TextControl, { |
| 237 |
label: __('Dark Label Text', 'blockenberg'), |
| 238 |
value: a.darkLabel, |
| 239 |
onChange: function (v) { set({ darkLabel: v }); } |
| 240 |
}) |
| 241 |
), |
| 242 |
|
| 243 |
/* Behaviour */ |
| 244 |
el(PanelBody, { title: __('Behaviour', 'blockenberg'), initialOpen: false }, |
| 245 |
el(SelectControl, { |
| 246 |
label: __('Default Theme', 'blockenberg'), |
| 247 |
value: a.defaultTheme, |
| 248 |
options: [ |
| 249 |
{ label: __('Light', 'blockenberg'), value: 'light' }, |
| 250 |
{ label: __('Dark', 'blockenberg'), value: 'dark' }, |
| 251 |
], |
| 252 |
onChange: function (v) { set({ defaultTheme: v }); } |
| 253 |
}), |
| 254 |
el(ToggleControl, { |
| 255 |
label: __('Respect System Preference', 'blockenberg'), |
| 256 |
help: __('If enabled, auto-applies dark mode when the OS is in dark mode (unless user overrides).', 'blockenberg'), |
| 257 |
checked: a.respectSystemPref, |
| 258 |
onChange: function (v) { set({ respectSystemPref: v }); }, |
| 259 |
__nextHasNoMarginBottom: true |
| 260 |
}), |
| 261 |
el(TextControl, { |
| 262 |
label: __('localStorage Key', 'blockenberg'), |
| 263 |
value: a.storageKey, |
| 264 |
onChange: function (v) { set({ storageKey: v }); } |
| 265 |
}), |
| 266 |
el(TextControl, { |
| 267 |
label: __('HTML Attribute Name', 'blockenberg'), |
| 268 |
value: a.dataAttribute, |
| 269 |
onChange: function (v) { set({ dataAttribute: v }); } |
| 270 |
}), |
| 271 |
el(TextControl, { |
| 272 |
label: __('Dark Value', 'blockenberg'), |
| 273 |
value: a.darkValue, |
| 274 |
onChange: function (v) { set({ darkValue: v }); } |
| 275 |
}), |
| 276 |
el(TextControl, { |
| 277 |
label: __('Light Value', 'blockenberg'), |
| 278 |
value: a.lightValue, |
| 279 |
onChange: function (v) { set({ lightValue: v }); } |
| 280 |
}) |
| 281 |
), |
| 282 |
|
| 283 |
/* Colors */ |
| 284 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 285 |
_tc() && el(_tc(), { label: __('Label', 'blockenberg'), value: a.typoLabel, onChange: function (v) { set({ typoLabel: v }); } }) |
| 286 |
), |
| 287 |
el(PanelColorSettings, { |
| 288 |
title: __('Colors', 'blockenberg'), |
| 289 |
initialOpen: false, |
| 290 |
colorSettings: [ |
| 291 |
{ value: a.lightBg, onChange: function (v) { set({ lightBg: v || '#f3f4f6' }); }, label: __('Light Mode Background', 'blockenberg') }, |
| 292 |
{ value: a.lightColor, onChange: function (v) { set({ lightColor: v || '#111827' }); }, label: __('Light Mode Icon/Text', 'blockenberg') }, |
| 293 |
{ value: a.darkBg, onChange: function (v) { set({ darkBg: v || '#1f2937' }); }, label: __('Dark Mode Background', 'blockenberg') }, |
| 294 |
{ value: a.darkColor, onChange: function (v) { set({ darkColor: v || '#f9fafb' }); }, label: __('Dark Mode Icon/Text', 'blockenberg') }, |
| 295 |
{ value: a.switchTrackLight, onChange: function (v) { set({ switchTrackLight: v || '#d1d5db' }); }, label: __('Switch Track (Light)', 'blockenberg') }, |
| 296 |
{ value: a.switchTrackDark, onChange: function (v) { set({ switchTrackDark: v || '#4f46e5' }); }, label: __('Switch Track (Dark)', 'blockenberg') }, |
| 297 |
{ value: a.switchThumbColor, onChange: function (v) { set({ switchThumbColor: v || '#ffffff' }); }, label: __('Switch Thumb', 'blockenberg') }, |
| 298 |
] |
| 299 |
}) |
| 300 |
), |
| 301 |
|
| 302 |
/* Canvas */ |
| 303 |
el('div', blockProps, |
| 304 |
el('div', { |
| 305 |
style: { padding: '8px 0' } |
| 306 |
}, |
| 307 |
el('p', { |
| 308 |
style: { fontSize: '11px', color: '#6b7280', marginBottom: '10px', textAlign: 'center' } |
| 309 |
}, __('Preview — click to toggle', 'blockenberg')), |
| 310 |
el(TogglePreview, { |
| 311 |
attrs: a, |
| 312 |
isDark: previewDark, |
| 313 |
align: align, |
| 314 |
}), |
| 315 |
el('button', { |
| 316 |
style: { |
| 317 |
display: 'block', |
| 318 |
margin: '12px auto 0', |
| 319 |
padding: '4px 12px', |
| 320 |
fontSize: '12px', |
| 321 |
cursor: 'pointer', |
| 322 |
borderRadius: '4px', |
| 323 |
border: '1px solid #d1d5db', |
| 324 |
background: '#fff', |
| 325 |
}, |
| 326 |
onClick: function () { setPreviewDark(!previewDark); } |
| 327 |
}, __('Toggle Preview', 'blockenberg')) |
| 328 |
) |
| 329 |
) |
| 330 |
); |
| 331 |
}, |
| 332 |
|
| 333 |
save: function (props) { |
| 334 |
var a = props.attributes; |
| 335 |
var blockProps = wp.blockEditor.useBlockProps.save({ |
| 336 |
className: 'bkdm-wrap', |
| 337 |
style: Object.assign( |
| 338 |
{ '--bkdm-lbl-fs': (a.labelFontSize || 14) + 'px' }, |
| 339 |
_tv(a.typoLabel || {}, '--bkdm-lbl-') |
| 340 |
) |
| 341 |
}); |
| 342 |
|
| 343 |
return el('div', Object.assign({}, blockProps, { |
| 344 |
'data-toggle-style': a.toggleStyle, |
| 345 |
'data-position': a.position, |
| 346 |
'data-float-corner': a.floatCorner, |
| 347 |
'data-float-x': a.floatOffsetX, |
| 348 |
'data-float-y': a.floatOffsetY, |
| 349 |
'data-storage-key': a.storageKey, |
| 350 |
'data-attr': a.dataAttribute, |
| 351 |
'data-dark-val': a.darkValue, |
| 352 |
'data-light-val': a.lightValue, |
| 353 |
'data-default': a.defaultTheme, |
| 354 |
'data-respect-system': String(a.respectSystemPref), |
| 355 |
'data-button-size': a.buttonSize, |
| 356 |
'data-border-radius': a.borderRadius, |
| 357 |
'data-duration': a.transitionDuration, |
| 358 |
'data-show-icon': String(a.showIcon), |
| 359 |
'data-show-label': String(a.showLabel), |
| 360 |
'data-light-icon': a.lightIcon, |
| 361 |
'data-dark-icon': a.darkIcon, |
| 362 |
'data-light-label': a.lightLabel, |
| 363 |
'data-dark-label': a.darkLabel, |
| 364 |
'data-hover-scale': String(a.hoverScale), |
| 365 |
'data-shadow': String(a.shadow), |
| 366 |
'data-light-bg': a.lightBg, |
| 367 |
'data-light-color': a.lightColor, |
| 368 |
'data-dark-bg': a.darkBg, |
| 369 |
'data-dark-color': a.darkColor, |
| 370 |
'data-track-light': a.switchTrackLight, |
| 371 |
'data-track-dark': a.switchTrackDark, |
| 372 |
'data-thumb': a.switchThumbColor, |
| 373 |
}), |
| 374 |
el('button', { |
| 375 |
className: 'bkdm-btn', |
| 376 |
'aria-label': 'Toggle dark mode', |
| 377 |
'aria-pressed': 'false', |
| 378 |
type: 'button', |
| 379 |
}) |
| 380 |
); |
| 381 |
} |
| 382 |
}); |
| 383 |
}() ); |
| 384 |
|