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

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

506 lines 34.3 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 Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var useEffect = wp.element.useEffect;
6 var useRef = wp.element.useRef;
7 var registerBlockType = wp.blocks.registerBlockType;
8 var __ = wp.i18n.__;
9 var InspectorControls = wp.blockEditor.InspectorControls;
10 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
11 var useBlockProps = wp.blockEditor.useBlockProps;
12 var RichText = wp.blockEditor.RichText;
13 var PanelBody = wp.components.PanelBody;
14 var RangeControl = wp.components.RangeControl;
15 var SelectControl = wp.components.SelectControl;
16 var TextControl = wp.components.TextControl;
17 var TextareaControl = wp.components.TextareaControl;
18 var ToggleControl = wp.components.ToggleControl;
19 var Button = wp.components.Button;
20
21 var _tc, _tv;
22 function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
23 function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
24
25 var CHART_CDN = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js';
26
27 function calcLoan(amount, annualRate, years) {
28 if (!amount || !annualRate || !years) return { monthly: 0, totalPayment: 0, totalInterest: 0 };
29 var r = annualRate / 1200;
30 var n = years * 12;
31 var monthly = amount * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
32 var totalPayment = monthly * n;
33 var totalInterest = totalPayment - amount;
34 return {
35 monthly: Math.round(monthly * 100) / 100,
36 totalPayment: Math.round(totalPayment * 100) / 100,
37 totalInterest: Math.round(totalInterest * 100) / 100
38 };
39 }
40
41 function formatMoney(val, currency, pos) {
42 var rounded = Math.round(val).toLocaleString('en-US');
43 return pos === 'after' ? rounded + currency : currency + rounded;
44 }
45
46 function buildAmortTable(amount, annualRate, years, rows) {
47 var r = annualRate / 1200;
48 var n = years * 12;
49 var monthly = amount * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
50 var balance = amount;
51 var result = [];
52 for (var i = 1; i <= n && i <= rows; i++) {
53 var interest = balance * r;
54 var principal = monthly - interest;
55 balance = balance - principal;
56 result.push({ month: i, payment: monthly, principal: principal, interest: interest, balance: Math.max(0, balance) });
57 }
58 return result;
59 }
60
61 // Editor live preview component
62 function LoanPreview(props) {
63 var a = props.attrs;
64 var chartRef = useRef(null);
65 var chartInstance = useRef(null);
66
67 var amount = a.loanAmountDefault || 300000;
68 var rate = a.interestDefault || 5.5;
69 var years = a.termDefault || 25;
70 var result = calcLoan(amount, rate, years);
71
72 function loadChartAndRender() {
73 if (typeof Chart !== 'undefined') {
74 renderChart();
75 return;
76 }
77 if (document.getElementById('bkbg-chartjs-cdn')) return;
78 var s = document.createElement('script');
79 s.id = 'bkbg-chartjs-cdn';
80 s.src = CHART_CDN;
81 s.onload = function () { renderChart(); };
82 document.head.appendChild(s);
83 }
84
85 function renderChart() {
86 if (!chartRef.current || typeof Chart === 'undefined') return;
87 if (chartInstance.current) { chartInstance.current.destroy(); }
88 chartInstance.current = new Chart(chartRef.current, {
89 type: 'doughnut',
90 data: {
91 labels: [__('Principal', 'blockenberg'), __('Interest', 'blockenberg')],
92 datasets: [{
93 data: [amount, result.totalInterest],
94 backgroundColor: [a.principalColor || '#6c3fb5', a.interestColor || '#f59e0b'],
95 borderWidth: 0
96 }]
97 },
98 options: {
99 cutout: '70%',
100 plugins: { legend: { position: 'bottom', labels: { padding: 16 } } },
101 animation: false
102 }
103 });
104 }
105
106 useEffect(function () {
107 if (a.showChart) loadChartAndRender();
108 return function () {
109 if (chartInstance.current) { chartInstance.current.destroy(); chartInstance.current = null; }
110 };
111 }, [a.showChart, a.loanAmountDefault, a.interestDefault, a.termDefault, a.principalColor, a.interestColor]);
112
113 var cardStyle = { background: a.cardBg || '#ffffff', border: '1px solid ' + (a.cardBorder || '#e5e7eb'), borderRadius: a.cardRadius + 'px', padding: '24px' };
114
115 return el('div', { className: 'bkbg-lc-inner', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } },
116
117 el('div', { className: 'bkbg-lc-sliders', style: cardStyle },
118 // Loan amount
119 el('div', { className: 'bkbg-lc-slider-group', style: { marginBottom: '24px' } },
120 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
121 el('label', { style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.loanLabel || __('Loan Amount', 'blockenberg')),
122 el('span', { style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, formatMoney(amount, a.currency || '$', a.currencyPos))
123 ),
124 el('input', {
125 type: 'range',
126 className: 'bkbg-lc-range',
127 min: a.loanAmountMin, max: a.loanAmountMax, step: a.loanAmountStep,
128 defaultValue: amount,
129 style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' },
130 readOnly: true
131 }),
132 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
133 el('span', null, formatMoney(a.loanAmountMin || 10000, a.currency || '$', a.currencyPos)),
134 el('span', null, formatMoney(a.loanAmountMax || 2000000, a.currency || '$', a.currencyPos))
135 )
136 ),
137
138 // Interest rate
139 el('div', { className: 'bkbg-lc-slider-group', style: { marginBottom: '24px' } },
140 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
141 el('label', { style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.interestLabel || __('Annual Interest Rate', 'blockenberg')),
142 el('span', { style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, rate + '%')
143 ),
144 el('input', {
145 type: 'range',
146 className: 'bkbg-lc-range',
147 min: a.interestMin, max: a.interestMax, step: a.interestStep,
148 defaultValue: rate,
149 style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' },
150 readOnly: true
151 }),
152 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
153 el('span', null, a.interestMin + '%'),
154 el('span', null, a.interestMax + '%')
155 )
156 ),
157
158 // Term
159 el('div', { className: 'bkbg-lc-slider-group' },
160 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
161 el('label', { style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.termLabel || __('Loan Term', 'blockenberg')),
162 el('span', { style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, years + ' ' + __('years', 'blockenberg'))
163 ),
164 el('input', {
165 type: 'range',
166 className: 'bkbg-lc-range',
167 min: a.termMin, max: a.termMax, step: a.termStep,
168 defaultValue: years,
169 style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' },
170 readOnly: true
171 }),
172 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
173 el('span', null, a.termMin + ' yr'),
174 el('span', null, a.termMax + ' yr')
175 )
176 )
177 ),
178
179 // Results
180 el('div', { className: 'bkbg-lc-results', style: { background: a.resultBg || '#f5f3ff', border: '1px solid ' + (a.resultBorder || '#ede9fe'), borderRadius: a.cardRadius + 'px', padding: '24px', marginTop: '16px', textAlign: 'center' } },
181 el('div', { style: { fontSize: '13px', color: '#6b7280', marginBottom: '4px', fontWeight: 500 } }, __('Monthly Payment', 'blockenberg')),
182 el('div', { className: 'bkbg-lc-monthly', style: { fontSize: a.monthlySize + 'px', fontWeight: 800, color: a.monthlyColor || '#6c3fb5', lineHeight: 1.1, marginBottom: '16px' } },
183 formatMoney(result.monthly, a.currency || '$', a.currencyPos)
184 ),
185 el('div', { style: { display: 'flex', justifyContent: 'center', gap: '32px', flexWrap: 'wrap' } },
186 el('div', { style: { textAlign: 'center' } },
187 el('div', { style: { fontSize: '20px', fontWeight: 700, color: a.principalColor || '#6c3fb5' } }, formatMoney(amount, a.currency || '$', a.currencyPos)),
188 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Principal', 'blockenberg'))
189 ),
190 el('div', { style: { textAlign: 'center' } },
191 el('div', { style: { fontSize: '20px', fontWeight: 700, color: a.interestColor || '#f59e0b' } }, formatMoney(result.totalInterest, a.currency || '$', a.currencyPos)),
192 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Total Interest', 'blockenberg'))
193 ),
194 el('div', { style: { textAlign: 'center' } },
195 el('div', { style: { fontSize: '20px', fontWeight: 700, color: '#374151' } }, formatMoney(result.totalPayment, a.currency || '$', a.currencyPos)),
196 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Total Payment', 'blockenberg'))
197 )
198 )
199 ),
200
201 a.showChart && el('div', { className: 'bkbg-lc-chart-wrap', style: { maxWidth: '280px', margin: '16px auto 0' } },
202 el('canvas', { ref: chartRef, width: 280, height: 280 })
203 ),
204
205 a.showCta && el('div', { style: { textAlign: 'center', marginTop: '24px' } },
206 el('a', {
207 href: a.ctaUrl || '#',
208 className: 'bkbg-lc-cta',
209 style: { display: 'inline-block', background: a.ctaBg || a.accentColor || '#6c3fb5', color: a.ctaColor || '#fff', borderRadius: a.btnRadius + 'px', padding: '12px 32px', fontWeight: 700, fontSize: '15px', textDecoration: 'none' }
210 }, a.ctaLabel || __('Apply Now', 'blockenberg'))
211 ),
212
213 a.showDisclaimer && a.disclaimer && el('p', {
214 style: { fontSize: '11px', color: '#9ca3af', textAlign: 'center', marginTop: '16px', lineHeight: 1.6 }
215 }, a.disclaimer)
216 );
217 }
218
219 registerBlockType('blockenberg/loan-calculator', {
220 edit: function (props) {
221 var attrs = props.attributes;
222 var setAttr = function (obj) { props.setAttributes(obj); };
223
224 var wrapStyle = { paddingTop: attrs.paddingTop + 'px', paddingBottom: attrs.paddingBottom + 'px' };
225 if (attrs.bgColor) wrapStyle.background = attrs.bgColor;
226
227 var blockProps = useBlockProps((function () {
228 var _tvFn = getTypoCssVars();
229 var s = Object.assign({}, wrapStyle);
230 if (_tvFn) {
231 Object.assign(s, _tvFn(attrs.titleTypo, '--bkbg-lcalc-tt-'));
232 Object.assign(s, _tvFn(attrs.subtitleTypo, '--bkbg-lcalc-st-'));
233 }
234 return { style: s };
235 })());
236
237 return el(Fragment, null,
238 el(InspectorControls, null,
239
240 el(PanelBody, { title: __('Loan Amount', 'blockenberg'), initialOpen: true },
241 el(TextControl, { label: __('Label', 'blockenberg'), value: attrs.loanLabel, onChange: function (v) { setAttr({ loanLabel: v }); } }),
242 el(RangeControl, { label: __('Default ($)', 'blockenberg'), value: attrs.loanAmountDefault, min: 1000, max: attrs.loanAmountMax, step: attrs.loanAmountStep, onChange: function (v) { setAttr({ loanAmountDefault: v }); } }),
243 el(RangeControl, { label: __('Minimum ($)', 'blockenberg'), value: attrs.loanAmountMin, min: 1000, max: 500000, step: 1000, onChange: function (v) { setAttr({ loanAmountMin: v }); } }),
244 el(RangeControl, { label: __('Maximum ($)', 'blockenberg'), value: attrs.loanAmountMax, min: 50000, max: 10000000, step: 10000, onChange: function (v) { setAttr({ loanAmountMax: v }); } }),
245 el(RangeControl, { label: __('Step ($)', 'blockenberg'), value: attrs.loanAmountStep, min: 100, max: 50000, step: 100, onChange: function (v) { setAttr({ loanAmountStep: v }); } })
246 ),
247
248 el(PanelBody, { title: __('Interest Rate', 'blockenberg'), initialOpen: false },
249 el(TextControl, { label: __('Label', 'blockenberg'), value: attrs.interestLabel, onChange: function (v) { setAttr({ interestLabel: v }); } }),
250 el(RangeControl, { label: __('Default (%)', 'blockenberg'), value: attrs.interestDefault, min: 0.1, max: attrs.interestMax, step: attrs.interestStep, onChange: function (v) { setAttr({ interestDefault: v }); } }),
251 el(RangeControl, { label: __('Minimum (%)', 'blockenberg'), value: attrs.interestMin, min: 0.1, max: 5, step: 0.1, onChange: function (v) { setAttr({ interestMin: v }); } }),
252 el(RangeControl, { label: __('Maximum (%)', 'blockenberg'), value: attrs.interestMax, min: 5, max: 30, step: 0.5, onChange: function (v) { setAttr({ interestMax: v }); } }),
253 el(RangeControl, { label: __('Step (%)', 'blockenberg'), value: attrs.interestStep, min: 0.05, max: 1, step: 0.05, onChange: function (v) { setAttr({ interestStep: v }); } })
254 ),
255
256 el(PanelBody, { title: __('Loan Term', 'blockenberg'), initialOpen: false },
257 el(TextControl, { label: __('Label', 'blockenberg'), value: attrs.termLabel, onChange: function (v) { setAttr({ termLabel: v }); } }),
258 el(RangeControl, { label: __('Default (years)', 'blockenberg'), value: attrs.termDefault, min: 1, max: attrs.termMax, step: 1, onChange: function (v) { setAttr({ termDefault: v }); } }),
259 el(RangeControl, { label: __('Minimum (years)', 'blockenberg'), value: attrs.termMin, min: 1, max: 10, step: 1, onChange: function (v) { setAttr({ termMin: v }); } }),
260 el(RangeControl, { label: __('Maximum (years)', 'blockenberg'), value: attrs.termMax, min: 5, max: 50, step: 1, onChange: function (v) { setAttr({ termMax: v }); } })
261 ),
262
263 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
264 el(SelectControl, {
265 label: __('Currency symbol', 'blockenberg'),
266 value: attrs.currency,
267 options: [
268 { label: '$ (Dollar)', value: '$' },
269 { label: '€ (Euro)', value: '' },
270 { label: '£ (Pound)', value: '£' },
271 { label: '¥ (Yen)', value: '¥' },
272 { label: 'A$ (AUD)', value: 'A$' },
273 { label: 'C$ (CAD)', value: 'C$' }
274 ],
275 onChange: function (v) { setAttr({ currency: v }); }
276 }),
277 el(SelectControl, {
278 label: __('Currency position', 'blockenberg'),
279 value: attrs.currencyPos,
280 options: [
281 { label: __('Before ($ 500)', 'blockenberg'), value: 'before' },
282 { label: __('After (500 $)', 'blockenberg'), value: 'after' }
283 ],
284 onChange: function (v) { setAttr({ currencyPos: v }); }
285 }),
286 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: attrs.maxWidth, min: 400, max: 1200, onChange: function (v) { setAttr({ maxWidth: v }); } }),
287 el(ToggleControl, { label: __('Show donut chart', 'blockenberg'), checked: attrs.showChart, onChange: function (v) { setAttr({ showChart: v }); }, __nextHasNoMarginBottom: true }),
288 el(ToggleControl, { label: __('Show amortization table', 'blockenberg'), checked: attrs.showAmortization, onChange: function (v) { setAttr({ showAmortization: v }); }, __nextHasNoMarginBottom: true }),
289 attrs.showAmortization && el(RangeControl, { label: __('Amortization rows', 'blockenberg'), value: attrs.amortizationRows, min: 3, max: 60, onChange: function (v) { setAttr({ amortizationRows: v }); } }),
290 el(ToggleControl, { label: __('Show CTA button', 'blockenberg'), checked: attrs.showCta, onChange: function (v) { setAttr({ showCta: v }); }, __nextHasNoMarginBottom: true }),
291 attrs.showCta && el(TextControl, { label: __('CTA label', 'blockenberg'), value: attrs.ctaLabel, onChange: function (v) { setAttr({ ctaLabel: v }); } }),
292 attrs.showCta && el(TextControl, { label: __('CTA URL', 'blockenberg'), value: attrs.ctaUrl, type: 'url', onChange: function (v) { setAttr({ ctaUrl: v }); } }),
293 attrs.showCta && el(ToggleControl, { label: __('Open in new tab', 'blockenberg'), checked: attrs.ctaNewTab, onChange: function (v) { setAttr({ ctaNewTab: v }); }, __nextHasNoMarginBottom: true }),
294 el(ToggleControl, { label: __('Show disclaimer', 'blockenberg'), checked: attrs.showDisclaimer, onChange: function (v) { setAttr({ showDisclaimer: v }); }, __nextHasNoMarginBottom: true }),
295 attrs.showDisclaimer && el(TextareaControl, { label: __('Disclaimer text', 'blockenberg'), value: attrs.disclaimer, rows: 3, onChange: function (v) { setAttr({ disclaimer: v }); } })
296 ),
297
298 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
299 getTypoControl() && el(getTypoControl(), { label: __('Title', 'blockenberg'), value: attrs.titleTypo || {}, onChange: function (v) { setAttr({ titleTypo: v }); } }),
300 getTypoControl() && el(getTypoControl(), { label: __('Subtitle', 'blockenberg'), value: attrs.subtitleTypo || {}, onChange: function (v) { setAttr({ subtitleTypo: v }); } }),
301 el(RangeControl, { label: __('Monthly payment size (px)', 'blockenberg'), value: attrs.monthlySize, min: 24, max: 80, onChange: function (v) { setAttr({ monthlySize: v }); } }),
302 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: attrs.cardRadius, min: 0, max: 32, onChange: function (v) { setAttr({ cardRadius: v }); } }),
303 el(RangeControl, { label: __('Button radius (px)', 'blockenberg'), value: attrs.btnRadius, min: 0, max: 32, onChange: function (v) { setAttr({ btnRadius: v }); } })
304 ),
305
306 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
307 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: attrs.paddingTop, min: 0, max: 200, onChange: function (v) { setAttr({ paddingTop: v }); } }),
308 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: attrs.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttr({ paddingBottom: v }); } })
309 ),
310
311 el(PanelColorSettings, {
312 title: __('Colors', 'blockenberg'), initialOpen: false,
313 colorSettings: [
314 { label: __('Accent', 'blockenberg'), value: attrs.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
315 { label: __('Principal color', 'blockenberg'), value: attrs.principalColor, onChange: function (v) { setAttr({ principalColor: v || '#6c3fb5' }); } },
316 { label: __('Interest color', 'blockenberg'), value: attrs.interestColor, onChange: function (v) { setAttr({ interestColor: v || '#f59e0b' }); } },
317 { label: __('Monthly payment', 'blockenberg'), value: attrs.monthlyColor, onChange: function (v) { setAttr({ monthlyColor: v || '#6c3fb5' }); } },
318 { label: __('Label text', 'blockenberg'), value: attrs.labelColor, onChange: function (v) { setAttr({ labelColor: v || '#374151' }); } },
319 { label: __('Card background', 'blockenberg'), value: attrs.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } },
320 { label: __('Card border', 'blockenberg'), value: attrs.cardBorder, onChange: function (v) { setAttr({ cardBorder: v || '#e5e7eb' }); } },
321 { label: __('Results background', 'blockenberg'), value: attrs.resultBg, onChange: function (v) { setAttr({ resultBg: v || '#f5f3ff' }); } },
322 { label: __('CTA background', 'blockenberg'), value: attrs.ctaBg, onChange: function (v) { setAttr({ ctaBg: v || '#6c3fb5' }); } },
323 { label: __('CTA text', 'blockenberg'), value: attrs.ctaColor, onChange: function (v) { setAttr({ ctaColor: v || '#ffffff' }); } },
324 { label: __('Block background', 'blockenberg'), value: attrs.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } }
325 ]
326 })
327 ),
328
329 el('div', blockProps,
330 attrs.showTitle && el(RichText, {
331 tagName: 'h2',
332 className: 'bkbg-lc-title',
333 style: { color: attrs.titleColor },
334 value: attrs.title,
335 onChange: function (v) { setAttr({ title: v }); },
336 placeholder: __('Loan Calculator…', 'blockenberg')
337 }),
338 attrs.showSubtitle && el(RichText, {
339 tagName: 'p',
340 className: 'bkbg-lc-subtitle',
341 style: { color: attrs.subtitleColor },
342 value: attrs.subtitle,
343 onChange: function (v) { setAttr({ subtitle: v }); },
344 placeholder: __('Subtitle…', 'blockenberg')
345 }),
346 el(LoanPreview, { attrs: attrs })
347 )
348 );
349 },
350
351 save: function (props) {
352 var a = props.attributes;
353 var opts = {
354 loanAmountDefault: a.loanAmountDefault,
355 loanAmountMin: a.loanAmountMin,
356 loanAmountMax: a.loanAmountMax,
357 loanAmountStep: a.loanAmountStep,
358 interestDefault: a.interestDefault,
359 interestMin: a.interestMin,
360 interestMax: a.interestMax,
361 interestStep: a.interestStep,
362 termDefault: a.termDefault,
363 termMin: a.termMin,
364 termMax: a.termMax,
365 termStep: a.termStep,
366 currency: a.currency,
367 currencyPos: a.currencyPos,
368 showChart: a.showChart,
369 showAmortization: a.showAmortization,
370 amortizationRows: a.amortizationRows,
371 showCta: a.showCta,
372 ctaLabel: a.ctaLabel,
373 ctaUrl: a.ctaUrl,
374 ctaNewTab: a.ctaNewTab,
375 showDisclaimer: a.showDisclaimer,
376 disclaimer: a.disclaimer,
377 loanLabel: a.loanLabel,
378 interestLabel: a.interestLabel,
379 termLabel: a.termLabel,
380 accentColor: a.accentColor,
381 principalColor: a.principalColor,
382 interestColor: a.interestColor,
383 monthlyColor: a.monthlyColor,
384 labelColor: a.labelColor,
385 cardBg: a.cardBg,
386 cardBorder: a.cardBorder,
387 resultBg: a.resultBg,
388 resultBorder: a.resultBorder,
389 ctaBg: a.ctaBg,
390 ctaColor: a.ctaColor,
391 cardRadius: a.cardRadius,
392 btnRadius: a.btnRadius,
393 maxWidth: a.maxWidth,
394 monthlySize: a.monthlySize
395 };
396
397 var wrapStyle = { paddingTop: a.paddingTop + 'px', paddingBottom: a.paddingBottom + 'px' };
398 if (a.bgColor) wrapStyle.background = a.bgColor;
399
400 var _tvFn = (typeof window.bkbgTypoCssVars !== 'undefined') ? window.bkbgTypoCssVars : null;
401 if (_tvFn) {
402 Object.assign(wrapStyle, _tvFn(a.titleTypo, '--bkbg-lcalc-tt-'));
403 Object.assign(wrapStyle, _tvFn(a.subtitleTypo, '--bkbg-lcalc-st-'));
404 }
405
406 var blockProps = wp.blockEditor.useBlockProps.save({ style: wrapStyle });
407
408 return el('div', blockProps,
409 a.showTitle && el('h2', {
410 className: 'bkbg-lc-title',
411 style: { color: a.titleColor },
412 dangerouslySetInnerHTML: { __html: a.title }
413 }),
414 a.showSubtitle && el('p', {
415 className: 'bkbg-lc-subtitle',
416 style: { color: a.subtitleColor },
417 dangerouslySetInnerHTML: { __html: a.subtitle }
418 }),
419 el('div', {
420 className: 'bkbg-lc-app',
421 'data-opts': JSON.stringify(opts),
422 style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' }
423 },
424 // Slider card placeholder
425 el('div', {
426 className: 'bkbg-lc-sliders',
427 style: { background: a.cardBg || '#ffffff', border: '1px solid ' + (a.cardBorder || '#e5e7eb'), borderRadius: a.cardRadius + 'px', padding: '24px' }
428 },
429 el('div', { className: 'bkbg-lc-slider-group', 'data-slider': 'amount', style: { marginBottom: '24px' } },
430 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
431 el('label', { className: 'bkbg-lc-slider-label', style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.loanLabel || __('Loan Amount', 'blockenberg')),
432 el('span', { className: 'bkbg-lc-slider-val', style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, '--')
433 ),
434 el('input', { type: 'range', className: 'bkbg-lc-range', style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' } }),
435 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
436 el('span', { className: 'bkbg-lc-range-min' }),
437 el('span', { className: 'bkbg-lc-range-max' })
438 )
439 ),
440 el('div', { className: 'bkbg-lc-slider-group', 'data-slider': 'interest', style: { marginBottom: '24px' } },
441 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
442 el('label', { className: 'bkbg-lc-slider-label', style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.interestLabel || __('Annual Interest Rate', 'blockenberg')),
443 el('span', { className: 'bkbg-lc-slider-val', style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, '--')
444 ),
445 el('input', { type: 'range', className: 'bkbg-lc-range', style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' } }),
446 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
447 el('span', { className: 'bkbg-lc-range-min' }),
448 el('span', { className: 'bkbg-lc-range-max' })
449 )
450 ),
451 el('div', { className: 'bkbg-lc-slider-group', 'data-slider': 'term' },
452 el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '8px' } },
453 el('label', { className: 'bkbg-lc-slider-label', style: { fontSize: '14px', fontWeight: 600, color: a.labelColor || '#374151' } }, a.termLabel || __('Loan Term', 'blockenberg')),
454 el('span', { className: 'bkbg-lc-slider-val', style: { fontSize: '20px', fontWeight: 700, color: a.accentColor || '#6c3fb5' } }, '--')
455 ),
456 el('input', { type: 'range', className: 'bkbg-lc-range', style: { width: '100%', accentColor: a.accentColor || '#6c3fb5' } }),
457 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '11px', color: '#9ca3af', marginTop: '4px' } },
458 el('span', { className: 'bkbg-lc-range-min' }),
459 el('span', { className: 'bkbg-lc-range-max' })
460 )
461 )
462 ),
463 // Results
464 el('div', {
465 className: 'bkbg-lc-results',
466 style: { background: a.resultBg || '#f5f3ff', border: '1px solid ' + (a.resultBorder || '#ede9fe'), borderRadius: a.cardRadius + 'px', padding: '24px', marginTop: '16px', textAlign: 'center' }
467 },
468 el('div', { style: { fontSize: '13px', color: '#6b7280', marginBottom: '4px', fontWeight: 500 } }, __('Monthly Payment', 'blockenberg')),
469 el('div', { className: 'bkbg-lc-monthly', style: { fontSize: a.monthlySize + 'px', fontWeight: 800, color: a.monthlyColor || '#6c3fb5', lineHeight: 1.1, marginBottom: '16px' } }, '--'),
470 el('div', { className: 'bkbg-lc-summary', style: { display: 'flex', justifyContent: 'center', gap: '32px', flexWrap: 'wrap' } },
471 el('div', { 'data-result': 'principal', style: { textAlign: 'center' } },
472 el('div', { className: 'bkbg-lc-res-val', style: { fontSize: '20px', fontWeight: 700, color: a.principalColor || '#6c3fb5' } }, '--'),
473 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Principal', 'blockenberg'))
474 ),
475 el('div', { 'data-result': 'interest', style: { textAlign: 'center' } },
476 el('div', { className: 'bkbg-lc-res-val', style: { fontSize: '20px', fontWeight: 700, color: a.interestColor || '#f59e0b' } }, '--'),
477 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Total Interest', 'blockenberg'))
478 ),
479 el('div', { 'data-result': 'total', style: { textAlign: 'center' } },
480 el('div', { className: 'bkbg-lc-res-val', style: { fontSize: '20px', fontWeight: 700, color: '#374151' } }, '--'),
481 el('div', { style: { fontSize: '11px', color: '#9ca3af' } }, __('Total Payment', 'blockenberg'))
482 )
483 )
484 ),
485 a.showChart && el('div', { className: 'bkbg-lc-chart-wrap', style: { maxWidth: '280px', margin: '16px auto 0' } },
486 el('canvas', { className: 'bkbg-lc-chart', width: 280, height: 280 })
487 ),
488 a.showAmortization && el('div', { className: 'bkbg-lc-amort-wrap', style: { marginTop: '24px', overflowX: 'auto' } }),
489 a.showCta && el('div', { style: { textAlign: 'center', marginTop: '24px' } },
490 el('a', {
491 href: a.ctaUrl || '#',
492 className: 'bkbg-lc-cta',
493 target: a.ctaNewTab ? '_blank' : undefined,
494 rel: a.ctaNewTab ? 'noopener noreferrer' : undefined,
495 style: { display: 'inline-block', background: a.ctaBg || a.accentColor || '#6c3fb5', color: a.ctaColor || '#fff', borderRadius: a.btnRadius + 'px', padding: '12px 32px', fontWeight: 700, fontSize: '15px', textDecoration: 'none' }
496 }, a.ctaLabel || 'Apply Now')
497 ),
498 a.showDisclaimer && a.disclaimer && el('p', {
499 style: { fontSize: '11px', color: '#9ca3af', textAlign: 'center', marginTop: '16px', lineHeight: 1.6 }
500 }, a.disclaimer)
501 )
502 );
503 }
504 });
505 }() );
506