PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.14
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.14
2.0.14 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-converter / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.14, at blocks/color-converter/index.js

224 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var useState = wp.element.useState;
4 var Fragment = wp.element.Fragment;
5 var registerBlockType = wp.blocks.registerBlockType;
6 var __ = wp.i18n.__;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var PanelBody = wp.components.PanelBody;
11 var RangeControl = wp.components.RangeControl; var SelectControl = wp.components.SelectControl; var TextControl = wp.components.TextControl;
12 var ToggleControl = wp.components.ToggleControl;
13 var Button = wp.components.Button;
14
15 function getTypographyControl() {
16 return (window.bkbgTypographyControl || function () { return null; });
17 }
18
19 var _tv = (function () {
20 var fn = window.bkbgTypoCssVars;
21 return fn ? fn : function () { return {}; };
22 })();
23
24 /* ── Color math ─────────────────────────────────────────────────────── */
25 function clamp(n, lo, hi) { return Math.max(lo, Math.min(hi, n)); }
26
27 function hexToRgb(hex) {
28 hex = hex.replace(/^#/, '');
29 if (hex.length === 3) hex = hex.split('').map(function(c) { return c+c; }).join('');
30 if (hex.length !== 6) return null;
31 var r = parseInt(hex.slice(0,2),16);
32 var g = parseInt(hex.slice(2,4),16);
33 var b = parseInt(hex.slice(4,6),16);
34 if (isNaN(r)||isNaN(g)||isNaN(b)) return null;
35 return { r:r, g:g, b:b };
36 }
37
38 function rgbToHex(r,g,b) {
39 return '#' + [r,g,b].map(function(x) { return clamp(Math.round(x),0,255).toString(16).padStart(2,'0'); }).join('');
40 }
41
42 function rgbToHsl(r,g,b) {
43 r/=255; g/=255; b/=255;
44 var max=Math.max(r,g,b), min=Math.min(r,g,b), l=(max+min)/2, h, s;
45 if (max===min) { h=0; s=0; } else {
46 var d=max-min;
47 s = l>0.5 ? d/(2-max-min) : d/(max+min);
48 switch(max) {
49 case r: h=((g-b)/d + (g<b?6:0))/6; break;
50 case g: h=((b-r)/d + 2)/6; break;
51 default: h=((r-g)/d + 4)/6;
52 }
53 }
54 return { h: Math.round(h*360), s: Math.round(s*100), l: Math.round(l*100) };
55 }
56
57 function hslToRgb(h,s,l) {
58 s/=100; l/=100; h/=360;
59 var r,g,b;
60 if (s===0) { r=g=b=l; } else {
61 function hue2rgb(p,q,t) { if(t<0)t+=1; if(t>1)t-=1; if(t<1/6)return p+(q-p)*6*t; if(t<1/2)return q; if(t<2/3)return p+(q-p)*(2/3-t)*6; return p; }
62 var q2=l<0.5?l*(1+s):l+s-l*s, p2=2*l-q2;
63 r=hue2rgb(p2,q2,h+1/3); g=hue2rgb(p2,q2,h); b=hue2rgb(p2,q2,h-1/3);
64 }
65 return { r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) };
66 }
67
68 function ColorPreview(props) {
69 var a = props.attributes;
70 var _hex = useState(a.defaultHex || '#6c3fb5'); var hex = _hex[0]; var setHexState = _hex[1];
71 var accent = a.accentColor || '#6c3fb5';
72
73 var rgb = hexToRgb(hex) || { r:108, g:63, b:181 };
74 var hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
75
76 function fromHex(v) {
77 var clean = v.startsWith('#') ? v : '#' + v;
78 var test = hexToRgb(clean);
79 if (test) setHexState(clean);
80 else setHexState(v);
81 }
82 function fromRgb(r,g,b) {
83 setHexState(rgbToHex(clamp(r,0,255), clamp(g,0,255), clamp(b,0,255)));
84 }
85 function fromHsl(h,s,l) {
86 var c = hslToRgb(clamp(h,0,360),clamp(s,0,100),clamp(l,0,100));
87 setHexState(rgbToHex(c.r,c.g,c.b));
88 }
89
90 function inputStyle() {
91 return { width:'100%', padding:'9px 12px', borderRadius: a.inputRadius+'px', border:'1.5px solid '+(a.inputBorderColor||'#e5e7eb'), fontSize:'15px', fontFamily:'monospace', outline:'none', boxSizing:'border-box' };
92 }
93 function labelStyle() {
94 return { display:'block', fontSize:'12px', fontWeight:600, color: a.labelColor, textTransform:'uppercase', letterSpacing:'.04em', marginBottom:'5px' };
95 }
96 function copyBtn(txt) {
97 if (!a.showCopyBtns) return null;
98 return el('button', {
99 style: { marginTop:'6px', padding:'4px 12px', borderRadius:'6px', border:'none', background: a.copyBg||'#f3f4f6', color: a.copyColor||'#374151', fontSize:'12px', fontWeight:600, cursor:'pointer', width:'100%' },
100 onClick: function() { try { navigator.clipboard.writeText(txt); } catch(e) {} }
101 }, 'Copy');
102 }
103
104 var isValidHex = /^#[0-9a-fA-F]{6}$/.test(hex.replace(/^#/,'').length===3 ? hex.replace(/^#/,'').split('').map(function(c){return c+c;}).join('') : hex.replace(/^#/,'')) || /^#?[0-9a-fA-F]{6}$/.test(hex);
105
106 return el('div', { style: { paddingTop: a.paddingTop+'px', paddingBottom: a.paddingBottom+'px', background: a.sectionBg||undefined } },
107 el('div', { style: { background: a.cardBg, borderRadius: a.cardRadius+'px', padding:'36px 32px', maxWidth: a.maxWidth+'px', margin:'0 auto', boxShadow:'0 4px 24px rgba(0,0,0,0.09)' } },
108
109 (a.showTitle || a.showSubtitle) && el('div', { style:{ marginBottom:'20px' }},
110 a.showTitle && el('div', { className: 'bkbg-ccv-title', style:{color:a.titleColor,marginBottom:'6px'} }, a.title),
111 a.showSubtitle && el('div', { className: 'bkbg-ccv-subtitle', style:{color:a.subtitleColor} }, a.subtitle)
112 ),
113
114 // Swatch
115 a.showSwatchLarge && el('div', { style:{ height: a.swatchHeight+'px', background: isValidHex?hex:'#6c3fb5', borderRadius: a.inputRadius+'px', border:'2px solid '+(a.swatchBorder||'#e5e7eb'), marginBottom:'24px', transition:'background .15s' } }),
116
117 // HEX
118 el('div', { style:{marginBottom:'18px'} },
119 el('label', { style: labelStyle() }, 'HEX'),
120 el('input', { style: inputStyle(), value: hex, onChange: function(e){ fromHex(e.target.value); } }),
121 copyBtn(hex)
122 ),
123
124 // RGB
125 el('div', { style:{marginBottom:'18px'} },
126 el('label', { style: labelStyle() }, 'RGB'),
127 el('div', { style:{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:'10px'} },
128 ['R','G','B'].map(function(ch, i) {
129 var val = [rgb.r, rgb.g, rgb.b][i];
130 return el('div', { key:ch },
131 el('label', { style:{fontSize:'11px',fontWeight:600,color:a.labelColor,display:'block',marginBottom:'4px'} }, ch),
132 el('input', { style: inputStyle(), type:'number', min:0, max:255, value: val,
133 onChange: function(e) {
134 var vals = [rgb.r, rgb.g, rgb.b]; vals[i]=parseInt(e.target.value)||0;
135 fromRgb(vals[0],vals[1],vals[2]);
136 }
137 })
138 );
139 })
140 ),
141 copyBtn('rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')')
142 ),
143
144 // HSL
145 el('div', { style:{marginBottom:'4px'} },
146 el('label', { style: labelStyle() }, 'HSL'),
147 el('div', { style:{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:'10px'} },
148 ['H','S','L'].map(function(ch, i) {
149 var val = [hsl.h, hsl.s, hsl.l][i];
150 var max = i===0?360:100;
151 return el('div', { key:ch },
152 el('label', { style:{fontSize:'11px',fontWeight:600,color:a.labelColor,display:'block',marginBottom:'4px'} }, ch + (i===0?'°':'%')),
153 el('input', { style: inputStyle(), type:'number', min:0, max:max, value: val,
154 onChange: function(e) {
155 var vals = [hsl.h, hsl.s, hsl.l]; vals[i]=parseInt(e.target.value)||0;
156 fromHsl(vals[0],vals[1],vals[2]);
157 }
158 })
159 );
160 })
161 ),
162 copyBtn('hsl(' + hsl.h + ', ' + hsl.s + '%, ' + hsl.l + '%)')
163 )
164 )
165 );
166 }
167
168 registerBlockType('blockenberg/color-converter', {
169 edit: function(props) {
170 var a = props.attributes; var set = props.setAttributes;
171 var bpStyle = {};
172 Object.assign(bpStyle, _tv(a.typoTitle, '--bkbg-ccv-tt'));
173 Object.assign(bpStyle, _tv(a.typoSubtitle, '--bkbg-ccv-st'));
174 var blockProps = useBlockProps({ style: bpStyle });
175 var colorSettings = [
176 { value: a.accentColor, onChange: function(v){ set({accentColor:v}); }, label: 'Accent Color' },
177 { value: a.cardBg, onChange: function(v){ set({cardBg:v}); }, label: 'Card Background' },
178 { value: a.swatchBorder, onChange: function(v){ set({swatchBorder:v}); }, label: 'Swatch Border' },
179 { value: a.inputBorderColor, onChange: function(v){ set({inputBorderColor:v}); }, label: 'Input Border' },
180 { value: a.copyBg, onChange: function(v){ set({copyBg:v}); }, label: 'Copy Button Background' },
181 { value: a.copyColor, onChange: function(v){ set({copyColor:v}); }, label: 'Copy Button Text' },
182 { value: a.labelColor, onChange: function(v){ set({labelColor:v}); }, label: 'Label Color' },
183 { value: a.titleColor, onChange: function(v){ set({titleColor:v}); }, label: 'Title Color' },
184 { value: a.subtitleColor, onChange: function(v){ set({subtitleColor:v}); }, label: 'Subtitle Color' },
185 { value: a.sectionBg, onChange: function(v){ set({sectionBg:v}); }, label: 'Section Background' }
186 ];
187 return el(Fragment, null,
188 el(InspectorControls, null,
189 el(PanelBody, { title: 'Header', initialOpen: false },
190 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Title', checked: a.showTitle, onChange: function(v){ set({showTitle:v}); } }),
191 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Subtitle', checked: a.showSubtitle, onChange: function(v){ set({showSubtitle:v}); } }),
192 el(TextControl, { label: 'Title', value: a.title, onChange: function(v){ set({title:v}); } }),
193 el(TextControl, { label: 'Subtitle', value: a.subtitle, onChange: function(v){ set({subtitle:v}); } })
194 ),
195 el(PanelBody, { title: 'Settings', initialOpen: true },
196 el(TextControl, { label: 'Default Color (Hex)', value: a.defaultHex, onChange: function(v){ set({defaultHex:v}); } }),
197 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Color Swatch', checked: a.showSwatchLarge, onChange: function(v){ set({showSwatchLarge:v}); } }),
198 el(ToggleControl, { __nextHasNoMarginBottom: true, label: 'Show Copy Buttons', checked: a.showCopyBtns, onChange: function(v){ set({showCopyBtns:v}); } })
199 ),
200
201 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
202 el(getTypographyControl(), { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { set({ typoTitle: v }); } }),
203 el(getTypographyControl(), { label: __('Subtitle', 'blockenberg'), value: a.typoSubtitle, onChange: function (v) { set({ typoSubtitle: v }); } })
204 ),
205 el(PanelColorSettings, { title: 'Colors', initialOpen: false, colorSettings: colorSettings }),
206 el(PanelBody, { title: 'Sizing & Layout', initialOpen: false },
207 el(RangeControl, { label: 'Swatch Height (px)',value: a.swatchHeight, min: 40, max: 300,step: 4, onChange: function(v){ set({swatchHeight:v}); } }),
208 el(RangeControl, { label: 'Card Border Radius', value: a.cardRadius, min: 0, max: 40, step: 1, onChange: function(v){ set({cardRadius:v}); } }),
209 el(RangeControl, { label: 'Input Border Radius',value: a.inputRadius, min: 0, max: 24, step: 1, onChange: function(v){ set({inputRadius:v}); } }),
210 el(RangeControl, { label: 'Max Width (px)', value: a.maxWidth, min: 300,max: 900,step: 10, onChange: function(v){ set({maxWidth:v}); } }),
211 el(RangeControl, { label: 'Padding Top (px)', value: a.paddingTop, min: 0, max: 160,step: 4, onChange: function(v){ set({paddingTop:v}); } }),
212 el(RangeControl, { label: 'Padding Bottom (px)',value: a.paddingBottom,min: 0, max: 160,step: 4, onChange: function(v){ set({paddingBottom:v}); } })
213 )
214 ),
215 el('div', blockProps, el(ColorPreview, { attributes: a, setAttributes: set }))
216 );
217 },
218 save: function(props) {
219 var a = props.attributes;
220 return el('div', wp.blockEditor.useBlockProps.save(), el('div', { className: 'bkbg-clr-app', 'data-opts': JSON.stringify(a) }));
221 }
222 });
223 }() );
224