| 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 |
|