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

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

207 lines 15.2 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, _tvf;
17 Object.defineProperty(window, '_tc', { get: function () { return _tc || (_tc = window.bkbgTypographyControl); } });
18 Object.defineProperty(window, '_tvf', { get: function () { return _tvf || (_tvf = window.bkbgTypoCssVars); } });
19 function getTypoControl(label, key, attrs, setA) { return _tc(label, key, attrs, setA); }
20 function getTypoCssVars(attrs) {
21 var v = {};
22 _tvf(v, 'titleTypo', attrs, '--bkwic-tt-');
23 _tvf(v, 'subtitleTypo', attrs, '--bkwic-st-');
24 return v;
25 }
26
27 var ACTIVITY_OPTIONS = [
28 { label: 'Sedentary (little or no exercise)', value: 'sedentary' },
29 { label: 'Light (light exercise 1-3 days/wk)', value: 'light' },
30 { label: 'Moderate (exercise 3-5 days/wk)', value: 'moderate' },
31 { label: 'Active (hard exercise 6-7 days/wk)', value: 'active' },
32 { label: 'Very Active (athlete / physical job)', value: 'very_active' }
33 ];
34 var CLIMATE_OPTIONS = [
35 { label: 'Temperate (cool/mild climate)', value: 'temperate' },
36 { label: 'Hot / Humid Climate', value: 'hot' },
37 { label: 'Cold / Dry Climate', value: 'cold' }
38 ];
39
40 var ACTIVITY_FACTOR = { sedentary:30, light:33, moderate:35, active:38, very_active:42 };
41 var CLIMATE_FACTOR = { temperate:0, hot:500, cold:-200 };
42
43 function calcWater(weightKg, activity, climate) {
44 var base = weightKg * (ACTIVITY_FACTOR[activity] || 35); // ml
45 base += (CLIMATE_FACTOR[climate] || 0);
46 return Math.max(500, base);
47 }
48
49 function tips(activity, climate) {
50 var list = ['Drink a glass of water first thing in the morning.', 'Carry a reusable water bottle throughout the day.'];
51 if (activity === 'active' || activity === 'very_active') list.push('Drink 500 ml extra for every hour of intense exercise.');
52 if (climate === 'hot') list.push('Hot climates increase sweat loss — drink more frequently.');
53 if (climate === 'cold') list.push('Cold weather can reduce thirst sensation — stay mindful of drinking.');
54 list.push('Herbal teas and water-rich foods count toward your daily intake.');
55 return list;
56 }
57
58 function WaterPreview(props) {
59 var a = props.attributes;
60 var accent = a.accentColor || '#3b82f6';
61
62 var _unit = useState(a.defaultUnit || 'kg'); var unit = _unit[0]; var setUnit = _unit[1];
63 var _wt = useState(String(a.defaultWeight || 70)); var wt = _wt[0]; var setWt = _wt[1];
64 var _act = useState(a.defaultActivity || 'moderate');var act = _act[0]; var setAct = _act[1];
65 var _cli = useState(a.defaultClimate || 'temperate');var cli=_cli[0]; var setCli = _cli[1];
66
67 var weightNum = parseFloat(wt) || 70;
68 var weightKg = unit === 'lbs' ? weightNum * 0.453592 : weightNum;
69 var mlTotal = calcWater(weightKg, act, cli);
70 var liters = (mlTotal / 1000).toFixed(1);
71 var oz = Math.round(mlTotal / 29.574);
72 var glasses = Math.round(mlTotal / (a.glassSize || 250));
73 var tipList = tips(act, cli);
74
75 return el('div', {style:{paddingTop:(a.paddingTop||60)+'px',paddingBottom:(a.paddingBottom||60)+'px',background:a.sectionBg||undefined}},
76 el('div', {style:{background:a.cardBg,borderRadius:(a.cardRadius||16)+'px',padding:'36px 32px',maxWidth:(a.maxWidth||500)+'px',margin:'0 auto',boxShadow:'0 4px 24px rgba(0,0,0,.09)'}},
77
78 (a.showTitle||a.showSubtitle) && el('div', {style:{marginBottom:'22px'}},
79 a.showTitle && el('div', {className:'bkbg-wic-title',style:{color:a.titleColor}}, a.title),
80 a.showSubtitle && el('div', {className:'bkbg-wic-subtitle',style:{color:a.subtitleColor}}, a.subtitle)
81 ),
82
83 // Weight + unit toggle
84 el('div', {style:{marginBottom:'14px'}},
85 el('label', {style:{display:'flex',justifyContent:'space-between',alignItems:'center',fontSize:'13px',fontWeight:600,color:a.labelColor||'#374151',marginBottom:'6px'}},
86 el('span', null, 'Body Weight'),
87 el('span', {style:{display:'flex',gap:'4px'}},
88 ['kg','lbs'].map(function(u) {
89 var active = unit === u;
90 return el('button', {key:u, onClick:function(){setUnit(u);},
91 style:{padding:'3px 10px',borderRadius:'6px',border:'none',fontSize:'12px',fontWeight:600,cursor:'pointer',
92 background:active?accent:'#e5e7eb',color:active?'#fff':'#374151',fontFamily:'inherit'}}, u);
93 })
94 )
95 ),
96 el('input', {type:'number',value:wt,min:'1',
97 style:{width:'100%',padding:'11px 14px',borderRadius:(a.inputRadius||8)+'px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),fontSize:'16px',fontFamily:'inherit',outline:'none',boxSizing:'border-box'},
98 onChange:function(e){setWt(e.target.value);}})
99 ),
100
101 el('div', {style:{marginBottom:'14px'}},
102 el('label', {style:{display:'block',fontSize:'13px',fontWeight:600,color:a.labelColor||'#374151',marginBottom:'6px'}}, 'Activity Level'),
103 el('select', {value:act, onChange:function(e){setAct(e.target.value);},
104 style:{width:'100%',padding:'11px 14px',borderRadius:(a.inputRadius||8)+'px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),fontSize:'15px',fontFamily:'inherit',outline:'none',background:'#fff',cursor:'pointer'}},
105 ACTIVITY_OPTIONS.map(function(o){return el('option',{key:o.value,value:o.value},o.label);}))
106 ),
107
108 el('div', {style:{marginBottom:'20px'}},
109 el('label', {style:{display:'block',fontSize:'13px',fontWeight:600,color:a.labelColor||'#374151',marginBottom:'6px'}}, 'Climate'),
110 el('select', {value:cli, onChange:function(e){setCli(e.target.value);},
111 style:{width:'100%',padding:'11px 14px',borderRadius:(a.inputRadius||8)+'px',border:'1.5px solid '+(a.inputBorder||'#e5e7eb'),fontSize:'15px',fontFamily:'inherit',outline:'none',background:'#fff',cursor:'pointer'}},
112 CLIMATE_OPTIONS.map(function(o){return el('option',{key:o.value,value:o.value},o.label);}))
113 ),
114
115 // Result
116 el('div', {style:{background:a.resultBg||accent,borderRadius:(a.inputRadius||8)+'px',padding:'24px',textAlign:'center',marginBottom:'16px'}},
117 el('div', {style:{fontSize:'13px',fontWeight:600,color:a.resultColor||'#fff',opacity:.8,marginBottom:'4px'}}, 'Daily Water Recommendation'),
118 el('div', {style:{fontSize:(a.resultSize||56)+'px',fontWeight:800,color:a.resultColor||'#fff',lineHeight:1,marginBottom:'4px'}}, liters + ' L'),
119 el('div', {style:{fontSize:'16px',color:a.resultColor||'#fff',opacity:.85}}, oz + ' fl oz · ' + Math.round(mlTotal) + ' ml')
120 ),
121
122 // Glasses
123 a.showGlasses && el('div', {style:{background:a.glassBg||'#eff6ff',borderRadius:(a.inputRadius||8)+'px',padding:'16px 20px',marginBottom:'16px',textAlign:'center'}},
124 el('div', {style:{fontSize:'13px',fontWeight:600,color:a.glassColor||accent,marginBottom:'8px'}}, '= ' + glasses + ' glasses of ' + (a.glassSize||250) + ' ml'),
125 el('div', {style:{display:'flex',flexWrap:'wrap',justifyContent:'center',gap:'6px'}},
126 Array.from({length:Math.min(glasses,16)}).map(function(_,i){
127 return el('span', {key:i, style:{fontSize:'22px',lineHeight:1}}, '💧');
128 }),
129 glasses > 16 && el('span', {style:{fontSize:'13px',color:a.glassColor||accent,alignSelf:'center'}}, '+' + (glasses-16) + ' more')
130 )
131 ),
132
133 // Tips
134 a.showTips && el('div', {style:{background:a.tipsBg||'#f0fdf4',border:'1.5px solid '+(a.tipsBorder||'#bbf7d0'),borderRadius:(a.inputRadius||8)+'px',padding:'16px 20px'}},
135 el('div', {style:{fontWeight:700,fontSize:'13px',color:a.tipsColor||'#166534',marginBottom:'10px'}}, '💡 Hydration Tips'),
136 el('ul', {style:{margin:0,paddingLeft:'18px',display:'flex',flexDirection:'column',gap:'5px'}},
137 tipList.map(function(t,i){
138 return el('li', {key:i, style:{fontSize:'13px',color:a.tipsColor||'#166534',lineHeight:1.5}}, t);
139 })
140 )
141 )
142 )
143 );
144 }
145
146 registerBlockType('blockenberg/water-intake-calculator', {
147 edit: function(props) {
148 var a = props.attributes; var set = props.setAttributes;
149 var blockProps = useBlockProps();
150 var colorSettings = [
151 { value: a.accentColor, onChange: function(v){set({accentColor:v});}, label: 'Accent Color' },
152 { value: a.cardBg, onChange: function(v){set({cardBg:v});}, label: 'Card Background' },
153 { value: a.resultBg, onChange: function(v){set({resultBg:v});}, label: 'Result Background' },
154 { value: a.resultColor, onChange: function(v){set({resultColor:v});}, label: 'Result Text' },
155 { value: a.glassColor, onChange: function(v){set({glassColor:v});}, label: 'Glass Icon Color' },
156 { value: a.glassBg, onChange: function(v){set({glassBg:v});}, label: 'Glasses Section Background' },
157 { value: a.tipsBg, onChange: function(v){set({tipsBg:v});}, label: 'Tips Background' },
158 { value: a.tipsBorder, onChange: function(v){set({tipsBorder:v});}, label: 'Tips Border' },
159 { value: a.tipsColor, onChange: function(v){set({tipsColor:v});}, label: 'Tips Text Color' },
160 { value: a.labelColor, onChange: function(v){set({labelColor:v});}, label: 'Label Color' },
161 { value: a.inputBorder, onChange: function(v){set({inputBorder:v});}, label: 'Input Border' },
162 { value: a.titleColor, onChange: function(v){set({titleColor:v});}, label: 'Title Color' },
163 { value: a.subtitleColor, onChange: function(v){set({subtitleColor:v});}, label: 'Subtitle Color' },
164 { value: a.sectionBg, onChange: function(v){set({sectionBg:v});}, label: 'Section Background' }
165 ];
166 return el(Fragment, null,
167 el(InspectorControls, null,
168 el(PanelBody, {title:'Header', initialOpen:false},
169 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Title', checked:a.showTitle, onChange:function(v){set({showTitle:v});}}),
170 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Subtitle',checked:a.showSubtitle,onChange:function(v){set({showSubtitle:v});}}),
171 el(TextControl,{label:'Title', value:a.title, onChange:function(v){set({title:v});}}),
172 el(TextControl,{label:'Subtitle',value:a.subtitle,onChange:function(v){set({subtitle:v});}})
173 ),
174 el(PanelBody, {title:'Calculator Settings', initialOpen:true},
175 el(SelectControl,{label:'Default Weight Unit', value:a.defaultUnit, options:[{label:'Kilograms (kg)',value:'kg'},{label:'Pounds (lbs)',value:'lbs'}], onChange:function(v){set({defaultUnit:v});}}),
176 el(TextControl, {label:'Default Weight', value:String(a.defaultWeight), onChange:function(v){set({defaultWeight:parseFloat(v)||70});}}),
177 el(SelectControl,{label:'Default Activity Level', value:a.defaultActivity, options:ACTIVITY_OPTIONS, onChange:function(v){set({defaultActivity:v});}}),
178 el(SelectControl,{label:'Default Climate', value:a.defaultClimate, options:CLIMATE_OPTIONS, onChange:function(v){set({defaultClimate:v});}}),
179 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Glass Count',checked:a.showGlasses,onChange:function(v){set({showGlasses:v});}}),
180 a.showGlasses && el(RangeControl,{label:'Glass Size (ml)',value:a.glassSize,min:100,max:500,step:50,onChange:function(v){set({glassSize:v});}}),
181 el(ToggleControl,{__nextHasNoMarginBottom:true,label:'Show Hydration Tips',checked:a.showTips,onChange:function(v){set({showTips:v});}})
182 ),
183
184 el( PanelBody, { title: __( 'Typography', 'blockenberg' ), initialOpen: false },
185 el(RangeControl,{label:'Result Font Size', value:a.resultSize, min:24,max:96, step:2, onChange:function(v){set({resultSize:v});}}),
186 getTypoControl( __( 'Title', 'blockenberg' ), 'titleTypo', a, set ),
187 getTypoControl( __( 'Subtitle', 'blockenberg' ), 'subtitleTypo', a, set ),
188 ),
189 el(PanelColorSettings,{title:'Colors',initialOpen:false,colorSettings:colorSettings}),
190 el(PanelBody,{title:'Sizing & Layout',initialOpen:false},
191 el(RangeControl,{label:'Card Border Radius', value:a.cardRadius, min:0, max:40, step:1, onChange:function(v){set({cardRadius:v});}}),
192 el(RangeControl,{label:'Input Border Radius',value:a.inputRadius, min:0, max:24, step:1, onChange:function(v){set({inputRadius:v});}}),
193 el(RangeControl,{label:'Max Width (px)', value:a.maxWidth, min:300,max:900,step:10,onChange:function(v){set({maxWidth:v});}}),
194 el(RangeControl,{label:'Padding Top (px)', value:a.paddingTop, min:0, max:160,step:4, onChange:function(v){set({paddingTop:v});}}),
195 el(RangeControl,{label:'Padding Bottom (px)',value:a.paddingBottom,min:0, max:160,step:4, onChange:function(v){set({paddingBottom:v});}})
196 )
197 ),
198 el('div', blockProps, el(WaterPreview, {attributes:a, setAttributes:set}))
199 );
200 },
201 save: function(props) {
202 var a = props.attributes;
203 return el('div', wp.blockEditor.useBlockProps.save({ style: getTypoCssVars(a) }), el('div', {className:'bkbg-wic-app','data-opts':JSON.stringify(a)}));
204 }
205 });
206 }() );
207