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 / date-difference / index.js

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

211 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 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 ToggleControl = wp.components.ToggleControl;
14
15 var _ddTC, _ddTV;
16 function _tc() { return _ddTC || (_ddTC = window.bkbgTypographyControl); }
17 function _tv(obj, prefix) { var fn = _ddTV || (_ddTV = window.bkbgTypoCssVars); return fn ? fn(obj, prefix) : {}; }
18
19 function diffDates(from, to) {
20 var d1 = new Date(from), d2 = new Date(to);
21 if (isNaN(d1) || isNaN(d2)) return null;
22 var swapped = false;
23 if (d1 > d2) { var t = d1; d1 = d2; d2 = t; swapped = true; }
24 var totalMs = d2 - d1;
25 var totalDays = Math.floor(totalMs / 86400000);
26 var totalWeeks= Math.floor(totalDays / 7);
27 var totalHours= Math.floor(totalMs / 3600000);
28 var totalMins = Math.floor(totalMs / 60000);
29
30 /* Calendar years/months/days */
31 var y = d2.getFullYear() - d1.getFullYear();
32 var m = d2.getMonth() - d1.getMonth();
33 var d = d2.getDate() - d1.getDate();
34 if (d < 0) { m--; var prev = new Date(d2.getFullYear(), d2.getMonth(), 0); d += prev.getDate(); }
35 if (m < 0) { y--; m += 12; }
36
37 /* Working days */
38 var wdays = 0, cur = new Date(d1);
39 while (cur < d2) { var dow = cur.getDay(); if (dow !== 0 && dow !== 6) wdays++; cur.setDate(cur.getDate()+1); }
40
41 return { years:y, months:m, days:d, totalDays:totalDays, totalWeeks:totalWeeks, totalHours:totalHours, totalMins:totalMins, workingDays:wdays, swapped:swapped };
42 }
43
44 function todayStr() {
45 var d = new Date(); var m = d.getMonth()+1; var day = d.getDate();
46 return d.getFullYear() + '-' + (m<10?'0'+m:m) + '-' + (day<10?'0'+day:day);
47 }
48
49 function DateDiffPreview(props) {
50 var a = props.attributes;
51 var setAttr = props.setAttributes;
52 var today = todayStr();
53 var _s = useState({ from: today, to: today });
54 var state = _s[0], setState = _s[1];
55 function set(k, v) { setState(function(p){ var o=Object.assign({},p); o[k]=v; return o; }); }
56
57 var diff = diffDates(state.from, state.to);
58 var accent = a.accentColor || '#6c3fb5';
59 var cRadius = (a.cardRadius || 16) + 'px';
60 var iRadius = (a.inputRadius|| 8) + 'px';
61 var maxW = (a.maxWidth || 620) + 'px';
62 var ptop = (a.paddingTop || 60) + 'px';
63 var pbot = (a.paddingBottom || 60) + 'px';
64 var numSize = (a.numSize || 40) + 'px';
65 var lclr = a.labelColor || '#374151';
66
67 var inpStyle = { width:'100%', padding:'10px 12px', border:'1.5px solid #e5e7eb', borderRadius:iRadius, fontSize:'15px', boxSizing:'border-box', outline:'none', background:'#fff', color:lclr };
68 var lblStyle = { fontSize:(a.inputLabelFontSize||13)+'px', fontWeight:600, color:lclr, display:'block', marginBottom:'4px' };
69
70 function statCard(label, value, unit, color) {
71 return el('div', { style:{ textAlign:'center', background:'#fff', borderRadius:'10px', padding:'16px 8px', border:'1.5px solid #e5e7eb' } },
72 el('div', { style:{ fontSize:(a.statLabelFontSize||11)+'px', textTransform:'uppercase', letterSpacing:'0.05em', color:'#9ca3af', marginBottom:'4px' } }, label),
73 el('div', { className:'bkbg-dd-stat-num', style:{ color:color, lineHeight:1, marginBottom:'2px' } }, value),
74 el('div', { style:{ fontSize:(a.statUnitFontSize||12)+'px', color:'#9ca3af' } }, unit)
75 );
76 }
77
78 var noResult = !diff || (state.from === state.to);
79
80 /* YMD summary */
81 var ymdSummary = diff && (a.showYMD !== false) && el('div', { style:{ textAlign:'center', padding:'20px', background:a.resultBg||'#f5f3ff', border:'1.5px solid '+(a.resultBorder||'#ede9fe'), borderRadius:cRadius, marginBottom:'16px' } },
82 el('div', { style:{ fontSize:'13px', color:'#9ca3af', textTransform:'uppercase', letterSpacing:'0.06em', marginBottom:'8px' } }, 'Duration'),
83 el('div', { style:{ fontSize:'22px', fontWeight:800, color:a.ymdColor||accent, lineHeight:1.3 } },
84 [diff.years > 0 && diff.years + ' yr', diff.months > 0 && diff.months + ' mo', diff.days > 0 && diff.days + ' day'].filter(Boolean).join(' ') || '0 days'
85 ),
86 diff.swapped && el('div', { style:{ fontSize:'12px', color:'#9ca3af', marginTop:'8px' } }, '(dates swapped — showing absolute difference)')
87 );
88
89 /* Stat cards */
90 var statCards = [];
91 if (diff && a.showTotalDays !== false) statCards.push({ label:'Total Days', val:diff.totalDays.toLocaleString(), unit:'days', color:a.daysColor ||'#3b82f6' });
92 if (diff && a.showWeeks !== false) statCards.push({ label:'Total Weeks', val:diff.totalWeeks.toLocaleString(), unit:'weeks', color:a.weeksColor ||'#10b981' });
93 if (diff && a.showHours !== false) statCards.push({ label:'Total Hours', val:diff.totalHours.toLocaleString(), unit:'hours', color:a.hoursColor ||'#f59e0b' });
94 if (diff && a.showMinutes !== false) statCards.push({ label:'Total Minutes', val:diff.totalMins.toLocaleString(), unit:'minutes', color:'#8b5cf6' });
95 if (diff && a.showWorkingDays !== false) statCards.push({ label:'Working Days', val:diff.workingDays.toLocaleString(),unit:'Mon–Fri', color:a.wdaysColor ||'#ef4444' });
96
97 var cols = statCards.length <= 2 ? '1fr '.repeat(statCards.length).trim()
98 : statCards.length <= 4 ? '1fr 1fr'
99 : '1fr 1fr 1fr';
100
101 return el('div', { className:'bkbg-dd-card', style:{ background:a.cardBg||'#fff', borderRadius:cRadius, maxWidth:maxW, margin:'0 auto', paddingTop:ptop, paddingBottom:pbot, paddingLeft:'32px', paddingRight:'32px', fontFamily:'inherit' } },
102 a.showTitle !== false && a.title && el('h2', { className:'bkbg-dd-title', style:{ color:a.titleColor||'#1e1b4b', textAlign:'center', marginTop:0, marginBottom:'8px' } }, a.title),
103 a.showSubtitle !== false && a.subtitle && el('p', { className:'bkbg-dd-subtitle', style:{ color:a.subtitleColor||'#6b7280', textAlign:'center', marginTop:0, marginBottom:'24px' } }, a.subtitle),
104
105 /* Date pickers */
106 el('div', { style:{ display:'flex', gap:'12px', alignItems:'flex-end', marginBottom:'20px', flexWrap:'wrap' } },
107 el('div', { style:{ flex:1 } },
108 el('label', { style:lblStyle }, a.labelFrom || 'From Date'),
109 el('input', { type:'date', value:state.from, style:inpStyle, onChange:function(e){set('from',e.target.value);} })
110 ),
111 a.showSwapBtn !== false && el('button', {
112 onClick: function () { setState(function(p){ return { from:p.to, to:p.from }; }); },
113 style:{ padding:'10px 14px', border:'1.5px solid '+accent, borderRadius:iRadius, background:'#fff', color:accent, cursor:'pointer', fontWeight:600, fontSize:'18px', flexShrink:0 }
114 }, ''),
115 el('div', { style:{ flex:1 } },
116 el('label', { style:lblStyle }, a.labelTo || 'To Date'),
117 el('input', { type:'date', value:state.to, style:inpStyle, onChange:function(e){set('to',e.target.value);} })
118 )
119 ),
120
121 noResult
122 ? el('div', { style:{ textAlign:'center', padding:'32px', color:'#9ca3af', background:a.resultBg||'#f5f3ff', borderRadius:cRadius, border:'1.5px solid '+(a.resultBorder||'#ede9fe') } }, 'Select two different dates to see the difference.')
123 : el(Fragment, null,
124 ymdSummary,
125 statCards.length > 0 && el('div', { style:{ display:'grid', gridTemplateColumns:cols, gap:'10px' } },
126 statCards.map(function(s,i){ return el(Fragment,{key:i}, statCard(s.label,s.val,s.unit,s.color)); })
127 )
128 )
129 );
130 }
131
132 registerBlockType('blockenberg/date-difference', {
133 edit: function (props) {
134 var a = props.attributes;
135 var setAttr = props.setAttributes;
136 var blockProps = useBlockProps({
137 className: 'bkbg-date-difference-block',
138 style: Object.assign({
139 '--bkbg-dd-ttl-fs': (a.titleSize || 26) + 'px',
140 '--bkbg-dd-sub-fs': (a.subtitleFontSize || 14) + 'px',
141 '--bkbg-dd-num-fs': (a.numSize || 40) + 'px'
142 }, _tv(a.typoTitle || {}, '--bkbg-dd-ttl-'), _tv(a.typoSubtitle || {}, '--bkbg-dd-sub-'), _tv(a.typoNumber || {}, '--bkbg-dd-num-'))
143 });
144
145 return el('div', blockProps,
146 el(InspectorControls, null,
147 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
148 el(TextControl, { label:'Title', value:a.title, onChange:function(v){setAttr({title:v});} }),
149 el(ToggleControl, { label:'Show title', checked:a.showTitle, onChange:function(v){setAttr({showTitle:v});}, __nextHasNoMarginBottom:true }),
150 el(TextControl, { label:'Subtitle', value:a.subtitle, onChange:function(v){setAttr({subtitle:v});} }),
151 el(ToggleControl, { label:'Show subtitle', checked:a.showSubtitle, onChange:function(v){setAttr({showSubtitle:v});}, __nextHasNoMarginBottom:true }),
152 el(TextControl, { label:'From label', value:a.labelFrom, onChange:function(v){setAttr({labelFrom:v});} }),
153 el(TextControl, { label:'To label', value:a.labelTo, onChange:function(v){setAttr({labelTo:v});} }),
154 el(ToggleControl, { label:'Show swap button', checked:a.showSwapBtn, onChange:function(v){setAttr({showSwapBtn:v});}, __nextHasNoMarginBottom:true }),
155 ),
156 el(PanelBody, { title: __('Display', 'blockenberg'), initialOpen: false },
157 el(ToggleControl, { label:'Years / months / days', checked:a.showYMD, onChange:function(v){setAttr({showYMD:v});}, __nextHasNoMarginBottom:true }),
158 el(ToggleControl, { label:'Total days', checked:a.showTotalDays, onChange:function(v){setAttr({showTotalDays:v});}, __nextHasNoMarginBottom:true }),
159 el(ToggleControl, { label:'Total weeks', checked:a.showWeeks, onChange:function(v){setAttr({showWeeks:v});}, __nextHasNoMarginBottom:true }),
160 el(ToggleControl, { label:'Total hours', checked:a.showHours, onChange:function(v){setAttr({showHours:v});}, __nextHasNoMarginBottom:true }),
161 el(ToggleControl, { label:'Total minutes', checked:a.showMinutes, onChange:function(v){setAttr({showMinutes:v});}, __nextHasNoMarginBottom:true }),
162 el(ToggleControl, { label:'Working days (Mon–Fri)',checked:a.showWorkingDays, onChange:function(v){setAttr({showWorkingDays:v});}, __nextHasNoMarginBottom:true }),
163 ),
164
165 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
166 _tc() && el(_tc(), { label: __('Title', 'blockenberg'), value: a.typoTitle, onChange: function(v){ setAttr({typoTitle:v}); } }),
167 _tc() && el(_tc(), { label: __('Subtitle', 'blockenberg'), value: a.typoSubtitle, onChange: function(v){ setAttr({typoSubtitle:v}); } }),
168 _tc() && el(_tc(), { label: __('Number', 'blockenberg'), value: a.typoNumber, onChange: function(v){ setAttr({typoNumber:v}); } }),
169 el(RangeControl, { label:'Stat label size', value:a.statLabelFontSize, min:9, max:16, onChange:function(v){setAttr({statLabelFontSize:v});}, __nextHasNoMarginBottom:true }),
170 el(RangeControl, { label:'Stat unit size', value:a.statUnitFontSize, min:9, max:16, onChange:function(v){setAttr({statUnitFontSize:v});}, __nextHasNoMarginBottom:true }),
171 el(RangeControl, { label:'Input label size', value:a.inputLabelFontSize, min:10, max:18, onChange:function(v){setAttr({inputLabelFontSize:v});}, __nextHasNoMarginBottom:true })
172 ),
173 el(PanelColorSettings, {
174 title: __('Colors', 'blockenberg'),
175 initialOpen: false, colorSettings: [
176 { label:'Accent', value:a.accentColor, onChange:function(v){setAttr({accentColor:v});} },
177 { label:'Card background', value:a.cardBg, onChange:function(v){setAttr({cardBg:v});} },
178 { label:'Result background',value:a.resultBg, onChange:function(v){setAttr({resultBg:v});} },
179 { label:'Result border', value:a.resultBorder, onChange:function(v){setAttr({resultBorder:v});} },
180 { label:'YMD number', value:a.ymdColor, onChange:function(v){setAttr({ymdColor:v});} },
181 { label:'Total days', value:a.daysColor, onChange:function(v){setAttr({daysColor:v});} },
182 { label:'Weeks', value:a.weeksColor, onChange:function(v){setAttr({weeksColor:v});} },
183 { label:'Hours', value:a.hoursColor, onChange:function(v){setAttr({hoursColor:v});} },
184 { label:'Working days', value:a.wdaysColor, onChange:function(v){setAttr({wdaysColor:v});} },
185 { label:'Title', value:a.titleColor, onChange:function(v){setAttr({titleColor:v});} },
186 { label:'Subtitle', value:a.subtitleColor,onChange:function(v){setAttr({subtitleColor:v});} },
187 ],
188 }),
189 el(PanelBody, { title: __('Sizing', 'blockenberg'), initialOpen: false },
190 el(RangeControl, { label:'Max width (px)', value:a.maxWidth, min:300, max:900, step:10, onChange:function(v){setAttr({maxWidth:v});} }),
191 el(RangeControl, { label:'Padding top', value:a.paddingTop, min:0, max:120, onChange:function(v){setAttr({paddingTop:v});} }),
192 el(RangeControl, { label:'Padding bottom', value:a.paddingBottom, min:0, max:120, onChange:function(v){setAttr({paddingBottom:v});} }),
193 el(RangeControl, { label:'Card radius (px)', value:a.cardRadius, min:0, max:32, onChange:function(v){setAttr({cardRadius:v});} }),
194 el(RangeControl, { label:'Input radius (px)',value:a.inputRadius, min:0, max:20, onChange:function(v){setAttr({inputRadius:v});} }),
195 )
196 ),
197 el(DateDiffPreview, { attributes: a, setAttributes: setAttr })
198 );
199 },
200
201 save: function (props) {
202 var a = props.attributes;
203 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-date-difference-block' });
204 return el('div', Object.assign({}, blockProps, {
205 className: (blockProps.className || '') + ' bkbg-dd-app',
206 'data-opts': JSON.stringify(a),
207 }));
208 },
209 });
210 }() );
211