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

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

273 lines 18.1 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 // Lazy lookup so the typography control is resolved at render time
16 function getTypographyControl() {
17 return (typeof window.bkbgTypographyControl !== 'undefined') ? window.bkbgTypographyControl : null;
18 }
19 function getTypoCssVars() {
20 return (typeof window.bkbgTypoCssVars !== 'undefined') ? window.bkbgTypoCssVars : function() { return {}; };
21 }
22
23 var DAYS_OF_WEEK = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
24 var ZODIAC = [
25 { sign:'Capricorn', symbol:'', end:[1,19] },
26 { sign:'Aquarius', symbol:'', end:[2,18] },
27 { sign:'Pisces', symbol:'', end:[3,20] },
28 { sign:'Aries', symbol:'', end:[4,19] },
29 { sign:'Taurus', symbol:'', end:[5,20] },
30 { sign:'Gemini', symbol:'', end:[6,20] },
31 { sign:'Cancer', symbol:'', end:[7,22] },
32 { sign:'Leo', symbol:'', end:[8,22] },
33 { sign:'Virgo', symbol:'', end:[9,22] },
34 { sign:'Libra', symbol:'', end:[10,22] },
35 { sign:'Scorpio', symbol:'', end:[11,21] },
36 { sign:'Sagittarius',symbol:'',end:[12,21] },
37 { sign:'Capricorn', symbol:'', end:[12,31] },
38 ];
39
40 function getZodiac(month, day) {
41 for (var i = 0; i < ZODIAC.length; i++) {
42 var z = ZODIAC[i];
43 if (month < z.end[0] || (month === z.end[0] && day <= z.end[1])) return z;
44 }
45 return ZODIAC[ZODIAC.length - 1];
46 }
47
48 function calcAge(birthDate, now) {
49 var years = now.getFullYear() - birthDate.getFullYear();
50 var months = now.getMonth() - birthDate.getMonth();
51 var days = now.getDate() - birthDate.getDate();
52 if (days < 0) {
53 months--;
54 var prevMonth = new Date(now.getFullYear(), now.getMonth(), 0);
55 days += prevMonth.getDate();
56 }
57 if (months < 0) { years--; months += 12; }
58 var totalDays = Math.floor((now - birthDate) / 86400000);
59 return { years: years, months: months, days: days, totalDays: totalDays };
60 }
61
62 function daysUntilBirthday(birthDate, now) {
63 var next = new Date(now.getFullYear(), birthDate.getMonth(), birthDate.getDate());
64 if (next < now) next.setFullYear(now.getFullYear() + 1);
65 return Math.ceil((next - now) / 86400000);
66 }
67
68 /* ── Preview component ────────────────────────────────────────────────── */
69 function AgePreview(props) {
70 var a = props.attrs;
71 var accent = a.accentColor || '#6c3fb5';
72 var cRadius= (a.cardRadius || 16) + 'px';
73 var aRadius= (a.ageCardRadius || 12) + 'px';
74
75 var bdState = useState('1990-01-01');
76 var bdValue = bdState[0];
77 var setBD = bdState[1];
78
79 var now = new Date();
80 var birthDate = new Date(bdValue);
81 var valid = !isNaN(birthDate.getTime()) && birthDate < now;
82 var age = valid ? calcAge(birthDate, now) : null;
83 var untilBd = valid ? daysUntilBirthday(birthDate, now) : null;
84 var zodiac = valid ? getZodiac(birthDate.getMonth() + 1, birthDate.getDate()) : null;
85 var bornDay = valid ? DAYS_OF_WEEK[birthDate.getDay()] : null;
86
87 var cardStyle = {
88 background: a.cardBg || '#ffffff',
89 borderRadius: cRadius,
90 padding: '32px',
91 boxShadow: '0 4px 24px rgba(0,0,0,0.08)',
92 maxWidth: (a.maxWidth || 680) + 'px',
93 margin: '0 auto',
94 paddingTop: (a.paddingTop || 60) + 'px',
95 paddingBottom: (a.paddingBottom || 60) + 'px',
96 boxSizing: 'border-box',
97 };
98
99 return el('div', { style: cardStyle },
100 a.showTitle && el('h2', { className: 'bkbg-age-title', style: { color: a.titleColor || '#1e1b4b', textAlign: 'center', marginTop: 0, marginBottom: 8 } }, a.title || __('Age Calculator', 'blockenberg')),
101 a.showSubtitle && el('p', { style: { color: a.subtitleColor || '#6b7280', textAlign: 'center', marginTop: 0, marginBottom: 28 } }, a.subtitle),
102
103 /* Date input */
104 el('div', { style: { marginBottom: '28px' } },
105 el('label', { style: { display: 'block', fontWeight: 600, color: a.labelColor || '#374151', marginBottom: '8px', fontSize: '14px' } }, __('Date of Birth', 'blockenberg')),
106 el('input', {
107 type: 'date',
108 value: bdValue,
109 max: now.toISOString().slice(0, 10),
110 onChange: function (e) { setBD(e.target.value); },
111 style: { width: '100%', padding: '12px 16px', borderRadius: '10px', border: '1.5px solid #e5e7eb', fontSize: '16px', boxSizing: 'border-box', outline: 'none', cursor: 'pointer' }
112 })
113 ),
114
115 /* Age cards */
116 valid && a.showAgeCards && el('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: '12px', marginBottom: '20px' } },
117 [
118 { val: age.years, label: a.yearsLabel || 'Years' },
119 { val: age.months, label: a.monthsLabel || 'Months' },
120 { val: age.days, label: a.daysLabel || 'Days' },
121 ].map(function (item) {
122 return el('div', {
123 key: item.label,
124 style: {
125 background: a.ageCardBg || accent, borderRadius: aRadius,
126 padding: '20px 12px', textAlign: 'center',
127 }
128 },
129 el('div', { className: 'bkbg-age-num', style: { color: a.ageCardColor || '#fff' } }, item.val),
130 el('div', { style: { fontSize: '13px', color: a.ageCardColor || '#fff', opacity: 0.8, marginTop: '6px', fontWeight: 600 } }, item.label)
131 );
132 })
133 ),
134
135 /* Birthday countdown */
136 valid && a.showNextBirthday && el('div', {
137 style: { background: a.resultBg || '#f5f3ff', border: '1.5px solid ' + (a.resultBorder || '#ede9fe'), borderRadius: '10px', padding: '16px 20px', display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '14px' }
138 },
139 el('span', { style: { fontSize: '28px' } }, '🎂'),
140 el('div', null,
141 el('div', { style: { fontWeight: 700, color: a.titleColor || '#1e1b4b', fontSize: '15px' } },
142 untilBd === 0 ? '🎉 Happy Birthday!' : (__('Next birthday in', 'blockenberg') + ' ' + untilBd + ' ' + __('days', 'blockenberg'))
143 ),
144 el('div', { style: { color: a.subtitleColor || '#6b7280', fontSize: '13px', marginTop: '2px' } },
145 age.years + 1 + __('th birthday coming soon', 'blockenberg')
146 )
147 )
148 ),
149
150 /* Zodiac & born day */
151 valid && (a.showZodiac || a.showBornDay) && el('div', { style: { display: 'grid', gridTemplateColumns: a.showZodiac && a.showBornDay ? '1fr 1fr' : '1fr', gap: '12px', marginBottom: '14px' } },
152 a.showZodiac && el('div', { style: { background: a.statsBg || '#fafafa', border: '1px solid ' + (a.statsBorder || '#e5e7eb'), borderRadius: '10px', padding: '14px 16px' } },
153 el('div', { style: { fontSize: '11px', fontWeight: 600, color: a.subtitleColor || '#6b7280', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: '4px' } }, __('Zodiac Sign', 'blockenberg')),
154 el('div', { style: { fontWeight: 700, color: a.titleColor || '#1e1b4b', fontSize: '16px' } }, zodiac.symbol + ' ' + zodiac.sign)
155 ),
156 a.showBornDay && el('div', { style: { background: a.statsBg || '#fafafa', border: '1px solid ' + (a.statsBorder || '#e5e7eb'), borderRadius: '10px', padding: '14px 16px' } },
157 el('div', { style: { fontSize: '11px', fontWeight: 600, color: a.subtitleColor || '#6b7280', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: '4px' } }, __('Born On', 'blockenberg')),
158 el('div', { style: { fontWeight: 700, color: a.titleColor || '#1e1b4b', fontSize: '16px' } }, '�
159 ' + bornDay)
160 )
161 ),
162
163 /* Life stats */
164 valid && a.showLifeStats && el('div', { style: { background: a.statsBg || '#fafafa', border: '1px solid ' + (a.statsBorder || '#e5e7eb'), borderRadius: '10px', padding: '16px 20px' } },
165 el('div', { style: { fontSize: '12px', fontWeight: 700, color: a.subtitleColor || '#6b7280', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: '12px' } }, __('Life Stats', 'blockenberg')),
166 el('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: '10px' } },
167 [
168 { label: __('Total Days', 'blockenberg'), val: age.totalDays.toLocaleString() },
169 { label: __('Total Weeks', 'blockenberg'), val: Math.floor(age.totalDays / 7).toLocaleString() },
170 { label: __('Total Hours', 'blockenberg'), val: (age.totalDays * 24).toLocaleString() },
171 { label: __('Heartbeats (est.)', 'blockenberg'), val: (age.totalDays * 24 * 60 * 72).toLocaleString() },
172 ].map(function (s) {
173 return el('div', { key: s.label },
174 el('div', { style: { fontSize: '11px', color: a.subtitleColor || '#6b7280', marginBottom: '2px' } }, s.label),
175 el('div', { style: { fontWeight: 700, color: accent, fontSize: '15px' } }, s.val)
176 );
177 })
178 )
179 ),
180
181 /* Empty state */
182 !valid && el('div', { style: { textAlign: 'center', color: '#9ca3af', padding: '32px 0', fontSize: '15px' } }, __('Enter your birth date above to see your age', 'blockenberg'))
183 );
184 }
185
186 registerBlockType('blockenberg/age-calculator', {
187 edit: function (props) {
188 var a = props.attributes;
189 var setAttr = props.setAttributes;
190 var blockProps = useBlockProps({ className: 'bkbg-age-wrap', style: (function () {
191 var s = { background: a.bgColor || undefined };
192 var _tv = getTypoCssVars();
193 Object.assign(s, _tv(a.titleTypo || {}, '--bkbg-age-title-'));
194 Object.assign(s, _tv(a.ageNumTypo || {}, '--bkbg-age-num-'));
195 s['--bkbg-age-title-sz'] = (a.titleSize || 28) + 'px';
196 s['--bkbg-age-num-sz'] = (a.ageNumSize || 52) + 'px';
197 return s;
198 })() });
199
200 return el(Fragment, null,
201 el(InspectorControls, null,
202
203 el(PanelBody, { title: __('Content', 'blockenberg'), initialOpen: true },
204 el(ToggleControl, { label: __('Show Title', 'blockenberg'), checked: a.showTitle, onChange: function (v) { setAttr({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
205 a.showTitle && el(TextControl, { label: __('Title', 'blockenberg'), value: a.title, onChange: function (v) { setAttr({ title: v }); } }),
206 el(ToggleControl, { label: __('Show Subtitle', 'blockenberg'), checked: a.showSubtitle, onChange: function (v) { setAttr({ showSubtitle: v }); }, __nextHasNoMarginBottom: true }),
207 a.showSubtitle && el(TextControl, { label: __('Subtitle', 'blockenberg'), value: a.subtitle, onChange: function (v) { setAttr({ subtitle: v }); } }),
208 el(TextControl, { label: __('Years Label', 'blockenberg'), value: a.yearsLabel, onChange: function (v) { setAttr({ yearsLabel: v }); } }),
209 el(TextControl, { label: __('Months Label', 'blockenberg'), value: a.monthsLabel, onChange: function (v) { setAttr({ monthsLabel: v }); } }),
210 el(TextControl, { label: __('Days Label', 'blockenberg'), value: a.daysLabel, onChange: function (v) { setAttr({ daysLabel: v }); } })
211 ),
212
213 el(PanelBody, { title: __('Display Options', 'blockenberg'), initialOpen: false },
214 el(ToggleControl, { label: __('Show Age Cards', 'blockenberg'), checked: a.showAgeCards, onChange: function (v) { setAttr({ showAgeCards: v }); }, __nextHasNoMarginBottom: true }),
215 el(ToggleControl, { label: __('Show Next Birthday', 'blockenberg'), checked: a.showNextBirthday, onChange: function (v) { setAttr({ showNextBirthday: v }); }, __nextHasNoMarginBottom: true }),
216 el(ToggleControl, { label: __('Show Zodiac Sign', 'blockenberg'), checked: a.showZodiac, onChange: function (v) { setAttr({ showZodiac: v }); }, __nextHasNoMarginBottom: true }),
217 el(ToggleControl, { label: __('Show Day of Week Born', 'blockenberg'), checked: a.showBornDay, onChange: function (v) { setAttr({ showBornDay: v }); }, __nextHasNoMarginBottom: true }),
218 el(ToggleControl, { label: __('Show Life Stats', 'blockenberg'), checked: a.showLifeStats, onChange: function (v) { setAttr({ showLifeStats: v }); }, __nextHasNoMarginBottom: true })
219 ),
220
221
222 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
223 (function () {
224 var TC = getTypographyControl();
225 if (!TC) return el('p', null, 'Typography control not loaded.');
226 return el(Fragment, null,
227 el(TC, { label: __('Title Typography', 'blockenberg'), value: a.titleTypo || {}, onChange: function (v) { setAttr({ titleTypo: v }); } }),
228 el(TC, { label: __('Age Number Typography', 'blockenberg'), value: a.ageNumTypo || {}, onChange: function (v) { setAttr({ ageNumTypo: v }); } })
229 );
230 })()
231 ),
232 el(PanelColorSettings, {
233 title: __('Colors', 'blockenberg'), initialOpen: false,
234 colorSettings: [
235 { label: __('Accent Color', 'blockenberg'), value: a.accentColor, onChange: function (v) { setAttr({ accentColor: v || '#6c3fb5' }); } },
236 { label: __('Age Card Background', 'blockenberg'),value: a.ageCardBg, onChange: function (v) { setAttr({ ageCardBg: v || '#6c3fb5' }); } },
237 { label: __('Age Card Text', 'blockenberg'), value: a.ageCardColor, onChange: function (v) { setAttr({ ageCardColor: v || '#ffffff' }); } },
238 { label: __('Result Background', 'blockenberg'), value: a.resultBg, onChange: function (v) { setAttr({ resultBg: v || '#f5f3ff' }); } },
239 { label: __('Stats Background', 'blockenberg'), value: a.statsBg, onChange: function (v) { setAttr({ statsBg: v || '#fafafa' }); } },
240 { label: __('Card Background', 'blockenberg'), value: a.cardBg, onChange: function (v) { setAttr({ cardBg: v || '#ffffff' }); } },
241 { label: __('Title Color', 'blockenberg'), value: a.titleColor, onChange: function (v) { setAttr({ titleColor: v || '#1e1b4b' }); } },
242 { label: __('Subtitle Color', 'blockenberg'), value: a.subtitleColor,onChange: function (v) { setAttr({ subtitleColor:v || '#6b7280' }); } },
243 { label: __('Section Background', 'blockenberg'), value: a.bgColor, onChange: function (v) { setAttr({ bgColor: v || '' }); } },
244 ]
245 }),
246
247 el(PanelBody, { title: __('Sizing', 'blockenberg'), initialOpen: false },
248 el(RangeControl, { label: __('Card Radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 40, onChange: function (v) { setAttr({ cardRadius: v }); } }),
249 el(RangeControl, { label: __('Age Card Radius (px)', 'blockenberg'),value: a.ageCardRadius,min: 0, max: 32, onChange: function (v) { setAttr({ ageCardRadius:v }); } }),
250 el(RangeControl, { label: __('Max Width (px)', 'blockenberg'), value: a.maxWidth, min: 320,max: 1200,onChange: function (v) { setAttr({ maxWidth: v }); } }),
251 el(RangeControl, { label: __('Padding Top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 160,onChange: function (v) { setAttr({ paddingTop: v }); } }),
252 el(RangeControl, { label: __('Padding Bottom (px)', 'blockenberg'), value: a.paddingBottom,min: 0, max: 160,onChange: function (v) { setAttr({ paddingBottom:v }); } })
253 )
254 ),
255
256 el('div', blockProps,
257 el(AgePreview, { attrs: a })
258 )
259 );
260 },
261
262 save: function (props) {
263 var a = props.attributes;
264 var blockProps = wp.blockEditor.useBlockProps.save({ className: 'bkbg-age-wrap', style: { background: a.bgColor || undefined } });
265 return el('div', blockProps,
266 el('div', { className: 'bkbg-age-app', 'data-opts': JSON.stringify(a) },
267 el('p', { className: 'bkbg-age-loading' }, __('Loading age calculator…', 'blockenberg'))
268 )
269 );
270 }
271 });
272 }() );
273