| 1 |
(function () { |
| 2 |
'use strict'; |
| 3 |
|
| 4 |
function initWordFlip(appEl) { |
| 5 |
var raw = appEl.dataset.opts; |
| 6 |
if (!raw) return; |
| 7 |
var opts; |
| 8 |
try { opts = JSON.parse(raw); } catch (e) { return; } |
| 9 |
|
| 10 |
var words = (opts.words && opts.words.length) ? opts.words : ['designers']; |
| 11 |
var mode = opts.flipMode || 'roll'; |
| 12 |
var interval = opts.interval || 2200; |
| 13 |
var speed = opts.flipSpeed || 420; |
| 14 |
|
| 15 |
// ── Build outer ─────────────────────────────────────────────── |
| 16 |
var wrap = document.createElement('div'); |
| 17 |
wrap.className = 'bkbg-wf-wrap'; |
| 18 |
wrap.style.padding = (opts.paddingV || 32) + 'px ' + (opts.paddingH || 24) + 'px'; |
| 19 |
wrap.style.backgroundColor = opts.showBg ? (opts.bgColor || '#fff') : ''; |
| 20 |
wrap.style.borderRadius = (opts.borderRadius || 0) + 'px'; |
| 21 |
wrap.style.textAlign = opts.textAlign || 'center'; |
| 22 |
|
| 23 |
var heading = document.createElement(opts.tag || 'h2'); |
| 24 |
heading.className = 'bkbg-wf-heading'; |
| 25 |
heading.style.color = opts.staticColor || '#0f172a'; |
| 26 |
|
| 27 |
if (opts.staticBefore) { |
| 28 |
var before = document.createElement('span'); |
| 29 |
before.textContent = opts.staticBefore; |
| 30 |
heading.appendChild(before); |
| 31 |
} |
| 32 |
|
| 33 |
// Slot |
| 34 |
var modeClass = { 'flip-3d': 'bkbg-wf-flip3d', 'fade-up': 'bkbg-wf-fadeup', 'zoom': 'bkbg-wf-zoom', 'roll': 'bkbg-wf-roll' }; |
| 35 |
var slot = document.createElement('span'); |
| 36 |
slot.className = 'bkbg-wf-slot ' + (modeClass[mode] || 'bkbg-wf-roll'); |
| 37 |
slot.style.setProperty('--bkbg-wf-speed', speed + 'ms'); |
| 38 |
slot.style.setProperty('--bkbg-wf-underline', opts.underlineColor || '#7c3aed'); |
| 39 |
slot.style.color = opts.flipColor || '#7c3aed'; |
| 40 |
slot.style.padding = '0 ' + (opts.flipPaddingH || 8) + 'px'; |
| 41 |
slot.style.borderRadius = (opts.flipBorderRadius || 4) + 'px'; |
| 42 |
slot.style.backgroundColor = opts.flipBg || 'transparent'; |
| 43 |
|
| 44 |
// Underline decoration |
| 45 |
var ul = opts.underlineStyle || 'none'; |
| 46 |
if (ul === 'solid') { slot.style.textDecoration = 'underline solid'; slot.style.textDecorationColor = opts.underlineColor || '#7c3aed'; slot.style.textUnderlineOffset = '4px'; } |
| 47 |
if (ul === 'wavy') { slot.classList.add('bkbg-wf-underline-wavy'); slot.style.textDecorationColor = opts.underlineColor || '#7c3aed'; } |
| 48 |
if (ul === 'dashed') { slot.style.textDecoration = 'underline dashed'; slot.style.textDecorationColor = opts.underlineColor || '#7c3aed'; slot.style.textUnderlineOffset = '4px'; } |
| 49 |
if (ul === 'highlight') { slot.classList.add('bkbg-wf-underline-highlight'); slot.style.position = 'relative'; slot.style.zIndex = '0'; } |
| 50 |
|
| 51 |
var inner = document.createElement('span'); |
| 52 |
inner.className = 'bkbg-wf-inner bkbg-wf-active'; |
| 53 |
inner.style.transition = 'transform ' + speed + 'ms cubic-bezier(0.23,1,0.32,1), opacity ' + speed + 'ms ease'; |
| 54 |
inner.textContent = words[0]; |
| 55 |
slot.appendChild(inner); |
| 56 |
|
| 57 |
heading.appendChild(slot); |
| 58 |
|
| 59 |
if (opts.staticAfter) { |
| 60 |
var after = document.createElement('span'); |
| 61 |
after.textContent = ' ' + opts.staticAfter; |
| 62 |
heading.appendChild(after); |
| 63 |
} |
| 64 |
|
| 65 |
wrap.appendChild(heading); |
| 66 |
appEl.parentNode.replaceChild(wrap, appEl); |
| 67 |
|
| 68 |
// ── Flip logic ──────────────────────────────────────────────── |
| 69 |
// Pre-compute dimensions to avoid resize flicker |
| 70 |
var idx = 0; |
| 71 |
|
| 72 |
function flipTo(nextWord) { |
| 73 |
var next = document.createElement('span'); |
| 74 |
next.className = 'bkbg-wf-inner bkbg-wf-enter'; |
| 75 |
next.style.transition = inner.style.transition; |
| 76 |
next.style.position = 'absolute'; next.style.top = '0'; next.style.left = '0'; next.style.width = '100%'; |
| 77 |
next.textContent = nextWord; |
| 78 |
slot.appendChild(next); |
| 79 |
|
| 80 |
// Current dimensions |
| 81 |
slot.style.width = inner.offsetWidth + 'px'; |
| 82 |
slot.style.height = inner.offsetHeight + 'px'; |
| 83 |
slot.style.position = 'relative'; |
| 84 |
slot.style.overflow = 'hidden'; |
| 85 |
|
| 86 |
void next.offsetWidth; // reflow |
| 87 |
// Animate current out |
| 88 |
inner.classList.remove('bkbg-wf-active'); |
| 89 |
inner.classList.add('bkbg-wf-exit'); |
| 90 |
next.classList.remove('bkbg-wf-enter'); |
| 91 |
next.classList.add('bkbg-wf-active'); |
| 92 |
next.style.position = ''; |
| 93 |
|
| 94 |
var oldInner = inner; |
| 95 |
inner = next; |
| 96 |
|
| 97 |
setTimeout(function () { |
| 98 |
oldInner.remove(); |
| 99 |
// Update slot width |
| 100 |
slot.style.width = ''; |
| 101 |
slot.style.height = ''; |
| 102 |
}, speed + 20); |
| 103 |
} |
| 104 |
|
| 105 |
setInterval(function () { |
| 106 |
idx = (idx + 1) % words.length; |
| 107 |
flipTo(words[idx]); |
| 108 |
}, interval); |
| 109 |
} |
| 110 |
|
| 111 |
document.addEventListener('DOMContentLoaded', function () { |
| 112 |
document.querySelectorAll('.bkbg-wf-app').forEach(initWordFlip); |
| 113 |
}); |
| 114 |
if (document.readyState === 'complete' || document.readyState === 'interactive') { |
| 115 |
document.querySelectorAll('.bkbg-wf-app').forEach(initWordFlip); |
| 116 |
} |
| 117 |
})(); |
| 118 |
|