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

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

239 lines 15.6 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 TextControl = wp.components.TextControl;
13 var TextareaControl = wp.components.TextareaControl;
14 var ToggleControl = wp.components.ToggleControl;
15 var SelectControl = wp.components.SelectControl;
16
17 var _ccTC, _ccTV;
18 function _tc() { return _ccTC || (_ccTC = window.bkbgTypographyControl); }
19 function _tv(typo, prefix) { return _ccTV ? _ccTV(typo, prefix) : ((_ccTV = window.bkbgTypoCssVars) ? _ccTV(typo, prefix) : {}); }
20
21 /* ── Static indicative rates (USD base) ─────────────────────────────────── */
22 var USD_RATES = {
23 USD:1,EUR:0.92,GBP:0.79,JPY:149.5,CAD:1.36,AUD:1.53,CHF:0.90,CNY:7.24,
24 INR:83.1,MXN:17.15,BRL:4.97,KRW:1325,SGD:1.34,HKD:7.82,NOK:10.58,SEK:10.42,
25 DKK:6.88,NZD:1.63,ZAR:18.63,TRY:32.6,RUB:90.5,PLN:4.03,THB:35.1,MYR:4.72,
26 IDR:15650,PHP:56.5,AED:3.67,SAR:3.75,EGP:30.9,NGN:1490,
27 };
28
29 var CURRENCIES = Object.keys(USD_RATES).map(function(k) { return { value: k, label: k + '' + getCurrencyName(k) }; });
30
31 function getCurrencyName(code) {
32 var names = { USD:'US Dollar',EUR:'Euro',GBP:'British Pound',JPY:'Japanese Yen',CAD:'Canadian Dollar',AUD:'Australian Dollar',CHF:'Swiss Franc',CNY:'Chinese Yuan',INR:'Indian Rupee',MXN:'Mexican Peso',BRL:'Brazilian Real',KRW:'South Korean Won',SGD:'Singapore Dollar',HKD:'Hong Kong Dollar',NOK:'Norwegian Krone',SEK:'Swedish Krona',DKK:'Danish Krone',NZD:'New Zealand Dollar',ZAR:'South African Rand',TRY:'Turkish Lira',RUB:'Russian Ruble',PLN:'Polish Zloty',THB:'Thai Baht',MYR:'Malaysian Ringgit',IDR:'Indonesian Rupiah',PHP:'Philippine Peso',AED:'UAE Dirham',SAR:'Saudi Riyal',EGP:'Egyptian Pound',NGN:'Nigerian Naira' };
33 return names[code] || code;
34 }
35
36 function convert(amount, from, to) {
37 if (!USD_RATES[from] || !USD_RATES[to]) return 0;
38 var usd = amount / USD_RATES[from];
39 return usd * USD_RATES[to];
40 }
41
42 function fmtResult(val) {
43 if (isNaN(val)) return '';
44 if (val >= 1000) return val.toLocaleString('en-US', { maximumFractionDigits: 2 });
45 return val.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 4 });
46 }
47
48 /* ── Preview component ────────────────────────────────────────────────── */
49 function ConverterPreview(props) {
50 var a = props.attrs;
51 var accent = a.accentColor || '#6c3fb5';
52 var cRadius = (a.cardRadius || 16) + 'px';
53 var btnR = (a.btnRadius || 8) + 'px';
54
55 var fromState = useState(a.defaultFrom || 'USD');
56 var from = fromState[0]; var setFrom = fromState[1];
57 var toState = useState(a.defaultTo || 'EUR');
58 var to = toState[0]; var setTo = toState[1];
59 var amtState = useState(a.defaultAmount || 100);
60 var amount = amtState[0]; var setAmount = amtState[1];
61
62 var result = convert(amount, from, to);
63 var rate = convert(1, from, to);
64
65 var quickPairs = a.quickPairs || [['USD','EUR'],['USD','GBP'],['USD','JPY']];
66
67 var cardStyle = {
68 background: a.cardBg || '#ffffff',
69 borderRadius: cRadius,
70 padding: '32px',
71 boxShadow: '0 4px 24px rgba(0,0,0,0.08)',
72 maxWidth: (a.maxWidth || 580) + 'px',
73 margin: '0 auto',
74 paddingTop: (a.paddingTop || 60) + 'px',
75 paddingBottom: (a.paddingBottom|| 60) + 'px',
76 boxSizing: 'border-box',
77 };
78
79 var wrapStyle = Object.assign({},
80 cardStyle,
81 { '--bkbg-cc-ttl-fs': (a.titleSize || 26) + 'px', '--bkbg-cc-res-fs': (a.resultSize || 40) + 'px' },
82 _tv(a.typoTitle, '--bkbg-cc-ttl-'),
83 _tv(a.typoResult, '--bkbg-cc-res-')
84 );
85
86 return el('div', { style: wrapStyle },
87 a.showTitle && el('h2', { className: 'bkbg-cc-title', style: { color: a.titleColor || '#1e1b4b', textAlign: 'center', marginTop: 0, marginBottom: 8 } }, a.title || __('Currency Converter', 'blockenberg')),
88 a.showSubtitle && el('p', { style: { color: a.subtitleColor || '#6b7280', textAlign: 'center', marginTop: 0, marginBottom: 24 } }, a.subtitle),
89
90 /* Quick pairs */
91 a.showQuickPairs && quickPairs && el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '20px', justifyContent: 'center' } },
92 quickPairs.map(function(pair, i) {
93 return el('button', {
94 key: i,
95 onClick: function() { setFrom(pair[0]); setTo(pair[1]); },
96 style: {
97 padding: '5px 12px', borderRadius: '99px', border: 'none', cursor: 'pointer',
98 fontSize: '12px', fontWeight: 600,
99 background: (from === pair[0] && to === pair[1]) ? accent : (a.quickPairBg || '#f3f4f6'),
100 color: (from === pair[0] && to === pair[1]) ? '#fff' : (a.quickPairColor || '#374151'),
101 }
102 }, pair[0] + '/' + pair[1]);
103 })
104 ),
105
106 /* Amount + From/To */
107 el('div', { style: { display: 'grid', gridTemplateColumns: '1fr auto 1fr', gap: '12px', alignItems: 'end', marginBottom: '24px' } },
108 el('div', null,
109 el('label', { style: { display: 'block', fontSize: (a.labelFontSize || 12) + 'px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '4px' } }, __('Amount', 'blockenberg')),
110 el('input', {
111 type: 'number', value: amount, min: 0, step: 'any',
112 onChange: function(e) { setAmount(parseFloat(e.target.value) || 0); },
113 style: { width: '100%', padding: '10px 12px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '16px', boxSizing: 'border-box', outline: 'none' }
114 })
115 ),
116 a.showSwapBtn
117 ? el('button', {
118 onClick: function() { var tmp = from; setFrom(to); setTo(tmp); },
119 style: { background: 'none', border: '1.5px solid ' + accent, borderRadius: '8px', padding: '10px 12px', cursor: 'pointer', color: accent, fontWeight: 700, fontSize: '18px', lineHeight: 1 }
120 }, '')
121 : el('div', null, ''),
122 el('div', null,
123 el('label', { style: { display: 'block', fontSize: (a.labelFontSize || 12) + 'px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '4px' } }, __('To', 'blockenberg')),
124 el('select', {
125 value: to, onChange: function(e) { setTo(e.target.value); },
126 style: { width: '100%', padding: '10px 12px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '14px', background: '#fff' }
127 }, CURRENCIES.map(function(c) { return el('option', { key: c.value, value: c.value }, c.label); }))
128 )
129 ),
130
131 /* From select — full width */
132 el('div', { style: { marginBottom: '20px' } },
133 el('label', { style: { display: 'block', fontSize: (a.labelFontSize || 12) + 'px', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '4px' } }, __('From Currency', 'blockenberg')),
134 el('select', {
135 value: from, onChange: function(e) { setFrom(e.target.value); },
136 style: { width: '100%', padding: '10px 12px', borderRadius: '8px', border: '1.5px solid #e5e7eb', fontSize: '14px', background: '#fff' }
137 }, CURRENCIES.map(function(c) { return el('option', { key: c.value, value: c.value }, c.label); }))
138 ),
139
140 /* Result */
141 el('div', {
142 style: {
143 background: a.resultBg || '#f5f3ff',
144 border: '1.5px solid ' + (a.resultBorder || '#ede9fe'),
145 borderRadius: cRadius,
146 padding: '24px',
147 textAlign: 'center',
148 marginBottom: '12px',
149 }
150 },
151 el('div', { style: { fontSize: '13px', color: '#9ca3af', marginBottom: '6px' } },
152 amount + ' ' + from + ' equals'
153 ),
154 el('div', { className: 'bkbg-cc-result-num', style: { color: a.resultColor || accent } },
155 fmtResult(result) + ' ' + to
156 ),
157 el('div', { style: { fontSize: '13px', color: '#9ca3af', marginTop: '8px' } },
158 '1 ' + from + ' = ' + fmtResult(rate) + ' ' + to
159 )
160 ),
161
162 /* Disclaimer */
163 a.showDisclaimer && el('p', { style: { margin: 0, color: '#9ca3af', fontSize: '12px', textAlign: 'center' } }, a.disclaimer)
164 );
165 }
166
167 registerBlockType('blockenberg/currency-converter', {
168 edit: function(props) {
169 var a = props.attributes;
170 var setAttr = props.setAttributes;
171 var blockProps = useBlockProps({ style: { background: a.bgColor || undefined } });
172
173 return el(Fragment, null,
174 el(InspectorControls, null,
175
176 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
177 el(ToggleControl, { label: __('Show Title', 'blockenberg'), checked: a.showTitle, onChange: function(v) { setAttr({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
178 a.showTitle && el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: function(v) { setAttr({ title: v }); } }),
179 el(ToggleControl, { label: __('Show Subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function(v) { setAttr({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
180 a.showSubtitle && el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: function(v) { setAttr({ subtitle: v }); } })
181 ),
182
183 el(PanelBody, { title: __('Defaults', 'blockenberg'), initialOpen: false },
184 el(SelectControl, { label: __('Default From Currency', 'blockenberg'), value: a.defaultFrom, options: CURRENCIES, onChange: function(v) { setAttr({ defaultFrom: v }); } }),
185 el(SelectControl, { label: __('Default To Currency', 'blockenberg'), value: a.defaultTo, options: CURRENCIES, onChange: function(v) { setAttr({ defaultTo: v }); } }),
186 el(RangeControl, { label: __('Default Amount', 'blockenberg'), value: a.defaultAmount, min: 1, max: 100000, onChange: function(v) { setAttr({ defaultAmount: v }); } })
187 ),
188
189 el(PanelBody, { title: __('Display Options', 'blockenberg'), initialOpen: false },
190 el(ToggleControl, { label: __('Show Swap Button', 'blockenberg'), checked: a.showSwapBtn, onChange: function(v) { setAttr({ showSwapBtn: v }); }, __nextHasNoMarginBottom: true }),
191 el(ToggleControl, { label: __('Show Quick Pair Buttons', 'blockenberg'), checked: a.showQuickPairs, onChange: function(v) { setAttr({ showQuickPairs: v }); }, __nextHasNoMarginBottom: true }),
192 el(ToggleControl, { label: __('Show Disclaimer', 'blockenberg'), checked: a.showDisclaimer, onChange: function(v) { setAttr({ showDisclaimer: v }); }, __nextHasNoMarginBottom: true }),
193 a.showDisclaimer && el(TextareaControl, { label: __('Disclaimer Text', 'blockenberg'), value: a.disclaimer, onChange: function(v) { setAttr({ disclaimer: v }); } })
194 ),
195
196
197 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
198 _tc() && el(_tc(), { label: __('Title', 'blockenberg'), typo: a.typoTitle || {}, onChange: function(v) { setAttr({ typoTitle: v }); } }),
199 _tc() && el(_tc(), { label: __('Result Number', 'blockenberg'), typo: a.typoResult || {}, onChange: function(v) { setAttr({ typoResult: v }); } }),
200 el(RangeControl, { label: __('Label font size (px)', 'blockenberg'), value: a.labelFontSize, min: 10, max: 18, onChange: function(v) { setAttr({ labelFontSize: v }); }, __nextHasNoMarginBottom: true })
201 ),
202 el(PanelColorSettings, {
203 title: __('Colors', 'blockenberg'), initialOpen: false,
204 colorSettings: [
205 { label: __('Accent Color', 'blockenberg'), value: a.accentColor, onChange: function(v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
206 { label: __('Result Number Color', 'blockenberg'), value: a.resultColor, onChange: function(v) { setAttr({ resultColor: v || '#6c3fb5' }); } },
207 { label: __('Quick Pair Background', 'blockenberg'), value: a.quickPairBg, onChange: function(v) { setAttr({ quickPairBg: v || '#f3f4f6' }); } },
208 { label: __('Result Background', 'blockenberg'), value: a.resultBg, onChange: function(v) { setAttr({ resultBg: v || '#f5f3ff' }); } },
209 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function(v) { setAttr({ cardBg: v || '#ffffff' }); } },
210 { label: __('Section Background', 'blockenberg'), value: a.bgColor, onChange: function(v) { setAttr({ bgColor: v || '' }); } },
211 ]
212 }),
213
214 el(PanelBody, { title: __('Sizing', 'blockenberg'), initialOpen: false },
215 el(RangeControl, { label: __('Card Radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 40, onChange: function(v) { setAttr({ cardRadius: v }); } }),
216 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 320, max: 1200, onChange: function(v) { setAttr({ maxWidth: v }); } }),
217 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 160, onChange: function(v) { setAttr({ paddingTop: v }); } }),
218 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 160, onChange: function(v) { setAttr({ paddingBottom: v }); } })
219 )
220 ),
221
222 el('div', blockProps,
223 el(ConverterPreview, { attrs: a })
224 )
225 );
226 },
227
228 save: function(props) {
229 var a = props.attributes;
230 var blockProps = wp.blockEditor.useBlockProps.save({ style: { background: a.bgColor || undefined } });
231 return el('div', blockProps,
232 el('div', { className: 'bkbg-cc-app', 'data-opts': JSON.stringify(a) },
233 el('p', { className: 'bkbg-cc-loading' }, 'Loading currency converter…')
234 )
235 );
236 }
237 });
238 }() );
239