| 1 |
( function () { |
| 2 |
const el = window.wp.element.createElement; |
| 3 |
const { registerBlockType } = window.wp.blocks; |
| 4 |
const { InspectorControls, useBlockProps, MediaUpload, PanelColorSettings } = window.wp.blockEditor; |
| 5 |
const { PanelBody, RangeControl, SelectControl, ToggleControl, TextControl, Button } = window.wp.components; |
| 6 |
const { useState } = window.wp.element; |
| 7 |
const { __ } = window.wp.i18n; |
| 8 |
|
| 9 |
var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 10 |
var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 11 |
|
| 12 |
const STYLES = [ |
| 13 |
{ label: 'Light', value: 'light' }, |
| 14 |
{ label: 'Dark', value: 'dark' }, |
| 15 |
{ label: 'Glass', value: 'glass' }, |
| 16 |
{ label: 'Gradient', value: 'gradient' }, |
| 17 |
]; |
| 18 |
|
| 19 |
function wrapStyle(a) { |
| 20 |
var _tvf = getTypoCssVars(); |
| 21 |
var s = { |
| 22 |
'--bkbg-sth-bg': a.bgColor, |
| 23 |
'--bkbg-sth-text': a.textColor, |
| 24 |
'--bkbg-sth-link': a.linkColor, |
| 25 |
'--bkbg-sth-link-hover': a.linkHoverColor, |
| 26 |
'--bkbg-sth-accent': a.accentColor, |
| 27 |
'--bkbg-sth-cta-bg': a.ctaBg, |
| 28 |
'--bkbg-sth-cta-text': a.ctaTextColor, |
| 29 |
'--bkbg-sth-border': a.borderColor, |
| 30 |
'--bkbg-sth-max-w': a.maxWidth + 'px', |
| 31 |
'--bkbg-sth-h': a.height + 'px', |
| 32 |
'--bkbg-sth-h-shrunk': a.heightShrunk + 'px', |
| 33 |
'--bkbg-sth-logo-sz': a.logoSize + 'px', |
| 34 |
'--bkbg-sth-logo-w': a.logoWeight, |
| 35 |
'--bkbg-sth-logo-lh': a.logoLineHeight, |
| 36 |
'--bkbg-sth-link-sz': a.linkSize + 'px', |
| 37 |
'--bkbg-sth-link-w': a.linkWeight, |
| 38 |
'--bkbg-sth-link-gap': a.linkGap + 'px', |
| 39 |
'--bkbg-sth-link-lh': a.linkLineHeight, |
| 40 |
'--bkbg-sth-cta-sz': a.ctaSize + 'px', |
| 41 |
'--bkbg-sth-cta-w': a.ctaWeight, |
| 42 |
'--bkbg-sth-cta-r': a.ctaRadius + 'px', |
| 43 |
}; |
| 44 |
Object.assign(s, _tvf(a.logoTypo, '--bksth-lg-')); |
| 45 |
Object.assign(s, _tvf(a.linkTypo, '--bksth-lk-')); |
| 46 |
Object.assign(s, _tvf(a.ctaTypo, '--bksth-ct-')); |
| 47 |
return s; |
| 48 |
} |
| 49 |
|
| 50 |
registerBlockType('blockenberg/sticky-header', { |
| 51 |
edit: function (props) { |
| 52 |
const { attributes: a, setAttributes } = props; |
| 53 |
const [editingLink, setEditingLink] = useState(null); |
| 54 |
|
| 55 |
function updateLink(i, key, val) { |
| 56 |
const next = a.navLinks.slice(); |
| 57 |
next[i] = Object.assign({}, next[i], { [key]: val }); |
| 58 |
setAttributes({ navLinks: next }); |
| 59 |
} |
| 60 |
function addLink() { |
| 61 |
setAttributes({ navLinks: [...a.navLinks, { label: 'New Link', url: '#', openNew: false }] }); |
| 62 |
} |
| 63 |
function removeLink(i) { |
| 64 |
setAttributes({ navLinks: a.navLinks.filter((_, x) => x !== i) }); |
| 65 |
if (editingLink === i) setEditingLink(null); |
| 66 |
} |
| 67 |
function moveLink(i, dir) { |
| 68 |
const next = a.navLinks.slice(); |
| 69 |
const target = i + dir; |
| 70 |
if (target < 0 || target >= next.length) return; |
| 71 |
[next[i], next[target]] = [next[target], next[i]]; |
| 72 |
setAttributes({ navLinks: next }); |
| 73 |
} |
| 74 |
|
| 75 |
const classList = [ |
| 76 |
'bkbg-sth-header', |
| 77 |
'bkbg-sth-style--' + a.style, |
| 78 |
a.borderBottom ? 'bkbg-sth-border-bottom' : '', |
| 79 |
a.shadow ? 'bkbg-sth-shadow' : '', |
| 80 |
].filter(Boolean).join(' '); |
| 81 |
|
| 82 |
const blockProps = useBlockProps({ className: 'bkbg-sth-wrap', style: wrapStyle(a) }); |
| 83 |
|
| 84 |
return el('div', blockProps, |
| 85 |
el(InspectorControls, null, |
| 86 |
|
| 87 |
el(PanelBody, { title: __('Logo'), initialOpen: true }, |
| 88 |
el(ToggleControl, { label: __('Show Logo'), checked: a.showLogo, onChange: v => setAttributes({ showLogo: v }), __nextHasNoMarginBottom: true }), |
| 89 |
el(TextControl, { label: __('Logo Text (fallback)'), value: a.logoText, onChange: v => setAttributes({ logoText: v }) }), |
| 90 |
a.logoUrl |
| 91 |
? el('div', { style: { marginBottom: 8 } }, |
| 92 |
el('img', { src: a.logoUrl, style: { maxWidth: a.logoWidth + 'px', height: 'auto', display: 'block', marginBottom: 8 } }), |
| 93 |
el(Button, { isDestructive: true, isSmall: true, onClick: () => setAttributes({ logoUrl: '', logoId: 0 }) }, __('Remove Logo')), |
| 94 |
) |
| 95 |
: el(MediaUpload, { |
| 96 |
onSelect: m => setAttributes({ logoUrl: m.url, logoId: m.id }), |
| 97 |
allowedTypes: ['image'], |
| 98 |
value: a.logoId, |
| 99 |
render: ({ open }) => el(Button, { variant: 'secondary', onClick: open, style: { width: '100%', justifyContent: 'center' } }, __('Upload Logo Image')), |
| 100 |
}), |
| 101 |
el(RangeControl, { label: __('Logo Image Width (px)'), value: a.logoWidth, min: 40, max: 300, onChange: v => setAttributes({ logoWidth: v }) }), |
| 102 |
el(TextControl, { label: __('Site URL'), value: a.siteUrl, onChange: v => setAttributes({ siteUrl: v }) }), |
| 103 |
), |
| 104 |
|
| 105 |
el(PanelBody, { title: __('Navigation Links'), initialOpen: true }, |
| 106 |
a.navLinks.map((lnk, i) => |
| 107 |
el('div', { key: i, style: { border: '1px solid ' + (editingLink === i ? '#6c3fb5' : '#e2e8f0'), borderRadius: 8, marginBottom: 8, overflow: 'hidden' } }, |
| 108 |
el('div', { |
| 109 |
style: { display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', cursor: 'pointer', background: editingLink === i ? '#f5f0ff' : '#fafafa' }, |
| 110 |
onClick: () => setEditingLink(editingLink === i ? null : i), |
| 111 |
}, |
| 112 |
el('span', { style: { flex: 1, fontWeight: 600, fontSize: 13 } }, lnk.label || __('Link') + ' ' + (i + 1)), |
| 113 |
el('span', { className: 'dashicons dashicons-' + (editingLink === i ? 'arrow-up-alt2' : 'arrow-down-alt2'), style: { fontSize: 16, color: '#94a3b8' } }), |
| 114 |
), |
| 115 |
editingLink === i && el('div', { style: { padding: '0 12px 12px' } }, |
| 116 |
el(TextControl, { label: __('Label'), value: lnk.label, onChange: v => updateLink(i, 'label', v) }), |
| 117 |
el(TextControl, { label: __('URL'), value: lnk.url, onChange: v => updateLink(i, 'url', v) }), |
| 118 |
el(ToggleControl, { label: __('Open in New Tab'), checked: lnk.openNew, onChange: v => updateLink(i, 'openNew', v), __nextHasNoMarginBottom: true }), |
| 119 |
el('div', { style: { display: 'flex', gap: 6, marginTop: 8 } }, |
| 120 |
el(Button, { isSmall: true, variant: 'secondary', onClick: () => moveLink(i, -1), disabled: i === 0 }, '↑'), |
| 121 |
el(Button, { isSmall: true, variant: 'secondary', onClick: () => moveLink(i, 1), disabled: i === a.navLinks.length - 1 }, '↓'), |
| 122 |
el(Button, { isSmall: true, isDestructive: true, onClick: () => removeLink(i) }, __('Remove')), |
| 123 |
), |
| 124 |
), |
| 125 |
) |
| 126 |
), |
| 127 |
el(Button, { variant: 'secondary', onClick: addLink, style: { width: '100%', justifyContent: 'center', marginTop: 8 } }, __('+ Add Link')), |
| 128 |
), |
| 129 |
|
| 130 |
el(PanelBody, { title: __('CTA Button'), initialOpen: false }, |
| 131 |
el(ToggleControl, { label: __('Show CTA Button'), checked: a.showCta, onChange: v => setAttributes({ showCta: v }), __nextHasNoMarginBottom: true }), |
| 132 |
el(TextControl, { label: __('Button Text'), value: a.ctaText, onChange: v => setAttributes({ ctaText: v }) }), |
| 133 |
el(TextControl, { label: __('Button URL'), value: a.ctaUrl, onChange: v => setAttributes({ ctaUrl: v }) }), |
| 134 |
el(ToggleControl, { label: __('Open in New Tab'), checked: a.ctaOpenNew, onChange: v => setAttributes({ ctaOpenNew: v }), __nextHasNoMarginBottom: true }), |
| 135 |
), |
| 136 |
|
| 137 |
el(PanelBody, { title: __('Style & Behavior'), initialOpen: false }, |
| 138 |
el(SelectControl, { label: __('Style'), value: a.style, options: STYLES, onChange: v => setAttributes({ style: v }) }), |
| 139 |
el(ToggleControl, { label: __('Sticky on Scroll'), checked: a.sticky, onChange: v => setAttributes({ sticky: v }), __nextHasNoMarginBottom: true }), |
| 140 |
el(ToggleControl, { label: __('Shrink on Scroll'), checked: a.scrollShrink, onChange: v => setAttributes({ scrollShrink: v }), __nextHasNoMarginBottom: true }), |
| 141 |
el(ToggleControl, { label: __('Show Mobile Menu Toggle'), checked: a.showMobileMenu, onChange: v => setAttributes({ showMobileMenu: v }), __nextHasNoMarginBottom: true }), |
| 142 |
el(ToggleControl, { label: __('Border Bottom'), checked: a.borderBottom, onChange: v => setAttributes({ borderBottom: v }), __nextHasNoMarginBottom: true }), |
| 143 |
el(ToggleControl, { label: __('Drop Shadow (when scrolled)'), checked: a.shadow, onChange: v => setAttributes({ shadow: v }), __nextHasNoMarginBottom: true }), |
| 144 |
el(RangeControl, { label: __('Header Height (px)'), value: a.height, min: 40, max: 120, onChange: v => setAttributes({ height: v }) }), |
| 145 |
el(RangeControl, { label: __('Shrunk Height (px)'), value: a.heightShrunk, min: 36, max: 100, onChange: v => setAttributes({ heightShrunk: v }) }), |
| 146 |
el(RangeControl, { label: __('Max Width (px)'), value: a.maxWidth, min: 760, max: 1600, onChange: v => setAttributes({ maxWidth: v }) }), |
| 147 |
el(RangeControl, { label: __('z-index'), value: a.zIndex, min: 1, max: 9999, onChange: v => setAttributes({ zIndex: v }) }), |
| 148 |
), |
| 149 |
|
| 150 |
el(PanelBody, { title: __('Typography'), initialOpen: false }, |
| 151 |
getTypoControl() && getTypoControl()({ label: __('Logo Text'), value: a.logoTypo, onChange: function (v) { setAttributes({ logoTypo: v }); } }), |
| 152 |
getTypoControl() && getTypoControl()({ label: __('Nav Links'), value: a.linkTypo, onChange: function (v) { setAttributes({ linkTypo: v }); } }), |
| 153 |
getTypoControl() && getTypoControl()({ label: __('CTA Button'), value: a.ctaTypo, onChange: function (v) { setAttributes({ ctaTypo: v }); } }), |
| 154 |
el(RangeControl, { label: __('Nav Gap (px)'), value: a.linkGap, min: 8, max: 64, onChange: v => setAttributes({ linkGap: v }) }), |
| 155 |
el(RangeControl, { label: __('CTA Radius (px)'), value: a.ctaRadius, min: 0, max: 32, onChange: v => setAttributes({ ctaRadius: v }) }), |
| 156 |
), |
| 157 |
|
| 158 |
el(PanelColorSettings, { |
| 159 |
title: __('Colors'), initialOpen: false, |
| 160 |
colorSettings: [ |
| 161 |
{ label: __('Background'), value: a.bgColor, onChange: v => setAttributes({ bgColor: v || '#ffffff' }) }, |
| 162 |
{ label: __('Text / Logo'), value: a.textColor, onChange: v => setAttributes({ textColor: v || '#0f172a' }) }, |
| 163 |
{ label: __('Nav Links'), value: a.linkColor, onChange: v => setAttributes({ linkColor: v || '#374151' }) }, |
| 164 |
{ label: __('Link Hover'), value: a.linkHoverColor,onChange: v => setAttributes({ linkHoverColor:v || '#6c3fb5' }) }, |
| 165 |
{ label: __('Accent'), value: a.accentColor, onChange: v => setAttributes({ accentColor: v || '#6c3fb5' }) }, |
| 166 |
{ label: __('CTA BG'), value: a.ctaBg, onChange: v => setAttributes({ ctaBg: v || '#6c3fb5' }) }, |
| 167 |
{ label: __('CTA Text'), value: a.ctaTextColor, onChange: v => setAttributes({ ctaTextColor: v || '#ffffff' }) }, |
| 168 |
{ label: __('Border'), value: a.borderColor, onChange: v => setAttributes({ borderColor: v || '#e2e8f0' }) }, |
| 169 |
] |
| 170 |
}), |
| 171 |
), |
| 172 |
|
| 173 |
/* ---- Editor Canvas ---- */ |
| 174 |
el('header', { |
| 175 |
className: classList, |
| 176 |
style: { position: 'relative' }, |
| 177 |
}, |
| 178 |
el('div', { className: 'bkbg-sth-inner' }, |
| 179 |
/* Logo */ |
| 180 |
a.showLogo && el('div', { className: 'bkbg-sth-logo' }, |
| 181 |
a.logoUrl |
| 182 |
? el('img', { src: a.logoUrl, alt: a.logoText, className: 'bkbg-sth-logo-img' }) |
| 183 |
: el('span', { className: 'bkbg-sth-logo-text' }, a.logoText), |
| 184 |
), |
| 185 |
/* Nav */ |
| 186 |
el('nav', { className: 'bkbg-sth-nav' }, |
| 187 |
a.navLinks.map((lnk, i) => |
| 188 |
el('a', { key: i, className: 'bkbg-sth-nav-link', href: lnk.url, onClick: e => e.preventDefault() }, lnk.label) |
| 189 |
) |
| 190 |
), |
| 191 |
/* CTA + Hamburger */ |
| 192 |
el('div', { className: 'bkbg-sth-actions' }, |
| 193 |
a.showCta && el('a', { className: 'bkbg-sth-cta', href: a.ctaUrl, onClick: e => e.preventDefault() }, a.ctaText), |
| 194 |
a.showMobileMenu && el('button', { className: 'bkbg-sth-hamburger', 'aria-label': 'Menu' }, |
| 195 |
el('span'), el('span'), el('span'), |
| 196 |
), |
| 197 |
), |
| 198 |
), |
| 199 |
), |
| 200 |
); |
| 201 |
}, |
| 202 |
|
| 203 |
save: function ({ attributes: a }) { |
| 204 |
const classList = [ |
| 205 |
'bkbg-sth-header', |
| 206 |
'bkbg-sth-style--' + a.style, |
| 207 |
a.sticky ? 'bkbg-sth-sticky' : '', |
| 208 |
a.scrollShrink ? 'bkbg-sth-shrink' : '', |
| 209 |
a.borderBottom ? 'bkbg-sth-border-bottom' : '', |
| 210 |
a.shadow ? 'bkbg-sth-shadow' : '', |
| 211 |
].filter(Boolean).join(' '); |
| 212 |
|
| 213 |
return el('div', { |
| 214 |
className: 'bkbg-sth-wrap', |
| 215 |
style: { ...wrapStyle(a), '--bkbg-sth-z': a.zIndex }, |
| 216 |
}, |
| 217 |
el('header', { className: classList, 'data-sticky': a.sticky ? '1' : '0', 'data-shrink': a.scrollShrink ? '1' : '0' }, |
| 218 |
el('div', { className: 'bkbg-sth-inner' }, |
| 219 |
a.showLogo && el('a', { href: a.siteUrl, className: 'bkbg-sth-logo' }, |
| 220 |
a.logoUrl |
| 221 |
? el('img', { src: a.logoUrl, alt: a.logoText, className: 'bkbg-sth-logo-img', style: { width: a.logoWidth + 'px' } }) |
| 222 |
: el('span', { className: 'bkbg-sth-logo-text' }, a.logoText), |
| 223 |
), |
| 224 |
el('nav', { className: 'bkbg-sth-nav', 'aria-label': 'Main navigation' }, |
| 225 |
a.navLinks.map((lnk, i) => |
| 226 |
el('a', { key: i, className: 'bkbg-sth-nav-link', href: lnk.url, target: lnk.openNew ? '_blank' : undefined, rel: lnk.openNew ? 'noopener noreferrer' : undefined }, lnk.label) |
| 227 |
) |
| 228 |
), |
| 229 |
el('div', { className: 'bkbg-sth-actions' }, |
| 230 |
a.showCta && el('a', { className: 'bkbg-sth-cta', href: a.ctaUrl, target: a.ctaOpenNew ? '_blank' : undefined, rel: a.ctaOpenNew ? 'noopener noreferrer' : undefined }, a.ctaText), |
| 231 |
a.showMobileMenu && el('button', { className: 'bkbg-sth-hamburger', 'aria-label': __('Open menu'), 'aria-expanded': 'false', 'aria-controls': 'bkbg-sth-mobile-nav' }, |
| 232 |
el('span'), el('span'), el('span'), |
| 233 |
), |
| 234 |
), |
| 235 |
), |
| 236 |
a.showMobileMenu && el('div', { id: 'bkbg-sth-mobile-nav', className: 'bkbg-sth-mobile-nav', 'aria-hidden': 'true' }, |
| 237 |
a.navLinks.map((lnk, i) => |
| 238 |
el('a', { key: i, className: 'bkbg-sth-mobile-link', href: lnk.url, target: lnk.openNew ? '_blank' : undefined }, lnk.label) |
| 239 |
), |
| 240 |
a.showCta && el('a', { className: 'bkbg-sth-cta bkbg-sth-mobile-cta', href: a.ctaUrl }, a.ctaText), |
| 241 |
), |
| 242 |
), |
| 243 |
); |
| 244 |
} |
| 245 |
}); |
| 246 |
}() ); |
| 247 |
|