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 / heart-rate-calculator / frontend.js

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

155 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function calcMaxHR(age, formula) {
5 if (formula === 'tanaka') return Math.round(208 - 0.7 * age);
6 if (formula === 'gellish') return Math.round(207 - 0.7 * age);
7 return 220 - age; // fox (default)
8 }
9
10 var ZONES = [
11 { num: 1, name: 'Recovery', icon: '🚶', pctLo: 50, pctHi: 60, purpose: 'Rest & recovery — improve base fitness and promote active recovery' },
12 { num: 2, name: 'Fat Burn', icon: '🔥', pctLo: 60, pctHi: 70, purpose: 'Fat burning & aerobic base — improve endurance and metabolic efficiency' },
13 { num: 3, name: 'Aerobic', icon: '🏃', pctLo: 70, pctHi: 80, purpose: 'Improve cardiovascular efficiency and increase aerobic capacity' },
14 { num: 4, name: 'Threshold', icon: '', pctLo: 80, pctHi: 90, purpose: 'Increase lactate threshold — improve speed and race performance' },
15 { num: 5, name: 'Max Effort', icon: '🚀', pctLo: 90, pctHi: 100, purpose: 'Maximum effort — develop peak power and neuromuscular speed' }
16 ];
17
18 var FORMULA_LABELS = {
19 fox: 'Fox (220 − age)',
20 tanaka: 'Tanaka (208 − 0.7×age)',
21 gellish: 'Gellish (207 − 0.7×age)'
22 };
23
24 function typoCssVarsForEl(typo, prefix, el) {
25 if (!typo || typeof typo !== 'object') return;
26 var map = {
27 family:'font-family', weight:'font-weight', style:'font-style',
28 decoration:'text-decoration', transform:'text-transform',
29 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
30 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
31 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
32 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m'
33 };
34 Object.keys(map).forEach(function(k) {
35 if (typo[k] !== undefined && typo[k] !== '') {
36 var v = typo[k];
37 if (['sizeDesktop','sizeTablet','sizeMobile'].indexOf(k) !== -1) v = v + (typo.sizeUnit || 'px');
38 else if (['lineHeightDesktop','lineHeightTablet','lineHeightMobile'].indexOf(k) !== -1) v = v + (typo.lineHeightUnit || '');
39 else if (['letterSpacingDesktop','letterSpacingTablet','letterSpacingMobile'].indexOf(k) !== -1) v = v + (typo.letterSpacingUnit || 'px');
40 else if (['wordSpacingDesktop','wordSpacingTablet','wordSpacingMobile'].indexOf(k) !== -1) v = v + (typo.wordSpacingUnit || 'px');
41 el.style.setProperty(prefix + map[k], String(v));
42 }
43 });
44 }
45
46 document.querySelectorAll('.bkbg-hrc-app').forEach(function (root) {
47 var opts = {};
48 try { opts = JSON.parse(root.getAttribute('data-opts') || '{}'); } catch(e) {}
49
50 var defaultAge = parseInt(opts.defaultAge) || 30;
51 var defaultFormula = opts.defaultFormula || 'fox';
52 var showIcon = opts.showZoneIcon !== false;
53 var showPurpose = opts.showPurpose !== false;
54
55 var accentColor = opts.accentColor || '#ef4444';
56 var sectionBg = opts.sectionBg || '#fff7f7';
57 var cardBg = opts.cardBg || '#ffffff';
58 var inputBg = opts.inputBg || '#f9fafb';
59 var labelColor = opts.labelColor || '#374151';
60 var titleColor = opts.titleColor || '#111827';
61 var subtitleColor = opts.subtitleColor || '#6b7280';
62 var zColors = [
63 opts.z1Color || '#6ee7b7',
64 opts.z2Color || '#34d399',
65 opts.z3Color || '#fbbf24',
66 opts.z4Color || '#f97316',
67 opts.z5Color || '#ef4444'
68 ];
69
70 var currentAge = defaultAge;
71 var currentFormula = defaultFormula;
72
73 typoCssVarsForEl(opts.typoTitle, '--bkbg-hrc-tt-', root);
74 typoCssVarsForEl(opts.typoSubtitle, '--bkbg-hrc-st-', root);
75
76 root.innerHTML =
77 '<div class="bkbg-hrc-card" style="background:' + cardBg + ';max-width:' + (opts.contentMaxWidth || 760) + 'px;">' +
78 '<h2 class="bkbg-hrc-title" style="color:' + titleColor + ';">' + (opts.title || 'Heart Rate Zone Calculator') + '</h2>' +
79 '<p class="bkbg-hrc-subtitle" style="color:' + subtitleColor + ';">' + (opts.subtitle || 'Find your personalized training zones based on your age') + '</p>' +
80
81 '<div class="bkbg-hrc-controls" style="background:' + sectionBg + ';">' +
82 '<div class="bkbg-hrc-control-group">' +
83 '<label class="bkbg-hrc-label" style="color:' + labelColor + ';">🎂 Your Age: <strong id="hrc-age-display" style="color:' + accentColor + ';">' + defaultAge + '</strong></label>' +
84 '<input type="range" class="bkbg-hrc-slider" id="hrc-age-slider" min="18" max="80" value="' + defaultAge + '" style="accent-color:' + accentColor + ';">' +
85 '</div>' +
86 '<div class="bkbg-hrc-control-group">' +
87 '<label class="bkbg-hrc-label" style="color:' + labelColor + ';">📐 Formula</label>' +
88 '<select class="bkbg-hrc-select" id="hrc-formula" style="background:' + inputBg + ';">' +
89 '<option value="fox"' + (defaultFormula === 'fox' ? ' selected' : '') + '>Fox: 220 − age</option>' +
90 '<option value="tanaka"' + (defaultFormula === 'tanaka' ? ' selected' : '') + '>Tanaka: 208 − 0.7×age</option>' +
91 '<option value="gellish"' + (defaultFormula === 'gellish' ? ' selected' : '') + '>Gellish: 207 − 0.7×age</option>' +
92 '</select>' +
93 '</div>' +
94 '</div>' +
95
96 '<div class="bkbg-hrc-maxhr" id="hrc-maxhr-box" style="border-color:' + accentColor + ';background:' + accentColor + '12;">' +
97 '<div class="bkbg-hrc-maxhr-label" style="color:' + labelColor + ';">❤️ Maximum Heart Rate</div>' +
98 '<div class="bkbg-hrc-maxhr-val" id="hrc-maxhr-val" style="color:' + accentColor + ';">' + calcMaxHR(defaultAge, defaultFormula) + '</div>' +
99 '<div class="bkbg-hrc-maxhr-unit" style="color:' + subtitleColor + ';">beats per minute</div>' +
100 '</div>' +
101
102 '<div class="bkbg-hrc-zones" id="hrc-zones"></div>' +
103 '</div>';
104
105 var ageSlider = root.querySelector('#hrc-age-slider');
106 var ageDisplay = root.querySelector('#hrc-age-display');
107 var fmlSelect = root.querySelector('#hrc-formula');
108 var maxhrVal = root.querySelector('#hrc-maxhr-val');
109 var zonesEl = root.querySelector('#hrc-zones');
110
111 function renderZones() {
112 var maxHR = calcMaxHR(currentAge, currentFormula);
113 maxhrVal.textContent = maxHR;
114
115 var html = '';
116 ZONES.forEach(function(z, i) {
117 var color = zColors[i];
118 var lo = Math.round(maxHR * z.pctLo / 100);
119 var hi = Math.round(maxHR * z.pctHi / 100);
120 html +=
121 '<div class="bkbg-hrc-zone-row" style="border-left-color:' + color + ';background:' + color + '18;">' +
122 '<div class="bkbg-hrc-zone-left">' +
123 '<div class="bkbg-hrc-zone-badge" style="background:' + color + ';color:#fff;">' +
124 (showIcon ? z.icon + ' ' : '') + 'Zone ' + z.num +
125 '</div>' +
126 '<div class="bkbg-hrc-zone-name">' + z.name + '</div>' +
127 '</div>' +
128 '<div class="bkbg-hrc-zone-center">' +
129 (showPurpose ? '<div class="bkbg-hrc-zone-purpose">' + z.purpose + '</div>' : '') +
130 '</div>' +
131 '<div class="bkbg-hrc-zone-right">' +
132 '<div class="bkbg-hrc-zone-bpm" style="color:' + color + ';">' + lo + '' + hi + '</div>' +
133 '<div class="bkbg-hrc-zone-pct">' + z.pctLo + '' + z.pctHi + '% max HR</div>' +
134 '</div>' +
135 '</div>';
136 });
137 zonesEl.innerHTML = html;
138 }
139
140 ageSlider.addEventListener('input', function () {
141 currentAge = parseInt(this.value);
142 ageDisplay.textContent = currentAge;
143 renderZones();
144 });
145
146 fmlSelect.addEventListener('change', function () {
147 currentFormula = this.value;
148 renderZones();
149 });
150
151 renderZones();
152 });
153
154 })();
155