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 / color-mixer / frontend.js

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

406 lines 16.3 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 /* ── Typography CSS-var helper ── */
5 var _typoKeys = {
6 family:'font-family', weight:'font-weight', style:'font-style',
7 transform:'text-transform', decoration:'text-decoration',
8 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
9 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
10 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
11 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
12 };
13 var _typoUnits = { size:'sizeUnit', lineHeight:'lineHeightUnit', letterSpacing:'letterSpacingUnit', wordSpacing:'wordSpacingUnit' };
14 var _typoUnitDefaults = { size:'px', lineHeight:'', letterSpacing:'px', wordSpacing:'px' };
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]; if (v === undefined || v === '') return;
19 var prop = _typoKeys[k];
20 var base = k.replace(/Desktop|Tablet|Mobile/, '');
21 var uKey = _typoUnits[base];
22 if (uKey && typeof v === 'number') v = v + (obj[uKey] || _typoUnitDefaults[base] || '');
23 el.style.setProperty(prefix + prop, v);
24 });
25 }
26
27 /* ---- Color utilities ---- */
28 function hexToRgb(hex) {
29 var c = (hex || '#000000').replace('#', '');
30 return [parseInt(c.slice(0,2),16), parseInt(c.slice(2,4),16), parseInt(c.slice(4,6),16)];
31 }
32
33 function rgbToHex(r, g, b) {
34 function h(x) { return Math.round(Math.min(255, Math.max(0, x))).toString(16).padStart(2,'0'); }
35 return '#' + h(r) + h(g) + h(b);
36 }
37
38 function mixColors(hexA, hexB, t) {
39 var a = hexToRgb(hexA), bv = hexToRgb(hexB);
40 return rgbToHex(a[0]+(bv[0]-a[0])*t, a[1]+(bv[1]-a[1])*t, a[2]+(bv[2]-a[2])*t);
41 }
42
43 function rgbToHsl(r, g, b) {
44 r /= 255; g /= 255; b /= 255;
45 var max = Math.max(r,g,b), min = Math.min(r,g,b);
46 var h, s, l = (max+min)/2;
47 if (max === min) { h = s = 0; }
48 else {
49 var d = max - min;
50 s = l > 0.5 ? d/(2-max-min) : d/(max+min);
51 switch(max) {
52 case r: h = (g-b)/d + (g<b?6:0); break;
53 case g: h = (b-r)/d + 2; break;
54 default: h = (r-g)/d + 4;
55 }
56 h /= 6;
57 }
58 return [Math.round(h*360), Math.round(s*100), Math.round(l*100)];
59 }
60
61 function hslToRgb(h, s, l) {
62 h /= 360; s /= 100; l /= 100;
63 var r, g, b;
64 if (s === 0) { r = g = b = l; }
65 else {
66 function hue2rgb(p, q, t) {
67 if (t<0) t+=1; if (t>1) t-=1;
68 if (t<1/6) return p+(q-p)*6*t;
69 if (t<1/2) return q;
70 if (t<2/3) return p+(q-p)*(2/3-t)*6;
71 return p;
72 }
73 var q = l<0.5 ? l*(1+s) : l+s-l*s, p = 2*l-q;
74 r = hue2rgb(p,q,h+1/3); g = hue2rgb(p,q,h); b = hue2rgb(p,q,h-1/3);
75 }
76 return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
77 }
78
79 function hslHex(h, s, l) {
80 var rgb = hslToRgb(h, s, l);
81 return rgbToHex(rgb[0], rgb[1], rgb[2]);
82 }
83
84 function hexToHsl(hex) {
85 var rgb = hexToRgb(hex);
86 return rgbToHsl(rgb[0], rgb[1], rgb[2]);
87 }
88
89 function luminance(hex) {
90 var rgb = hexToRgb(hex);
91 return 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2];
92 }
93 function textOn(hex) { return luminance(hex) > 140 ? '#111827' : '#f9fafb'; }
94
95 function getHarmonies(hex) {
96 var hsl = hexToHsl(hex);
97 var h = hsl[0], s = hsl[1], l = hsl[2];
98 return {
99 complementary: [hslHex((h+180)%360, s, l)],
100 analogous: [hslHex((h+30)%360, s, l), hslHex((h+330)%360, s, l)],
101 triadic: [hslHex((h+120)%360, s, l), hslHex((h+240)%360, s, l)],
102 split: [hslHex((h+150)%360, s, l), hslHex((h+210)%360, s, l)]
103 };
104 }
105
106 function copyText(text, el) {
107 navigator.clipboard && navigator.clipboard.writeText(text).catch(function () {
108 var t = document.createElement('textarea');
109 t.value = text; document.body.appendChild(t); t.select();
110 document.execCommand('copy'); document.body.removeChild(t);
111 });
112 var orig = el.querySelector('.bkbg-cm-format-val');
113 if (orig) { var ov = orig.textContent; orig.textContent = 'Copied!'; setTimeout(function(){ orig.textContent = ov; }, 1500); }
114 }
115
116 function formatRgb(hex) {
117 var c = hexToRgb(hex);
118 return 'rgb(' + c[0] + ', ' + c[1] + ', ' + c[2] + ')';
119 }
120
121 function formatHsl(hex) {
122 var c = hexToHsl(hex);
123 return 'hsl(' + c[0] + ', ' + c[1] + '%, ' + c[2] + '%)';
124 }
125
126 function initBlock(root) {
127 var opts;
128 try { opts = JSON.parse(root.getAttribute('data-opts')); } catch (e) { return; }
129
130 var a = opts;
131 var colorA = a.colorA || '#6366f1';
132 var colorB = a.colorB || '#ec4899';
133 var ratio = (parseInt(a.defaultRatio) || 50) / 100;
134
135 root.innerHTML = '';
136
137 var wrap = document.createElement('div');
138 wrap.className = 'bkbg-cm-wrap';
139 wrap.style.cssText = 'background:' + a.sectionBg + ';max-width:' + a.contentMaxWidth + 'px;margin:0 auto;';
140 root.appendChild(wrap);
141
142 typoCssVarsForEl(wrap, a.typoTitle, '--bkbg-cm-tt-');
143 typoCssVarsForEl(wrap, a.typoSubtitle, '--bkbg-cm-st-');
144
145 if (a.showTitle) {
146 var h = document.createElement('div');
147 h.className = 'bkbg-cm-title';
148 h.style.color = a.titleColor;
149 h.textContent = a.title;
150 wrap.appendChild(h);
151 }
152
153 if (a.showSubtitle) {
154 var s = document.createElement('div');
155 s.className = 'bkbg-cm-subtitle';
156 s.style.color = a.subtitleColor;
157 s.textContent = a.subtitle;
158 wrap.appendChild(s);
159 }
160
161 /* -- Pickers card -- */
162 var pickCard = document.createElement('div');
163 pickCard.className = 'bkbg-cm-card';
164 pickCard.style.background = a.cardBg;
165 var pickersRow = document.createElement('div');
166 pickersRow.className = 'bkbg-cm-pickers';
167 pickCard.appendChild(pickersRow);
168 wrap.appendChild(pickCard);
169
170 function makePickerCol(colorRef, label, onChange) {
171 var col = document.createElement('div');
172 col.className = 'bkbg-cm-picker-col';
173
174 var swatchWrap = document.createElement('div');
175 swatchWrap.className = 'bkbg-cm-swatch';
176 swatchWrap.style.background = colorRef;
177
178 var colorInp = document.createElement('input');
179 colorInp.type = 'color';
180 colorInp.value = colorRef;
181 colorInp.addEventListener('input', function () {
182 swatchWrap.style.background = colorInp.value;
183 hexDisplay.textContent = colorInp.value.toUpperCase();
184 onChange(colorInp.value);
185 renderAll();
186 });
187 swatchWrap.appendChild(colorInp);
188 col.appendChild(swatchWrap);
189
190 var hexDisplay = document.createElement('code');
191 hexDisplay.style.cssText = 'font-size:13px;color:' + a.labelColor + ';';
192 hexDisplay.textContent = colorRef.toUpperCase();
193 col.appendChild(hexDisplay);
194
195 var lbl = document.createElement('div');
196 lbl.className = 'bkbg-cm-swatch-label';
197 lbl.style.color = a.subtitleColor;
198 lbl.textContent = label;
199 col.appendChild(lbl);
200
201 return col;
202 }
203
204 var colA = makePickerCol(colorA, 'Color A', function (v) { colorA = v; });
205 var plusDiv = document.createElement('div');
206 plusDiv.className = 'bkbg-cm-plus';
207 plusDiv.style.color = a.labelColor;
208 plusDiv.textContent = '+';
209 var colB = makePickerCol(colorB, 'Color B', function (v) { colorB = v; });
210 [colA, plusDiv, colB].forEach(function (el) { pickersRow.appendChild(el); });
211
212 /* -- Mix card -- */
213 var mixCard = document.createElement('div');
214 mixCard.className = 'bkbg-cm-card';
215 mixCard.style.background = a.cardBg;
216 wrap.appendChild(mixCard);
217
218 var ratioRow = document.createElement('div');
219 ratioRow.className = 'bkbg-cm-ratio-row';
220 var ratioLabelA = document.createElement('span');
221 ratioLabelA.style.color = a.labelColor;
222 var ratioTitle = document.createElement('span');
223 ratioTitle.style.cssText = 'font-weight:600;color:' + a.labelColor + ';';
224 ratioTitle.textContent = 'Mix Ratio';
225 var ratioLabelB = document.createElement('span');
226 ratioLabelB.style.color = a.labelColor;
227 [ratioLabelA, ratioTitle, ratioLabelB].forEach(function (el) { ratioRow.appendChild(el); });
228 mixCard.appendChild(ratioRow);
229
230 var slider = document.createElement('input');
231 slider.type = 'range';
232 slider.min = 0; slider.max = 100; slider.value = Math.round(ratio * 100);
233 slider.className = 'bkbg-cm-slider';
234 slider.addEventListener('input', function () {
235 ratio = parseInt(slider.value) / 100;
236 renderAll();
237 });
238 mixCard.appendChild(slider);
239
240 var resultSwatch = document.createElement('div');
241 resultSwatch.className = 'bkbg-cm-result-swatch';
242 mixCard.appendChild(resultSwatch);
243
244 /* Formats */
245 var formatsEl = null, copiedHint = null;
246 if (a.showFormats) {
247 formatsEl = document.createElement('div');
248 formatsEl.className = 'bkbg-cm-formats';
249 mixCard.appendChild(formatsEl);
250
251 copiedHint = document.createElement('div');
252 copiedHint.className = 'bkbg-cm-copied-hint';
253 copiedHint.style.color = a.accentColor;
254 copiedHint.textContent = 'Copied!';
255 mixCard.appendChild(copiedHint);
256 }
257
258 /* Gradient */
259 var gradientEl = null;
260 if (a.showGradient) {
261 var gradCard = document.createElement('div');
262 gradCard.className = 'bkbg-cm-card';
263 gradCard.style.background = a.cardBg;
264 var gradTitle = document.createElement('div');
265 gradTitle.style.cssText = 'font-size:13px;font-weight:600;color:' + a.labelColor + ';margin-bottom:8px;';
266 gradTitle.textContent = 'Gradient (A → B)';
267 gradCard.appendChild(gradTitle);
268 gradientEl = document.createElement('div');
269 gradientEl.className = 'bkbg-cm-gradient-bar';
270 gradCard.appendChild(gradientEl);
271 wrap.appendChild(gradCard);
272 }
273
274 /* Harmonies */
275 var harmoniesEl = null;
276 if (a.showHarmonies) {
277 var harmCard = document.createElement('div');
278 harmCard.className = 'bkbg-cm-card';
279 harmCard.style.background = a.cardBg;
280 var harmTitle = document.createElement('div');
281 harmTitle.className = 'bkbg-cm-harmonies-title';
282 harmTitle.style.color = a.labelColor;
283 harmTitle.textContent = 'Color Harmonies (of mixed color)';
284 harmCard.appendChild(harmTitle);
285 harmoniesEl = document.createElement('div');
286 harmCard.appendChild(harmoniesEl);
287 wrap.appendChild(harmCard);
288 }
289
290 function makeFormatBox(val, lbl) {
291 var box = document.createElement('div');
292 box.className = 'bkbg-cm-format-box';
293 box.title = 'Click to copy';
294 var valEl = document.createElement('div');
295 valEl.className = 'bkbg-cm-format-val';
296 valEl.style.color = a.labelColor;
297 valEl.textContent = val;
298 var lblEl = document.createElement('div');
299 lblEl.className = 'bkbg-cm-format-lbl';
300 lblEl.textContent = lbl;
301 box.appendChild(valEl);
302 box.appendChild(lblEl);
303 box.addEventListener('click', function () {
304 navigator.clipboard && navigator.clipboard.writeText(val).catch(function () {
305 var t = document.createElement('textarea'); t.value = val;
306 document.body.appendChild(t); t.select(); document.execCommand('copy'); document.body.removeChild(t);
307 });
308 var orig = valEl.textContent;
309 valEl.textContent = 'Copied!';
310 if (copiedHint) { copiedHint.classList.add('bkbg-cm-show'); }
311 setTimeout(function () {
312 valEl.textContent = orig;
313 if (copiedHint) copiedHint.classList.remove('bkbg-cm-show');
314 }, 1500);
315 });
316 return box;
317 }
318
319 function makeHarmonyGroup(title, colors) {
320 var group = document.createElement('div');
321 group.className = 'bkbg-cm-harmony-group';
322 var lbl = document.createElement('div');
323 lbl.className = 'bkbg-cm-harmony-label';
324 lbl.style.color = a.labelColor;
325 lbl.textContent = title;
326 group.appendChild(lbl);
327 var swatches = document.createElement('div');
328 swatches.className = 'bkbg-cm-harmony-swatches';
329 colors.forEach(function (c) {
330 var col = document.createElement('div');
331 var sw = document.createElement('button');
332 sw.className = 'bkbg-cm-harmony-swatch';
333 sw.style.background = c;
334 sw.title = c.toUpperCase() + ' – click to copy';
335 sw.addEventListener('click', function () {
336 navigator.clipboard && navigator.clipboard.writeText(c.toUpperCase()).catch(function(){});
337 var orig = sw.style.transform; sw.style.transform = 'scale(0.9)';
338 setTimeout(function(){sw.style.transform = orig;},200);
339 });
340 var hx = document.createElement('div');
341 hx.className = 'bkbg-cm-harmony-hex';
342 hx.style.color = a.labelColor;
343 hx.textContent = c.toUpperCase();
344 col.appendChild(sw);
345 col.appendChild(hx);
346 swatches.appendChild(col);
347 });
348 group.appendChild(swatches);
349 return group;
350 }
351
352 function renderAll() {
353 var t = ratio;
354 var mixed = mixColors(colorA, colorB, t);
355 var aStr = Math.round((1-t)*100);
356 var bStr = Math.round(t*100);
357
358 ratioLabelA.textContent = 'A (' + aStr + '%)';
359 ratioLabelB.textContent = 'B (' + bStr + '%)';
360
361 // slider track gradient
362 slider.style.background = 'linear-gradient(to right, ' + colorA + ' 0%, ' + mixed + ' ' + (t*100) + '%, ' + colorB + ' 100%)';
363 slider.style.color = mixed;
364
365 resultSwatch.style.background = mixed;
366 resultSwatch.title = mixed.toUpperCase();
367
368 if (formatsEl) {
369 formatsEl.innerHTML = '';
370 [
371 { val: mixed.toUpperCase(), lbl: 'HEX' },
372 { val: formatRgb(mixed), lbl: 'RGB' },
373 { val: formatHsl(mixed), lbl: 'HSL' }
374 ].forEach(function (f) { formatsEl.appendChild(makeFormatBox(f.val, f.lbl)); });
375 }
376
377 if (gradientEl) {
378 gradientEl.style.background = 'linear-gradient(to right, ' + colorA + ', ' + colorB + ')';
379 }
380
381 if (harmoniesEl) {
382 harmoniesEl.innerHTML = '';
383 var h = getHarmonies(mixed);
384 [
385 { title: 'Complementary', colors: h.complementary },
386 { title: 'Analogous', colors: h.analogous },
387 { title: 'Triadic', colors: h.triadic },
388 { title: 'Split-Comp.', colors: h.split }
389 ].forEach(function (g) { harmoniesEl.appendChild(makeHarmonyGroup(g.title, g.colors)); });
390 }
391 }
392
393 renderAll();
394 }
395
396 function init() {
397 document.querySelectorAll('.bkbg-cm-app').forEach(initBlock);
398 }
399
400 if (document.readyState === 'loading') {
401 document.addEventListener('DOMContentLoaded', init);
402 } else {
403 init();
404 }
405 })();
406