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 / gradient-generator / frontend.js

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

356 lines 16.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 PRESETS = [
5 { label:'Purple Dream', stops:'#6c3fb5 0%,#06b6d4 100%', type:'linear', angle:135 },
6 { label:'Sunset', stops:'#f97316 0%,#ef4444 50%,#a855f7 100%', type:'linear', angle:135 },
7 { label:'Ocean', stops:'#0ea5e9 0%,#10b981 100%', type:'linear', angle:135 },
8 { label:'Midnight', stops:'#1e1b4b 0%,#6c3fb5 50%,#0ea5e9 100%', type:'linear', angle:225 },
9 { label:'Peach', stops:'#f9a8d4 0%,#fed7aa 100%', type:'linear', angle:90 },
10 { label:'Radial Burst', stops:'#fde68a 0%,#f97316 60%,#ef4444 100%', type:'radial', angle:135 },
11 { label:'Forest', stops:'#064e3b 0%,#10b981 100%', type:'linear', angle:135 },
12 { label:'Rose Gold', stops:'#fda4af 0%,#fb7185 40%,#f43f5e 100%', type:'linear', angle:135 }
13 ];
14
15 function parseStops(str) {
16 return (str || '#6c3fb5 0%,#06b6d4 100%').split(',').map(function(s) {
17 s = s.trim();
18 var parts = s.match(/^(#[\w]+|rgba?\([^)]+\))\s+(\d+%?)$/);
19 if (parts) return { color: parts[1], pos: parts[2] };
20 return { color: s, pos: '' };
21 });
22 }
23
24 function buildGradient(type, angle, stops) {
25 var stopStr = stops.map(function(s) { return s.color + (s.pos ? ' ' + s.pos : ''); }).join(', ');
26 if (type === 'radial') return 'radial-gradient(circle, ' + stopStr + ')';
27 if (type === 'conic') return 'conic-gradient(from ' + angle + 'deg, ' + stopStr + ')';
28 return 'linear-gradient(' + angle + 'deg, ' + stopStr + ')';
29 }
30
31 function initGradientGenerator(app) {
32 var opts;
33 try { opts = JSON.parse(app.getAttribute('data-opts') || '{}'); } catch(e) { opts = {}; }
34
35 function typoCssVarsForEl(typo, prefix, el) {
36 if (!typo || typeof typo !== 'object') return;
37 var map = {
38 family:'font-family', weight:'font-weight', style:'font-style',
39 decoration:'text-decoration', transform:'text-transform',
40 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
41 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
42 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
43 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
44 };
45 Object.keys(map).forEach(function(k) {
46 if (typo[k] !== undefined && typo[k] !== '') {
47 var v = typo[k];
48 if (['sizeDesktop','sizeTablet','sizeMobile'].indexOf(k) !== -1) v = v + (typo.sizeUnit || 'px');
49 else if (['lineHeightDesktop','lineHeightTablet','lineHeightMobile'].indexOf(k) !== -1) v = v + (typo.lineHeightUnit || '');
50 else if (['letterSpacingDesktop','letterSpacingTablet','letterSpacingMobile'].indexOf(k) !== -1) v = v + (typo.letterSpacingUnit || 'px');
51 else if (['wordSpacingDesktop','wordSpacingTablet','wordSpacingMobile'].indexOf(k) !== -1) v = v + (typo.wordSpacingUnit || 'px');
52 el.style.setProperty(prefix + map[k], String(v));
53 }
54 });
55 }
56
57 var accent = opts.accentColor || '#6c3fb5';
58 var cardBg = opts.cardBg || '#ffffff';
59 var controlsBg = opts.controlsBg || '#f9fafb';
60 var controlsBorder= opts.controlsBorder || '#e5e7eb';
61 var cssBg = opts.cssBg || '#1e1b4b';
62 var cssColor = opts.cssColor || '#c4b5fd';
63 var copyBg = opts.copyBg || accent;
64 var copyColor = opts.copyColor || '#ffffff';
65 var labelColor = opts.labelColor || '#374151';
66 var titleColor = opts.titleColor || '';
67 var subtitleColor = opts.subtitleColor || '';
68 var sectionBg = opts.sectionBg || '';
69
70 var paddingTop = (opts.paddingTop != null ? opts.paddingTop : 60) + 'px';
71 var paddingBottom = (opts.paddingBottom != null ? opts.paddingBottom : 60) + 'px';
72 var maxWidth = (opts.maxWidth || 600) + 'px';
73 var cardRadius = (opts.cardRadius || 16) + 'px';
74 var previewRadius = (opts.previewRadius || 12) + 'px';
75 var previewHeight = (opts.previewHeight || 200) + 'px';
76 var titleSize = (opts.titleSize || 28) + 'px';
77
78 var showPresets = opts.showPresets !== false;
79 var showCssOutput = opts.showCssOutput !== false;
80 var showTitle = opts.showTitle && opts.title;
81 var showSubtitle = opts.showSubtitle && opts.subtitle;
82
83 // State
84 var state = {
85 type: opts.defaultType || 'linear',
86 angle: opts.defaultAngle != null ? opts.defaultAngle : 135,
87 stops: parseStops(opts.defaultStops)
88 };
89
90 // Build initial HTML
91 app.style.paddingTop = paddingTop;
92 app.style.paddingBottom = paddingBottom;
93 if (sectionBg) app.style.background = sectionBg;
94
95 typoCssVarsForEl(opts.typoTitle, '--bkbg-gg-tt-', app);
96 typoCssVarsForEl(opts.typoBody, '--bkbg-gg-bd-', app);
97
98 var wrap = document.createElement('div');
99 wrap.className = 'bkbg-gg-wrap';
100 wrap.style.cssText = 'background:' + cardBg + ';border-radius:' + cardRadius + ';max-width:' + maxWidth;
101 app.appendChild(wrap);
102
103 // Header
104 if (showTitle || showSubtitle) {
105 var header = document.createElement('div');
106 header.className = 'bkbg-gg-header';
107 if (showTitle) {
108 var h = document.createElement('div');
109 h.className = 'bkbg-gg-title';
110 h.style.cssText = (titleColor ? 'color:' + titleColor : '');
111 h.textContent = opts.title;
112 header.appendChild(h);
113 }
114 if (showSubtitle) {
115 var sub = document.createElement('div');
116 sub.className = 'bkbg-gg-subtitle';
117 if (subtitleColor) sub.style.color = subtitleColor;
118 sub.textContent = opts.subtitle;
119 header.appendChild(sub);
120 }
121 wrap.appendChild(header);
122 }
123
124 // Preview swatch
125 var preview = document.createElement('div');
126 preview.className = 'bkbg-gg-preview';
127 preview.style.height = previewHeight;
128 preview.style.borderRadius = previewRadius;
129 wrap.appendChild(preview);
130
131 // Controls box
132 var controls = document.createElement('div');
133 controls.className = 'bkbg-gg-controls';
134 controls.style.cssText = 'background:' + controlsBg + ';border:1.5px solid ' + controlsBorder;
135 wrap.appendChild(controls);
136
137 // Type + angle row
138 var typeRow = document.createElement('div');
139 typeRow.className = 'bkbg-gg-type-row';
140 controls.appendChild(typeRow);
141
142 var typeGroup = document.createElement('div');
143 var typeLabel = document.createElement('label');
144 typeLabel.className = 'bkbg-gg-label';
145 typeLabel.style.color = labelColor;
146 typeLabel.textContent = 'Type';
147 var typeSelect = document.createElement('select');
148 typeSelect.className = 'bkbg-gg-select';
149 typeSelect.style.cssText = 'border:1.5px solid ' + controlsBorder;
150 ['linear','radial','conic'].forEach(function(t) {
151 var o = document.createElement('option');
152 o.value = t; o.textContent = t.charAt(0).toUpperCase() + t.slice(1);
153 typeSelect.appendChild(o);
154 });
155 typeSelect.value = state.type;
156 typeGroup.appendChild(typeLabel);
157 typeGroup.appendChild(typeSelect);
158 typeRow.appendChild(typeGroup);
159
160 var angleGroup = document.createElement('div');
161 angleGroup.id = 'bkbg-gg-angle-group';
162 var angleLabel = document.createElement('label');
163 angleLabel.className = 'bkbg-gg-label';
164 angleLabel.style.color = labelColor;
165 angleLabel.textContent = 'Angle';
166 var angleRow = document.createElement('div');
167 angleRow.className = 'bkbg-gg-angle-row';
168 var angleSlider = document.createElement('input');
169 angleSlider.type = 'range'; angleSlider.min = 0; angleSlider.max = 360; angleSlider.step = 5;
170 angleSlider.value = state.angle;
171 var angleVal = document.createElement('span');
172 angleVal.className = 'bkbg-gg-angle-val';
173 angleVal.textContent = state.angle + '°';
174 angleRow.appendChild(angleSlider);
175 angleRow.appendChild(angleVal);
176 angleGroup.appendChild(angleLabel);
177 angleGroup.appendChild(angleRow);
178 typeRow.appendChild(angleGroup);
179 if (state.type === 'radial') angleGroup.style.display = 'none';
180
181 // Stops container
182 var stopsContainer = document.createElement('div');
183 stopsContainer.className = 'bkbg-gg-stops';
184 controls.appendChild(stopsContainer);
185
186 function createStopRow(idx) {
187 var row = document.createElement('div');
188 row.className = 'bkbg-gg-stop-row';
189 row.dataset.idx = idx;
190
191 var swatch = document.createElement('input');
192 swatch.type = 'color';
193 swatch.className = 'bkbg-gg-color-swatch';
194 swatch.style.cssText = 'background:' + state.stops[idx].color;
195 swatch.value = state.stops[idx].color;
196
197 var colorText = document.createElement('input');
198 colorText.type = 'text';
199 colorText.className = 'bkbg-gg-input-text bkbg-gg-input-color';
200 colorText.style.cssText = 'border:1.5px solid ' + controlsBorder;
201 colorText.value = state.stops[idx].color;
202 colorText.placeholder = '#rrggbb';
203
204 var posInput = document.createElement('input');
205 posInput.type = 'text';
206 posInput.className = 'bkbg-gg-input-text bkbg-gg-input-pos';
207 posInput.style.cssText = 'border:1.5px solid ' + controlsBorder;
208 posInput.value = state.stops[idx].pos;
209 posInput.placeholder = '0%';
210
211 var removeBtn = document.createElement('button');
212 removeBtn.className = 'bkbg-gg-btn-remove';
213 removeBtn.textContent = '×';
214 removeBtn.disabled = state.stops.length <= 2;
215
216 swatch.addEventListener('input', function() {
217 state.stops[idx].color = swatch.value;
218 colorText.value = swatch.value;
219 refresh();
220 });
221 colorText.addEventListener('input', function() {
222 state.stops[idx].color = colorText.value;
223 if (/^#[0-9a-fA-F]{6}$/.test(colorText.value)) swatch.value = colorText.value;
224 refresh();
225 });
226 posInput.addEventListener('input', function() {
227 state.stops[idx].pos = posInput.value;
228 refresh();
229 });
230 removeBtn.addEventListener('click', function() {
231 if (state.stops.length <= 2) return;
232 state.stops.splice(idx, 1);
233 renderStops();
234 refresh();
235 });
236
237 row.appendChild(swatch);
238 row.appendChild(colorText);
239 row.appendChild(posInput);
240 row.appendChild(removeBtn);
241 return row;
242 }
243
244 function renderStops() {
245 stopsContainer.innerHTML = '';
246 state.stops.forEach(function(_, i) {
247 stopsContainer.appendChild(createStopRow(i));
248 });
249 }
250 renderStops();
251
252 // Add stop button
253 var addBtn = document.createElement('button');
254 addBtn.className = 'bkbg-gg-btn-add';
255 addBtn.style.cssText = 'color:' + accent + ';border-color:' + controlsBorder;
256 addBtn.textContent = '+ Add Color Stop';
257 addBtn.addEventListener('click', function() {
258 if (state.stops.length >= 5) return;
259 state.stops.push({ color: '#ffffff', pos: '100%' });
260 renderStops();
261 refresh();
262 });
263 controls.appendChild(addBtn);
264
265 // Presets
266 if (showPresets) {
267 var presetsSection = document.createElement('div');
268 presetsSection.className = 'bkbg-gg-presets-section';
269 var presetsHdr = document.createElement('div');
270 presetsHdr.className = 'bkbg-gg-presets-label';
271 presetsHdr.style.color = labelColor;
272 presetsHdr.textContent = 'Presets';
273 presetsSection.appendChild(presetsHdr);
274 var presetsGrid = document.createElement('div');
275 presetsGrid.className = 'bkbg-gg-presets-grid';
276 PRESETS.forEach(function(p) {
277 var btn = document.createElement('button');
278 btn.className = 'bkbg-gg-preset-btn';
279 var sw = document.createElement('div');
280 sw.className = 'bkbg-gg-preset-swatch';
281 sw.style.background = buildGradient(p.type, p.angle, parseStops(p.stops));
282 var nm = document.createElement('span');
283 nm.className = 'bkbg-gg-preset-name';
284 nm.textContent = p.label;
285 btn.appendChild(sw);
286 btn.appendChild(nm);
287 btn.addEventListener('click', function() {
288 state.stops = parseStops(p.stops);
289 state.type = p.type;
290 state.angle = p.angle;
291 typeSelect.value = p.type;
292 angleSlider.value = p.angle;
293 angleVal.textContent = p.angle + '°';
294 angleGroup.style.display = (p.type === 'radial') ? 'none' : '';
295 renderStops();
296 refresh();
297 });
298 presetsGrid.appendChild(btn);
299 });
300 presetsSection.appendChild(presetsGrid);
301 wrap.appendChild(presetsSection);
302 }
303
304 // CSS output
305 var cssCode, copyBtn;
306 if (showCssOutput) {
307 var cssSection = document.createElement('div');
308 cssSection.className = 'bkbg-gg-css-section';
309 var cssBlock = document.createElement('div');
310 cssBlock.className = 'bkbg-gg-css-block';
311 cssBlock.style.cssText = 'background:' + cssBg + ';color:' + cssColor;
312 cssCode = document.createElement('span');
313 cssBlock.appendChild(cssCode);
314 copyBtn = document.createElement('button');
315 copyBtn.className = 'bkbg-gg-copy-btn';
316 copyBtn.style.cssText = 'background:' + copyBg + ';color:' + copyColor;
317 copyBtn.textContent = 'Copy CSS';
318 copyBtn.addEventListener('click', function() {
319 var text = 'background: ' + buildGradient(state.type, state.angle, state.stops) + ';';
320 try {
321 navigator.clipboard.writeText(text).then(function() {
322 copyBtn.textContent = '✓ Copied!';
323 copyBtn.style.background = '#10b981';
324 setTimeout(function() { copyBtn.textContent = 'Copy CSS'; copyBtn.style.background = copyBg; }, 1500);
325 });
326 } catch(e) {}
327 });
328 cssSection.appendChild(cssBlock);
329 cssSection.appendChild(copyBtn);
330 wrap.appendChild(cssSection);
331 }
332
333 // Wire type and angle controls
334 typeSelect.addEventListener('change', function() {
335 state.type = typeSelect.value;
336 angleGroup.style.display = (state.type === 'radial') ? 'none' : '';
337 refresh();
338 });
339 angleSlider.addEventListener('input', function() {
340 state.angle = parseInt(angleSlider.value);
341 angleVal.textContent = state.angle + '°';
342 refresh();
343 });
344
345 function refresh() {
346 var g = buildGradient(state.type, state.angle, state.stops);
347 preview.style.background = g;
348 if (cssCode) cssCode.textContent = 'background: ' + g + ';';
349 }
350
351 refresh();
352 }
353
354 document.querySelectorAll('.bkbg-gg-app').forEach(initGradientGenerator);
355 })();
356