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

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

151 lines 11.4 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 TextControl = wp.components.TextControl;
12 var RangeControl = wp.components.RangeControl;
13 var ToggleControl = wp.components.ToggleControl;
14 var SelectControl = wp.components.SelectControl;
15
16 var _exptTC, _exptTV;
17 function _tc() { return _exptTC || (_exptTC = window.bkbgTypographyControl); }
18 function _tv(t, p) { return (_exptTV || (_exptTV = window.bkbgTypoCssVars)) ? _exptTV(t, p) : {}; }
19
20 var CATS = ['Housing','Food','Transport','Entertainment','Health','Shopping','Utilities','Other'];
21 var CAT_COLORS = ['#6366f1','#f59e0b','#10b981','#ec4899','#ef4444','#3b82f6','#14b8a6','#8b5cf6'];
22
23 registerBlockType('blockenberg/expense-tracker', {
24 edit: function (props) {
25 var a = props.attributes;
26 var set = props.setAttributes;
27 var blockProps = useBlockProps({ className: 'bkbg-expt-root', style: Object.assign({},
28 _tv(a.typoTitle || {}, '--bkbg-expt-ttl-'),
29 _tv(a.typoSubtitle || {}, '--bkbg-expt-sub-')
30 ) });
31
32 var previewExpenses = [
33 { id: 1, name: 'Rent', amount: 800, category: 'Housing', date: '2024-01-01' },
34 { id: 2, name: 'Groceries', amount: 120, category: 'Food', date: '2024-01-03' },
35 { id: 3, name: 'Bus Pass', amount: 45, category: 'Transport', date: '2024-01-05' },
36 { id: 4, name: 'Netflix', amount: 15, category: 'Entertainment', date: '2024-01-06' }
37 ];
38 var total = previewExpenses.reduce(function (s, e) { return s + e.amount; }, 0);
39 var catTotals = {};
40 previewExpenses.forEach(function (e) {
41 catTotals[e.category] = (catTotals[e.category] || 0) + e.amount;
42 });
43
44 function previewBlock() {
45 return el('div', { style: { background: a.sectionBg, padding: '24px', borderRadius: '12px', maxWidth: a.contentMaxWidth + 'px', fontFamily: 'system-ui,sans-serif' } },
46 a.showTitle && el('h2', { className: 'bkbg-expt-title', style: { margin: '0 0 4px', color: a.titleColor } }, a.title),
47 a.showSubtitle && el('p', { className: 'bkbg-expt-subtitle', style: { margin: '0 0 20px', color: a.subtitleColor } }, a.subtitle),
48
49 /* Summary cards */
50 el('div', { style: { display: 'flex', gap: '12px', marginBottom: '20px', flexWrap: 'wrap' } },
51 el('div', { style: { background: a.cardBg, borderRadius: '8px', padding: '14px 18px', flex: '1', minWidth: '120px', border: '1px solid ' + a.borderColor } },
52 el('div', { style: { color: a.accentColor, fontSize: '22px', fontWeight: 700 } }, a.currency + total.toFixed(2)),
53 el('div', { style: { color: a.subtitleColor, fontSize: '12px', marginTop: '2px' } }, 'Total Spent')
54 ),
55 a.showBudget && el('div', { style: { background: a.cardBg, borderRadius: '8px', padding: '14px 18px', flex: '1', minWidth: '120px', border: '1px solid ' + a.borderColor } },
56 el('div', { style: { color: total > a.defaultBudget ? a.dangerColor : a.labelColor, fontSize: '22px', fontWeight: 700 } }, a.currency + (a.defaultBudget - total).toFixed(2)),
57 el('div', { style: { color: a.subtitleColor, fontSize: '12px', marginTop: '2px' } }, 'Remaining Budget')
58 )
59 ),
60
61 /* Chart preview */
62 a.showChart && el('div', { style: { background: a.cardBg, borderRadius: '8px', padding: '16px', marginBottom: '16px', border: '1px solid ' + a.borderColor } },
63 el('div', { style: { fontWeight: 600, color: a.labelColor, marginBottom: '12px' } }, 'By Category'),
64 el('div', { style: { display: 'flex', flexDirection: 'column', gap: '8px' } },
65 Object.keys(catTotals).map(function (cat, i) {
66 var pct = Math.round((catTotals[cat] / total) * 100);
67 return el('div', { key: cat },
68 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '13px', marginBottom: '3px', color: a.labelColor } },
69 el('span', null, cat),
70 el('span', null, a.currency + catTotals[cat].toFixed(2))
71 ),
72 el('div', { style: { height: '8px', background: '#e5e7eb', borderRadius: '4px', overflow: 'hidden' } },
73 el('div', { style: { height: '100%', width: pct + '%', background: CAT_COLORS[CATS.indexOf(cat) % CAT_COLORS.length], borderRadius: '4px', transition: 'width 0.4s' } })
74 )
75 );
76 })
77 )
78 ),
79
80 /* Expense list preview */
81 el('div', { style: { background: a.cardBg, borderRadius: '8px', border: '1px solid ' + a.borderColor, overflow: 'hidden' } },
82 previewExpenses.map(function (exp) {
83 var catIdx = CATS.indexOf(exp.category);
84 var catColor = CAT_COLORS[catIdx % CAT_COLORS.length] || a.accentColor;
85 return el('div', { key: exp.id, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px', borderBottom: '1px solid ' + a.borderColor, fontSize: '14px' } },
86 el('div', { style: { display: 'flex', alignItems: 'center', gap: '10px' } },
87 el('div', { style: { width: '8px', height: '8px', borderRadius: '50%', background: catColor, flexShrink: 0 } }),
88 el('div', null,
89 el('div', { style: { color: a.labelColor, fontWeight: 500 } }, exp.name),
90 el('div', { style: { color: a.subtitleColor, fontSize: '12px' } }, exp.category + ' · ' + exp.date)
91 )
92 ),
93 el('div', { style: { color: a.labelColor, fontWeight: 600 } }, a.currency + exp.amount.toFixed(2))
94 );
95 })
96 )
97 );
98 }
99
100 return el(Fragment, null,
101 el(InspectorControls, null,
102 el(PanelBody, { title: 'Content', initialOpen: true },
103 el(TextControl, { label: 'Title', value: a.title, onChange: function (v) { set({ title: v }); }, __nextHasNoMarginBottom: true }),
104 el('div', { style: { marginBottom: '16px' } }),
105 el(TextControl, { label: 'Subtitle', value: a.subtitle, onChange: function (v) { set({ subtitle: v }); }, __nextHasNoMarginBottom: true }),
106 el('div', { style: { marginBottom: '16px' } }),
107 el(ToggleControl, { label: 'Show Title', checked: a.showTitle, onChange: function (v) { set({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
108 el(ToggleControl, { label: 'Show Subtitle', checked: a.showSubtitle, onChange: function (v) { set({ showSubtitle: v }); }, __nextHasNoMarginBottom: true })
109 ),
110 el(PanelBody, { title: 'Settings', initialOpen: false },
111 el(SelectControl, { label: 'Currency Symbol', value: a.currency, options: [{ label: 'USD ($)', value: '$' }, { label: 'EUR (€)', value: '' }, { label: 'GBP (£)', value: '£' }, { label: 'JPY (¥)', value: '¥' }, { label: 'RUB (₽)', value: '' }], onChange: function (v) { set({ currency: v }); }, __nextHasNoMarginBottom: true }),
112 el('div', { style: { marginBottom: '16px' } }),
113 el(ToggleControl, { label: 'Show Budget', checked: a.showBudget, onChange: function (v) { set({ showBudget: v }); }, __nextHasNoMarginBottom: true }),
114 a.showBudget && el(RangeControl, { label: 'Default Monthly Budget', value: a.defaultBudget, min: 100, max: 100000, step: 50, onChange: function (v) { set({ defaultBudget: v }); }, __nextHasNoMarginBottom: true }),
115 el('div', { style: { marginBottom: '16px' } }),
116 el(ToggleControl, { label: 'Show Category Chart', checked: a.showChart, onChange: function (v) { set({ showChart: v }); }, __nextHasNoMarginBottom: true }),
117 el('div', { style: { marginBottom: '16px' } }),
118 el(RangeControl, { label: 'Max Width (px)', value: a.contentMaxWidth, min: 400, max: 1200, step: 10, onChange: function (v) { set({ contentMaxWidth: v }); }, __nextHasNoMarginBottom: true })
119 ),
120 el(PanelBody, { title: 'Typography', initialOpen: false },
121 _tc() && el(_tc(), { label: 'Title', typo: a.typoTitle || {}, onChange: function (v) { set({ typoTitle: v }); } }),
122 _tc() && el(_tc(), { label: 'Subtitle', typo: a.typoSubtitle || {}, onChange: function (v) { set({ typoSubtitle: v }); } })
123 ),
124 el(PanelColorSettings, {
125 title: 'Colors',
126 initialOpen: false,
127 colorSettings: [
128 { label: 'Accent Color', value: a.accentColor, onChange: function (v) { set({ accentColor: v || '#10b981' }); } },
129 { label: 'Danger / Over-Budget', value: a.dangerColor, onChange: function (v) { set({ dangerColor: v || '#ef4444' }); } },
130 { label: 'Section Background', value: a.sectionBg, onChange: function (v) { set({ sectionBg: v || '#f0fdf4' }); } },
131 { label: 'Card Background', value: a.cardBg, onChange: function (v) { set({ cardBg: v || '#ffffff' }); } },
132 { label: 'Title Color', value: a.titleColor, onChange: function (v) { set({ titleColor: v || '#064e3b' }); } },
133 { label: 'Label Color', value: a.labelColor, onChange: function (v) { set({ labelColor: v || '#374151' }); } },
134 { label: 'Subtitle Color', value: a.subtitleColor, onChange: function (v) { set({ subtitleColor: v || '#6b7280' }); } },
135 { label: 'Border Color', value: a.borderColor, onChange: function (v) { set({ borderColor: v || '#d1fae5' }); } }
136 ]
137 })
138 ),
139 el('div', blockProps, previewBlock())
140 );
141 },
142 save: function (props) {
143 var a = props.attributes;
144 var useBlockProps = wp.blockEditor.useBlockProps;
145 return el('div', useBlockProps.save(),
146 el('div', { className: 'bkbg-expt-app', 'data-opts': JSON.stringify(a) })
147 );
148 }
149 });
150 }() );
151