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

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

235 lines 15.7 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
8 function getTypographyControl() {
9 return (window.bkbgTypographyControl || function () { return null; });
10 }
11
12 function _tv(typo, prefix) {
13 if (!typo) return {};
14 var s = {};
15 if (typo.family) s[prefix + 'font-family'] = "'" + typo.family + "', sans-serif";
16 if (typo.weight) s[prefix + 'font-weight'] = typo.weight;
17 if (typo.transform) s[prefix + 'text-transform'] = typo.transform;
18 if (typo.style) s[prefix + 'font-style'] = typo.style;
19 if (typo.decoration) s[prefix + 'text-decoration'] = typo.decoration;
20 var su = typo.sizeUnit || 'px';
21 if (typo.sizeDesktop !== '' && typo.sizeDesktop != null) s[prefix + 'font-size-d'] = typo.sizeDesktop + su;
22 if (typo.sizeTablet !== '' && typo.sizeTablet != null) s[prefix + 'font-size-t'] = typo.sizeTablet + su;
23 if (typo.sizeMobile !== '' && typo.sizeMobile != null) s[prefix + 'font-size-m'] = typo.sizeMobile + su;
24 var lhu = typo.lineHeightUnit || '';
25 if (typo.lineHeightDesktop !== '' && typo.lineHeightDesktop != null) s[prefix + 'line-height-d'] = typo.lineHeightDesktop + lhu;
26 if (typo.lineHeightTablet !== '' && typo.lineHeightTablet != null) s[prefix + 'line-height-t'] = typo.lineHeightTablet + lhu;
27 if (typo.lineHeightMobile !== '' && typo.lineHeightMobile != null) s[prefix + 'line-height-m'] = typo.lineHeightMobile + lhu;
28 var lsu = typo.letterSpacingUnit || 'px';
29 if (typo.letterSpacingDesktop !== '' && typo.letterSpacingDesktop != null) s[prefix + 'letter-spacing-d'] = typo.letterSpacingDesktop + lsu;
30 if (typo.letterSpacingTablet !== '' && typo.letterSpacingTablet != null) s[prefix + 'letter-spacing-t'] = typo.letterSpacingTablet + lsu;
31 if (typo.letterSpacingMobile !== '' && typo.letterSpacingMobile != null) s[prefix + 'letter-spacing-m'] = typo.letterSpacingMobile + lsu;
32 var wsu = typo.wordSpacingUnit || 'px';
33 if (typo.wordSpacingDesktop !== '' && typo.wordSpacingDesktop != null) s[prefix + 'word-spacing-d'] = typo.wordSpacingDesktop + wsu;
34 if (typo.wordSpacingTablet !== '' && typo.wordSpacingTablet != null) s[prefix + 'word-spacing-t'] = typo.wordSpacingTablet + wsu;
35 if (typo.wordSpacingMobile !== '' && typo.wordSpacingMobile != null) s[prefix + 'word-spacing-m'] = typo.wordSpacingMobile + wsu;
36 return s;
37 }
38
39 var InspectorControls = wp.blockEditor.InspectorControls;
40 var PanelColorSettings = wp.blockEditor.PanelColorSettings;
41 var useBlockProps = wp.blockEditor.useBlockProps;
42 var RichText = wp.blockEditor.RichText;
43 var PanelBody = wp.components.PanelBody;
44 var RangeControl = wp.components.RangeControl;
45 var SelectControl = wp.components.SelectControl;
46 var TextControl = wp.components.TextControl;
47 var ToggleControl = wp.components.ToggleControl;
48
49 var DEFAULT_CATEGORIES = [
50 { name:'Housing', amount:1200, icon:'🏠' },
51 { name:'Food', amount:400, icon:'🍔' },
52 { name:'Transport', amount:250, icon:'🚗' },
53 { name:'Utilities', amount:150, icon:'💡' },
54 { name:'Healthcare', amount:100, icon:'🏥' },
55 { name:'Entertainment',amount:200, icon:'🎬' }
56 ];
57
58 function EditorPreview(props) {
59 var a = props.attributes;
60 var cur = a.currency;
61
62 var totalExpenses = DEFAULT_CATEGORIES.reduce(function(s,c){ return s+c.amount; }, 0);
63 var totalIncome = a.defaultIncome;
64 var savings = a.showSavingsGoal ? a.defaultSavings : 0;
65 var surplus = totalIncome - totalExpenses - savings;
66 var surplusColor = surplus >= 0 ? a.surplusColor : a.expenseColor;
67
68 var wrapStyle = {
69 background: a.sectionBg, borderRadius:'14px', padding:'32px 24px',
70 maxWidth: a.contentMaxWidth+'px', margin:'0 auto', fontFamily:'inherit', boxSizing:'border-box'
71 };
72 var cardStyle = {
73 background:a.cardBg, borderRadius:'12px', padding:'16px 18px',
74 border:'1.5px solid #e5e7eb', marginBottom:'12px'
75 };
76
77 // Summary cards
78 var summaryCards = [
79 { label:'Total Income', value: cur+totalIncome.toLocaleString(), color: a.accentColor },
80 { label:'Total Expenses', value: cur+totalExpenses.toLocaleString(), color: a.expenseColor },
81 { label:'Savings Goal', value: cur+(a.defaultSavings||0).toLocaleString(), color: a.savingsColor, hide: !a.showSavingsGoal },
82 { label:'Surplus / Deficit', value: (surplus>=0?'+':'')+cur+Math.abs(surplus).toLocaleString(), color: surplusColor }
83 ].filter(function(c){ return !c.hide; });
84
85 // Balance bar
86 var expPct = totalIncome > 0 ? Math.min(100, (totalExpenses/totalIncome)*100) : 0;
87 var savPct = totalIncome > 0 ? Math.min(100-expPct, (savings/totalIncome)*100) : 0;
88 var surPct = 100 - expPct - savPct;
89
90 return el('div', { style: wrapStyle },
91 el(RichText, { tagName:'h3', className:'bkbg-bp-title', value:a.title, onChange:function(v){ props.setAttributes({title:v}); },
92 style:{ color:a.titleColor, margin:'0 0 6px 0' }, placeholder:'Block title...' }),
93 el(RichText, { tagName:'p', className:'bkbg-bp-subtitle', value:a.subtitle, onChange:function(v){ props.setAttributes({subtitle:v}); },
94 style:{ color:a.subtitleColor, margin:'0 0 24px 0' }, placeholder:'Subtitle...' }),
95
96 // Income row
97 el('div', { style: Object.assign({}, cardStyle, { display:'flex', alignItems:'center', gap:'16px' }) },
98 el('span', { style:{ fontSize:'22px' } }, '💰'),
99 el('div', { style:{ flex:1 } },
100 el('div', { style:{ fontSize:'12px', fontWeight:'600', color:'#6b7280', textTransform:'uppercase', letterSpacing:'0.06em' } }, 'Monthly Income'),
101 el('div', { style:{ fontSize:'22px', fontWeight:'700', color:a.accentColor } }, cur + Number(a.defaultIncome).toLocaleString())
102 ),
103 el('input', { type:'number', readOnly:true, value:a.defaultIncome,
104 style:{ width:'120px', border:'1.5px solid #e5e7eb', borderRadius:'8px', padding:'8px 12px', fontSize:'15px', background:a.inputBg, color:a.labelColor } })
105 ),
106
107 // Expense categories
108 el('div', { style:{ marginBottom:'16px' } },
109 el('div', { style:{ fontSize:'13px', fontWeight:'700', color:a.labelColor, textTransform:'uppercase', letterSpacing:'0.06em', marginBottom:'10px' } }, 'Expense Categories'),
110 DEFAULT_CATEGORIES.map(function(cat) {
111 return el('div', { key:cat.name, style:{ display:'flex', alignItems:'center', gap:'12px', padding:'10px 14px', background:a.cardBg, borderRadius:'9px', marginBottom:'7px', border:'1.5px solid #f3f4f6' } },
112 el('span', { style:{ fontSize:'18px', minWidth:'26px' } }, cat.icon),
113 el('span', { style:{ flex:1, fontSize:'14px', fontWeight:'500', color:a.labelColor } }, cat.name),
114 el('span', { style:{ fontSize:'14px', fontWeight:'700', color:a.expenseColor } }, cur + cat.amount.toLocaleString())
115 );
116 })
117 ),
118
119 // Savings goal
120 a.showSavingsGoal && el('div', { style: Object.assign({}, cardStyle, { display:'flex', alignItems:'center', gap:'16px', borderColor:'#e9d5ff' }) },
121 el('span', { style:{ fontSize:'22px' } }, '🎯'),
122 el('div', { style:{ flex:1 } },
123 el('div', { style:{ fontSize:'12px', fontWeight:'600', textTransform:'uppercase', letterSpacing:'0.06em', color:'#6b7280' } }, 'Savings Goal'),
124 el('div', { style:{ fontSize:'20px', fontWeight:'700', color:a.savingsColor } }, cur + (a.defaultSavings||0).toLocaleString())
125 )
126 ),
127
128 // Summary cards
129 el('div', { style:{ display:'grid', gridTemplateColumns:'repeat(auto-fit,minmax(140px,1fr))', gap:'10px', margin:'16px 0' } },
130 summaryCards.map(function(c) {
131 return el('div', { key:c.label, style:{ background:a.cardBg, borderRadius:'10px', padding:'12px 14px', borderLeft:'4px solid '+c.color } },
132 el('div', { style:{ fontSize:'11px', fontWeight:'600', color:'#6b7280', textTransform:'uppercase', letterSpacing:'0.05em', marginBottom:'4px' } }, c.label),
133 el('div', { style:{ fontSize:'18px', fontWeight:'700', color:c.color } }, c.value)
134 );
135 })
136 ),
137
138 // Balance bar
139 a.showPieBreakdown && el('div', { style:{ marginBottom:'8px' } },
140 el('div', { style:{ fontSize:'12px', fontWeight:'700', color:a.labelColor, marginBottom:'8px' } }, 'Income Allocation'),
141 el('div', { style:{ display:'flex', borderRadius:'999px', overflow:'hidden', height:'22px' } },
142 el('div', { style:{ width:expPct+'%', background:a.expenseColor, transition:'width 0.4s' }, title:'Expenses' }),
143 el('div', { style:{ width:savPct+'%', background:a.savingsColor, transition:'width 0.4s' }, title:'Savings' }),
144 el('div', { style:{ width:Math.max(0,surPct)+'%', background:a.surplusColor, transition:'width 0.4s' }, title:'Surplus' })
145 ),
146 el('div', { style:{ display:'flex', gap:'16px', marginTop:'6px', flexWrap:'wrap' } },
147 el('span', { style:{ fontSize:'12px', color:a.expenseColor, fontWeight:'600' } }, '● Expenses ' + Math.round(expPct)+'%'),
148 el('span', { style:{ fontSize:'12px', color:a.savingsColor, fontWeight:'600' } }, '● Savings ' + Math.round(savPct)+'%'),
149 el('span', { style:{ fontSize:'12px', color:a.surplusColor, fontWeight:'600' } }, '● Surplus ' + Math.max(0,Math.round(surPct))+'%')
150 )
151 )
152 );
153 }
154
155 registerBlockType('blockenberg/budget-planner', {
156 edit: function(props) {
157 var a = props.attributes;
158 var set = props.setAttributes;
159
160 var colorSettings = [
161 { value:a.accentColor, onChange:function(v){ set({accentColor: v||'#22c55e'}); }, label:'Income color' },
162 { value:a.expenseColor, onChange:function(v){ set({expenseColor: v||'#f43f5e'}); }, label:'Expense color' },
163 { value:a.savingsColor, onChange:function(v){ set({savingsColor: v||'#8b5cf6'}); }, label:'Savings color' },
164 { value:a.surplusColor, onChange:function(v){ set({surplusColor: v||'#0ea5e9'}); }, label:'Surplus color' },
165 { value:a.sectionBg, onChange:function(v){ set({sectionBg: v||'#f0fdf4'}); }, label:'Section background'},
166 { value:a.cardBg, onChange:function(v){ set({cardBg: v||'#ffffff'}); }, label:'Card background' },
167 { value:a.inputBg, onChange:function(v){ set({inputBg: v||'#f9fafb'}); }, label:'Input background' },
168 { value:a.titleColor, onChange:function(v){ set({titleColor: v||'#111827'}); }, label:'Title color' },
169 { value:a.subtitleColor, onChange:function(v){ set({subtitleColor: v||'#6b7280'}); }, label:'Subtitle color' },
170 { value:a.labelColor, onChange:function(v){ set({labelColor: v||'#374151'}); }, label:'Label color' }
171 ];
172
173 return el(Fragment, null,
174 el(InspectorControls, null,
175 el(PanelBody, { title:'Budget Settings', initialOpen:true },
176 el(TextControl, { label:'Currency Symbol', value:a.currency, onChange:function(v){ set({currency:v}); } }),
177 el(TextControl, { label:'Default Monthly Income ($)', type:'number', value:String(a.defaultIncome), onChange:function(v){ set({defaultIncome:parseFloat(v)||0}); } }),
178 el(TextControl, { label:'Default Savings Goal ($)', type:'number', value:String(a.defaultSavings), onChange:function(v){ set({defaultSavings:parseFloat(v)||0}); } })
179 ),
180 el(PanelBody, { title:'Display Options', initialOpen:false },
181 el(ToggleControl, { __nextHasNoMarginBottom:true, label:'Show Savings Goal row', checked:a.showSavingsGoal, onChange:function(v){ set({showSavingsGoal: v}); } }),
182 el(ToggleControl, { __nextHasNoMarginBottom:true, label:'Show allocation bar', checked:a.showPieBreakdown, onChange:function(v){ set({showPieBreakdown:v}); } }),
183 el(ToggleControl, { __nextHasNoMarginBottom:true, label:'Show budgeting tips', checked:a.showTips, onChange:function(v){ set({showTips: v}); } })
184 ),
185 el(PanelBody, { title:'Sizing', initialOpen:false },
186 el(RangeControl, { label:'Max Width (px)', value:a.contentMaxWidth, min:400, max:1200, step:20, onChange:function(v){ set({contentMaxWidth:v}); } })
187 ),
188
189 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
190 el(getTypographyControl(), { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function (v) { set({ typoTitle: v }); } }),
191 el(getTypographyControl(), { label: __('Subtitle', 'blockenberg'), value: a.typoSubtitle, onChange: function (v) { set({ typoSubtitle: v }); } })
192 ),
193 el(PanelColorSettings, { title:'Colors', initialOpen:false, disableCustomGradients:true, colorSettings:colorSettings })
194 ),
195 el('div', useBlockProps({ style: Object.assign({}, _tv(a.typoTitle, '--bkbg-bp-title-'), _tv(a.typoSubtitle, '--bkbg-bp-sub-')) }),
196 el(EditorPreview, { attributes:a, setAttributes:set })
197 )
198 );
199 },
200
201 save: function(props) {
202 var a = props.attributes;
203 return el('div', useBlockProps.save(),
204 el('div', {
205 className: 'bkbg-bp-app',
206 'data-opts': JSON.stringify({
207 title: a.title,
208 subtitle: a.subtitle,
209 currency: a.currency,
210 showSavingsGoal: a.showSavingsGoal,
211 showPieBreakdown:a.showPieBreakdown,
212 showTips: a.showTips,
213 defaultIncome: a.defaultIncome,
214 defaultSavings: a.defaultSavings,
215 accentColor: a.accentColor,
216 expenseColor: a.expenseColor,
217 savingsColor: a.savingsColor,
218 surplusColor: a.surplusColor,
219 sectionBg: a.sectionBg,
220 cardBg: a.cardBg,
221 inputBg: a.inputBg,
222 titleColor: a.titleColor,
223 subtitleColor: a.subtitleColor,
224 labelColor: a.labelColor,
225 titleFontSize: a.titleFontSize,
226 contentMaxWidth: a.contentMaxWidth,
227 typoTitle: a.typoTitle,
228 typoSubtitle: a.typoSubtitle
229 })
230 })
231 );
232 }
233 });
234 }() );
235