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 / one-page-nav / frontend.js

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

178 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 var _typoKeys = {
5 family:'font-family', weight:'font-weight', style:'font-style',
6 transform:'text-transform', decoration:'text-decoration',
7 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
8 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
9 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
10 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
11 };
12 var _typoUnits = { size:'sizeUnit', lineHeight:'lineHeightUnit', letterSpacing:'letterSpacingUnit', wordSpacing:'wordSpacingUnit' };
13 var _typoUnitDefaults = { size:'px', lineHeight:'', letterSpacing:'px', wordSpacing:'px' };
14 function typoCssVarsForEl(el, obj, prefix) {
15 if (!obj || typeof obj !== 'object') return;
16 Object.keys(_typoKeys).forEach(function (k) {
17 var v = obj[k]; if (v === undefined || v === '') return;
18 var prop = _typoKeys[k];
19 var base = k.replace(/Desktop|Tablet|Mobile/, '');
20 var uKey = _typoUnits[base];
21 if (uKey && typeof v === 'number') v = v + (obj[uKey] || _typoUnitDefaults[base] || '');
22 el.style.setProperty(prefix + prop, v);
23 });
24 }
25
26 function initBlock(root) {
27 var optsRaw = root.getAttribute('data-opts');
28 var opts;
29 try { opts = JSON.parse(optsRaw); } catch (e) { opts = {}; }
30
31 var items = opts.items || [];
32 var position = opts.position || 'right';
33 var dotShape = opts.dotShape || 'circle';
34 var dotSize = opts.dotSize || 12;
35 var dotGap = opts.dotGap || 14;
36 var edgeOffset = opts.edgeOffset || 24;
37 var scrollOff = opts.scrollOffset || 0;
38 var showTips = opts.showTooltips !== false;
39 var animDots = opts.animateDots !== false;
40 var progLine = opts.progressLine !== false;
41 var dotColor = opts.dotColor || '#d1d5db';
42 var activeColor = opts.activeDotColor || '#6366f1';
43 var hoverColor = opts.hoverDotColor || '#a5b4fc';
44 var progColor = opts.progressLineColor || '#6366f1';
45 var tipBg = opts.tooltipBg || '#1e1b4b';
46 var tipColor = opts.tooltipColor || '#ffffff';
47
48 if (!items.length) return;
49
50 // ---- Build nav ---- //
51 var nav = document.createElement('nav');
52 nav.className = 'bkbg-opn-nav bkbg-opn-' + position;
53 if (dotShape === 'diamond') nav.classList.add('bkbg-opn-diamond');
54 if (dotShape === 'square') nav.classList.add('bkbg-opn-square');
55 nav.setAttribute('aria-label', 'Page navigation');
56 nav.style.cssText = [
57 (position === 'right' ? 'right' : 'left') + ':' + edgeOffset + 'px',
58 '--bkbg-opn-dot:' + dotColor,
59 '--bkbg-opn-active:' + activeColor,
60 '--bkbg-opn-hover:' + hoverColor
61 ].join(';');
62
63 typoCssVarsForEl(nav, opts.tooltipTypo, '--bkbg-opn-tp-');
64
65 // Progress line track
66 var track, trackFill;
67 if (progLine) {
68 track = document.createElement('div');
69 track.className = 'bkbg-opn-track';
70 trackFill = document.createElement('div');
71 trackFill.className = 'bkbg-opn-track-fill';
72 trackFill.style.background = progColor;
73 track.appendChild(trackFill);
74 nav.appendChild(track);
75 }
76
77 var dotEls = [];
78
79 items.forEach(function (item, i) {
80 var wrapper = document.createElement('div');
81 wrapper.className = 'bkbg-opn-item';
82 if (animDots) wrapper.classList.add('bkbg-opn-animate');
83 wrapper.style.padding = Math.round(dotGap / 2) + 'px 0';
84 wrapper.setAttribute('aria-label', item.label);
85 wrapper.setAttribute('role', 'button');
86 wrapper.setAttribute('tabindex', '0');
87
88 // Dot
89 var dot = document.createElement('div');
90 dot.className = 'bkbg-opn-dot';
91 dot.style.cssText = 'width:' + dotSize + 'px;height:' + dotSize + 'px;';
92 wrapper.appendChild(dot);
93
94 // Tooltip
95 if (showTips) {
96 var tip = document.createElement('div');
97 tip.className = 'bkbg-opn-tooltip';
98 tip.textContent = item.label;
99 tip.style.cssText = 'background:' + tipBg + ';color:' + tipColor + ';';
100 wrapper.appendChild(tip);
101 }
102
103 dotEls.push(wrapper);
104 nav.appendChild(wrapper);
105
106 // Click + keyboard
107 function scrollToSection() {
108 var el = document.getElementById(item.targetId);
109 if (!el) return;
110 var top = el.getBoundingClientRect().top + window.pageYOffset + scrollOff;
111 window.scrollTo({ top: top, behavior: 'smooth' });
112 }
113 wrapper.addEventListener('click', scrollToSection);
114 wrapper.addEventListener('keydown', function (e) {
115 if (e.key === 'Enter' || e.key === ' ') scrollToSection();
116 });
117 });
118
119 document.body.appendChild(nav);
120
121 // ---- Active dot tracking ---- //
122 var ticking = false;
123 var activeIndex = 0;
124
125 function findActiveIndex() {
126 var winH = window.innerHeight;
127 var scrollY = window.pageYOffset;
128 var best = 0;
129
130 items.forEach(function (item, i) {
131 var el = document.getElementById(item.targetId);
132 if (!el) return;
133 var top = el.getBoundingClientRect().top + scrollY;
134 // Activate when section top is in upper 60% of viewport
135 if (scrollY + winH * 0.4 >= top) {
136 best = i;
137 }
138 });
139 return best;
140 }
141
142 function updateNav() {
143 var idx = findActiveIndex();
144 if (idx === activeIndex && ticking === false) {
145 // no change but still update progress if first time
146 }
147 activeIndex = idx;
148
149 dotEls.forEach(function (el, i) {
150 if (i === idx) { el.classList.add('bkbg-opn-active'); }
151 else { el.classList.remove('bkbg-opn-active'); }
152 });
153
154 // Progress line: fill from first dot to active dot
155 if (trackFill && dotEls.length > 1) {
156 var pct = idx / (dotEls.length - 1) * 100;
157 trackFill.style.height = pct + '%';
158 }
159
160 ticking = false;
161 }
162
163 window.addEventListener('scroll', function () {
164 if (!ticking) {
165 requestAnimationFrame(updateNav);
166 ticking = true;
167 }
168 }, { passive: true });
169
170 // Initial call
171 updateNav();
172 }
173
174 document.querySelectorAll('.bkbg-opn-app').forEach(function (root) {
175 initBlock(root);
176 });
177 })();
178