| 1 |
(function () { |
| 2 |
'use strict'; |
| 3 |
|
| 4 |
var ACTIVITY_FACTOR = { sedentary: 30, light: 33, moderate: 35, active: 38, very_active: 42 }; |
| 5 |
var CLIMATE_FACTOR = { temperate: 0, hot: 500, cold: -200 }; |
| 6 |
|
| 7 |
function calcWater(weightKg, activity, climate) { |
| 8 |
var base = weightKg * (ACTIVITY_FACTOR[activity] || 35); |
| 9 |
base += (CLIMATE_FACTOR[climate] || 0); |
| 10 |
return Math.max(500, base); |
| 11 |
} |
| 12 |
|
| 13 |
function getTips(activity, climate) { |
| 14 |
var list = [ |
| 15 |
'Drink a glass of water first thing in the morning.', |
| 16 |
'Carry a reusable water bottle throughout the day.' |
| 17 |
]; |
| 18 |
if (activity === 'active' || activity === 'very_active') { |
| 19 |
list.push('Drink 500 ml extra for every hour of intense exercise.'); |
| 20 |
} |
| 21 |
if (climate === 'hot') list.push('Hot climates increase sweat loss — drink more frequently.'); |
| 22 |
if (climate === 'cold') list.push('Cold weather can reduce thirst sensation — stay mindful of drinking.'); |
| 23 |
list.push('Herbal teas and water-rich foods count toward your daily intake.'); |
| 24 |
return list; |
| 25 |
} |
| 26 |
|
| 27 |
function init(app) { |
| 28 |
var a; |
| 29 |
try { a = JSON.parse(app.getAttribute('data-opts')); } catch (e) { return; } |
| 30 |
|
| 31 |
var accent = a.accentColor || '#3b82f6'; |
| 32 |
|
| 33 |
app.style.paddingTop = (a.paddingTop || 60) + 'px'; |
| 34 |
app.style.paddingBottom = (a.paddingBottom || 60) + 'px'; |
| 35 |
if (a.sectionBg) app.style.background = a.sectionBg; |
| 36 |
app.innerHTML = ''; |
| 37 |
|
| 38 |
var wrap = document.createElement('div'); |
| 39 |
wrap.className = 'bkbg-wic-wrap'; |
| 40 |
wrap.style.maxWidth = (a.maxWidth || 500) + 'px'; |
| 41 |
wrap.style.borderRadius = (a.cardRadius || 16) + 'px'; |
| 42 |
wrap.style.background = a.cardBg || '#fff'; |
| 43 |
app.appendChild(wrap); |
| 44 |
|
| 45 |
if (a.showTitle || a.showSubtitle) { |
| 46 |
var header = document.createElement('div'); |
| 47 |
header.className = 'bkbg-wic-header'; |
| 48 |
if (a.showTitle && a.title) { |
| 49 |
var title = document.createElement('div'); |
| 50 |
title.className = 'bkbg-wic-title'; |
| 51 |
title.textContent = a.title; |
| 52 |
if (a.titleColor) title.style.color = a.titleColor; |
| 53 |
header.appendChild(title); |
| 54 |
} |
| 55 |
if (a.showSubtitle && a.subtitle) { |
| 56 |
var sub = document.createElement('div'); |
| 57 |
sub.className = 'bkbg-wic-subtitle'; |
| 58 |
sub.textContent = a.subtitle; |
| 59 |
if (a.subtitleColor) sub.style.color = a.subtitleColor; |
| 60 |
header.appendChild(sub); |
| 61 |
} |
| 62 |
wrap.appendChild(header); |
| 63 |
} |
| 64 |
|
| 65 |
var ir = (a.inputRadius || 8) + 'px'; |
| 66 |
var ib = '1.5px solid ' + (a.inputBorder || '#e5e7eb'); |
| 67 |
var currentUnit = a.defaultUnit || 'kg'; |
| 68 |
|
| 69 |
// Weight field |
| 70 |
var weightField = document.createElement('div'); |
| 71 |
weightField.className = 'bkbg-wic-field'; |
| 72 |
|
| 73 |
var weightLabelRow = document.createElement('div'); |
| 74 |
weightLabelRow.className = 'bkbg-wic-label'; |
| 75 |
if (a.labelColor) weightLabelRow.style.color = a.labelColor; |
| 76 |
|
| 77 |
var weightLabelSpan = document.createElement('span'); |
| 78 |
weightLabelSpan.textContent = 'Body Weight'; |
| 79 |
|
| 80 |
var unitToggle = document.createElement('div'); |
| 81 |
unitToggle.className = 'bkbg-wic-unit-toggle'; |
| 82 |
|
| 83 |
['kg','lbs'].forEach(function(u) { |
| 84 |
var btn = document.createElement('button'); |
| 85 |
btn.className = 'bkbg-wic-unit-btn'; |
| 86 |
btn.textContent = u; |
| 87 |
btn.dataset.unit = u; |
| 88 |
btn.style.background = u === currentUnit ? accent : '#e5e7eb'; |
| 89 |
btn.style.color = u === currentUnit ? '#fff' : '#374151'; |
| 90 |
btn.addEventListener('click', function() { |
| 91 |
var old = currentUnit; |
| 92 |
currentUnit = u; |
| 93 |
var cur = parseFloat(weightInput.value) || 0; |
| 94 |
if (old === 'kg' && u === 'lbs') weightInput.value = (cur * 2.20462).toFixed(1); |
| 95 |
else if (old === 'lbs' && u === 'kg') weightInput.value = (cur * 0.453592).toFixed(1); |
| 96 |
unitToggle.querySelectorAll('.bkbg-wic-unit-btn').forEach(function(b) { |
| 97 |
var active = b.dataset.unit === currentUnit; |
| 98 |
b.style.background = active ? accent : '#e5e7eb'; |
| 99 |
b.style.color = active ? '#fff' : '#374151'; |
| 100 |
}); |
| 101 |
recalculate(); |
| 102 |
}); |
| 103 |
unitToggle.appendChild(btn); |
| 104 |
}); |
| 105 |
|
| 106 |
weightLabelRow.appendChild(weightLabelSpan); |
| 107 |
weightLabelRow.appendChild(unitToggle); |
| 108 |
weightField.appendChild(weightLabelRow); |
| 109 |
|
| 110 |
var weightInput = document.createElement('input'); |
| 111 |
weightInput.type = 'number'; |
| 112 |
weightInput.className = 'bkbg-wic-input'; |
| 113 |
weightInput.value = String(a.defaultWeight || 70); |
| 114 |
weightInput.min = '1'; |
| 115 |
weightInput.style.borderRadius = ir; |
| 116 |
weightInput.style.border = ib; |
| 117 |
weightInput.addEventListener('input', recalculate); |
| 118 |
weightField.appendChild(weightInput); |
| 119 |
wrap.appendChild(weightField); |
| 120 |
|
| 121 |
function makeSelect(labelText, options, defaultVal) { |
| 122 |
var field = document.createElement('div'); |
| 123 |
field.className = 'bkbg-wic-field'; |
| 124 |
var lbl = document.createElement('div'); |
| 125 |
lbl.className = 'bkbg-wic-label'; |
| 126 |
lbl.textContent = labelText; |
| 127 |
if (a.labelColor) lbl.style.color = a.labelColor; |
| 128 |
var sel = document.createElement('select'); |
| 129 |
sel.className = 'bkbg-wic-select'; |
| 130 |
sel.style.borderRadius = ir; |
| 131 |
sel.style.border = ib; |
| 132 |
options.forEach(function(o) { |
| 133 |
var opt = document.createElement('option'); |
| 134 |
opt.value = o[0]; |
| 135 |
opt.textContent = o[1]; |
| 136 |
if (o[0] === defaultVal) opt.selected = true; |
| 137 |
sel.appendChild(opt); |
| 138 |
}); |
| 139 |
sel.addEventListener('change', recalculate); |
| 140 |
field.appendChild(lbl); |
| 141 |
field.appendChild(sel); |
| 142 |
wrap.appendChild(field); |
| 143 |
return sel; |
| 144 |
} |
| 145 |
|
| 146 |
var actSel = makeSelect('Activity Level', [ |
| 147 |
['sedentary', 'Sedentary (little or no exercise)'], |
| 148 |
['light', 'Light (light exercise 1-3 days/wk)'], |
| 149 |
['moderate', 'Moderate (exercise 3-5 days/wk)'], |
| 150 |
['active', 'Active (hard exercise 6-7 days/wk)'], |
| 151 |
['very_active','Very Active (athlete / physical job)'] |
| 152 |
], a.defaultActivity || 'moderate'); |
| 153 |
|
| 154 |
var climSel = makeSelect('Climate', [ |
| 155 |
['temperate','Temperate (cool/mild climate)'], |
| 156 |
['hot', 'Hot / Humid Climate'], |
| 157 |
['cold', 'Cold / Dry Climate'] |
| 158 |
], a.defaultClimate || 'temperate'); |
| 159 |
|
| 160 |
// Result card |
| 161 |
var resultCard = document.createElement('div'); |
| 162 |
resultCard.className = 'bkbg-wic-result'; |
| 163 |
resultCard.style.background = a.resultBg || accent; |
| 164 |
resultCard.style.borderRadius = ir; |
| 165 |
|
| 166 |
var resultLbl = document.createElement('div'); resultLbl.className = 'bkbg-wic-result-label'; resultLbl.style.color = a.resultColor||'#fff'; resultLbl.textContent = 'Daily Water Recommendation'; |
| 167 |
var resultMain = document.createElement('div'); resultMain.className = 'bkbg-wic-result-main'; resultMain.style.color = a.resultColor||'#fff'; resultMain.style.fontSize = (a.resultSize||56)+'px'; |
| 168 |
var resultSub = document.createElement('div'); resultSub.className = 'bkbg-wic-result-sub'; resultSub.style.color = a.resultColor||'#fff'; |
| 169 |
resultCard.appendChild(resultLbl); resultCard.appendChild(resultMain); resultCard.appendChild(resultSub); |
| 170 |
wrap.appendChild(resultCard); |
| 171 |
|
| 172 |
// Glasses |
| 173 |
var glassesEl = null; |
| 174 |
if (a.showGlasses) { |
| 175 |
glassesEl = document.createElement('div'); |
| 176 |
glassesEl.className = 'bkbg-wic-glasses'; |
| 177 |
glassesEl.style.background = a.glassBg || '#eff6ff'; |
| 178 |
glassesEl.style.borderRadius = ir; |
| 179 |
wrap.appendChild(glassesEl); |
| 180 |
} |
| 181 |
|
| 182 |
// Tips |
| 183 |
var tipsEl = null; |
| 184 |
if (a.showTips) { |
| 185 |
tipsEl = document.createElement('div'); |
| 186 |
tipsEl.className = 'bkbg-wic-tips'; |
| 187 |
tipsEl.style.background = a.tipsBg || '#f0fdf4'; |
| 188 |
tipsEl.style.borderColor = a.tipsBorder || '#bbf7d0'; |
| 189 |
tipsEl.style.borderRadius = ir; |
| 190 |
wrap.appendChild(tipsEl); |
| 191 |
} |
| 192 |
|
| 193 |
function recalculate() { |
| 194 |
var wt = parseFloat(weightInput.value) || (a.defaultWeight || 70); |
| 195 |
var activity= actSel.value; |
| 196 |
var climate = climSel.value; |
| 197 |
var wKg = currentUnit === 'lbs' ? wt * 0.453592 : wt; |
| 198 |
var ml = calcWater(wKg, activity, climate); |
| 199 |
var liters = (ml / 1000).toFixed(1); |
| 200 |
var oz = Math.round(ml / 29.574); |
| 201 |
var glasses = Math.round(ml / (a.glassSize || 250)); |
| 202 |
|
| 203 |
resultMain.textContent = liters + ' L'; |
| 204 |
resultSub.textContent = oz + ' fl oz · ' + Math.round(ml) + ' ml'; |
| 205 |
|
| 206 |
if (glassesEl) { |
| 207 |
glassesEl.innerHTML = ''; |
| 208 |
var glLbl = document.createElement('div'); |
| 209 |
glLbl.className = 'bkbg-wic-glasses-label'; |
| 210 |
glLbl.style.color = a.glassColor || accent; |
| 211 |
glLbl.textContent = '= ' + glasses + ' glasses of ' + (a.glassSize || 250) + ' ml'; |
| 212 |
var glRow = document.createElement('div'); |
| 213 |
glRow.className = 'bkbg-wic-glasses-row'; |
| 214 |
var limit = Math.min(glasses, 16); |
| 215 |
for (var i = 0; i < limit; i++) { |
| 216 |
var ico = document.createElement('span'); |
| 217 |
ico.className = 'bkbg-wic-glass-icon'; |
| 218 |
ico.textContent = '💧'; |
| 219 |
glRow.appendChild(ico); |
| 220 |
} |
| 221 |
if (glasses > 16) { |
| 222 |
var more = document.createElement('span'); |
| 223 |
more.className = 'bkbg-wic-glass-more'; |
| 224 |
more.style.color = a.glassColor || accent; |
| 225 |
more.textContent = '+' + (glasses - 16) + ' more'; |
| 226 |
glRow.appendChild(more); |
| 227 |
} |
| 228 |
glassesEl.appendChild(glLbl); |
| 229 |
glassesEl.appendChild(glRow); |
| 230 |
} |
| 231 |
|
| 232 |
if (tipsEl) { |
| 233 |
tipsEl.innerHTML = ''; |
| 234 |
var tipHead = document.createElement('div'); |
| 235 |
tipHead.className = 'bkbg-wic-tips-heading'; |
| 236 |
tipHead.style.color = a.tipsColor || '#166534'; |
| 237 |
tipHead.textContent = '💡 Hydration Tips'; |
| 238 |
var ul = document.createElement('ul'); |
| 239 |
ul.className = 'bkbg-wic-tips-list'; |
| 240 |
getTips(activity, climate).forEach(function(tip) { |
| 241 |
var li = document.createElement('li'); |
| 242 |
li.textContent = tip; |
| 243 |
li.style.color = a.tipsColor || '#166534'; |
| 244 |
ul.appendChild(li); |
| 245 |
}); |
| 246 |
tipsEl.appendChild(tipHead); |
| 247 |
tipsEl.appendChild(ul); |
| 248 |
} |
| 249 |
} |
| 250 |
|
| 251 |
recalculate(); |
| 252 |
} |
| 253 |
|
| 254 |
document.querySelectorAll('.bkbg-wic-app').forEach(init); |
| 255 |
})(); |
| 256 |
|