PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / scrollytelling / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/scrollytelling/frontend.js

235 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 /* ── typography CSS-var helper ──────────────────────────── */
3 var _typoKeys = {
4 family:'font-family', weight:'font-weight', style:'font-style',
5 decoration:'text-decoration', transform:'text-transform',
6 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
7 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
8 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
9 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
10 };
11 function typoCssVarsForEl(el, obj, prefix) {
12 if (!obj || typeof obj !== 'object') return;
13 Object.keys(_typoKeys).forEach(function (k) {
14 var v = obj[k];
15 if (v === undefined || v === '' || v === null) return;
16 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
17 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
18 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
19 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
20 el.style.setProperty(prefix + _typoKeys[k], String(v));
21 });
22 }
23
24 function init() {
25 document.querySelectorAll('.bkbg-sty-app').forEach(function (appEl) {
26 if (appEl.dataset.rendered) return;
27 appEl.dataset.rendered = '1';
28 var opts;
29 try { opts = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { opts = {}; }
30 var o = Object.assign({
31 chapters: [], defaultBgUrl: '',
32 stickyHeight: '70vh', textPosition: 'left',
33 showProgress: true, transitionStyle: 'fade', panelWidth: 420,
34 eyebrowColor: '#a5b4fc', titleColor: '#ffffff', textColor: '#e5e7eb',
35 textBg: '', progressColor: '#6366f1', accentColor: '#6366f1',
36 paddingTop: 0, paddingBottom: 0
37 }, opts);
38
39 var chapters = o.chapters || [];
40 if (!chapters.length) { appEl.style.display = 'none'; return; }
41
42 function mk(tag, cls, style) {
43 var n = document.createElement(tag);
44 if (cls) n.className = cls;
45 if (style) Object.assign(n.style, style);
46 return n;
47 }
48
49 /* Section wrapper */
50 var section = mk('div', 'bkbg-sty-section', {
51 paddingTop: o.paddingTop + 'px',
52 paddingBottom: o.paddingBottom + 'px'
53 });
54
55 typoCssVarsForEl(section, o.titleTypo, '--bksty-tt-');
56 typoCssVarsForEl(section, o.eyebrowTypo, '--bksty-et-');
57 typoCssVarsForEl(section, o.bodyTypo, '--bksty-bt-');
58
59 /* Sticky background */
60 var sticky = mk('div', 'bkbg-sty-sticky', { height: o.stickyHeight });
61
62 /* Two bg layers for crossfade */
63 var bgA = mk('div', 'bkbg-sty-bg-layer');
64 var bgB = mk('div', 'bkbg-sty-bg-layer');
65 var overlay = mk('div', 'bkbg-sty-overlay');
66
67 var firstBg = chapters[0].imageUrl || o.defaultBgUrl;
68 if (firstBg) {
69 bgA.style.backgroundImage = 'url(' + firstBg + ')';
70 bgA.style.opacity = '1';
71 }
72 bgB.style.opacity = '0';
73
74 sticky.appendChild(bgA);
75 sticky.appendChild(bgB);
76 sticky.appendChild(overlay);
77 section.appendChild(sticky);
78
79 /* Text panels */
80 var panelsWrap = mk('div', 'bkbg-sty-panels');
81 /* Pull panels UP to overlap sticky (sticky is pos:sticky so panels scroll over it) */
82 panelsWrap.style.marginTop = '-' + o.stickyHeight;
83
84 var panelEls = [];
85
86 chapters.forEach(function (ch) {
87 var panel = mk('div', 'bkbg-sty-panel sty-pos-' + o.textPosition, {
88 minHeight: o.stickyHeight,
89 padding: '0 48px'
90 });
91
92 var inner = mk('div', 'bkbg-sty-panel-inner', {
93 width: o.panelWidth + 'px',
94 background: o.textBg || 'rgba(0,0,0,0.45)',
95 color: o.textColor
96 });
97
98 if (ch.eyebrow) {
99 var ew = mk('span', 'bkbg-sty-eyebrow', { color: o.eyebrowColor });
100 ew.textContent = ch.eyebrow;
101 inner.appendChild(ew);
102 }
103
104 var titleEl = mk('h2', 'bkbg-sty-title', { color: o.titleColor });
105 titleEl.innerHTML = ch.title || '';
106 inner.appendChild(titleEl);
107
108 if (ch.text) {
109 var textEl = mk('p', 'bkbg-sty-text', { color: o.textColor });
110 textEl.innerHTML = ch.text;
111 inner.appendChild(textEl);
112 }
113
114 panel.appendChild(inner);
115 panelsWrap.appendChild(panel);
116 panelEls.push(panel);
117 });
118
119 section.appendChild(panelsWrap);
120
121 /* Progress indicator */
122 var progressEl = null;
123 var progressDots = [];
124 if (o.showProgress) {
125 progressEl = mk('div', 'bkbg-sty-progress');
126 chapters.forEach(function (_, i) {
127 var dot = mk('div', 'bkbg-sty-progress-dot' + (i === 0 ? ' active' : ''), {
128 background: i === 0 ? o.progressColor : 'rgba(255,255,255,0.4)',
129 border: '2px solid ' + o.progressColor
130 });
131 dot.title = chapters[i].title || '';
132 dot.dataset.index = i;
133 dot.addEventListener('click', function () {
134 panelEls[i].scrollIntoView({ behavior: 'smooth', block: 'center' });
135 });
136 progressEl.appendChild(dot);
137 progressDots.push(dot);
138 });
139 section.appendChild(progressEl);
140 }
141
142 /* IntersectionObserver for chapter changes */
143 var activeBgUrl = firstBg;
144 var activeLayer = bgA; /* currently shown */
145 var hiddenLayer = bgB;
146 var activeIndex = -1;
147
148 function setActiveChapter(idx) {
149 if (idx === activeIndex) return;
150 activeIndex = idx;
151 var ch = chapters[idx];
152
153 /* swap overlay */
154 var opacity = (ch.overlayOpacity || 0) / 100;
155 overlay.style.background = ch.overlayColor
156 ? 'rgba(' + hexToRgb(ch.overlayColor) + ',' + opacity + ')'
157 : 'rgba(0,0,0,' + opacity + ')';
158
159 /* bg transition */
160 var newUrl = ch.imageUrl || o.defaultBgUrl;
161 if (newUrl !== activeBgUrl) {
162 hiddenLayer.style.backgroundImage = 'url(' + newUrl + ')';
163
164 if (o.transitionStyle === 'slide') {
165 hiddenLayer.style.transform = 'translateX(100%)';
166 hiddenLayer.style.opacity = '1';
167 hiddenLayer.style.transition = 'transform 0.6s ease, opacity 0.1s';
168 activeLayer.style.transition = 'transform 0.6s ease';
169 requestAnimationFrame(function () {
170 hiddenLayer.style.transform = 'translateX(0)';
171 activeLayer.style.transform = 'translateX(-100%)';
172 });
173 } else {
174 hiddenLayer.style.opacity = '0';
175 hiddenLayer.style.transition = 'opacity 0.6s ease';
176 activeLayer.style.transition = 'opacity 0.6s ease';
177 requestAnimationFrame(function () {
178 hiddenLayer.style.opacity = '1';
179 activeLayer.style.opacity = '0';
180 });
181 }
182
183 /* swap references */
184 var tmp = activeLayer; activeLayer = hiddenLayer; hiddenLayer = tmp;
185 activeBgUrl = newUrl;
186
187 /* reset hidden layer after transition */
188 setTimeout(function () {
189 hiddenLayer.style.transform = '';
190 hiddenLayer.style.transition = '';
191 }, 700);
192 }
193
194 /* progress dots */
195 if (progressDots.length) {
196 progressDots.forEach(function (d, i) {
197 d.classList.toggle('active', i === idx);
198 d.style.background = i === idx ? o.progressColor : 'rgba(255,255,255,0.4)';
199 });
200 }
201 }
202
203 /* helper: hex to rgb */
204 function hexToRgb(hex) {
205 var r = parseInt(hex.slice(1, 3), 16);
206 var g = parseInt(hex.slice(3, 5), 16);
207 var b = parseInt(hex.slice(5, 7), 16);
208 return r + ',' + g + ',' + b;
209 }
210
211 var obs = new IntersectionObserver(function (entries) {
212 entries.forEach(function (entry) {
213 if (entry.isIntersecting) {
214 var idx = panelEls.indexOf(entry.target);
215 if (idx > -1) setActiveChapter(idx);
216 }
217 });
218 /* show progress when section is in view */
219 if (progressEl) {
220 var anyVisible = entries.some(function (e) { return e.isIntersecting; });
221 if (anyVisible) progressEl.classList.add('visible');
222 }
223 }, { threshold: 0.4 });
224
225 panelEls.forEach(function (p) { obs.observe(p); });
226 if (activeIndex === -1 && panelEls.length) setActiveChapter(0);
227
228 appEl.parentNode.insertBefore(section, appEl);
229 });
230 }
231
232 if (document.readyState !== 'loading') { init(); }
233 else { document.addEventListener('DOMContentLoaded', init); }
234 })();
235