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 / kinetic-text / frontend.js

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

189 lines 8.5 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 reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
5
6 /* ── Typography CSS vars helper ──────────────────────────────── */
7 var _typoKeys = {
8 family:'font-family', weight:'font-weight', style:'font-style',
9 decoration:'text-decoration', transform:'text-transform',
10 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
11 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
12 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
13 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
14 };
15 function typoCssVarsForEl(el, obj, prefix) {
16 if (!obj || typeof obj !== 'object') return;
17 Object.keys(_typoKeys).forEach(function (k) {
18 var v = obj[k];
19 if (v === undefined || v === '' || v === null) return;
20 if (k === 'sizeDesktop' || k === 'sizeTablet' || k === 'sizeMobile') v = v + (obj.sizeUnit || 'px');
21 else if (k === 'lineHeightDesktop' || k === 'lineHeightTablet' || k === 'lineHeightMobile') v = v + (obj.lineHeightUnit || '');
22 else if (k === 'letterSpacingDesktop' || k === 'letterSpacingTablet' || k === 'letterSpacingMobile') v = v + (obj.letterSpacingUnit || 'px');
23 else if (k === 'wordSpacingDesktop' || k === 'wordSpacingTablet' || k === 'wordSpacingMobile') v = v + (obj.wordSpacingUnit || 'px');
24 el.style.setProperty(prefix + _typoKeys[k], String(v));
25 });
26 }
27
28 /* ── Scatter vector helpers ────────────────────────────────────── */
29 function randBetween(a, b) { return a + Math.random() * (b - a); }
30
31 function getScatterVector(mode, radius, index, total) {
32 switch (mode) {
33 case 'rain': {
34 var angle = randBetween(-0.4, 0.4) * Math.PI + Math.PI / 2;
35 return {
36 x: Math.cos(angle) * randBetween(radius * 0.2, radius * 0.6),
37 y: Math.sin(angle) * randBetween(radius * 0.6, radius),
38 rot: randBetween(-60, 60)
39 };
40 }
41 case 'float': {
42 return {
43 x: randBetween(-radius * 0.3, radius * 0.3),
44 y: -randBetween(radius * 0.5, radius),
45 rot: randBetween(-30, 30)
46 };
47 }
48 case 'spin': {
49 var a = (index / total) * Math.PI * 2 + randBetween(-0.5, 0.5);
50 var r = randBetween(radius * 0.5, radius);
51 return { x: Math.cos(a) * r, y: Math.sin(a) * r, rot: randBetween(-180, 180) };
52 }
53 default: { /* explode */
54 var ang = randBetween(0, Math.PI * 2);
55 var rad = randBetween(radius * 0.4, radius);
56 return { x: Math.cos(ang) * rad, y: Math.sin(ang) * rad, rot: randBetween(-90, 90) };
57 }
58 }
59 }
60
61 /* ── Build & animate one kinetic text block ──────────────────────── */
62 function initBlock(root) {
63 var app = root.querySelector('.bkbg-kt-app');
64 if (!app) return;
65
66 var raw = app.getAttribute('data-opts') || '{}';
67 var o;
68 try { o = JSON.parse(raw); } catch (e) { o = {}; }
69
70 var text = o.text || '';
71 var tag = o.tag || 'h2';
72 var trigger = o.trigger || 'hover';
73 var mode = o.scatterMode || 'explode';
74 var radius = Number(o.scatterRadius) || 120;
75 var scatterDur = Number(o.scatterDuration) || 400;
76 var returnDur = Number(o.returnDuration) || 600;
77 var stagger = Number(o.stagger) || 20;
78 var fontSize = Number(o.fontSize) || 56;
79 var fontWeight = Number(o.fontWeight) || 700;
80 var letterSpacing = Number(o.letterSpacing) || 0;
81 var textAlign = o.textAlign || 'center';
82 var textColor = o.textColor || '#0f172a';
83 var hoverColor = o.hoverColor || '#6366f1';
84 var bgColor = o.bgColor || 'transparent';
85
86 /* ── Parent wrapper ─────────────────────────────────────────── */
87 root.style.background = bgColor;
88 typoCssVarsForEl(root, o.textTypo, '--bkbg-kt-tx-');
89
90 var container = document.createElement(tag);
91 container.className = 'bkbg-kt-text';
92 container.style.cssText = [
93 'text-align:' + textAlign,
94 'justify-content:' + (textAlign === 'center' ? 'center' : textAlign === 'right' ? 'flex-end' : 'flex-start'),
95 'display:flex',
96 'flex-wrap:wrap',
97 'align-items:baseline',
98 'margin:0',
99 'user-select:none',
100 'cursor:default'
101 ].join(';');
102
103 /* ── Split into spans ──────────────────────────────────────── */
104 var chars = text.split('');
105 var spans = chars.map(function (ch) {
106 var span = document.createElement('span');
107 span.className = 'bkbg-kt-char';
108 span.textContent = ch === ' ' ? '\u00a0' : ch;
109 span.style.color = textColor;
110 container.appendChild(span);
111 return span;
112 });
113
114 app.appendChild(container);
115 if (reduced) return;
116
117 /* ── Scatter state ────────────────────────────────────────── */
118 var scattered = false;
119 var vectors = [];
120
121 function computeVectors() {
122 vectors = spans.map(function (_, i) {
123 return getScatterVector(mode, radius, i, spans.length);
124 });
125 }
126 computeVectors();
127
128 function scatter() {
129 if (scattered) return;
130 scattered = true;
131 spans.forEach(function (span, i) {
132 var v = vectors[i];
133 var del = i * stagger;
134 span.classList.add('bkbg-kt-scattered');
135 span.style.transitionDuration = scatterDur + 'ms';
136 span.style.transitionDelay = del + 'ms';
137 span.style.transform = 'translate(' + v.x + 'px,' + v.y + 'px) rotate(' + v.rot + 'deg)';
138 span.style.opacity = '0';
139 span.style.color = hoverColor;
140 });
141 }
142
143 function collect() {
144 if (!scattered) return;
145 scattered = false;
146 computeVectors();
147 spans.forEach(function (span, i) {
148 var del = (spans.length - 1 - i) * stagger * 0.5;
149 span.classList.remove('bkbg-kt-scattered');
150 span.style.transitionDuration = returnDur + 'ms';
151 span.style.transitionDelay = del + 'ms';
152 span.style.transform = 'translate(0,0) rotate(0deg)';
153 span.style.opacity = '1';
154 span.style.color = textColor;
155 });
156 }
157
158 /* ── Attach trigger ───────────────────────────────────────── */
159 if (trigger === 'hover') {
160 container.addEventListener('mouseenter', scatter);
161 container.addEventListener('mouseleave', collect);
162 } else if (trigger === 'click') {
163 container.addEventListener('click', function () {
164 scattered ? collect() : scatter();
165 });
166 } else if (trigger === 'auto') {
167 var loopTimeout;
168 function loopScatter() {
169 scatter();
170 loopTimeout = setTimeout(function () {
171 collect();
172 loopTimeout = setTimeout(loopScatter, returnDur + 800);
173 }, scatterDur + spans.length * stagger + 400);
174 }
175 loopScatter();
176 }
177 }
178
179 function init() {
180 document.querySelectorAll('.wp-block-blockenberg-kinetic-text').forEach(initBlock);
181 }
182
183 if (document.readyState === 'loading') {
184 document.addEventListener('DOMContentLoaded', init);
185 } else {
186 init();
187 }
188 })();
189