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

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

203 lines 14.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 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
16 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
17 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
18 var _tvf = function (typo, prefix) { var fn = getTypoCssVars(); return fn ? fn(typo, prefix) : {}; };
19
20 function pad2(n) { return String(Math.abs(Math.floor(n))).padStart(2,'0'); }
21 function fmtHMS(totalSec) {
22 var neg = totalSec < 0;
23 var s = Math.abs(totalSec);
24 var h = Math.floor(s/3600); s -= h*3600;
25 var m = Math.floor(s/60); s -= m*60;
26 return (neg?'':'')+pad2(h)+':'+pad2(m)+':'+pad2(s);
27 }
28 function calcTotal(h,m,s){ return (parseInt(h)||0)*3600+(parseInt(m)||0)*60+(parseInt(s)||0); }
29
30 function TDCPreview(props) {
31 var a = props.attributes;
32 var accent = a.accentColor || '#6c3fb5';
33
34 var _op = useState(a.defaultOp||'add'); var op = _op[0]; var setOp = _op[1];
35 var _h1 = useState(a.defaultH1||1); var h1=_h1[0]; var setH1=_h1[1];
36 var _m1 = useState(a.defaultM1||30); var m1=_m1[0]; var setM1=_m1[1];
37 var _s1 = useState(a.defaultS1||0); var s1=_s1[0]; var setS1=_s1[1];
38 var _h2 = useState(a.defaultH2||0); var h2=_h2[0]; var setH2=_h2[1];
39 var _m2 = useState(a.defaultM2||45); var m2=_m2[0]; var setM2=_m2[1];
40 var _s2 = useState(a.defaultS2||0); var s2=_s2[0]; var setS2=_s2[1];
41
42 var t1 = calcTotal(h1,m1,s1);
43 var t2 = calcTotal(h2,m2,s2);
44 var total = op === 'add' ? t1+t2 : t1-t2;
45 var absTotal = Math.abs(total);
46 var days = Math.floor(absTotal/86400);
47 var hours = Math.floor((absTotal%86400)/3600);
48 var mins = Math.floor((absTotal%3600)/60);
49 var secs = absTotal%60;
50
51 var fnStat = function(val,label) { return el('div',{style:{background:a.statBg||'#f3f4f6',border:'1px solid '+(a.statBorder||'#e5e7eb'),borderRadius:'10px',padding:'12px',textAlign:'center',flex:1}},
52 el('div',{style:{fontSize:'22px',fontWeight:800,color:a.statValue||'#111827'}},''+val),
53 el('div',{style:{fontSize:'12px',color:a.statLabel||'#6b7280',marginTop:'3px'}},label)
54 );};
55
56 var inpStyle={padding:'8px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),borderRadius:(a.inputRadius||8)+'px',fontSize:'16px',fontFamily:'inherit',textAlign:'center',outline:'none',width:'100%'};
57 var lblStyle={display:'block',fontSize:'12px',fontWeight:600,color:a.labelColor||'#374151',textTransform:'uppercase',letterSpacing:'.05em',marginBottom:'4px',textAlign:'center'};
58
59 function durationRow(hval,mval,sval,onH,onM,onS) {
60 return el('div',{style:{display:'grid',gridTemplateColumns:'1fr 1fr '+(a.showSeconds?'1fr':''),gap:'8px'}},
61 el('div',null, el('label',{style:lblStyle},'Hours'), el('input',{type:'number',value:hval,min:0,style:inpStyle,onChange:function(e){onH(parseInt(e.target.value)||0);}})),
62 el('div',null, el('label',{style:lblStyle},'Minutes'), el('input',{type:'number',value:mval,min:0,max:59,style:inpStyle,onChange:function(e){onM(parseInt(e.target.value)||0);}})),
63 a.showSeconds && el('div',null, el('label',{style:lblStyle},'Seconds'), el('input',{type:'number',value:sval,min:0,max:59,style:inpStyle,onChange:function(e){onS(parseInt(e.target.value)||0);}}))
64 );
65 }
66
67 var opButton = function(val, icon, active) { return el('button',{onClick:function(){setOp(val);},style:{flex:1,padding:'9px',border:'none',cursor:'pointer',fontWeight:700,fontSize:'18px',fontFamily:'inherit',transition:'all .15s',background:active?(a.opActiveBg||accent):(a.opInactiveBg||'#f3f4f6'),color:active?(a.opActiveColor||'#fff'):(a.opInactiveColor||'#374151')}}, icon); };
68
69 return el('div',{style:{paddingTop:(a.paddingTop||60)+'px',paddingBottom:(a.paddingBottom||60)+'px',background:a.sectionBg||undefined}},
70 el('div',{style:{background:a.cardBg||'#fff',borderRadius:(a.cardRadius||16)+'px',padding:'32px',maxWidth:(a.maxWidth||560)+'px',margin:'0 auto',boxShadow:'0 4px 24px rgba(0,0,0,.09)'}},
71
72 (a.showTitle||a.showSubtitle) && el('div',{style:{marginBottom:'22px'}},
73 a.showTitle && el('div',{className:'bkbg-tdc-title',style:{color:a.titleColor,marginBottom:'6px'}},a.title),
74 a.showSubtitle && el('div',{className:'bkbg-tdc-subtitle',style:{color:a.subtitleColor,opacity:.75}},a.subtitle)
75 ),
76
77 // Operation toggle
78 el('div',{style:{display:'flex',borderRadius:'10px',overflow:'hidden',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),marginBottom:'20px'}},
79 opButton('add', '+ Add Durations', op==='add'),
80 opButton('sub', '− Subtract Durations', op==='sub')
81 ),
82
83 // Duration 1
84 el('div',{style:{marginBottom:'12px',background:a.statBg||'#f8f7ff',borderRadius:'10px',padding:'14px'}},
85 el('div',{style:{fontSize:'13px',fontWeight:700,color:a.labelColor||'#374151',marginBottom:'10px'}},'Duration A'),
86 durationRow(h1,m1,s1,setH1,setM1,setS1)
87 ),
88
89 // Operator symbol
90 el('div',{style:{textAlign:'center',fontSize:'22px',fontWeight:800,color:accent,margin:'4px 0'}}, op==='add' ? '+' : ''),
91
92 // Duration 2
93 el('div',{style:{marginBottom:'18px',background:a.statBg||'#f8f7ff',borderRadius:'10px',padding:'14px'}},
94 el('div',{style:{fontSize:'13px',fontWeight:700,color:a.labelColor||'#374151',marginBottom:'10px'}},'Duration B'),
95 durationRow(h2,m2,s2,setH2,setM2,setS2)
96 ),
97
98 // Result card
99 el('div',{style:{background:a.resultBg||accent,borderRadius:'12px',padding:'20px',textAlign:'center',color:a.resultColor||'#fff',marginBottom:'16px'}},
100 el('div',{style:{fontSize:'13px',opacity:.8,marginBottom:'6px',fontWeight:600}},op==='add'?'Total Duration':'Difference'),
101 el('div',{className:'bkbg-tdc-result-time',style:{letterSpacing:'.04em',lineHeight:1,fontFamily:'monospace'}},
102 fmtHMS(total))
103 ),
104
105 // Stat breakdown
106 el('div',{style:{display:'flex',gap:'8px',flexWrap:'wrap'}},
107 a.showDaysBreakdown && fnStat(days,'Days'),
108 fnStat(hours,'Hours'),
109 fnStat(mins,'Minutes'),
110 a.showSeconds && fnStat(secs,'Seconds'),
111 a.showTotalSec && fnStat(Math.abs(total).toLocaleString(),'Total Seconds')
112 )
113 )
114 );
115 }
116
117 registerBlockType('blockenberg/time-duration-calculator', {
118 edit: function(props) {
119 var a = props.attributes; var set = props.setAttributes;
120 var blockProps = useBlockProps((function () {
121 var tv = Object.assign({}, _tvf(a.titleTypo, '--bktdc-tt-'), _tvf(a.resultTypo, '--bktdc-rt-'));
122 return { style: tv };
123 })());
124 var colorSettings = [
125 {value:a.accentColor, onChange:function(v){set({accentColor:v});}, label:'Accent Color'},
126 {value:a.cardBg, onChange:function(v){set({cardBg:v});}, label:'Card Background'},
127 {value:a.resultBg, onChange:function(v){set({resultBg:v});}, label:'Result Card Background'},
128 {value:a.resultColor, onChange:function(v){set({resultColor:v});}, label:'Result Card Text'},
129 {value:a.statBg, onChange:function(v){set({statBg:v});}, label:'Stat Card Background'},
130 {value:a.statBorder, onChange:function(v){set({statBorder:v});}, label:'Stat Card Border'},
131 {value:a.statValue, onChange:function(v){set({statValue:v});}, label:'Stat Value Color'},
132 {value:a.statLabel, onChange:function(v){set({statLabel:v});}, label:'Stat Label Color'},
133 {value:a.opActiveBg, onChange:function(v){set({opActiveBg:v});}, label:'Active Op Background'},
134 {value:a.opActiveColor, onChange:function(v){set({opActiveColor:v});}, label:'Active Op Text'},
135 {value:a.opInactiveBg, onChange:function(v){set({opInactiveBg:v});}, label:'Inactive Op Background'},
136 {value:a.opInactiveColor,onChange:function(v){set({opInactiveColor:v});}, label:'Inactive Op Text'},
137 {value:a.inputBorder, onChange:function(v){set({inputBorder:v});}, label:'Input Border'},
138 {value:a.labelColor, onChange:function(v){set({labelColor:v});}, label:'Label Color'},
139 {value:a.titleColor, onChange:function(v){set({titleColor:v});}, label:'Title Color'},
140 {value:a.subtitleColor, onChange:function(v){set({subtitleColor:v});}, label:'Subtitle Color'},
141 {value:a.sectionBg, onChange:function(v){set({sectionBg:v});}, label:'Section Background'}
142 ];
143 return el(Fragment, null,
144 el(InspectorControls, null,
145 el(PanelBody,{title:'Header',initialOpen:false},
146 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Title', checked:a.showTitle, onChange:function(v){set({showTitle:v});}}),
147 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Subtitle',checked:a.showSubtitle,onChange:function(v){set({showSubtitle:v});}}),
148 el(TextControl,{label:'Title', value:a.title, onChange:function(v){set({title:v});}}),
149 el(TextControl,{label:'Subtitle',value:a.subtitle,onChange:function(v){set({subtitle:v});}})
150 ),
151 el(PanelBody,{title:'Calculator Defaults',initialOpen:true},
152 el(SelectControl,{label:'Default Operation',value:a.defaultOp,options:[{label:'+ Add',value:'add'},{label:'− Subtract',value:'sub'}],onChange:function(v){set({defaultOp:v});}}),
153 el('div',{style:{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:'8px'}},
154 el(TextControl,{label:'Duration A – Hours', value:String(a.defaultH1),type:'number',onChange:function(v){set({defaultH1:parseInt(v)||0});}}),
155 el(TextControl,{label:'Minutes', value:String(a.defaultM1),type:'number',onChange:function(v){set({defaultM1:parseInt(v)||0});}}),
156 el(TextControl,{label:'Seconds', value:String(a.defaultS1),type:'number',onChange:function(v){set({defaultS1:parseInt(v)||0});}})
157 ),
158 el('div',{style:{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:'8px'}},
159 el(TextControl,{label:'Duration B – Hours', value:String(a.defaultH2),type:'number',onChange:function(v){set({defaultH2:parseInt(v)||0});}}),
160 el(TextControl,{label:'Minutes', value:String(a.defaultM2),type:'number',onChange:function(v){set({defaultM2:parseInt(v)||0});}}),
161 el(TextControl,{label:'Seconds', value:String(a.defaultS2),type:'number',onChange:function(v){set({defaultS2:parseInt(v)||0});}})
162 ),
163 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Seconds Input', checked:a.showSeconds, onChange:function(v){set({showSeconds:v});}}),
164 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Total Seconds Stat',checked:a.showTotalSec, onChange:function(v){set({showTotalSec:v});}}),
165 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Days Breakdown', checked:a.showDaysBreakdown,onChange:function(v){set({showDaysBreakdown:v});}})
166 ),
167
168 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
169 getTypoControl() && el(getTypoControl(), {
170 label: __('Title Typography', 'blockenberg'),
171 value: a.titleTypo || {},
172 onChange: function (v) { set({ titleTypo: v }); }
173 }),
174 getTypoControl() && el(getTypoControl(), {
175 label: __('Result Typography', 'blockenberg'),
176 value: a.resultTypo || {},
177 onChange: function (v) { set({ resultTypo: v }); }
178 })
179 ),
180 el(PanelColorSettings,{title:'Colors',initialOpen:false,colorSettings:colorSettings}),
181 el(PanelBody,{title:'Sizing & Layout',initialOpen:false},
182 el(RangeControl,{label:'Card Border Radius',value:a.cardRadius, min:0, max:40,step:1, onChange:function(v){set({cardRadius:v});}}),
183 el(RangeControl,{label:'Input Border Radius',value:a.inputRadius,min:0,max:20,step:1, onChange:function(v){set({inputRadius:v});}}),
184 el(RangeControl,{label:'Max Width (px)', value:a.maxWidth, min:300,max:900,step:10,onChange:function(v){set({maxWidth:v});}}),
185 el(RangeControl,{label:'Padding Top', value:a.paddingTop, min:0, max:160,step:4, onChange:function(v){set({paddingTop:v});}}),
186 el(RangeControl,{label:'Padding Bottom', value:a.paddingBottom,min:0,max:160,step:4,onChange:function(v){set({paddingBottom:v});}})
187 )
188 ),
189 el('div', blockProps, el(TDCPreview, {attributes:a}))
190 );
191 },
192 save: function(props) {
193 var a = props.attributes;
194 var bp = wp.blockEditor.useBlockProps.save((function () {
195 var tv = Object.assign({}, _tvf(a.titleTypo, '--bktdc-tt-'), _tvf(a.resultTypo, '--bktdc-rt-'));
196 return { style: tv };
197 })());
198 return el('div', bp,
199 el('div',{className:'bkbg-tdc-app','data-opts':JSON.stringify(a)}));
200 }
201 });
202 }() );
203