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-harmony / index.js

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

240 lines 11.9 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 useEffect = wp.element.useEffect;
5 var Fragment = wp.element.Fragment;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var __ = wp.i18n.__;
8 var InspectorControls = wp.blockEditor.InspectorControls;
9 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
10 var useBlockProps = wp.blockEditor.useBlockProps;
11 var RichText = wp.blockEditor.RichText;
12 var PanelBody = wp.components.PanelBody;
13 var RangeControl = wp.components.RangeControl;
14 var SelectControl = wp.components.SelectControl;
15 var ToggleControl = wp.components.ToggleControl;
16 var ColorPicker = wp.components.ColorPicker;
17
18 function getTypographyControl() {
19 return (window.bkbgTypographyControl || function () { return null; });
20 }
21
22 var _tv = (function () {
23 var fn = window.bkbgTypoCssVars;
24 return fn ? fn : function () { return {}; };
25 })();
26
27 var HARMONIES = {
28 complementary: 'Complementary',
29 triadic: 'Triadic',
30 analogous: 'Analogous',
31 splitComplementary: 'Split-Complementary',
32 tetradic: 'Tetradic',
33 square: 'Square'
34 };
35
36 /* ---- HSL ↔ Hex helpers ---- */
37 function hexToHsl(hex) {
38 var r = parseInt(hex.slice(1,3),16)/255;
39 var g = parseInt(hex.slice(3,5),16)/255;
40 var b = parseInt(hex.slice(5,7),16)/255;
41 var max = Math.max(r,g,b), min = Math.min(r,g,b);
42 var h, s, l = (max+min)/2;
43 if (max === min) { h = s = 0; }
44 else {
45 var d = max - min;
46 s = l > 0.5 ? d/(2-max-min) : d/(max+min);
47 switch(max){
48 case r: h = ((g-b)/d + (g<b?6:0))/6; break;
49 case g: h = ((b-r)/d + 2)/6; break;
50 default: h = ((r-g)/d + 4)/6; break;
51 }
52 }
53 return { h: h*360, s: s*100, l: l*100 };
54 }
55
56 function hslToHex(h, s, l) {
57 h = ((h % 360) + 360) % 360;
58 s /= 100; l /= 100;
59 var a = s * Math.min(l, 1-l);
60 function f(n) {
61 var k = (n + h/30) % 12;
62 var c = l - a * Math.max(-1, Math.min(k-3, 9-k, 1));
63 return Math.round(255*c).toString(16).padStart(2,'0');
64 }
65 return '#' + f(0) + f(8) + f(4);
66 }
67
68 function getHarmony(baseHex, type) {
69 var hsl = hexToHsl(baseHex);
70 var h = hsl.h, s = hsl.s, l = hsl.l;
71 var res = [baseHex];
72 switch (type) {
73 case 'complementary': res.push(hslToHex(h+180,s,l)); break;
74 case 'triadic': res.push(hslToHex(h+120,s,l), hslToHex(h+240,s,l)); break;
75 case 'analogous': res.push(hslToHex(h-30,s,l), hslToHex(h+30,s,l), hslToHex(h-60,s,l), hslToHex(h+60,s,l)); break;
76 case 'splitComplementary': res.push(hslToHex(h+150,s,l), hslToHex(h+210,s,l)); break;
77 case 'tetradic': res.push(hslToHex(h+90,s,l), hslToHex(h+180,s,l), hslToHex(h+270,s,l)); break;
78 case 'square': res.push(hslToHex(h+90,s,l), hslToHex(h+180,s,l), hslToHex(h+270,s,l)); break;
79 default: res.push(hslToHex(h+180,s,l)); break;
80 }
81 return res;
82 }
83
84 function SwatchRow(props) {
85 var colors = getHarmony(props.base, props.harmony);
86 var size = props.swatchSize || 80;
87
88 return el('div', { style: { display: 'flex', gap: 12, justifyContent: 'center', flexWrap: 'wrap' } },
89 colors.map(function (hex, i) {
90 return el('div', { key: i, style: { textAlign: 'center' } },
91 el('div', {
92 style: {
93 width: size, height: size, borderRadius: 12,
94 background: hex, border: '2px solid rgba(0,0,0,0.08)',
95 cursor: 'copy', boxShadow: '0 2px 8px rgba(0,0,0,0.12)',
96 marginBottom: 6
97 },
98 title: 'Click to copy ' + hex
99 }),
100 props.showHex && el('div', { style: { fontSize: 12, fontFamily: 'monospace', color: '#374151' } }, hex.toUpperCase()),
101 i === 0 && el('div', { style: { fontSize: 10, color: '#9ca3af', marginTop: 2 } }, 'Base')
102 );
103 })
104 );
105 }
106
107 function EditorPreview(props) {
108 var a = props.attributes;
109 var setAttributes = props.setAttributes;
110 var bpStyle = { background: a.sectionBg, borderRadius: 16, padding: '28px 20px' };
111 Object.assign(bpStyle, _tv(a.typoTitle, '--bkbg-coh-tt'));
112 Object.assign(bpStyle, _tv(a.typoSubtitle, '--bkbg-coh-st'));
113 var blockProps = useBlockProps({ style: bpStyle });
114
115 return el(Fragment, null,
116 el(InspectorControls, null,
117 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
118 ),
119 el(PanelBody, { title: __('Palette Settings', 'blockenberg'), initialOpen: false },
120 el('div', { style: { marginBottom: 12 } },
121 el('p', { style: { fontSize: 12, fontWeight: 600, margin: '0 0 8px' } }, __('Default Base Color', 'blockenberg')),
122 el(ColorPicker, {
123 color: a.defaultColor,
124 onChange: function (v) { setAttributes({ defaultColor: v }); },
125 enableAlpha: false
126 })
127 ),
128 el(SelectControl, {
129 label: __('Default Harmony Type', 'blockenberg'),
130 value: a.defaultHarmony,
131 options: Object.keys(HARMONIES).map(function (k) { return { label: HARMONIES[k], value: k }; }),
132 onChange: function (v) { setAttributes({ defaultHarmony: v }); }
133 }),
134 el(RangeControl, {
135 label: __('Swatch Size (px)', 'blockenberg'),
136 value: a.swatchSize, min: 48, max: 140,
137 onChange: function (v) { setAttributes({ swatchSize: v }); }
138 }),
139 el(ToggleControl, {
140 __nextHasNoMarginBottom: true,
141 label: __('Show Hex Values', 'blockenberg'),
142 checked: a.showHex,
143 onChange: function (v) { setAttributes({ showHex: v }); }
144 }),
145 el(ToggleControl, {
146 __nextHasNoMarginBottom: true,
147 label: __('Show RGB Values', 'blockenberg'),
148 checked: a.showRgb,
149 onChange: function (v) { setAttributes({ showRgb: v }); }
150 }),
151 el(ToggleControl, {
152 __nextHasNoMarginBottom: true,
153 label: __('Show Export Button', 'blockenberg'),
154 checked: a.showExport,
155 onChange: function (v) { setAttributes({ showExport: v }); }
156 })
157 ),
158
159 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
160 el(getTypographyControl(), { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { setAttributes({ typoTitle: v }); } }),
161 el(getTypographyControl(), { label: __('Subtitle', 'blockenberg'), value: a.typoSubtitle, onChange: function (v) { setAttributes({ typoSubtitle: v }); } })
162 ),
163 el(PanelColorSettings, {
164 title: __('Colors', 'blockenberg'),
165 initialOpen: false,
166 colorSettings: [
167 { label: __('Accent Color', 'blockenberg'), value: a.accentColor, onChange: function (v) { setAttributes({ accentColor: v || '#6366f1' }); } },
168 { label: __('Section Background', 'blockenberg'), value: a.sectionBg, onChange: function (v) { setAttributes({ sectionBg: v || '#f8fafc' }); } },
169 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function (v) { setAttributes({ cardBg: v || '#ffffff' }); } },
170 { label: __('Title Color', 'blockenberg'), value: a.titleColor, onChange: function (v) { setAttributes({ titleColor: v || '#1e1b4b' }); } }
171 ]
172 })
173 ),
174 el('div', blockProps,
175 el(RichText, {
176 tagName: 'h3', className: 'bkbg-coh-title',
177 value: a.title,
178 onChange: function (v) { setAttributes({ title: v }); },
179 placeholder: __('Title', 'blockenberg'),
180 style: { color: a.titleColor, margin: '0 0 4px', textAlign: 'center' }
181 }),
182 el(RichText, {
183 tagName: 'p', className: 'bkbg-coh-subtitle',
184 value: a.subtitle,
185 onChange: function (v) { setAttributes({ subtitle: v }); },
186 placeholder: __('Subtitle', 'blockenberg'),
187 style: { color: a.titleColor + 'bb', textAlign: 'center', margin: '0 0 20px' }
188 }),
189 // Harmony type tabs
190 el('div', { style: { display: 'flex', justifyContent: 'center', gap: 8, flexWrap: 'wrap', marginBottom: 20 } },
191 Object.keys(HARMONIES).map(function (k) {
192 var active = k === a.defaultHarmony;
193 return el('div', {
194 key: k,
195 style: {
196 padding: '5px 14px', borderRadius: 20, fontSize: 13, fontWeight: 600, cursor: 'default',
197 border: '2px solid ' + a.accentColor,
198 background: active ? a.accentColor : 'transparent',
199 color: active ? '#fff' : a.accentColor
200 }
201 }, HARMONIES[k]);
202 })
203 ),
204 // Swatch row
205 el('div', { style: { background: a.cardBg, borderRadius: 14, padding: '20px', marginBottom: 14 } },
206 el(SwatchRow, { base: a.defaultColor || '#6366f1', harmony: a.defaultHarmony, swatchSize: a.swatchSize, showHex: a.showHex })
207 ),
208 // Color picker preview
209 el('div', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 12, marginBottom: 14 } },
210 el('div', {
211 style: { width: 44, height: 44, borderRadius: 50, background: a.defaultColor, border: '3px solid ' + a.accentColor }
212 }),
213 el('div', { style: { fontFamily: 'monospace', fontSize: 16, fontWeight: 700, color: a.titleColor } },
214 (a.defaultColor || '#6366f1').toUpperCase()
215 )
216 ),
217 a.showExport && el('button', {
218 style: {
219 background: a.accentColor, color: '#fff', border: 'none', borderRadius: 10,
220 padding: '10px 24px', fontWeight: 700, cursor: 'default', fontSize: 14
221 }
222 }, '📋 Export Palette')
223 )
224 );
225 }
226
227 registerBlockType('blockenberg/color-harmony', {
228 edit: EditorPreview,
229 save: function (props) {
230 var a = props.attributes;
231 return el('div', useBlockProps.save(),
232 el('div', { className: 'bkbg-coh-app', 'data-opts': JSON.stringify(a) },
233 el(RichText.Content, { tagName: 'h3', className: 'bkbg-coh-title', value: a.title }),
234 el(RichText.Content, { tagName: 'p', className: 'bkbg-coh-subtitle', value: a.subtitle })
235 )
236 );
237 }
238 });
239 }() );
240