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

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

355 lines 20.5 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;
12 var SelectControl = wp.components.SelectControl;
13 var TextControl = wp.components.TextControl;
14 var ToggleControl = wp.components.ToggleControl;
15 var CheckboxControl = wp.components.CheckboxControl;
16
17 var _tc, _tvf;
18 Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } });
19 Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
20 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
21 function getTypoCssVars(attrs) {
22 var v = {};
23 _tvf(v, 'titleTypo', attrs, '--bkuc-tt-');
24 _tvf(v, 'subtitleTypo', attrs, '--bkuc-st-');
25 return v;
26 }
27
28 /* ── Conversion data ────────────────────────────────────────────────────── */
29 var CATEGORIES = {
30 length: {
31 label: 'Length',
32 units: {
33 meter: { label: 'Meter (m)', toBase: 1 },
34 kilometer: { label: 'Kilometer (km)', toBase: 1000 },
35 centimeter: { label: 'Centimeter (cm)', toBase: 0.01 },
36 millimeter: { label: 'Millimeter (mm)', toBase: 0.001 },
37 mile: { label: 'Mile (mi)', toBase: 1609.344 },
38 yard: { label: 'Yard (yd)', toBase: 0.9144 },
39 foot: { label: 'Foot (ft)', toBase: 0.3048 },
40 inch: { label: 'Inch (in)', toBase: 0.0254 },
41 nautical_mile: { label: 'Nautical Mile', toBase: 1852 },
42 },
43 defaultFrom: 'meter',
44 defaultTo: 'foot',
45 },
46 weight: {
47 label: 'Weight',
48 units: {
49 kilogram: { label: 'Kilogram (kg)', toBase: 1 },
50 gram: { label: 'Gram (g)', toBase: 0.001 },
51 milligram: { label: 'Milligram (mg)', toBase: 0.000001 },
52 pound: { label: 'Pound (lb)', toBase: 0.453592 },
53 ounce: { label: 'Ounce (oz)', toBase: 0.0283495 },
54 ton: { label: 'Metric Ton (t)', toBase: 1000 },
55 stone: { label: 'Stone (st)', toBase: 6.35029 },
56 },
57 defaultFrom: 'kilogram',
58 defaultTo: 'pound',
59 },
60 temperature: {
61 label: 'Temperature',
62 units: {
63 celsius: { label: 'Celsius (°C)', toBase: null },
64 fahrenheit: { label: 'Fahrenheit (°F)', toBase: null },
65 kelvin: { label: 'Kelvin (K)', toBase: null },
66 },
67 defaultFrom: 'celsius',
68 defaultTo: 'fahrenheit',
69 },
70 volume: {
71 label: 'Volume',
72 units: {
73 liter: { label: 'Liter (L)', toBase: 1 },
74 milliliter: { label: 'Milliliter (mL)', toBase: 0.001 },
75 cubic_meter:{ label: 'Cubic Meter (m³)',toBase: 1000 },
76 gallon_us: { label: 'Gallon (US)', toBase: 3.78541 },
77 gallon_uk: { label: 'Gallon (UK)', toBase: 4.54609 },
78 quart: { label: 'Quart (US)', toBase: 0.946353 },
79 pint: { label: 'Pint (US)', toBase: 0.473176 },
80 cup: { label: 'Cup (US)', toBase: 0.236588 },
81 fluid_oz: { label: 'Fluid Oz (US)', toBase: 0.0295735 },
82 tablespoon: { label: 'Tablespoon', toBase: 0.0147868 },
83 teaspoon: { label: 'Teaspoon', toBase: 0.00492892 },
84 },
85 defaultFrom: 'liter',
86 defaultTo: 'gallon_us',
87 },
88 area: {
89 label: 'Area',
90 units: {
91 sqmeter: { label: 'Square Meter (m²)', toBase: 1 },
92 sqkilometer:{ label: 'Square Km (km²)', toBase: 1000000 },
93 sqcentimeter:{ label:'Square Cm (cm²)', toBase: 0.0001 },
94 sqfoot: { label: 'Square Foot (ft²)', toBase: 0.092903 },
95 sqinch: { label: 'Square Inch (in²)', toBase: 0.00064516 },
96 sqyard: { label: 'Square Yard (yd²)', toBase: 0.836127 },
97 squaremile: { label: 'Square Mile (mi²)', toBase: 2589988 },
98 acre: { label: 'Acre', toBase: 4046.86 },
99 hectare: { label: 'Hectare (ha)', toBase: 10000 },
100 },
101 defaultFrom: 'sqmeter',
102 defaultTo: 'sqfoot',
103 },
104 speed: {
105 label: 'Speed',
106 units: {
107 ms: { label: 'Meter/second (m/s)', toBase: 1 },
108 kmh: { label: 'Km/hour (km/h)', toBase: 0.277778 },
109 mph: { label: 'Mile/hour (mph)', toBase: 0.44704 },
110 knot: { label: 'Knot (kn)', toBase: 0.514444 },
111 fts: { label: 'Foot/second (ft/s)', toBase: 0.3048 },
112 mach: { label: 'Mach', toBase: 343 },
113 },
114 defaultFrom: 'kmh',
115 defaultTo: 'mph',
116 },
117 };
118
119 function convertValue(cat, fromKey, toKey, value) {
120 if (isNaN(value) || value === '') return '';
121 var num = parseFloat(value);
122 if (cat === 'temperature') {
123 var c;
124 if (fromKey === 'celsius') c = num;
125 else if (fromKey === 'fahrenheit') c = (num - 32) * 5 / 9;
126 else c = num - 273.15;
127
128 if (toKey === 'celsius') return c;
129 if (toKey === 'fahrenheit') return c * 9 / 5 + 32;
130 return c + 273.15;
131 }
132 var units = CATEGORIES[cat].units;
133 var base = num * units[fromKey].toBase;
134 return base / units[toKey].toBase;
135 }
136
137 function fmtResult(val, dp) {
138 if (val === '' || isNaN(val)) return '';
139 var n = parseFloat(val);
140 if (Math.abs(n) < 1e-10 && n !== 0) return n.toExponential(4);
141 return parseFloat(n.toFixed(dp)).toLocaleString('en-US', { maximumFractionDigits: dp });
142 }
143
144 /* ── Preview component ──────────────────────────────────────────────────── */
145 function ConverterPreview(props) {
146 var a = props.attrs;
147 var cats = (a.enabledCategories && a.enabledCategories.length) ? a.enabledCategories : ['length', 'weight', 'temperature'];
148
149 var catState = useState(a.defaultCategory || 'length');
150 var activeCat = catState[0]; var setActiveCat = catState[1];
151
152 var cat = CATEGORIES[activeCat] || CATEGORIES['length'];
153 var unitKeys = Object.keys(cat.units);
154
155 var fromState = useState(cat.defaultFrom);
156 var fromKey = fromState[0]; var setFromKey = fromState[1];
157 var toState = useState(cat.defaultTo);
158 var toKey = toState[0]; var setToKey = toState[1];
159 var valState = useState('1');
160 var value = valState[0]; var setValue = valState[1];
161
162 var result = convertValue(activeCat, fromKey, toKey, value);
163 var resultFmt = fmtResult(result, a.decimalPlaces || 4);
164
165 var accent = a.accentColor || '#6c3fb5';
166 var cRadius = (a.cardRadius || 16) + 'px';
167
168 var cardStyle = {
169 background: a.cardBg || '#ffffff',
170 borderRadius: cRadius,
171 padding: '32px',
172 boxShadow: '0 4px 24px rgba(0,0,0,0.08)',
173 maxWidth: (a.maxWidth || 640) + 'px',
174 margin: '0 auto',
175 paddingTop: (a.paddingTop || 60) + 'px',
176 paddingBottom: (a.paddingBottom || 60) + 'px',
177 boxSizing: 'border-box',
178 };
179
180 var unitOptions = unitKeys.map(function(k) { return { label: cat.units[k].label, value: k }; });
181
182 return el('div', { className: 'bkbg-uc-card', style: cardStyle },
183 a.showTitle && el('h2', { className: 'bkbg-uc-title', style: { color: a.titleColor || '#1e1b4b' } }, a.title || 'Unit Converter'),
184 a.showSubtitle && el('p', { className: 'bkbg-uc-subtitle', style: { color: a.subtitleColor || '#6b7280' } }, a.subtitle),
185
186 /* Category tabs */
187 a.showCategoryTabs && el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '24px', justifyContent: 'center' } },
188 cats.map(function(catKey) {
189 var isActive = activeCat === catKey;
190 var catDef = CATEGORIES[catKey];
191 if (!catDef) return null;
192 return el('button', {
193 key: catKey,
194 onClick: function() {
195 setActiveCat(catKey);
196 setFromKey(CATEGORIES[catKey].defaultFrom);
197 setToKey(CATEGORIES[catKey].defaultTo);
198 },
199 style: {
200 padding: '6px 14px',
201 borderRadius: '99px',
202 border: 'none',
203 cursor: 'pointer',
204 fontWeight: 600,
205 fontSize: '13px',
206 background: isActive ? (a.tabActiveBg || accent) : (a.tabInactiveBg || '#f3f4f6'),
207 color: isActive ? (a.tabActiveColor || '#fff') : (a.tabInactiveColor || '#374151'),
208 transition: 'all 0.2s',
209 }
210 }, catDef.label);
211 })
212 ),
213
214 /* From / To row */
215 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr auto 1fr', gap: '12px', alignItems: 'end', marginBottom: '20px' } },
216 el('div', null,
217 el('label', { style: { display: 'block', fontSize: '12px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '4px' } }, __('From', 'blockenberg')),
218 el('select', {
219 value: fromKey,
220 onChange: function(e) { setFromKey(e.target.value); },
221 style: { width: '100%', padding: '8px 10px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '14px', background: '#fff' }
222 }, unitOptions.map(function(o) { return el('option', { key: o.value, value: o.value }, o.label); }))
223 ),
224 el('button', {
225 onClick: function() { var tmp = fromKey; setFromKey(toKey); setToKey(tmp); },
226 style: { background: 'none', border: '1.5px solid ' + accent, borderRadius: '8px', padding: '8px 12px', cursor: 'pointer', color: accent, fontWeight: 700, fontSize: '18px', lineHeight: 1 }
227 }, ''),
228 el('div', null,
229 el('label', { style: { display: 'block', fontSize: '12px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '4px' } }, __('To', 'blockenberg')),
230 el('select', {
231 value: toKey,
232 onChange: function(e) { setToKey(e.target.value); },
233 style: { width: '100%', padding: '8px 10px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '14px', background: '#fff' }
234 }, unitOptions.map(function(o) { return el('option', { key: o.value, value: o.value }, o.label); }))
235 )
236 ),
237
238 /* Value input */
239 el('div', { style: { marginBottom: '20px' } },
240 el('label', { style: { display: 'block', fontSize: '13px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '6px' } }, __('Value', 'blockenberg')),
241 el('input', {
242 type: 'number',
243 value: value,
244 onChange: function(e) { setValue(e.target.value); },
245 style: { width: '100%', padding: '12px 14px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '18px', boxSizing: 'border-box', outline: 'none' }
246 })
247 ),
248
249 /* Result */
250 el('div', {
251 style: {
252 background: a.resultBg || '#f5f3ff',
253 border: '1.5px solid ' + (a.resultBorder || '#ede9fe'),
254 borderRadius: cRadius,
255 padding: '20px 24px',
256 textAlign: 'center',
257 }
258 },
259 el('div', { style: { fontSize: '13px', color: '#9ca3af', marginBottom: '4px' } }, (cat.units[fromKey] ? cat.units[fromKey].label : fromKey) + '' + (cat.units[toKey] ? cat.units[toKey].label : toKey)),
260 el('div', {
261 style: { fontSize: (a.resultSize || 40) + 'px', fontWeight: 800, color: a.resultColor || accent, lineHeight: 1.1 }
262 }, resultFmt),
263 el('div', { style: { fontSize: '14px', color: '#6b7280', marginTop: '4px' } }, cat.units[toKey] ? cat.units[toKey].label : '')
264 )
265 );
266 }
267
268 registerBlockType('blockenberg/unit-converter', {
269 edit: function(props) {
270 var a = props.attributes;
271 var setAttr = props.setAttributes;
272 var blockProps = useBlockProps((function () { var _tv = getTypoCssVars(a); var s = {}; Object.assign(s, _tv); if (a.bgColor) s.background = a.bgColor; return { style: s }; })());
273
274 var ALL_CATS = ['length', 'weight', 'temperature', 'volume', 'area', 'speed'];
275
276 return el(Fragment, null,
277 el(InspectorControls, null,
278
279 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
280 el(ToggleControl, { label: __('Show Title', 'blockenberg'), checked: a.showTitle, onChange: function(v) { setAttr({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
281 a.showTitle && el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: function(v) { setAttr({ title: v }); } }),
282 el(ToggleControl, { label: __('Show Subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function(v) { setAttr({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
283 a.showSubtitle && el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: function(v) { setAttr({ subtitle: v }); } }),
284 el(SelectControl, { label: __('Default Category', 'blockenberg'), value: a.defaultCategory, options: ALL_CATS.map(function(k) { return { label: CATEGORIES[k].label, value: k }; }), onChange: function(v) { setAttr({ defaultCategory: v }); } }),
285 el(RangeControl, { label: __('Decimal Places', 'blockenberg'), value: a.decimalPlaces, min: 0, max: 10, onChange: function(v) { setAttr({ decimalPlaces: v }); } })
286 ),
287
288 el(PanelBody, { title: __('Enabled Categories', 'blockenberg'), initialOpen: false },
289 ALL_CATS.map(function(k) {
290 var enabled = (a.enabledCategories || ALL_CATS).includes(k);
291 return el(CheckboxControl, {
292 key: k,
293 label: CATEGORIES[k].label,
294 checked: enabled,
295 __nextHasNoMarginBottom: true,
296 onChange: function(v) {
297 var cur = (a.enabledCategories || ALL_CATS).filter(function(x) { return x !== k; });
298 if (v) cur.push(k);
299 setAttr({ enabledCategories: ALL_CATS.filter(function(x) { return cur.includes(x); }) });
300 }
301 });
302 })
303 ),
304
305 el(PanelBody, { title: __('Display Options', 'blockenberg'), initialOpen: false },
306 el(ToggleControl, { label: __('Show Category Tabs', 'blockenberg'), checked: a.showCategoryTabs, onChange: function(v) { setAttr({ showCategoryTabs: v }); }, __nextHasNoMarginBottom: true }),
307 el(ToggleControl, { label: __('Show Swap Button', 'blockenberg'), checked: a.showSwapButton, onChange: function(v) { setAttr({ showSwapButton: v }); }, __nextHasNoMarginBottom: true })
308 ),
309
310
311 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
312 getTypoControl(__('Title', 'blockenberg'), 'titleTypo', a, setAttr),
313 getTypoControl(__('Subtitle', 'blockenberg'), 'subtitleTypo', a, setAttr),
314 el(RangeControl, { label: __('Result Number Size (px)', 'blockenberg'), value: a.resultSize, min: 24, max: 80, onChange: function(v) { setAttr({ resultSize: v }); } })
315 ),
316 el(PanelColorSettings, {
317 title: __('Colors', 'blockenberg'), initialOpen: false,
318 colorSettings: [
319 { label: __('Accent Color', 'blockenberg'), value: a.accentColor, onChange: function(v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
320 { label: __('Result Number Color', 'blockenberg'), value: a.resultColor, onChange: function(v) { setAttr({ resultColor: v || '#6c3fb5' }); } },
321 { label: __('Active Tab Background', 'blockenberg'), value: a.tabActiveBg, onChange: function(v) { setAttr({ tabActiveBg: v || '#6c3fb5' }); } },
322 { label: __('Active Tab Text', 'blockenberg'), value: a.tabActiveColor, onChange: function(v) { setAttr({ tabActiveColor: v || '#ffffff' }); } },
323 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function(v) { setAttr({ cardBg: v || '#ffffff' }); } },
324 { label: __('Result Background', 'blockenberg'), value: a.resultBg, onChange: function(v) { setAttr({ resultBg: v || '#f5f3ff' }); } },
325 { label: __('Section Background', 'blockenberg'), value: a.bgColor, onChange: function(v) { setAttr({ bgColor: v || '' }); } },
326 ]
327 }),
328
329 el(PanelBody, { title: __('Sizing', 'blockenberg'), initialOpen: false },
330 el(RangeControl, { label: __('Card Radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 40, onChange: function(v) { setAttr({ cardRadius: v }); } }),
331 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 320, max: 1200, onChange: function(v) { setAttr({ maxWidth: v }); } }),
332 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 160, onChange: function(v) { setAttr({ paddingTop: v }); } }),
333 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 160, onChange: function(v) { setAttr({ paddingBottom: v }); } })
334 )
335 ),
336
337 el('div', blockProps,
338 el(ConverterPreview, { attrs: a })
339 )
340 );
341 },
342
343 save: function(props) {
344 var a = props.attributes;
345 var blockProps = wp.blockEditor.useBlockProps.save((function () { var _tv = getTypoCssVars(a); var s = {}; Object.assign(s, _tv); if (a.bgColor) s.background = a.bgColor; return { style: s }; })());
346 var opts = JSON.stringify(a);
347 return el('div', blockProps,
348 el('div', { className: 'bkbg-uc-app', 'data-opts': opts },
349 el('p', { className: 'bkbg-uc-loading' }, 'Loading converter…')
350 )
351 );
352 }
353 });
354 }() );
355