| 1 |
(function () { |
| 2 |
var typoMap = [ |
| 3 |
['family','font-family'],['weight','font-weight'],['style','font-style'], |
| 4 |
['decoration','text-decoration'],['transform','text-transform'], |
| 5 |
['sizeDesktop','font-size-d'],['sizeTablet','font-size-t'],['sizeMobile','font-size-m'], |
| 6 |
['lineHeightDesktop','line-height-d'],['lineHeightTablet','line-height-t'],['lineHeightMobile','line-height-m'], |
| 7 |
['letterSpacingDesktop','letter-spacing-d'],['letterSpacingTablet','letter-spacing-t'],['letterSpacingMobile','letter-spacing-m'], |
| 8 |
['wordSpacingDesktop','word-spacing-d'],['wordSpacingTablet','word-spacing-t'],['wordSpacingMobile','word-spacing-m'] |
| 9 |
]; |
| 10 |
function typoCssVarsForEl(typo, prefix, el) { |
| 11 |
if (!typo || typeof typo !== 'object') return; |
| 12 |
for (var i = 0; i < typoMap.length; i++) { |
| 13 |
var v = typo[typoMap[i][0]]; |
| 14 |
if (v !== undefined && v !== '' && v !== null) el.style.setProperty(prefix + typoMap[i][1], String(v)); |
| 15 |
} |
| 16 |
} |
| 17 |
|
| 18 |
function init() { |
| 19 |
document.querySelectorAll('.bkbg-ir-app').forEach(function (appEl) { |
| 20 |
if (appEl.dataset.rendered) return; |
| 21 |
appEl.dataset.rendered = '1'; |
| 22 |
|
| 23 |
var opts; |
| 24 |
try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; } |
| 25 |
|
| 26 |
var o = Object.assign({ |
| 27 |
imageUrl: '', |
| 28 |
imageAlt: '', |
| 29 |
trigger: 'scroll', |
| 30 |
direction: 'left', |
| 31 |
revealStyle: 'sweep', |
| 32 |
aspectRatio: '16-9', |
| 33 |
borderRadius: 8, |
| 34 |
showOverlayLabel: true, |
| 35 |
overlayLabel: 'Hover to reveal', |
| 36 |
revealedLabel: '', |
| 37 |
showRevealedLabel: false, |
| 38 |
caption: '', |
| 39 |
showCaption: false, |
| 40 |
overlayOpacity: 75, |
| 41 |
animationDuration: 600, |
| 42 |
revealOnce: true, |
| 43 |
scrollThreshold: 30, |
| 44 |
overlayBg: '#1e1b4b', |
| 45 |
overlayTextColor: '#ffffff', |
| 46 |
captionColor: '#6b7280', |
| 47 |
labelSize: 18, |
| 48 |
maxWidth: 0, |
| 49 |
}, opts); |
| 50 |
|
| 51 |
if (!o.imageUrl) return; |
| 52 |
|
| 53 |
// Aspect ratio |
| 54 |
var RATIO_MAP = { |
| 55 |
'1-1': '100%', |
| 56 |
'4-3': '75%', |
| 57 |
'3-2': '66.67%', |
| 58 |
'16-9': '56.25%', |
| 59 |
'21-9': '42.86%', |
| 60 |
'9-16': '177.78%', |
| 61 |
}; |
| 62 |
|
| 63 |
// Figure |
| 64 |
var figure = document.createElement('figure'); |
| 65 |
figure.className = 'bkbg-ir-figure'; |
| 66 |
figure.style.margin = '0'; |
| 67 |
figure.style.position = 'relative'; |
| 68 |
typoCssVarsForEl(o.labelTypo, '--bkbg-ir-lb-', figure); |
| 69 |
typoCssVarsForEl(o.captionTypo, '--bkbg-ir-cp-', figure); |
| 70 |
|
| 71 |
// Container |
| 72 |
var container = document.createElement('div'); |
| 73 |
container.className = 'bkbg-ir-container trigger-' + o.trigger; |
| 74 |
container.style.position = 'relative'; |
| 75 |
container.style.overflow = 'hidden'; |
| 76 |
container.style.borderRadius = o.borderRadius + 'px'; |
| 77 |
container.style.lineHeight = '0'; |
| 78 |
if (o.maxWidth > 0) { |
| 79 |
container.style.maxWidth = o.maxWidth + 'px'; |
| 80 |
container.style.margin = '0 auto'; |
| 81 |
} |
| 82 |
|
| 83 |
if (o.aspectRatio !== 'auto' && RATIO_MAP[o.aspectRatio]) { |
| 84 |
container.classList.add('is-fixed-ratio'); |
| 85 |
container.style.paddingTop = RATIO_MAP[o.aspectRatio]; |
| 86 |
container.style.height = '0'; |
| 87 |
} else { |
| 88 |
container.classList.add('is-auto-ratio'); |
| 89 |
} |
| 90 |
|
| 91 |
// Image |
| 92 |
var img = document.createElement('img'); |
| 93 |
img.src = o.imageUrl; |
| 94 |
img.alt = o.imageAlt; |
| 95 |
img.className = 'bkbg-ir-img style-' + o.revealStyle; |
| 96 |
img.style.width = '100%'; |
| 97 |
img.style.height = '100%'; |
| 98 |
img.style.display = 'block'; |
| 99 |
img.style.objectFit = 'cover'; |
| 100 |
img.style.transitionDuration = o.animationDuration + 'ms'; |
| 101 |
if (o.aspectRatio !== 'auto') { |
| 102 |
img.style.position = 'absolute'; |
| 103 |
img.style.top = '0'; |
| 104 |
img.style.left = '0'; |
| 105 |
} |
| 106 |
|
| 107 |
// Overlay |
| 108 |
var overlay = document.createElement('div'); |
| 109 |
overlay.className = 'bkbg-ir-overlay style-' + o.revealStyle; |
| 110 |
overlay.style.position = 'absolute'; |
| 111 |
overlay.style.inset = '0'; |
| 112 |
overlay.style.background = o.overlayBg; |
| 113 |
overlay.style.opacity = String(o.overlayOpacity / 100); |
| 114 |
overlay.style.display = 'flex'; |
| 115 |
overlay.style.alignItems = 'center'; |
| 116 |
overlay.style.justifyContent = 'center'; |
| 117 |
overlay.style.transitionDuration = o.animationDuration + 'ms'; |
| 118 |
|
| 119 |
if (o.revealStyle === 'sweep') { |
| 120 |
overlay.classList.add('dir-' + o.direction); |
| 121 |
} |
| 122 |
|
| 123 |
if (o.showOverlayLabel && o.overlayLabel) { |
| 124 |
var labelEl = document.createElement('div'); |
| 125 |
labelEl.className = 'bkbg-ir-overlay-label'; |
| 126 |
labelEl.textContent = o.overlayLabel; |
| 127 |
labelEl.style.color = o.overlayTextColor; |
| 128 |
labelEl.style.pointerEvents = 'none'; |
| 129 |
overlay.appendChild(labelEl); |
| 130 |
} |
| 131 |
|
| 132 |
// Revealed label |
| 133 |
var revealedLabelEl = null; |
| 134 |
if (o.showRevealedLabel && o.revealedLabel) { |
| 135 |
revealedLabelEl = document.createElement('div'); |
| 136 |
revealedLabelEl.className = 'bkbg-ir-revealed-label'; |
| 137 |
revealedLabelEl.textContent = o.revealedLabel; |
| 138 |
revealedLabelEl.style.color = o.overlayTextColor; |
| 139 |
revealedLabelEl.style.fontSize = o.labelSize + 'px'; |
| 140 |
revealedLabelEl.style.fontWeight = '600'; |
| 141 |
revealedLabelEl.style.position = 'absolute'; |
| 142 |
revealedLabelEl.style.bottom = '12px'; |
| 143 |
revealedLabelEl.style.left = '12px'; |
| 144 |
revealedLabelEl.style.right = '12px'; |
| 145 |
revealedLabelEl.style.textAlign = 'center'; |
| 146 |
revealedLabelEl.style.opacity = '0'; |
| 147 |
revealedLabelEl.style.transition = 'opacity 0.3s ease 0.3s'; |
| 148 |
revealedLabelEl.style.pointerEvents = 'none'; |
| 149 |
// Add semi-transparent background for readability |
| 150 |
revealedLabelEl.style.background = 'rgba(0,0,0,0.4)'; |
| 151 |
revealedLabelEl.style.borderRadius = '4px'; |
| 152 |
revealedLabelEl.style.padding = '6px 10px'; |
| 153 |
} |
| 154 |
|
| 155 |
container.appendChild(img); |
| 156 |
container.appendChild(overlay); |
| 157 |
if (revealedLabelEl) container.appendChild(revealedLabelEl); |
| 158 |
figure.appendChild(container); |
| 159 |
|
| 160 |
// Caption |
| 161 |
if (o.showCaption && o.caption) { |
| 162 |
var cap = document.createElement('figcaption'); |
| 163 |
cap.className = 'bkbg-ir-caption'; |
| 164 |
cap.textContent = o.caption; |
| 165 |
cap.style.color = o.captionColor; |
| 166 |
figure.appendChild(cap); |
| 167 |
} |
| 168 |
|
| 169 |
// Reveal function |
| 170 |
var revealed = false; |
| 171 |
function reveal() { |
| 172 |
if (revealed && o.revealOnce) return; |
| 173 |
revealed = true; |
| 174 |
container.classList.add('is-revealed'); |
| 175 |
if (revealedLabelEl) revealedLabelEl.style.opacity = '1'; |
| 176 |
} |
| 177 |
function unreveal() { |
| 178 |
if (o.revealOnce) return; |
| 179 |
revealed = false; |
| 180 |
container.classList.remove('is-revealed'); |
| 181 |
if (revealedLabelEl) revealedLabelEl.style.opacity = '0'; |
| 182 |
} |
| 183 |
|
| 184 |
// Trigger |
| 185 |
if (o.trigger === 'hover') { |
| 186 |
container.style.cursor = 'default'; |
| 187 |
container.addEventListener('mouseenter', reveal); |
| 188 |
container.addEventListener('mouseleave', unreveal); |
| 189 |
} else if (o.trigger === 'click') { |
| 190 |
container.style.cursor = 'pointer'; |
| 191 |
container.addEventListener('click', function () { |
| 192 |
if (revealed) { unreveal(); } else { reveal(); } |
| 193 |
}); |
| 194 |
} else { |
| 195 |
// Scroll — IntersectionObserver |
| 196 |
var threshold = Math.max(0.05, Math.min(0.95, o.scrollThreshold / 100)); |
| 197 |
if ('IntersectionObserver' in window) { |
| 198 |
var io = new IntersectionObserver(function (entries) { |
| 199 |
entries.forEach(function (entry) { |
| 200 |
if (entry.isIntersecting) { |
| 201 |
reveal(); |
| 202 |
if (o.revealOnce) io.unobserve(container); |
| 203 |
} else { |
| 204 |
unreveal(); |
| 205 |
} |
| 206 |
}); |
| 207 |
}, { threshold: threshold }); |
| 208 |
io.observe(container); |
| 209 |
} else { |
| 210 |
// Fallback: reveal immediately |
| 211 |
reveal(); |
| 212 |
} |
| 213 |
} |
| 214 |
|
| 215 |
appEl.parentNode.insertBefore(figure, appEl); |
| 216 |
appEl.style.display = 'none'; |
| 217 |
}); |
| 218 |
} |
| 219 |
|
| 220 |
if (document.readyState !== 'loading') { |
| 221 |
init(); |
| 222 |
} else { |
| 223 |
document.addEventListener('DOMContentLoaded', init); |
| 224 |
} |
| 225 |
})(); |
| 226 |
|