Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 35ea522283 | |||
| fc62b64624 | |||
| e66b9e6c29 | |||
| f0e90aa772 | |||
| 4406b2013d | |||
| 9d61ebb533 | |||
| 100b47e947 | |||
| 47e6e69eb7 | |||
| 8e8280bcb0 | |||
| 580ad5d248 | |||
| 974699dd81 | |||
| dbee12341a | |||
| 4028b7c626 | |||
| cc9e526fda | |||
| 79daa8cea1 | |||
| 9c1cb1966b | |||
| 29ad9e2265 | |||
| 47f0c6f3fb | |||
| 9d51b006c0 | |||
| 895d8abe02 | |||
| 2e4cc5ec76 | |||
| b186fafbba | |||
| af81e8d683 | |||
| fec2c72b13 | |||
| 32126a3702 |
@@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
+139
-56
@@ -9,6 +9,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import uuid
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi import FastAPI, File, Form, HTTPException, Request, UploadFile
|
from fastapi import FastAPI, File, Form, HTTPException, Request, UploadFile
|
||||||
@@ -109,7 +110,8 @@ async def upload_files(
|
|||||||
gender: str = Form(...),
|
gender: str = Form(...),
|
||||||
fat_percentage: float = Form(...),
|
fat_percentage: float = Form(...),
|
||||||
focus: str = Form(default="Endurance"),
|
focus: str = Form(default="Endurance"),
|
||||||
session_id: str = Form(default="default"),
|
next_testing_date: str = Form(...),
|
||||||
|
report_type: str = Form(default="full"),
|
||||||
spirometry_pdf: UploadFile = File(...),
|
spirometry_pdf: UploadFile = File(...),
|
||||||
pnoe_csv: UploadFile = File(...),
|
pnoe_csv: UploadFile = File(...),
|
||||||
oxygenation_csv: UploadFile = File(None),
|
oxygenation_csv: UploadFile = File(None),
|
||||||
@@ -176,6 +178,11 @@ async def upload_files(
|
|||||||
|
|
||||||
# Prepare patient information
|
# Prepare patient information
|
||||||
patient_name = f"{first_name} {last_name}"
|
patient_name = f"{first_name} {last_name}"
|
||||||
|
print(f"DEBUG: Received next_testing_date: '{next_testing_date}'")
|
||||||
|
|
||||||
|
# Generate session_id internally using timestamp for unique identification
|
||||||
|
session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
patient_info = {
|
patient_info = {
|
||||||
"patient_name": patient_name,
|
"patient_name": patient_name,
|
||||||
"first_name": first_name,
|
"first_name": first_name,
|
||||||
@@ -187,6 +194,7 @@ async def upload_files(
|
|||||||
"fat_percentage": fat_percentage,
|
"fat_percentage": fat_percentage,
|
||||||
"focus": focus,
|
"focus": focus,
|
||||||
"session_id": session_id,
|
"session_id": session_id,
|
||||||
|
"next_testing_date": next_testing_date,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate report
|
# Generate report
|
||||||
@@ -196,12 +204,14 @@ async def upload_files(
|
|||||||
pnoe_csv_path=str(pnoe_path),
|
pnoe_csv_path=str(pnoe_path),
|
||||||
patient_info=patient_info,
|
patient_info=patient_info,
|
||||||
oxygenation_csv_path=oxygenation_csv_path,
|
oxygenation_csv_path=oxygenation_csv_path,
|
||||||
|
report_type=report_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Store in session
|
# Store in session
|
||||||
request.session["patient_info"] = patient_info
|
request.session["patient_info"] = patient_info
|
||||||
request.session["temp_dir"] = str(session_temp_dir)
|
request.session["temp_dir"] = str(session_temp_dir)
|
||||||
request.session["report_path"] = result["report_path"]
|
request.session["report_path"] = result["report_path"]
|
||||||
|
request.session["report_type"] = report_type
|
||||||
request.session["graphs_generated"] = result["graphs_generated"]
|
request.session["graphs_generated"] = result["graphs_generated"]
|
||||||
request.session["analysis_data"] = result["analysis_data"]
|
request.session["analysis_data"] = result["analysis_data"]
|
||||||
|
|
||||||
@@ -233,6 +243,7 @@ async def upload_files(
|
|||||||
str(pnoe_path),
|
str(pnoe_path),
|
||||||
str(spirometry_csv_path),
|
str(spirometry_csv_path),
|
||||||
None, # No SECA file needed anymore
|
None, # No SECA file needed anymore
|
||||||
|
str(oxygenation_path) if oxygenation_path else None, # Oxygenation CSV
|
||||||
)
|
)
|
||||||
# Set patient info manually since we're not reading from SECA
|
# Set patient info manually since we're not reading from SECA
|
||||||
weight_kg = float(weight.replace("lbs", "").replace("kg", "").strip())
|
weight_kg = float(weight.replace("lbs", "").replace("kg", "").strip())
|
||||||
@@ -283,8 +294,18 @@ async def upload_files(
|
|||||||
@app.get("/preview", response_class=HTMLResponse)
|
@app.get("/preview", response_class=HTMLResponse)
|
||||||
async def preview(request: Request):
|
async def preview(request: Request):
|
||||||
"""Preview generated report"""
|
"""Preview generated report"""
|
||||||
|
# Check for required session data
|
||||||
if not request.session.get("report_path"):
|
if not request.session.get("report_path"):
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url="/", status_code=303)
|
||||||
|
|
||||||
|
# Ensure metrics exist in session, initialize if missing
|
||||||
|
if "metrics" not in request.session:
|
||||||
|
request.session["metrics"] = {"pnoe": {}, "spirometry": {}}
|
||||||
|
|
||||||
|
# Ensure patient_info exists
|
||||||
|
if "patient_info" not in request.session:
|
||||||
|
request.session["patient_info"] = {}
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"preview.html", {"request": request, "session": request.session}
|
"preview.html", {"request": request, "session": request.session}
|
||||||
)
|
)
|
||||||
@@ -302,8 +323,16 @@ async def serve_graph(filename: str):
|
|||||||
@app.get("/edit", response_class=HTMLResponse)
|
@app.get("/edit", response_class=HTMLResponse)
|
||||||
async def edit_form(request: Request):
|
async def edit_form(request: Request):
|
||||||
"""Display edit metrics form"""
|
"""Display edit metrics form"""
|
||||||
if not request.session.get("metrics"):
|
# Check for required session data
|
||||||
|
if not request.session.get("report_path") or not request.session.get(
|
||||||
|
"patient_info"
|
||||||
|
):
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url="/", status_code=303)
|
||||||
|
|
||||||
|
# Ensure metrics exist in session, initialize if missing
|
||||||
|
if "metrics" not in request.session:
|
||||||
|
request.session["metrics"] = {"pnoe": {}, "spirometry": {}}
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"edit.html", {"request": request, "session": request.session}
|
"edit.html", {"request": request, "session": request.session}
|
||||||
)
|
)
|
||||||
@@ -318,69 +347,117 @@ async def edit_metrics(request: Request):
|
|||||||
# Get form data
|
# Get form data
|
||||||
form_data = await request.form()
|
form_data = await request.form()
|
||||||
|
|
||||||
|
# Helper function to safely convert form values to float
|
||||||
|
def safe_float(value):
|
||||||
|
"""Convert form value to float, return None if empty or invalid"""
|
||||||
|
if not value or value.strip() == "":
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return float(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return None
|
||||||
|
|
||||||
# Build metric overrides
|
# Build metric overrides
|
||||||
metric_overrides = {"pnoe": {}, "spirometry": {}}
|
metric_overrides = {"pnoe": {}, "spirometry": {}}
|
||||||
|
|
||||||
# Pnoe overrides
|
# Pnoe overrides - only add if value is provided and valid
|
||||||
if form_data.get("vo2_max"):
|
vo2_max_val = safe_float(form_data.get("vo2_max"))
|
||||||
metric_overrides["pnoe"]["vo2_max"] = float(form_data["vo2_max"])
|
if vo2_max_val is not None:
|
||||||
if form_data.get("vo2_max_per_kg"):
|
metric_overrides["pnoe"]["vo2_max"] = vo2_max_val
|
||||||
metric_overrides["pnoe"]["vo2_max_per_kg"] = float(form_data["vo2_max_per_kg"])
|
|
||||||
if form_data.get("peak_vt"):
|
|
||||||
metric_overrides["pnoe"]["peak_vt"] = float(form_data["peak_vt"])
|
|
||||||
if form_data.get("peak_vt_hr"):
|
|
||||||
metric_overrides["pnoe"]["peak_vt_hr"] = float(form_data["peak_vt_hr"])
|
|
||||||
if form_data.get("fat_max_value"):
|
|
||||||
metric_overrides["pnoe"]["fat_max_value"] = float(form_data["fat_max_value"])
|
|
||||||
if form_data.get("fat_max_hr"):
|
|
||||||
metric_overrides["pnoe"]["fat_max_hr"] = float(form_data["fat_max_hr"])
|
|
||||||
|
|
||||||
# VT1 and VT2 overrides
|
vo2_max_per_kg_val = safe_float(form_data.get("vo2_max_per_kg"))
|
||||||
if (
|
if vo2_max_per_kg_val is not None:
|
||||||
form_data.get("vt1_hr")
|
metric_overrides["pnoe"]["vo2_max_per_kg"] = vo2_max_per_kg_val
|
||||||
or form_data.get("vt1_speed")
|
|
||||||
or form_data.get("vt1_time")
|
peak_vt_val = safe_float(form_data.get("peak_vt"))
|
||||||
):
|
if peak_vt_val is not None:
|
||||||
metric_overrides["pnoe"]["vt1"] = {
|
metric_overrides["pnoe"]["peak_vt"] = peak_vt_val
|
||||||
"HeartRate": float(form_data.get("vt1_hr", 0)),
|
|
||||||
"Speed": float(form_data.get("vt1_speed", 0)),
|
peak_vt_hr_val = safe_float(form_data.get("peak_vt_hr"))
|
||||||
"Time": float(form_data.get("vt1_time", 0)),
|
if peak_vt_hr_val is not None:
|
||||||
|
metric_overrides["pnoe"]["peak_vt_hr"] = peak_vt_hr_val
|
||||||
|
|
||||||
|
fat_max_value_val = safe_float(form_data.get("fat_max_value"))
|
||||||
|
if fat_max_value_val is not None:
|
||||||
|
metric_overrides["pnoe"]["fat_max_value"] = fat_max_value_val
|
||||||
|
|
||||||
|
fat_max_hr_val = safe_float(form_data.get("fat_max_hr"))
|
||||||
|
if fat_max_hr_val is not None:
|
||||||
|
metric_overrides["pnoe"]["fat_max_hr"] = fat_max_hr_val
|
||||||
|
|
||||||
|
# VT1 and VT2 overrides - use existing values if not provided
|
||||||
|
existing_metrics = request.session.get("metrics", {})
|
||||||
|
existing_pnoe = existing_metrics.get("pnoe", {})
|
||||||
|
existing_vt1 = existing_pnoe.get("vt1", {})
|
||||||
|
existing_vt2 = existing_pnoe.get("vt2", {})
|
||||||
|
|
||||||
|
vt1_hr_val = safe_float(form_data.get("vt1_hr"))
|
||||||
|
vt1_speed_val = safe_float(form_data.get("vt1_speed"))
|
||||||
|
vt1_time_val = safe_float(form_data.get("vt1_time"))
|
||||||
|
|
||||||
|
if vt1_hr_val is not None or vt1_speed_val is not None or vt1_time_val is not None:
|
||||||
|
vt1_dict = {
|
||||||
|
"HeartRate": vt1_hr_val
|
||||||
|
if vt1_hr_val is not None
|
||||||
|
else existing_vt1.get("HeartRate", 0),
|
||||||
|
"Speed": vt1_speed_val
|
||||||
|
if vt1_speed_val is not None
|
||||||
|
else existing_vt1.get("Speed", 0),
|
||||||
|
"Time": vt1_time_val
|
||||||
|
if vt1_time_val is not None
|
||||||
|
else existing_vt1.get("Time", 0),
|
||||||
}
|
}
|
||||||
|
metric_overrides["pnoe"]["vt1"] = vt1_dict
|
||||||
|
|
||||||
if (
|
vt2_hr_val = safe_float(form_data.get("vt2_hr"))
|
||||||
form_data.get("vt2_hr")
|
vt2_speed_val = safe_float(form_data.get("vt2_speed"))
|
||||||
or form_data.get("vt2_speed")
|
vt2_time_val = safe_float(form_data.get("vt2_time"))
|
||||||
or form_data.get("vt2_time")
|
|
||||||
):
|
if vt2_hr_val is not None or vt2_speed_val is not None or vt2_time_val is not None:
|
||||||
metric_overrides["pnoe"]["vt2"] = {
|
vt2_dict = {
|
||||||
"HeartRate": float(form_data.get("vt2_hr", 0)),
|
"HeartRate": vt2_hr_val
|
||||||
"Speed": float(form_data.get("vt2_speed", 0)),
|
if vt2_hr_val is not None
|
||||||
"Time": float(form_data.get("vt2_time", 0)),
|
else existing_vt2.get("HeartRate", 0),
|
||||||
|
"Speed": vt2_speed_val
|
||||||
|
if vt2_speed_val is not None
|
||||||
|
else existing_vt2.get("Speed", 0),
|
||||||
|
"Time": vt2_time_val
|
||||||
|
if vt2_time_val is not None
|
||||||
|
else existing_vt2.get("Time", 0),
|
||||||
}
|
}
|
||||||
|
metric_overrides["pnoe"]["vt2"] = vt2_dict
|
||||||
|
|
||||||
# Heart rate zones
|
# Heart rate zones - only add if value is provided
|
||||||
for i in range(1, 6):
|
for i in range(1, 6):
|
||||||
zone_key = f"zone{i}_bpm"
|
zone_key = f"zone{i}_bpm"
|
||||||
if form_data.get(zone_key):
|
zone_val = form_data.get(zone_key)
|
||||||
metric_overrides["pnoe"][zone_key] = form_data[zone_key]
|
if zone_val and zone_val.strip():
|
||||||
|
metric_overrides["pnoe"][zone_key] = zone_val.strip()
|
||||||
|
|
||||||
# Spirometry overrides
|
# Spirometry overrides - only add if value is provided and valid
|
||||||
if form_data.get("fvc_best"):
|
fvc_best_val = safe_float(form_data.get("fvc_best"))
|
||||||
metric_overrides["spirometry"]["fvc_best"] = float(form_data["fvc_best"])
|
if fvc_best_val is not None:
|
||||||
if form_data.get("fvc_pred"):
|
metric_overrides["spirometry"]["fvc_best"] = fvc_best_val
|
||||||
metric_overrides["spirometry"]["fvc_pred"] = float(form_data["fvc_pred"])
|
|
||||||
if form_data.get("fev1_best"):
|
fvc_pred_val = safe_float(form_data.get("fvc_pred"))
|
||||||
metric_overrides["spirometry"]["fev1_best"] = float(form_data["fev1_best"])
|
if fvc_pred_val is not None:
|
||||||
if form_data.get("fev1_pred"):
|
metric_overrides["spirometry"]["fvc_pred"] = fvc_pred_val
|
||||||
metric_overrides["spirometry"]["fev1_pred"] = float(form_data["fev1_pred"])
|
|
||||||
if form_data.get("fev1_fvc_pct_best"):
|
fev1_best_val = safe_float(form_data.get("fev1_best"))
|
||||||
metric_overrides["spirometry"]["fev1_fvc_pct_best"] = float(
|
if fev1_best_val is not None:
|
||||||
form_data["fev1_fvc_pct_best"]
|
metric_overrides["spirometry"]["fev1_best"] = fev1_best_val
|
||||||
)
|
|
||||||
if form_data.get("fev1_fvc_pct_pred"):
|
fev1_pred_val = safe_float(form_data.get("fev1_pred"))
|
||||||
metric_overrides["spirometry"]["fev1_fvc_pct_pred"] = float(
|
if fev1_pred_val is not None:
|
||||||
form_data["fev1_fvc_pct_pred"]
|
metric_overrides["spirometry"]["fev1_pred"] = fev1_pred_val
|
||||||
)
|
|
||||||
|
fev1_fvc_pct_best_val = safe_float(form_data.get("fev1_fvc_pct_best"))
|
||||||
|
if fev1_fvc_pct_best_val is not None:
|
||||||
|
metric_overrides["spirometry"]["fev1_fvc_pct_best"] = fev1_fvc_pct_best_val
|
||||||
|
|
||||||
|
fev1_fvc_pct_pred_val = safe_float(form_data.get("fev1_fvc_pct_pred"))
|
||||||
|
if fev1_fvc_pct_pred_val is not None:
|
||||||
|
metric_overrides["spirometry"]["fev1_fvc_pct_pred"] = fev1_fvc_pct_pred_val
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get file paths from session
|
# Get file paths from session
|
||||||
@@ -404,6 +481,8 @@ async def edit_metrics(request: Request):
|
|||||||
raise ValueError("Could not find all required uploaded files")
|
raise ValueError("Could not find all required uploaded files")
|
||||||
|
|
||||||
# Regenerate report with overrides
|
# Regenerate report with overrides
|
||||||
|
# Get report_type from session or default to "full"
|
||||||
|
report_type = request.session.get("report_type", "full")
|
||||||
oxygenation_csv_path = str(oxygenation_path) if oxygenation_path else None
|
oxygenation_csv_path = str(oxygenation_path) if oxygenation_path else None
|
||||||
result = await report_service.generate_report(
|
result = await report_service.generate_report(
|
||||||
spirometry_pdf_path=str(spirometry_path),
|
spirometry_pdf_path=str(spirometry_path),
|
||||||
@@ -413,6 +492,7 @@ async def edit_metrics(request: Request):
|
|||||||
if (metric_overrides["pnoe"] or metric_overrides["spirometry"])
|
if (metric_overrides["pnoe"] or metric_overrides["spirometry"])
|
||||||
else None,
|
else None,
|
||||||
oxygenation_csv_path=oxygenation_csv_path,
|
oxygenation_csv_path=oxygenation_csv_path,
|
||||||
|
report_type=report_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update session with new report
|
# Update session with new report
|
||||||
@@ -442,6 +522,7 @@ async def edit_metrics(request: Request):
|
|||||||
str(pnoe_path),
|
str(pnoe_path),
|
||||||
spirometry_csv_path,
|
spirometry_csv_path,
|
||||||
None, # No SECA file
|
None, # No SECA file
|
||||||
|
str(oxygenation_path) if oxygenation_path else None, # Oxygenation CSV
|
||||||
)
|
)
|
||||||
# Set patient info manually
|
# Set patient info manually
|
||||||
weight_str = patient_info.get("weight", "0")
|
weight_str = patient_info.get("weight", "0")
|
||||||
@@ -457,6 +538,7 @@ async def edit_metrics(request: Request):
|
|||||||
"fat_percentage": patient_info.get("fat_percentage", 0),
|
"fat_percentage": patient_info.get("fat_percentage", 0),
|
||||||
"gender": patient_info.get("gender", "female"),
|
"gender": patient_info.get("gender", "female"),
|
||||||
}
|
}
|
||||||
|
# Calculate fat_mass and lean_mass (extract_patient_info does this when no SECA file)
|
||||||
context_gen.extract_patient_info(patient_info.get("last_name", ""))
|
context_gen.extract_patient_info(patient_info.get("last_name", ""))
|
||||||
|
|
||||||
spirometry_overrides = metric_overrides.get("spirometry", {})
|
spirometry_overrides = metric_overrides.get("spirometry", {})
|
||||||
@@ -503,7 +585,6 @@ async def generate_report(
|
|||||||
height: str = Form(..., description="Patient height (e.g., 5'4\")"),
|
height: str = Form(..., description="Patient height (e.g., 5'4\")"),
|
||||||
weight: str = Form(..., description="Patient weight (e.g., 123lbs)"),
|
weight: str = Form(..., description="Patient weight (e.g., 123lbs)"),
|
||||||
focus: str = Form(default="Endurance", description="Training focus"),
|
focus: str = Form(default="Endurance", description="Training focus"),
|
||||||
session_id: str = Form(default="default", description="Session ID"),
|
|
||||||
spirometry_pdf: UploadFile = File(..., description="Spirometry PDF file"),
|
spirometry_pdf: UploadFile = File(..., description="Spirometry PDF file"),
|
||||||
pnoe_csv: UploadFile = File(..., description="Pnoe CSV file"),
|
pnoe_csv: UploadFile = File(..., description="Pnoe CSV file"),
|
||||||
seca_excel: UploadFile = File(..., description="SECA Excel file"),
|
seca_excel: UploadFile = File(..., description="SECA Excel file"),
|
||||||
@@ -523,7 +604,6 @@ async def generate_report(
|
|||||||
height: Patient height
|
height: Patient height
|
||||||
weight: Patient weight
|
weight: Patient weight
|
||||||
focus: Training focus (default: Endurance)
|
focus: Training focus (default: Endurance)
|
||||||
session_id: Session identifier (default: default)
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ReportResponse with report path, graphs generated, and analysis data
|
ReportResponse with report path, graphs generated, and analysis data
|
||||||
@@ -560,6 +640,9 @@ async def generate_report(
|
|||||||
with open(seca_path, "wb") as f:
|
with open(seca_path, "wb") as f:
|
||||||
shutil.copyfileobj(seca_excel.file, f)
|
shutil.copyfileobj(seca_excel.file, f)
|
||||||
|
|
||||||
|
# Generate session_id internally using timestamp for unique identification
|
||||||
|
session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
# Prepare patient information
|
# Prepare patient information
|
||||||
patient_info = {
|
patient_info = {
|
||||||
"patient_name": patient_name,
|
"patient_name": patient_name,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<!-- Name and Date Section -->
|
<!-- Name and Date Section -->
|
||||||
<div class="text-right mt-16">
|
<div class="text-right mt-16">
|
||||||
<h2 class="text-4xl font-bold tracking-wider mb-2">
|
<h2 class="text-4xl font-bold tracking-wider mb-2">
|
||||||
{{ first_name|upper }}
|
{{ name|upper }}
|
||||||
</h2>
|
</h2>
|
||||||
<h2 class="text-4xl font-bold tracking-wider mb-6">
|
<h2 class="text-4xl font-bold tracking-wider mb-6">
|
||||||
{{ surname|upper }}
|
{{ surname|upper }}
|
||||||
|
|||||||
+511
-34
@@ -1,38 +1,515 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-6">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-6">Fuelling Analysis</h1>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Flowchart Image -->
|
||||||
<div class="px-8 py-6">
|
<div class="mb-8 flex justify-center">
|
||||||
<!-- VO2 Pulse Section -->
|
<img
|
||||||
<div class="mb-8">
|
src="data:image/png;base64,{{ fuelling_analysis_flowchart }}"
|
||||||
<!-- VO2 Pulse Header -->
|
alt="Fuelling Analysis Flowchart"
|
||||||
<div class="bg-gray-200 p-4 rounded-lg mb-4 text-center">
|
class="w-full max-w-4xl h-auto object-contain"
|
||||||
<h2 class="text-lg font-bold text-black">VO2 Pulse</h2>
|
/>
|
||||||
<p class="text-black">Begins to drop at {{ vo2_pulse_drop_bpm | default('180 bpm') }} ({{ vo2_pulse_drop_zone | default('Zone 4') }})</p>
|
</div>
|
||||||
</div>
|
|
||||||
|
<!-- Carbohydrate Storage Table -->
|
||||||
<!-- VO2 Pulse Graph -->
|
<div class="mb-8">
|
||||||
<div class="flex justify-center mb-6">
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
<img src="data:image/png;base64, {{ vo2_pulse_chart }}"
|
Estimated Carbohydrate Storage by Weight and Sex in Athletes
|
||||||
alt="VO2 Pulse Chart"
|
</h2>
|
||||||
class="w-full max-w-4xl h-auto object-contain">
|
|
||||||
</div>
|
<div class="flex justify-center">
|
||||||
|
<table
|
||||||
|
class="table-auto border-collapse border border-gray-400 text-sm"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-gray-200">
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Weight (kg)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Sex
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Muscle Glycogen (g)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Liver Glycogen (g)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Blood Glucose (g)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Total Carb (g)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
Total Carb (kcal)
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
50
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
292
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
402
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1608
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
50
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
228
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
317
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1268
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
60
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
351
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
460
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1842
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
60
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
273
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
362
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1450
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
70
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
410
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
519
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
2076
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
70
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
318
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
408
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1632
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
80
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
468
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
578
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
2310
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
80
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
364
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
454
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1814
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
90
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
526
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
636
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
2544
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
90
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
409
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
499
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
1996
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
100
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
male
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
585
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
105
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
694
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
2778
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-gray-50">
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
100
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
female
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
455
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
85
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
4.5
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
544
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="border border-gray-400 px-4 py-2 text-center"
|
||||||
|
>
|
||||||
|
2178
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VO2 Breath Section -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<!-- VO2 Breath Header -->
|
|
||||||
<div class="bg-gray-200 p-4 rounded-lg mb-4 text-center">
|
|
||||||
<h2 class="text-lg font-bold text-black">VO2 Breath</h2>
|
|
||||||
<p class="text-black">Begins to drop at {{ vo2_breath_drop_bpm | default('173 bpm') }} ({{ vo2_breath_drop_zone | default('Zone 3') }})</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- VO2 Breath Graph -->
|
|
||||||
<div class="flex justify-center mb-6">
|
|
||||||
<img src="data:image/png;base64, {{ vo2_breath_chart }}"
|
|
||||||
alt="VO2 Breath Chart"
|
|
||||||
class="w-full max-w-4xl h-auto object-contain">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+33
-226
@@ -1,231 +1,38 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="px-8 py-6">
|
<div class="px-8 py-6">
|
||||||
<!-- Fat Metabolism Section -->
|
<!-- VO2 Pulse Section -->
|
||||||
<div class="mb-2">
|
<div class="mb-8">
|
||||||
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
<!-- VO2 Pulse Header -->
|
||||||
Fat Metabolism
|
<div class="bg-gray-200 p-4 rounded-lg mb-4 text-center">
|
||||||
</h2>
|
<h2 class="text-lg font-bold text-black">VO2 Pulse</h2>
|
||||||
|
<p class="text-black">Begins to drop at {{ vo2_pulse_drop_bpm | default('180 bpm') }} ({{ vo2_pulse_drop_zone | default('Zone 4') }})</p>
|
||||||
<!-- Fat Metabolism Info Boxes -->
|
</div>
|
||||||
<div class="grid grid-cols-2 gap-4 mb-4">
|
|
||||||
<!-- Fat Max Box -->
|
<!-- VO2 Pulse Graph -->
|
||||||
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
<div class="flex justify-center mb-6">
|
||||||
<h3 class="text-base font-bold text-black mb-2">Fat Max</h3>
|
<img src="data:image/png;base64, {{ vo2_pulse_chart }}"
|
||||||
<p class="text-xs text-gray-600 italic mb-2">
|
alt="VO2 Pulse Chart"
|
||||||
{{ fat_max_optimal | default('*Optimal
|
class="w-full max-w-4xl h-auto object-contain">
|
||||||
10-12Kcals/minute') }}
|
</div>
|
||||||
</p>
|
|
||||||
<p class="text-lg font-bold text-black">
|
|
||||||
{{ fat_max_value | default('3.8Kcals/min') }}
|
|
||||||
</p>
|
|
||||||
<p class="text-xs text-black">
|
|
||||||
{{ fat_max_heart_rate | default('49% of Max Heart Rate')
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<p class="text-xs text-black">
|
|
||||||
{{ fat_max_bpm | default('97 bpm') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Carbs and Fat Crossover Box -->
|
|
||||||
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
|
||||||
<h3 class="text-base font-bold text-black mb-3">
|
|
||||||
Carbs and Fat Crossover
|
|
||||||
</h3>
|
|
||||||
<p class="text-lg font-bold text-black">
|
|
||||||
{{ crossover_bpm | default('100bpm') }}
|
|
||||||
</p>
|
|
||||||
<p class="text-xs text-black">
|
|
||||||
{{ crossover_heart_rate | default('51% of Max Heart
|
|
||||||
Rate') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fat Metabolism Graph -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<div class="bg-gray-100 p-2 rounded-lg mb-2">
|
|
||||||
<p class="text-black font-semibold text-center text-sm"></p>
|
|
||||||
{{ fat_metabolism_note | default('100bpm at a speed of
|
|
||||||
4.0mph and incline of 2%') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<img
|
|
||||||
src="data:image/png;base64, {{ fat_metabolism_chart }}"
|
|
||||||
alt="Fat Metabolism Chart"
|
|
||||||
class="w-full max-w-4xl h-auto object-contain"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Recovery Section -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
|
||||||
Recovery
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<!-- Recovery Info Boxes -->
|
|
||||||
<div class="grid grid-cols-3 gap-4 mb-4">
|
|
||||||
<!-- Cardiac Recovery -->
|
|
||||||
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
|
||||||
<h3 class="text-sm font-bold text-black mb-2">
|
|
||||||
Cardiac Recovery
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-gray-600 mb-2">
|
|
||||||
{{ cardiac_recovery_time | default('(1 minute)') }}
|
|
||||||
</p>
|
|
||||||
<p class="text-lg font-bold text-black">
|
|
||||||
{{ cardiac_recovery_percentage | default('33%') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Metabolic Recovery -->
|
|
||||||
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
|
||||||
<h3 class="text-sm font-bold text-black mb-2">
|
|
||||||
Metabolic (CO2) Recovery
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-gray-600 mb-2">
|
|
||||||
{{ metabolic_recovery_time | default('(2 minute)') }}
|
|
||||||
</p>
|
|
||||||
<p class="text-lg font-bold text-black">
|
|
||||||
{{ metabolic_recovery_percentage | default('65%') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Breath Frequency Recovery -->
|
|
||||||
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
|
||||||
<h3 class="text-sm font-bold text-black mb-2">
|
|
||||||
Breath Frequency Recovery
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-gray-600 mb-2">
|
|
||||||
{{ breath_recovery_time | default('(2.5 minute)') }}
|
|
||||||
</p>
|
|
||||||
<p class="text-lg font-bold text-black">
|
|
||||||
{{ breath_recovery_percentage | default('76%') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Recovery Graph -->
|
|
||||||
<div class="flex justify-center mb-6">
|
|
||||||
<img
|
|
||||||
src="data:image/png;base64, {{ recovery_chart }}"
|
|
||||||
alt="Recovery Chart"
|
|
||||||
class="w-full max-w-4xl h-auto object-contain"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Resting Heart Rate Table -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<h3 class="text-base font-bold text-black mb-2 text-center">
|
|
||||||
Resting Heart Rate - {{ resting_heart_rate | default('53bpm') }}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<table class="w-full border-collapse text-xs">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Age (F)
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Below Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Above Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Good
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold"
|
|
||||||
>
|
|
||||||
Excellent
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold relative"
|
|
||||||
>
|
|
||||||
Athlete
|
|
||||||
<!-- Arrow indicator -->
|
|
||||||
<div
|
|
||||||
class="absolute -bottom-3 left-1/2 transform -translate-x-1/2"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="w-0 h-0 border-l-3 border-r-3 border-t-6 border-transparent border-t-black"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="bg-cyan-200 border border-gray-400 p-2 text-black font-semibold text-center"
|
|
||||||
>
|
|
||||||
{{ hr_age_range | default('26-35') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_poor | default('82bpm +') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_below_avg | default('75-81bpm') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_average | default('71-74bpm') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_above_avg | default('66-70bpm') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_good | default('62-65bpm') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-gray-100 border border-gray-400 p-2 text-black text-center"
|
|
||||||
>
|
|
||||||
{{ hr_excellent | default('55-61bpm') }}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="bg-green-200 border border-gray-400 p-2 text-black text-center font-bold"
|
|
||||||
>
|
|
||||||
{{ hr_athlete | default('44-54bpm') }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- VO2 Breath Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<!-- VO2 Breath Header -->
|
||||||
|
<div class="bg-gray-200 p-4 rounded-lg mb-4 text-center">
|
||||||
|
<h2 class="text-lg font-bold text-black">VO2 Breath</h2>
|
||||||
|
<p class="text-black">Begins to drop at {{ vo2_breath_drop_bpm | default('173 bpm') }} ({{ vo2_breath_drop_zone | default('Zone 3') }})</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- VO2 Breath Graph -->
|
||||||
|
<div class="flex justify-center mb-6">
|
||||||
|
<img src="data:image/png;base64, {{ vo2_breath_chart }}"
|
||||||
|
alt="VO2 Breath Chart"
|
||||||
|
class="w-full max-w-4xl h-auto object-contain">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+127
-67
@@ -1,76 +1,136 @@
|
|||||||
<div class="page bg-white p-8 max-w-4xl mx-auto">
|
<div class="w-full page bg-white">
|
||||||
<!-- Header -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<h1 class="text-3xl font-bold text-gray-900 mb-4">Local Muscle Activity</h1>
|
|
||||||
<h2 class="text-xl font-semibold text-gray-800 mb-2">Muscle Oxygenation Assessment</h2>
|
|
||||||
<p class="text-sm text-gray-600 leading-relaxed">
|
|
||||||
SMO2 testing (Skeletal Muscle Oxygen Saturation) is an analysis of how effectively oxygen is being used at a particular muscle. It helps determine limitations on if the muscle is effectively using oxygen when exercising.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right Leg Section -->
|
<!-- Main Content -->
|
||||||
<div class="mb-12">
|
<div class="px-8 py-6">
|
||||||
<h3 class="text-lg font-semibold text-center text-gray-800 mb-6">Indications - Right Leg</h3>
|
<!-- Fat Metabolism Section -->
|
||||||
|
<div class="mb-2">
|
||||||
<div class="flex gap-8">
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
<!-- Chart Image -->
|
Fat Metabolism
|
||||||
<div class="flex-1">
|
</h2>
|
||||||
<img src="right-leg-chart.png" alt="Right Leg SMO2 Chart" class="w-full h-auto">
|
|
||||||
|
<!-- Fat Metabolism Info Boxes -->
|
||||||
|
<div class="grid grid-cols-2 gap-4 mb-4">
|
||||||
|
<!-- Fat Max Box -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
||||||
|
<h3 class="text-base font-bold text-black mb-2">Fat Max</h3>
|
||||||
|
<p class="text-xs text-gray-600 italic mb-2">
|
||||||
|
{{ fat_max_optimal | default('*Optimal
|
||||||
|
10-12Kcals/minute') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
{{ fat_max_value | default('3.8Kcals/min') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-black">
|
||||||
|
{{ fat_max_heart_rate | default('49% of Max Heart Rate')
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-black">
|
||||||
|
{{ fat_max_bpm | default('97 bpm') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Carbs and Fat Crossover Box -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
||||||
|
<h3 class="text-base font-bold text-black mb-3">
|
||||||
|
Carbs and Fat Crossover
|
||||||
|
</h3>
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
{{ crossover_bpm | default('100bpm') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-black">
|
||||||
|
{{ crossover_heart_rate | default('51% of Max Heart
|
||||||
|
Rate') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Side Info -->
|
<!-- Fat Metabolism Graph -->
|
||||||
<div class="w-48 space-y-4">
|
<div class="mb-4">
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
<!-- <div class="bg-gray-100 p-2 rounded-lg mb-2">
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Surplus</div>
|
<p class="text-black font-semibold text-center text-sm"></p>
|
||||||
<div class="text-xs text-gray-600">Supply > Demand at a heart rate and speed of:</div>
|
{{ fat_metabolism_note | default('100bpm at a speed of
|
||||||
<div class="text-sm font-bold text-gray-800">n/a</div>
|
4.0mph and incline of 2%') }}
|
||||||
|
</p>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64, {{ fat_metabolism_chart }}"
|
||||||
|
alt="Fat Metabolism Chart"
|
||||||
|
class="w-full max-w-4xl h-auto object-contain"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
</div>
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Supply Threshold</div>
|
|
||||||
<div class="text-xs text-gray-600">Demand outstrips supply at a heart rate of:</div>
|
<!-- Recovery Section -->
|
||||||
<div class="text-sm font-bold text-gray-800">154bpm @ 5.0mph</div>
|
<div class="mb-2">
|
||||||
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
|
Recovery
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Recovery Info Boxes -->
|
||||||
|
<div class="grid grid-cols-3 gap-4 mb-4">
|
||||||
|
<!-- Cardiac Recovery -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
||||||
|
<h3 class="text-sm font-bold text-black mb-2">
|
||||||
|
Cardiac Recovery
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-gray-600 mb-2">
|
||||||
|
{{ cardiac_recovery_time | default('(1 minute)') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
{{ cardiac_recovery_percentage | default('33%') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
<!-- Metabolic Recovery -->
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Recovery</div>
|
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
||||||
<div class="text-xs text-gray-600">"Optimal >100%"</div>
|
<h3 class="text-sm font-bold text-black mb-2">
|
||||||
<div class="text-sm font-bold text-gray-800">n/a</div>
|
Metabolic (CO2) Recovery
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-gray-600 mb-2">
|
||||||
|
{{ metabolic_recovery_time | default('(2 minute)') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
{{ metabolic_recovery_percentage | default('65%') }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Breath Frequency Recovery -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg text-center">
|
||||||
|
<h3 class="text-sm font-bold text-black mb-2">
|
||||||
|
Breath Frequency Recovery
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-gray-600 mb-2">
|
||||||
|
{{ breath_recovery_time | default('(2.5 minute)') }}
|
||||||
|
</p>
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
{{ breath_recovery_percentage | default('76%') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recovery Graph -->
|
||||||
|
<div class="flex justify-center mb-6">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64, {{ recovery_chart }}"
|
||||||
|
alt="Recovery Chart"
|
||||||
|
class="w-full max-w-4xl h-auto object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Resting Heart Rate Table -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64, {{ rhr_table }}"
|
||||||
|
alt="Resting Heart Rate Table"
|
||||||
|
class="table-image"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Left Leg Section -->
|
</div>
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-semibold text-center text-gray-800 mb-6">Indications - Left Leg</h3>
|
|
||||||
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<!-- Chart Image -->
|
|
||||||
<div class="flex-1">
|
|
||||||
<img src="left-leg-chart.png" alt="Left Leg SMO2 Chart" class="w-full h-auto">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right Side Info -->
|
|
||||||
<div class="w-48 space-y-4">
|
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Surplus</div>
|
|
||||||
<div class="text-xs text-gray-600">Supply > Demand at a heart rate and speed of:</div>
|
|
||||||
<div class="text-sm font-bold text-gray-800">n/a</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Supply Threshold</div>
|
|
||||||
<div class="text-xs text-gray-600">Demand outstrips supply at a heart rate of:</div>
|
|
||||||
<div class="text-sm font-bold text-gray-800">165 bpm @ 5.5mph</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-gray-100 p-3 rounded">
|
|
||||||
<div class="text-xs font-semibold text-gray-700 mb-1">Recovery</div>
|
|
||||||
<div class="text-xs text-gray-600">"Optimal >100%"</div>
|
|
||||||
<div class="text-sm font-bold text-gray-800">n/a</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|||||||
+157
-212
@@ -1,216 +1,161 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="page bg-white p-8 max-w-4xl mx-auto">
|
||||||
<!-- Header Section -->
|
<!-- Header -->
|
||||||
<!-- Main Content -->
|
|
||||||
<div class="px-8 py-6">
|
|
||||||
<!-- Page Title -->
|
|
||||||
<h1 class="text-3xl font-bold text-black mb-8 text-center">Training Recommendations</h1>
|
|
||||||
|
|
||||||
<!-- Training Recommendations Section -->
|
|
||||||
<div class="grid grid-cols-2 gap-8 mb-8">
|
|
||||||
<!-- Left Side: Zone Recommendations -->
|
|
||||||
<div class="bg-gray-200 p-6 rounded-lg">
|
|
||||||
<!-- Zone 2 Recommendations -->
|
|
||||||
<div class="mb-6">
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 2 {{ zone2_frequency | default('3-4x/week') }}:</h3>
|
|
||||||
<ul class="text-sm text-black space-y-1 list-disc list-inside">
|
|
||||||
<li>{{ zone2_duration | default('40+ minutes') }} of Steady State Cardio (HR {{ zone2_hr_range | default('____') }} bpm)</li>
|
|
||||||
<li>{{ zone2_speed | default('____ mph') }} at {{ zone2_incline | default('2% Incline') }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zone 3 Recommendations -->
|
|
||||||
<div class="mb-6">
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 3 {{ zone3_frequency | default('1-2x/week') }}:</h3>
|
|
||||||
<ul class="text-sm text-black space-y-1 list-disc list-inside">
|
|
||||||
<li>{{ zone3_duration | default('10-20 minutes') }} in zone 3 (HR {{ zone3_hr_range | default('____ bpm') }})</li>
|
|
||||||
<li>{{ zone3_speed | default('____mph') }} + at {{ zone3_incline | default('2% Incline') }}</li>
|
|
||||||
<li>Slow down cadence until HR reaches {{ zone3_target_hr | default('___ bpm') }}</li>
|
|
||||||
<li>{{ zone3_recovery_speed | default('____mph') }} at {{ zone3_recovery_incline | default('2% Incline') }}</li>
|
|
||||||
<li>Maintain HR in zone 1 ({{ zone1_hr_range | default('____bpm') }}) for {{ zone1_duration | default('4-8 minutes') }}</li>
|
|
||||||
<li>Repeat {{ zone3_repeats | default('2-3 times') }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Right Side: Training Table -->
|
|
||||||
<div>
|
|
||||||
<table class="w-full border-collapse text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Type</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Sets</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Effort Duration</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">RPE</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Recovery Duration</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<!-- Short Row -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">Short</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ short_sets | default('8-10') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ short_duration | default('10-30 seconds') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ short_zone | default('5') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ short_rpe | default('10') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ short_recovery | default('20-60 seconds') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Medium Row -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">Medium</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ medium_sets | default('6-8') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ medium_duration | default('30-90 seconds') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ medium_zone | default('4') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ medium_rpe | default('8-9') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ medium_recovery | default('30-90 seconds') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Long Row -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">Long</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ long_sets | default('4-6') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ long_duration | default('5-10 minutes') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ long_zone | default('3/4') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ long_rpe | default('7-8') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ long_recovery | default('2.5-5 minutes') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Tempo Row -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">Tempo</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ tempo_sets | default('2-3') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ tempo_duration | default('10-20 minutes') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ tempo_zone | default('3') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ tempo_rpe | default('6-7') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ tempo_recovery | default('4-8 minutes') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Cardio Row -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">Cardio</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ cardio_sets | default('1') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ cardio_duration | default('>40 minutes') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ cardio_zone | default('2') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ cardio_rpe | default('4-5') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ cardio_recovery | default('N/A') }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Training Week Example Section -->
|
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-2xl font-bold text-black mb-6 text-center">Training Week Example with Progression</h2>
|
<h1 class="text-3xl font-bold text-gray-900 mb-4">
|
||||||
|
Local Muscle Activity
|
||||||
<!-- Week 1 -->
|
</h1>
|
||||||
<div class="mb-6">
|
<h2 class="text-xl font-semibold text-gray-800 mb-2">
|
||||||
<div class="grid grid-cols-7 gap-2">
|
Muscle Oxygenation Assessment
|
||||||
<!-- Monday -->
|
</h2>
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
<p class="text-sm text-gray-600 leading-relaxed">
|
||||||
<div class="font-bold text-black mb-1">Monday</div>
|
SMO2 testing (Skeletal Muscle Oxygen Saturation) is an analysis of
|
||||||
<div class="text-sm text-black">{{ week1_mon_zone | default('Zone 2') }}</div>
|
how effectively oxygen is being used at a particular muscle. It
|
||||||
<div class="text-sm text-black">{{ week1_mon_duration | default('45 mins') }}</div>
|
helps determine limitations on if the muscle is effectively using
|
||||||
</div>
|
oxygen when exercising.
|
||||||
|
</p>
|
||||||
<!-- Tuesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Tuesday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_tue_zone | default('Zone 2') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_tue_duration | default('45 mins') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Wednesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Wednesday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_wed_zone | default('Zone 3') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_wed_duration1 | default('10mins On') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_wed_duration2 | default('8mins Rest') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_wed_sets | default('x2') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Thursday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Thursday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_thu_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Friday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Friday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_fri_zone | default('Zone 2') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_fri_duration | default('45 mins') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Saturday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Saturday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_sat_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sunday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Sunday</div>
|
|
||||||
<div class="text-sm text-black">{{ week1_sun_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Week 2 -->
|
|
||||||
<div class="mb-6">
|
|
||||||
<div class="grid grid-cols-7 gap-2">
|
|
||||||
<!-- Monday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Monday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_mon_zone | default('Zone 2') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_mon_duration | default('50 mins') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tuesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Tuesday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_tue_zone | default('Zone 2') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_tue_duration | default('50 mins') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Wednesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Wednesday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_wed_zone | default('Zone 3') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_wed_duration1 | default('10mins On') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_wed_duration2 | default('6mins Rest') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_wed_sets | default('x2') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Thursday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Thursday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_thu_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Friday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Friday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_fri_zone | default('Zone 2') }}</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_fri_duration | default('50 mins') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Saturday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Saturday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_sat_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sunday -->
|
|
||||||
<div class="bg-gray-200 p-3 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-1">Sunday</div>
|
|
||||||
<div class="text-sm text-black">{{ week2_sun_content | default('') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Footer Section -->
|
<!-- Combined Muscle Oxygenation Chart -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex justify-center mb-4">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64,{{ muscle_oxygenation_chart }}"
|
||||||
|
alt="Muscle Oxygenation Chart"
|
||||||
|
class="w-full h-auto max-w-6xl"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metrics Summary Grid: Left and Right as two side-by-side panels, fields as two columns inside each -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
|
<!-- Left Leg Metrics -->
|
||||||
|
<div class="bg-blue-50 p-3 rounded-lg border-l-4 border-blue-300 h-full flex flex-col">
|
||||||
|
<h3 class="text-base font-bold text-gray-900 mb-3 text-center">
|
||||||
|
Left Leg Analysis
|
||||||
|
</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-3">
|
||||||
|
<!-- Baseline SmO2 -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Baseline SmO₂
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ left_baseline_smo2 | default('75.4%') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Minimum SmO2 -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Minimum SmO₂
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ left_minimum_smo2 | default('69.3%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
{{ left_minimum_lap | default('Lap 6') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Oxygen Drop -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Oxygen Drop
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ left_oxygen_drop | default('6.0%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
{{ left_drop_percentage | default('8% decrease') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Recovery -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Recovery
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">Optimal >100%</div>
|
||||||
|
<div class="text-base font-bold text-green-600">
|
||||||
|
{{ left_recovery_percentage | default('109%') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Leg Metrics -->
|
||||||
|
<div class="bg-purple-50 p-3 rounded-lg border-l-4 border-purple-300 h-full flex flex-col">
|
||||||
|
<h3 class="text-base font-bold text-gray-900 mb-3 text-center">
|
||||||
|
Right Leg Analysis
|
||||||
|
</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-3">
|
||||||
|
<!-- Baseline SmO2 -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Baseline SmO₂
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ right_baseline_smo2 | default('82.9%') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Minimum SmO2 -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Minimum SmO₂
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ right_minimum_smo2 | default('73.7%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
{{ right_minimum_lap | default('Lap 6') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Oxygen Drop -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Oxygen Drop
|
||||||
|
</div>
|
||||||
|
<div class="text-base font-bold text-gray-900">
|
||||||
|
{{ right_oxygen_drop | default('9.3%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
{{ right_drop_percentage | default('11% decrease') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Recovery -->
|
||||||
|
<div class="bg-white p-2 rounded shadow-sm col-span-2 md:col-span-1">
|
||||||
|
<div class="text-xs font-semibold text-gray-700">
|
||||||
|
Recovery
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-500">Optimal >100%</div>
|
||||||
|
<div class="text-base font-bold text-blue-600">
|
||||||
|
{{ right_recovery_percentage | default('97%') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Key Findings Summary -->
|
||||||
|
<div class="bg-gray-100 p-3 rounded-lg">
|
||||||
|
<h3 class="text-sm font-bold text-gray-900 mb-2">Key Findings</h3>
|
||||||
|
<div class="text-xs text-gray-700 space-y-1">
|
||||||
|
<p>
|
||||||
|
• <strong>Left leg</strong> showed better oxygen maintenance
|
||||||
|
during high-intensity work
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
•
|
||||||
|
<strong>
|
||||||
|
{{ recovery_assessment | default('Excellent recovery capacity') }}
|
||||||
|
</strong>
|
||||||
|
- both legs recovered well
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
• <strong>Heart rate progression:</strong> {{ hr_warmup |
|
||||||
|
default('93') }} → {{ hr_max | default('168') }} bpm
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
• <strong>Test duration:</strong> {{ test_duration |
|
||||||
|
default('~21 minutes active test') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+522
-141
@@ -1,148 +1,529 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
|
<!-- Header Section -->
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-6">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-8 text-center">
|
||||||
|
Training Recommendations
|
||||||
|
</h1>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Training Recommendations Section -->
|
||||||
<div class="px-8 py-6">
|
<div class="grid grid-cols-2 gap-8 mb-8">
|
||||||
<!-- Page Title -->
|
<!-- Left Side: Zone Recommendations -->
|
||||||
<div class="text-center mb-8">
|
<div class="bg-gray-200 p-4 rounded-lg border-2 border-gray-300">
|
||||||
<h1 class="text-3xl font-bold text-black mb-2">Training Week</h1>
|
<!-- Zone 2 Recommendations -->
|
||||||
<p class="text-gray-600 italic">(To be filled out by your trainer)</p>
|
<div class="mb-4">
|
||||||
</div>
|
<h3 class="text-sm font-bold text-black mb-2">
|
||||||
|
Zone 2 {{ zone2_frequency | default('3-4x/week') }}:
|
||||||
<!-- First Training Week Grid -->
|
</h3>
|
||||||
<div class="mb-8">
|
<ul
|
||||||
<div class="grid grid-cols-7 gap-2 mb-4">
|
class="text-xs text-black space-y-0.5 list-disc list-inside ml-2"
|
||||||
<!-- Week 1 Headers -->
|
>
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
<li>
|
||||||
<div class="font-bold text-black">Monday</div>
|
{{ zone2_duration | default('40+ minutes') }} of
|
||||||
|
Steady State Cardio (HR
|
||||||
|
<span class="border-b border-black"
|
||||||
|
>{{ zone2_hr_range | default('____') }}</span
|
||||||
|
>
|
||||||
|
bpm)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="border-b border-black"
|
||||||
|
>{{ zone2_speed | default('___') }}</span
|
||||||
|
>
|
||||||
|
mph at {{ zone2_incline | default('2% Incline') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zone 3 Recommendations -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-bold text-black mb-2">
|
||||||
|
Zone 3: {{ zone3_frequency | default('1-2x/week') }}:
|
||||||
|
</h3>
|
||||||
|
<ul
|
||||||
|
class="text-xs text-black space-y-0.5 list-disc list-inside ml-2"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
{{ zone3_duration | default('10-20 minutes') }} in
|
||||||
|
zone 3 (HR
|
||||||
|
<span class="border-b border-black"
|
||||||
|
>{{ zone3_hr_range | default('____') }}</span
|
||||||
|
>
|
||||||
|
bpm)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="border-b border-black"
|
||||||
|
>{{ zone3_speed | default('___') }}</span
|
||||||
|
>mph + at {{ zone3_incline | default('2% Incline')
|
||||||
|
}}
|
||||||
|
</li>
|
||||||
|
<li class="text-orange-500">
|
||||||
|
Slow down cadence until HR reaches
|
||||||
|
<span class="border-b border-orange-500"
|
||||||
|
>{{ zone3_target_hr | default('___') }}</span
|
||||||
|
>bpm
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="border-b border-black"
|
||||||
|
>{{ zone3_recovery_speed | default('____')
|
||||||
|
}}</span
|
||||||
|
>mph at {{ zone3_recovery_incline | default('2%
|
||||||
|
Incline') }}
|
||||||
|
</li>
|
||||||
|
<li class="text-orange-500">
|
||||||
|
Maintain HR in zone 1 (<span
|
||||||
|
class="border-b border-orange-500"
|
||||||
|
>{{ zone1_hr_range | default('____') }}</span
|
||||||
|
>bpm) for {{ zone1_duration | default('4-8 minutes')
|
||||||
|
}}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Repeat {{ zone3_repeats | default('2-3 times') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Side: Training Table -->
|
||||||
|
<div>
|
||||||
|
<table class="w-full border-collapse text-xs">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
Type
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
Sets
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
Effort Duration
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
Zone
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
RPE
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="bg-cyan-300 border border-gray-400 px-2 py-1.5 text-black font-bold text-xs"
|
||||||
|
>
|
||||||
|
Recovery Duration
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Short Row -->
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black font-medium text-xs"
|
||||||
|
>
|
||||||
|
Short
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ short_sets | default('8-10') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ short_duration | default('10-30 seconds') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ short_zone | default('5') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ short_rpe | default('10') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ short_recovery | default('20-60 seconds') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Medium Row -->
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black font-medium text-xs"
|
||||||
|
>
|
||||||
|
Medium
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ medium_sets | default('6-8') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ medium_duration | default('30-90 seconds') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ medium_zone | default('4') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ medium_rpe | default('8-9') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ medium_recovery | default('30-90 seconds') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Long Row -->
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black font-medium text-xs"
|
||||||
|
>
|
||||||
|
Long
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ long_sets | default('4-6') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ long_duration | default('5-10 minutes') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ long_zone | default('3/4') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ long_rpe | default('7-8') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ long_recovery | default('2.5-5 minutes') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Tempo Row -->
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black font-medium text-xs"
|
||||||
|
>
|
||||||
|
Tempo
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ tempo_sets | default('2-3') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ tempo_duration | default('10-20 minutes') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ tempo_zone | default('3') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ tempo_rpe | default('6-7') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ tempo_recovery | default('4-8 minutes') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Cardio Row -->
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black font-medium text-xs"
|
||||||
|
>
|
||||||
|
Cardio
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ cardio_sets | default('1') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ cardio_duration | default('>40 minutes') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ cardio_zone | default('2') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ cardio_rpe | default('4-5') }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="bg-gray-100 border border-gray-400 px-2 py-1.5 text-center text-black text-xs"
|
||||||
|
>
|
||||||
|
{{ cardio_recovery | default('N/A') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Tuesday</div>
|
<!-- Training Week Example Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-black mb-6 text-center">
|
||||||
|
Training Week Example with Progression
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Week 1 -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<div class="grid grid-cols-7 gap-1">
|
||||||
|
<!-- Monday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Monday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Tuesday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Tuesday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Wednesday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Wednesday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Thursday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Thursday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Friday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Friday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Saturday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Saturday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sunday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Sunday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-7 gap-1 mt-1">
|
||||||
|
<!-- Monday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_mon_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_mon_duration | default('45 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Tuesday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_tue_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_tue_duration | default('45 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Wednesday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_wed_zone | default('Zone 3') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_wed_duration1 | default('10mins On') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_wed_duration2 | default('8mins Rest') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_wed_sets | default('x2') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Thursday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_thu_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Friday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_fri_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_fri_duration | default('45 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Saturday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_sat_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sunday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week1_sun_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 2 -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<div class="grid grid-cols-7 gap-1">
|
||||||
|
<!-- Monday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Monday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Tuesday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Tuesday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Wednesday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Wednesday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Thursday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Thursday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Friday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Friday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Saturday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Saturday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sunday -->
|
||||||
|
<div class="bg-cyan-300 p-2 text-center">
|
||||||
|
<div class="font-bold text-black text-sm mb-1">
|
||||||
|
Sunday
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-7 gap-1 mt-1">
|
||||||
|
<!-- Monday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_mon_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_mon_duration | default('50 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Tuesday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_tue_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_tue_duration | default('50 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Wednesday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_wed_zone | default('Zone 3') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_wed_duration1 | default('10mins On') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_wed_duration2 | default('6mins Rest') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_wed_sets | default('x2') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Thursday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_thu_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Friday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_fri_zone | default('Zone 2') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_fri_duration | default('50 mins') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Saturday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_sat_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sunday Content -->
|
||||||
|
<div class="bg-gray-200 p-2 text-center min-h-[60px]">
|
||||||
|
<div class="text-xs text-black">
|
||||||
|
{{ week2_sun_content | default('') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Wednesday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Thursday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Friday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Saturday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Sunday</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Week 1 Content Boxes -->
|
|
||||||
<div class="grid grid-cols-7 gap-2 mb-8">
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Second Training Week Grid -->
|
<!-- Footer Section -->
|
||||||
<div class="mb-8">
|
|
||||||
<div class="grid grid-cols-7 gap-2 mb-4">
|
|
||||||
<!-- Week 2 Headers -->
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Monday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Tuesday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Wednesday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Thursday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Friday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Saturday</div>
|
|
||||||
</div>
|
|
||||||
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
|
||||||
<div class="font-bold text-black">Sunday</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Week 2 Content Boxes -->
|
|
||||||
<div class="grid grid-cols-7 gap-2 mb-8">
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Training Week Guidelines Section -->
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-2xl font-bold text-black mb-6 text-center">Training Week Guidelines</h2>
|
|
||||||
|
|
||||||
<!-- Guidelines Grid -->
|
|
||||||
<div class="grid grid-cols-5 gap-4 mb-6">
|
|
||||||
<!-- Zone 1 -->
|
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 1</h3>
|
|
||||||
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
|
||||||
<li>Zone 1 training is low intensity, for active recovery.</li>
|
|
||||||
<li>It can be done daily or even consecutively, depending on fitness, volume, and health.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zone 2 -->
|
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 2</h3>
|
|
||||||
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
|
||||||
<li>Zone 2 training can be done on consecutive or daily basis with moderate sessions.</li>
|
|
||||||
<li>Can be steady state or interval sessions.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zone 3 -->
|
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 3</h3>
|
|
||||||
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
|
||||||
<li>Zone 3 training can be done 1-5 times per week.</li>
|
|
||||||
<li>Wait 24 to 48 hours between sessions for adequate recovery.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zone 4 -->
|
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 4</h3>
|
|
||||||
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
|
||||||
<li>Zone 4 training: 1-4 times per week.</li>
|
|
||||||
<li>Wait 24 to 48 hours between intense sessions for recovery.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zone 5 -->
|
|
||||||
<div>
|
|
||||||
<h3 class="text-lg font-bold text-black mb-3">Zone 5</h3>
|
|
||||||
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
|
||||||
<li>Zone 5 training: 1-2 times per week.</li>
|
|
||||||
<li>Wait 48 hours between sessions for recovery.</li>
|
|
||||||
<li>Zone 5 increases VO2 max and endurance at VO2 max.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Important Note -->
|
|
||||||
<div class="text-center">
|
|
||||||
<p class="text-lg font-bold text-black italic">Zone 3, 4, 5 can be combined with Zone 1 or 2 - the higher zone should be done first!</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+132
-54
@@ -3,68 +3,146 @@
|
|||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="px-8 py-6">
|
<div class="px-8 py-6">
|
||||||
<!-- Page Title -->
|
<!-- Page Title -->
|
||||||
<h1 class="text-3xl font-bold text-black mb-8">Next Steps:</h1>
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-2">Training Week</h1>
|
||||||
|
<p class="text-gray-600 italic">(To be filled out by your trainer)</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Calorie Tracking Section -->
|
<!-- First Training Week Grid -->
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-xl font-bold text-black mb-4">Calorie Tracking</h2>
|
<div class="grid grid-cols-7 gap-2 mb-4">
|
||||||
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
<!-- Week 1 Headers -->
|
||||||
<li>Download and create an account with My Fitness Pal (or preferred nutrition tracker)</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Fill out the "My Profile" section with your goals (ie: height, weight, target weight)
|
<div class="font-bold text-black">Monday</div>
|
||||||
<ul class="mt-2 ml-6 space-y-1 list-disc list-inside">
|
</div>
|
||||||
<li>Input your Macros</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Click the three dots on the bottom right corner</li>
|
<div class="font-bold text-black">Tuesday</div>
|
||||||
<li>Click "Goals"</li>
|
</div>
|
||||||
<li>Click "Calorie, Carbs, Protein and Fat Goals" under the Nutrition Goals</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Set the Calories, Carbs, Protein, and Fat to the recommended macro outlined above.</li>
|
<div class="font-bold text-black">Wednesday</div>
|
||||||
</ul>
|
</div>
|
||||||
</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Once completed fill out your food intake from each meal on the main page</li>
|
<div class="font-bold text-black">Thursday</div>
|
||||||
</ul>
|
</div>
|
||||||
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Friday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Saturday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Sunday</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Recommendation Note -->
|
<!-- Week 1 Content Boxes -->
|
||||||
<div class="mt-6 text-center">
|
<div class="grid grid-cols-7 gap-2 mb-8">
|
||||||
<p class="text-black italic font-semibold">It's highly recommended to purchase a weight and food scale for more accurate results.</p>
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Daily Tasks Section -->
|
<!-- Second Training Week Grid -->
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-xl font-bold text-black mb-4">Daily Tasks</h2>
|
<div class="grid grid-cols-7 gap-2 mb-4">
|
||||||
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
<!-- Week 2 Headers -->
|
||||||
<li>Weigh yourself in the morning, after your first bowel movement, and naked</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Log your weight into your my fitness pal app</li>
|
<div class="font-bold text-black">Monday</div>
|
||||||
<li>Track calories in grams - FOLLOW YOUR PERSONAL RECOMMENDATIONS.</li>
|
</div>
|
||||||
<li>Log in a diary:
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<ul class="mt-2 ml-6 space-y-1 list-disc list-inside">
|
<div class="font-bold text-black">Tuesday</div>
|
||||||
<li>Log any additional prescribed recommendation (i.e breath work)</li>
|
</div>
|
||||||
<li>Complete the prescribed training recommendations (i.e Zone 2 Training)</li>
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
<li>Log additional physical activity (i.e Monday - Strength Training 1 hour)</li>
|
<div class="font-bold text-black">Wednesday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Thursday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-cyan-300 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Friday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Saturday</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-200 p-2 text-center rounded-lg">
|
||||||
|
<div class="font-bold text-black">Sunday</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 2 Content Boxes -->
|
||||||
|
<div class="grid grid-cols-7 gap-2 mb-8">
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
<div class="bg-gray-100 border-2 border-gray-300 h-32 rounded-lg"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Training Week Guidelines Section -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-bold text-black mb-6 text-center">Training Week Guidelines</h2>
|
||||||
|
|
||||||
|
<!-- Guidelines Grid -->
|
||||||
|
<div class="grid grid-cols-5 gap-4 mb-6">
|
||||||
|
<!-- Zone 1 -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold text-black mb-3">Zone 1</h3>
|
||||||
|
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
||||||
|
<li>Zone 1 training is low intensity, for active recovery.</li>
|
||||||
|
<li>It can be done daily or even consecutively, depending on fitness, volume, and health.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
|
||||||
</div>
|
<!-- Zone 2 -->
|
||||||
|
<div>
|
||||||
<!-- Two weeks after Appointment Section -->
|
<h3 class="text-lg font-bold text-black mb-3">Zone 2</h3>
|
||||||
<div class="mb-8">
|
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
||||||
<h2 class="text-xl font-bold text-black mb-4">Two weeks after Appointment</h2>
|
<li>Zone 2 training can be done on consecutive or daily basis with moderate sessions.</li>
|
||||||
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
<li>Can be steady state or interval sessions.</li>
|
||||||
<li>Should you find the macronutrient breakdown difficult to follow, reach out to us to discuss a change within your caloric parameters</li>
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
|
||||||
|
<!-- Zone 3 -->
|
||||||
<!-- Contact Information -->
|
<div>
|
||||||
<div class="mb-12 text-center">
|
<h3 class="text-lg font-bold text-black mb-3">Zone 3</h3>
|
||||||
<p class="text-lg font-bold text-black">Should you have any questions or concerns please contact us!</p>
|
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
||||||
</div>
|
<li>Zone 3 training can be done 1-5 times per week.</li>
|
||||||
|
<li>Wait 24 to 48 hours between sessions for adequate recovery.</li>
|
||||||
<!-- Recommended Next Testing Date -->
|
</ul>
|
||||||
<div class="mb-8 text-center">
|
</div>
|
||||||
<h2 class="text-2xl font-bold text-black">
|
|
||||||
<span class="underline">Recommended Next Testing Date:</span>
|
<!-- Zone 4 -->
|
||||||
<span class="ml-2">October 2025</span>
|
<div>
|
||||||
</h2>
|
<h3 class="text-lg font-bold text-black mb-3">Zone 4</h3>
|
||||||
|
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
||||||
|
<li>Zone 4 training: 1-4 times per week.</li>
|
||||||
|
<li>Wait 24 to 48 hours between intense sessions for recovery.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zone 5 -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold text-black mb-3">Zone 5</h3>
|
||||||
|
<ul class="text-sm text-black space-y-2 list-disc list-inside">
|
||||||
|
<li>Zone 5 training: 1-2 times per week.</li>
|
||||||
|
<li>Wait 48 hours between sessions for recovery.</li>
|
||||||
|
<li>Zone 5 increases VO2 max and endurance at VO2 max.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Important Note -->
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="text-lg font-bold text-black italic">Zone 3, 4, 5 can be combined with Zone 1 or 2 - the higher zone should be done first!</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+105
-53
@@ -1,57 +1,109 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-6">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-8">Next Steps:</h1>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Calorie Tracking Section -->
|
||||||
<div class="px-6">
|
<div class="mb-8">
|
||||||
<!-- Page Title -->
|
<h2 class="text-xl font-bold text-black mb-4">Calorie Tracking</h2>
|
||||||
<h1 class="text-2xl font-bold text-black mb-4">Glossary</h1>
|
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
||||||
|
<li>
|
||||||
<!-- Body Fat Percentage -->
|
Download and create an account with My Fitness Pal (or
|
||||||
<div class="mb-3">
|
preferred nutrition tracker)
|
||||||
<h2 class="text-base font-bold text-black mb-1">Body Fat Percentage:</h2>
|
</li>
|
||||||
<p class="text-xs text-black leading-snug">The percentage of your overall body weight that is composed of fat cells. Body fat percentage can be reduced by either losing weight from fat mass, while maintaining lean mass, or maintaining fat mass while increasing lean mass.</p>
|
<li>
|
||||||
|
Fill out the "My Profile" section with your goals (ie:
|
||||||
|
height, weight, target weight)
|
||||||
|
<ul class="mt-2 ml-6 space-y-1 list-disc list-inside">
|
||||||
|
<li>Input your Macros</li>
|
||||||
|
<li>Click the three dots on the bottom right corner</li>
|
||||||
|
<li>Click "Goals"</li>
|
||||||
|
<li>
|
||||||
|
Click "Calorie, Carbs, Protein and Fat Goals" under
|
||||||
|
the Nutrition Goals
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Set the Calories, Carbs, Protein, and Fat to the
|
||||||
|
recommended macro outlined above.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Once completed fill out your food intake from each meal on
|
||||||
|
the main page
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Recommendation Note -->
|
||||||
|
<div class="mt-6 text-center">
|
||||||
|
<p class="text-black italic font-semibold">
|
||||||
|
It's highly recommended to purchase a weight and food scale
|
||||||
|
for more accurate results.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Daily Tasks Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-xl font-bold text-black mb-4">Daily Tasks</h2>
|
||||||
|
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
||||||
|
<li>
|
||||||
|
Weigh yourself in the morning, after your first bowel
|
||||||
|
movement, and naked
|
||||||
|
</li>
|
||||||
|
<li>Log your weight into your my fitness pal app</li>
|
||||||
|
<li>
|
||||||
|
Track calories in grams - FOLLOW YOUR PERSONAL
|
||||||
|
RECOMMENDATIONS.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Log in a diary:
|
||||||
|
<ul class="mt-2 ml-6 space-y-1 list-disc list-inside">
|
||||||
|
<li>
|
||||||
|
Log any additional prescribed recommendation (i.e
|
||||||
|
breath work)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Complete the prescribed training recommendations
|
||||||
|
(i.e Zone 2 Training)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Log additional physical activity (i.e Monday -
|
||||||
|
Strength Training 1 hour)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Two weeks after Appointment Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-xl font-bold text-black mb-4">
|
||||||
|
Two weeks after Appointment
|
||||||
|
</h2>
|
||||||
|
<ul class="text-black space-y-2 list-disc list-inside ml-4">
|
||||||
|
<li>
|
||||||
|
Should you find the macronutrient breakdown difficult to
|
||||||
|
follow, reach out to us to discuss a change within your
|
||||||
|
caloric parameters
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Contact Information -->
|
||||||
|
<div class="mb-12 text-center">
|
||||||
|
<p class="text-lg font-bold text-black">
|
||||||
|
Should you have any questions or concerns please contact us!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recommended Next Testing Date -->
|
||||||
|
<div class="mb-8 text-center">
|
||||||
|
<h2 class="text-2xl font-bold text-black">
|
||||||
|
<span class="underline">Recommended Next Testing Date:</span>
|
||||||
|
<span class="ml-2">{{ next_testing_date }}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Metabolic Rate -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<h2 class="text-base font-bold text-black mb-1">Metabolic Rate:</h2>
|
|
||||||
<p class="text-xs text-black leading-snug">Metabolic Rate measures the number of calories your body burns for basic functions and movement, based on factors like weight, age, gender, and height. A higher metabolic rate helps prevent weight gain and supports weight loss by ensuring you burn enough calories. Tracking metabolic rate is key for managing weight and preventing conditions linked to metabolic dysfunction. Positive influences include resistance exercise, proper sleep, and adequate protein, while negative factors include extreme dieting, yo-yo dieting, and excessive cardio. Improving it involves resistance training and optimal nutrition.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fuel Source -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<h2 class="text-base font-bold text-black mb-1">Fuel Source:</h2>
|
|
||||||
<p class="text-xs text-black leading-snug mb-1">Fat-burning efficiency measures your cells' ability to use fat as fuel, reflecting mitochondrial and cellular health. It indicates how well your body balances fat and carbohydrate usage to support energy needs, assessed by analyzing oxygen and carbon dioxide in your breath. High fat-burning efficiency suggests strong metabolic and mitochondrial function, linked to better weight management and longevity.</p>
|
|
||||||
<p class="text-xs text-black leading-snug">To improve fat-burning efficiency, focus on Zone 2 endurance training and potentially intermittent fasting to enhance oxygen absorption and cellular function. Zone 5 interval training will also help improve fat burning mitochondrial density and capillarization. Factors that reduce fat burning ability include diets high in processed foods, alcohol, and large meals before bed. Conditions related to metabolic stress also hinder fat burning abilities.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- NEAT -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<h2 class="text-base font-bold text-black mb-1">NEAT (Non-Exercise Activity Thermogenesis)</h2>
|
|
||||||
<p class="text-xs text-black leading-snug">refers to the energy expended for all activities that are not deliberate exercise or structured physical activity. This includes daily movements such as walking, fidgeting, standing, cleaning, typing, and even simple tasks like cooking or shopping. NEAT contributes significantly to the total caloric expenditure and plays a key role in maintaining body weight and overall energy balance. It varies widely among individuals, depending on lifestyle, occupation, and habits.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Spirometry -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<h2 class="text-base font-bold text-black mb-1">Spirometry:</h2>
|
|
||||||
<p class="text-xs text-black leading-snug mb-1">Spirometry is a diagnostic device used to provide objective measurements of lung volumes and capacities. Lung function is crucial for oxygen delivery during physical activity, and comparing spirometry results to expected values can highlight any potential limitations to performance.</p>
|
|
||||||
<p class="text-xs text-black leading-snug mb-1">"From a Performance standpoint, it is essential in making informed training recommendations related to respiratory health to optimize endurance performance and metabolic health."</p>
|
|
||||||
|
|
||||||
<!-- Spirometry Sub-definitions -->
|
|
||||||
<ul class="text-xs text-black space-y-1 list-disc list-inside ml-3">
|
|
||||||
<li><strong>FEV1:</strong> Forced Expiratory Volume - the total amount of air expelled in the first second.</li>
|
|
||||||
<li><strong>FVC:</strong> Forced Vital Capacity - the maximum amount of air exhaled in one breath after a maximum inhalation</li>
|
|
||||||
<li><strong>FEV1/FVC:</strong> Calculated ratio used in the diagnosis of obstructive & restrictive lung disease.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class="text-xs text-black leading-snug mt-1">By comparing these measurements to expected values based on age, gender, height and ethnicity, healthcare professionals can diagnose a range of lung conditions such as asthma, COPD, restrictive lung diseases, and more.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- VO2 max -->
|
|
||||||
<div>
|
|
||||||
<h2 class="text-base font-bold text-black mb-1">VO2 max:</h2>
|
|
||||||
<p class="text-xs text-black leading-snug mb-1">VO2 Max, or maximal oxygen consumption serves as a valuable indicator of overall fitness, cardiovascular health, and endurance capacity. VO2 max reflects the efficiency of your heart lung system in pumping oxygen-rich blood to working muscles. A higher VO2 max indicates a stronger cardiovascular system, which is associated with a reduced risk of heart disease and other cardiovascular issues.</p>
|
|
||||||
<p class="text-xs text-black leading-snug">Understanding and training to increase your VO2 max can contribute to enhanced physical performance, longevity and well-being.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+53
-84
@@ -1,88 +1,57 @@
|
|||||||
<!-- Header -->
|
<div class="w-full page bg-white">
|
||||||
<div class="w-full page">
|
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="p-4 text-sm">
|
<div class="px-6">
|
||||||
<h1 class="text-2xl font-bold mb-4">Glossary</h1>
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-2xl font-bold text-black mb-4">Glossary</h1>
|
||||||
<div class="space-y-3 leading-tight">
|
|
||||||
<!-- Peak VT -->
|
<!-- Body Fat Percentage -->
|
||||||
<div>
|
<div class="mb-3">
|
||||||
<p class="font-semibold">Peak VT:</p>
|
<h2 class="text-base font-bold text-black mb-1">Body Fat Percentage:</h2>
|
||||||
<p class="mb-1">
|
<p class="text-xs text-black leading-snug">The percentage of your overall body weight that is composed of fat cells. Body fat percentage can be reduced by either losing weight from fat mass, while maintaining lean mass, or maintaining fat mass while increasing lean mass.</p>
|
||||||
Peak Volume of air moved throughout the test.
|
|
||||||
</p>
|
|
||||||
<p class="mb-1">
|
|
||||||
Respiratory Capability Limitations that can be found include:
|
|
||||||
</p>
|
|
||||||
<ul class="list-disc ml-4 space-y-0">
|
|
||||||
<li>
|
|
||||||
<strong>Endurance:</strong> Normal capacity, but cannot maintain their VT over time.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>Strength/Power:</strong> Normal capacity, but peak VT is not 75-85% of their FEV1 despite FEV1 being normal
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>Coordination (Hyper/Hypo-Ventilation):</strong> Normal capacity, but uses low volumes +/- high BFs at lower intensities. A breathing coordination limitation can also be identified by the loss of volume at higher intensities, which are then recovered upon recovery/stop of activity.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- VO2 Pulse -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">VO2 Pulse:</p>
|
|
||||||
<p>
|
|
||||||
VO2 Pulse refers to the relationship between oxygen consumption (VO2) and heart rate (HR) during exercise. This measure gives insight into how efficiently the body is using oxygen in relation to the heart's output. A higher VO2 Pulse suggests that an individual is able to deliver oxygen more efficiently to the muscles with each heartbeat.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- VO2 Breath -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">VO2 Breath:</p>
|
|
||||||
<p>
|
|
||||||
VO2 Breath refers to the amount of oxygen consumed per breath during exercise, which indicates how effectively the body delivers oxygen to the bloodstream through the lungs with each breath. A more efficient VO2 Breath means the body requires less effort to obtain the same amount of oxygen, indicating better respiratory efficiency and oxygen utilization.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Carb & Fat Crossover -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">Carb & Fat Crossover:</p>
|
|
||||||
<p class="mb-1">
|
|
||||||
The point during exercise at which the body shifts its predominant fuel source from fats to carbohydrates. This transition typically occurs as exercise intensity increases, and marks the transition from Zone 2 into Zone 3. As exercise intensity increases, the body starts to rely more on carbohydrates because they provide faster energy.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Endurance training (e.g., long, steady-state cardio within Zones 1 & 2) increases the body's ability to burn fat efficiently at higher intensities, shifting the crossover point to a faster speed, or higher heart rate/intensity. Because fat stores are much larger and can provide a steady stream of energy for prolonged periods, a higher CHO/FAT crossover can help delay fatigue, which is especially beneficial in longer-duration events, where carbohydrate depletion can lead to a significant drop in performance.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Cardiovascular Recovery -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">Cardiovascular Recovery:</p>
|
|
||||||
<p>
|
|
||||||
The percentage your heart rate drops within the first minute of the inactive recovery phase in relation to the lowest heart rate recorded prior to the start of the test.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Metabolic (CO2) Recovery -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">Metabolic (CO2) Recovery:</p>
|
|
||||||
<p class="mb-1">
|
|
||||||
The percentage that your VCO2 levels (amount of CO2 you are exhaling) drop within the first 1.5 minutes of the inactive recovery phase in relation to the lowest VCO2 recorded prior to the start of the test.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
refers to the rate at which the body clears carbon dioxide (CO2) after exercise, reflecting the efficiency of the cardiovascular and respiratory systems in returning CO2 levels to baseline. A faster VCO2 recovery indicates effective management of metabolic byproducts, signaling a healthier metabolic system and lower risk of metabolic disorders.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Breath Frequency Recovery -->
|
|
||||||
<div>
|
|
||||||
<p class="font-semibold">Breath Frequency Recovery:</p>
|
|
||||||
<p>
|
|
||||||
Refers to the speed at which the body returns to a normal breathing rate after physical exertion. Faster breath frequency recovery indicates a well-conditioned cardiovascular and respiratory system, allowing the body to efficiently regulate oxygen and CO2 levels. It supports better endurance, faster recovery between intervals, and the ability to sustain higher performance during repeated efforts or prolonged activity. Additionally, a quick return to baseline signals that the autonomic nervous system is functioning well, reducing stress on the body and promoting more efficient recovery. This also reflects a healthier metabolic system, better management of metabolic byproducts like CO2, and a lower risk of chronic conditions.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Metabolic Rate -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<h2 class="text-base font-bold text-black mb-1">Metabolic Rate:</h2>
|
||||||
|
<p class="text-xs text-black leading-snug">Metabolic Rate measures the number of calories your body burns for basic functions and movement, based on factors like weight, age, gender, and height. A higher metabolic rate helps prevent weight gain and supports weight loss by ensuring you burn enough calories. Tracking metabolic rate is key for managing weight and preventing conditions linked to metabolic dysfunction. Positive influences include resistance exercise, proper sleep, and adequate protein, while negative factors include extreme dieting, yo-yo dieting, and excessive cardio. Improving it involves resistance training and optimal nutrition.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fuel Source -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<h2 class="text-base font-bold text-black mb-1">Fuel Source:</h2>
|
||||||
|
<p class="text-xs text-black leading-snug mb-1">Fat-burning efficiency measures your cells' ability to use fat as fuel, reflecting mitochondrial and cellular health. It indicates how well your body balances fat and carbohydrate usage to support energy needs, assessed by analyzing oxygen and carbon dioxide in your breath. High fat-burning efficiency suggests strong metabolic and mitochondrial function, linked to better weight management and longevity.</p>
|
||||||
|
<p class="text-xs text-black leading-snug">To improve fat-burning efficiency, focus on Zone 2 endurance training and potentially intermittent fasting to enhance oxygen absorption and cellular function. Zone 5 interval training will also help improve fat burning mitochondrial density and capillarization. Factors that reduce fat burning ability include diets high in processed foods, alcohol, and large meals before bed. Conditions related to metabolic stress also hinder fat burning abilities.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- NEAT -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<h2 class="text-base font-bold text-black mb-1">NEAT (Non-Exercise Activity Thermogenesis)</h2>
|
||||||
|
<p class="text-xs text-black leading-snug">refers to the energy expended for all activities that are not deliberate exercise or structured physical activity. This includes daily movements such as walking, fidgeting, standing, cleaning, typing, and even simple tasks like cooking or shopping. NEAT contributes significantly to the total caloric expenditure and plays a key role in maintaining body weight and overall energy balance. It varies widely among individuals, depending on lifestyle, occupation, and habits.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Spirometry -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<h2 class="text-base font-bold text-black mb-1">Spirometry:</h2>
|
||||||
|
<p class="text-xs text-black leading-snug mb-1">Spirometry is a diagnostic device used to provide objective measurements of lung volumes and capacities. Lung function is crucial for oxygen delivery during physical activity, and comparing spirometry results to expected values can highlight any potential limitations to performance.</p>
|
||||||
|
<p class="text-xs text-black leading-snug mb-1">"From a Performance standpoint, it is essential in making informed training recommendations related to respiratory health to optimize endurance performance and metabolic health."</p>
|
||||||
|
|
||||||
|
<!-- Spirometry Sub-definitions -->
|
||||||
|
<ul class="text-xs text-black space-y-1 list-disc list-inside ml-3">
|
||||||
|
<li><strong>FEV1:</strong> Forced Expiratory Volume - the total amount of air expelled in the first second.</li>
|
||||||
|
<li><strong>FVC:</strong> Forced Vital Capacity - the maximum amount of air exhaled in one breath after a maximum inhalation</li>
|
||||||
|
<li><strong>FEV1/FVC:</strong> Calculated ratio used in the diagnosis of obstructive & restrictive lung disease.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="text-xs text-black leading-snug mt-1">By comparing these measurements to expected values based on age, gender, height and ethnicity, healthcare professionals can diagnose a range of lung conditions such as asthma, COPD, restrictive lung diseases, and more.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- VO2 max -->
|
||||||
|
<div>
|
||||||
|
<h2 class="text-base font-bold text-black mb-1">VO2 max:</h2>
|
||||||
|
<p class="text-xs text-black leading-snug mb-1">VO2 Max, or maximal oxygen consumption serves as a valuable indicator of overall fitness, cardiovascular health, and endurance capacity. VO2 max reflects the efficiency of your heart lung system in pumping oxygen-rich blood to working muscles. A higher VO2 max indicates a stronger cardiovascular system, which is associated with a reduced risk of heart disease and other cardiovascular issues.</p>
|
||||||
|
<p class="text-xs text-black leading-snug">Understanding and training to increase your VO2 max can contribute to enhanced physical performance, longevity and well-being.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<div class="w-full page bg-white">
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-6">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-6">Glossary</h1>
|
||||||
|
|
||||||
|
<!-- Body Fat Percentage -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-lg font-bold text-black mb-2">Body Fat Percentage:</h2>
|
||||||
|
<p class="text-sm text-black leading-relaxed">The percentage of your overall body weight that is composed of fat cells. Body fat percentage can be reduced by either losing weight from fat mass, while maintaining lean mass, or maintaining fat mass while increasing lean mass.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metabolic Rate -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-lg font-bold text-black mb-2">Metabolic Rate:</h2>
|
||||||
|
<p class="text-sm text-black leading-relaxed">Metabolic Rate measures the number of calories your body burns for basic functions and movement, based on factors like weight, age, gender, and height. A higher metabolic rate helps prevent weight gain and supports weight loss by ensuring you burn enough calories. Tracking metabolic rate is key for managing weight and preventing conditions linked to metabolic dysfunction. Positive influences include resistance exercise, proper sleep, and adequate protein, while negative factors include extreme dieting, yo-yo dieting, and excessive cardio. Improving it involves resistance training and optimal nutrition.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fuel Source -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-lg font-bold text-black mb-2">Fuel Source:</h2>
|
||||||
|
<p class="text-sm text-black leading-relaxed mb-2">Fat-burning efficiency measures your cells' ability to use fat as fuel, reflecting mitochondrial and cellular health. It indicates how well your body balances fat and carbohydrate usage to support energy needs, assessed by analyzing oxygen and carbon dioxide in your breath. High fat-burning efficiency suggests strong metabolic and mitochondrial function, linked to better weight management and longevity.</p>
|
||||||
|
<p class="text-sm text-black leading-relaxed">To improve fat-burning efficiency, focus on Zone 2 endurance training and potentially intermittent fasting to enhance oxygen absorption and cellular function. Zone 5 interval training will also help improve fat burning mitochondrial density and capillarization. Factors that reduce fat burning ability include diets high in processed foods, alcohol, and large meals before bed. Conditions related to metabolic stress also hinder fat burning abilities.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- NEAT -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-lg font-bold text-black mb-2">NEAT (Non-Exercise Activity Thermogenesis)</h2>
|
||||||
|
<p class="text-sm text-black leading-relaxed">refers to the energy expended for all activities that are not deliberate exercise or structured physical activity. This includes daily movements such as walking, fidgeting, standing, cleaning, typing, and even simple tasks like cooking or shopping. NEAT contributes significantly to the total caloric expenditure and plays a key role in maintaining body weight and overall energy balance. It varies widely among individuals, depending on lifestyle, occupation, and habits.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
+81
-31
@@ -1,38 +1,88 @@
|
|||||||
|
<!-- Header -->
|
||||||
<div class="w-full page">
|
<div class="w-full page">
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="p-8">
|
<div class="p-4 text-sm">
|
||||||
<h1 class="text-4xl font-bold mb-8">Glossary</h1>
|
<h1 class="text-2xl font-bold mb-4">Glossary</h1>
|
||||||
|
|
||||||
<!-- Local Muscle Activity/SMO2 Definition -->
|
<div class="space-y-3 leading-tight">
|
||||||
<div class="mb-12 text-sm leading-relaxed">
|
<!-- Peak VT -->
|
||||||
<p class="font-semibold mb-2">Local Muscle Activity/SMO2:</p>
|
<div>
|
||||||
<p>
|
<p class="font-semibold">Peak VT:</p>
|
||||||
SmO2 testing is a valuable tool for understanding how muscles
|
<p class="mb-1">
|
||||||
respond to various physiological stressors and how to fine-tune
|
Peak Volume of air moved throughout the test.
|
||||||
training, nutrition and hydration accordingly. Monitoring
|
</p>
|
||||||
changes in tissue oxygen saturation and utilization helps
|
<p class="mb-1">
|
||||||
identify an individual's optimal intensity to work at, as well
|
Respiratory Capability Limitations that can be found include:
|
||||||
as how well they recover between bouts of intensity. This can
|
</p>
|
||||||
help optimize training to improve performance, prevent
|
<ul class="list-disc ml-4 space-y-0">
|
||||||
overtraining, and tailor strategies for better results.
|
<li>
|
||||||
</p>
|
<strong>Endurance:</strong> Normal capacity, but cannot maintain their VT over time.
|
||||||
<p>
|
</li>
|
||||||
During competitions, athletes can also use SmO2 data to pace
|
<li>
|
||||||
themselves effectively. Adjusting intensity based on muscle
|
<strong>Strength/Power:</strong> Normal capacity, but peak VT is not 75-85% of their FEV1 despite FEV1 being normal
|
||||||
oxygenation can help prevent premature fatigue and optimize race
|
</li>
|
||||||
outcomes
|
<li>
|
||||||
</p>
|
<strong>Coordination (Hyper/Hypo-Ventilation):</strong> Normal capacity, but uses low volumes +/- high BFs at lower intensities. A breathing coordination limitation can also be identified by the loss of volume at higher intensities, which are then recovered upon recovery/stop of activity.
|
||||||
</div>
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="w-full max-w-5xl">
|
<!-- VO2 Pulse -->
|
||||||
<h1 class="text-2xl font-bold mb-4 text-center">
|
<div>
|
||||||
Body Fat Percent Master Chart
|
<p class="font-semibold">VO2 Pulse:</p>
|
||||||
</h1>
|
<p>
|
||||||
<img
|
VO2 Pulse refers to the relationship between oxygen consumption (VO2) and heart rate (HR) during exercise. This measure gives insight into how efficiently the body is using oxygen in relation to the heart's output. A higher VO2 Pulse suggests that an individual is able to deliver oxygen more efficiently to the muscles with each heartbeat.
|
||||||
src="data:image/png;base64,{{ body_fat_percentage_chart }}"
|
</p>
|
||||||
alt="Body Fat Percentage"
|
</div>
|
||||||
class="w-full h-auto object-contain chart-large"
|
|
||||||
/>
|
<!-- VO2 Breath -->
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold">VO2 Breath:</p>
|
||||||
|
<p>
|
||||||
|
VO2 Breath refers to the amount of oxygen consumed per breath during exercise, which indicates how effectively the body delivers oxygen to the bloodstream through the lungs with each breath. A more efficient VO2 Breath means the body requires less effort to obtain the same amount of oxygen, indicating better respiratory efficiency and oxygen utilization.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Carb & Fat Crossover -->
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold">Carb & Fat Crossover:</p>
|
||||||
|
<p class="mb-1">
|
||||||
|
The point during exercise at which the body shifts its predominant fuel source from fats to carbohydrates. This transition typically occurs as exercise intensity increases, and marks the transition from Zone 2 into Zone 3. As exercise intensity increases, the body starts to rely more on carbohydrates because they provide faster energy.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Endurance training (e.g., long, steady-state cardio within Zones 1 & 2) increases the body's ability to burn fat efficiently at higher intensities, shifting the crossover point to a faster speed, or higher heart rate/intensity. Because fat stores are much larger and can provide a steady stream of energy for prolonged periods, a higher CHO/FAT crossover can help delay fatigue, which is especially beneficial in longer-duration events, where carbohydrate depletion can lead to a significant drop in performance.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cardiovascular Recovery -->
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold">Cardiovascular Recovery:</p>
|
||||||
|
<p>
|
||||||
|
The percentage your heart rate drops within the first minute of the inactive recovery phase in relation to the lowest heart rate recorded prior to the start of the test.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metabolic (CO2) Recovery -->
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold">Metabolic (CO2) Recovery:</p>
|
||||||
|
<p class="mb-1">
|
||||||
|
The percentage that your VCO2 levels (amount of CO2 you are exhaling) drop within the first 1.5 minutes of the inactive recovery phase in relation to the lowest VCO2 recorded prior to the start of the test.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
refers to the rate at which the body clears carbon dioxide (CO2) after exercise, reflecting the efficiency of the cardiovascular and respiratory systems in returning CO2 levels to baseline. A faster VCO2 recovery indicates effective management of metabolic byproducts, signaling a healthier metabolic system and lower risk of metabolic disorders.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Breath Frequency Recovery -->
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold">Breath Frequency Recovery:</p>
|
||||||
|
<p>
|
||||||
|
Refers to the speed at which the body returns to a normal breathing rate after physical exertion. Faster breath frequency recovery indicates a well-conditioned cardiovascular and respiratory system, allowing the body to efficiently regulate oxygen and CO2 levels. It supports better endurance, faster recovery between intervals, and the ability to sustain higher performance during repeated efforts or prolonged activity. Additionally, a quick return to baseline signals that the autonomic nervous system is functioning well, reducing stress on the body and promoting more efficient recovery. This also reflects a healthier metabolic system, better management of metabolic byproducts like CO2, and a lower risk of chronic conditions.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+32
-808
@@ -1,814 +1,38 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page">
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="p-6">
|
<div class="p-8">
|
||||||
<h1 class="text-3xl font-bold mb-6">Glossary</h1>
|
<h1 class="text-4xl font-bold mb-8">Glossary</h1>
|
||||||
|
|
||||||
<!-- Resting Heart Rate Section -->
|
<!-- Local Muscle Activity/SMO2 Definition -->
|
||||||
<div class="mb-8">
|
<div class="mb-12 text-sm leading-relaxed">
|
||||||
<h2 class="text-xl font-bold mb-4 text-center">
|
<p class="font-semibold mb-2">Local Muscle Activity/SMO2:</p>
|
||||||
Resting Heart Rate
|
<p>
|
||||||
</h2>
|
SmO2 testing is a valuable tool for understanding how muscles
|
||||||
|
respond to various physiological stressors and how to fine-tune
|
||||||
<!-- Male Table -->
|
training, nutrition and hydration accordingly. Monitoring
|
||||||
<div class="mb-4">
|
changes in tissue oxygen saturation and utilization helps
|
||||||
<table
|
identify an individual's optimal intensity to work at, as well
|
||||||
class="w-full border-collapse border border-gray-300 text-xs"
|
as how well they recover between bouts of intensity. This can
|
||||||
>
|
help optimize training to improve performance, prevent
|
||||||
<thead>
|
overtraining, and tailor strategies for better results.
|
||||||
<tr class="bg-cyan-200">
|
</p>
|
||||||
<th
|
<p>
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
During competitions, athletes can also use SmO2 data to pace
|
||||||
>
|
themselves effectively. Adjusting intensity based on muscle
|
||||||
Age (M)
|
oxygenation can help prevent premature fatigue and optimize race
|
||||||
</th>
|
outcomes
|
||||||
<th
|
</p>
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Below Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Above Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Good
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Excellent
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Athlete
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
18-25
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
85bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
76-84bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
74-78bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-73bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
61-65bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
60-60bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
26-35
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
83bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
77-82bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
73-76bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
69-72bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
65-68bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
60-64bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
55-59bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
36-45
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
85bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
79-84bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
74-78bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-73bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
65-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
60-64bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
55-59bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
46-55
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
84bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
76-83bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
73-77bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-72bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
61-65bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
56-60bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
56-65
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
85bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
78-84bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
74-77bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-73bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
65-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
60-64bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
50-59bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
65+
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
84bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
77-83bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
73-76bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-73bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
65-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
60-64bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
55-59bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Female Table -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<table
|
|
||||||
class="w-full border-collapse border border-gray-300 text-xs"
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr class="bg-cyan-200">
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Age (F)
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Below Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Above Average
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Good
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Excellent
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Athlete
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
18-25
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
81bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
74-81bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
73-78bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
62-65bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
56-61bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
50-55bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
26-35
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
82bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
75-81bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
71-74bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66-70bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
62-65bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
55-61bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
54-54bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
36-45
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
83bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
76-82bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
71-75bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
67-70bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
63-66bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
57-62bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
47-56bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
46-55
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
84bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
77-83bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
72-76bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
68-71bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
64-67bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
58-63bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
49-57bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
56-65
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
82bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
76-81bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
72-75bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
68-71bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
62-67bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
57-61bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
51-56bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
65+
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
80bpm +
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
74-79bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
70-73bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66-69bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
62-65bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
56-61bpm
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
52-55bpm
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VO2 Master Chart Section -->
|
<div class="w-full max-w-5xl">
|
||||||
<div class="mb-4">
|
<h1 class="text-2xl font-bold mb-4 text-center">
|
||||||
<h2 class="text-xl font-bold mb-4 text-center">
|
Body Fat Percent Master Chart
|
||||||
VO2 Master Chart
|
</h1>
|
||||||
</h2>
|
<img
|
||||||
|
src="data:image/png;base64,{{ body_fat_percentage_chart }}"
|
||||||
<!-- Male VO2 Table -->
|
alt="Body Fat Percentage"
|
||||||
<div class="mb-4">
|
class="w-full h-auto object-contain chart-large"
|
||||||
<table
|
/>
|
||||||
class="w-full border-collapse border border-gray-300 text-xs"
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr class="bg-cyan-200">
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Age (M)
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Very Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Fair
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Good
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Excellent
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Superior
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
20-29
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
29.0-38.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
38.1-44.9
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
44.9-50.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
50.2-61.8
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
57.1-66.3
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
66.3+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
30-39
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
27.2-34.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
34.1-39.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
39.6-45.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
45.2-51.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
51.6-59.8
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
59.8+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
40-49
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
24.2-30.5
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
30.5-35.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
35.7-40.3
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
40.3-46.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
46.7-55.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
55.6+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
50-59
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
20.9-26.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
26.1-30.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
30.7-35.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
35.1-41.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
41.2-50.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
50.7+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
60-69
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
17.4-22.4
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
22.4-26.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
26.6-30.5
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
30.5-36.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
36.1-43.0
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
43.0+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Female VO2 Table -->
|
|
||||||
<div class="mb-4">
|
|
||||||
<table
|
|
||||||
class="w-full border-collapse border border-gray-300 text-xs"
|
|
||||||
>
|
|
||||||
<thead>
|
|
||||||
<tr class="bg-cyan-200">
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Age (F)
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Very Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Poor
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Fair
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Good
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Excellent
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="border border-gray-300 p-1 font-bold text-center"
|
|
||||||
>
|
|
||||||
Superior
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
20-29
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
21.7-28.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
28.6-34.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
34.6-40.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
40.6-46.5
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
46.5-56.0
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
56.0+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
30-39
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
19.0-24.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
24.1-28.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
28.2-32.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
32.2-35.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
35.7-45.8
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
45.8+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
40-49
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
17.0-21.3
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
21.3-24.9
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
24.9-28.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
28.7-34.0
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
34.0-41.7
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
41.7+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
50-59
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
16.0-19.1
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
19.1-24.4
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
21.8-27.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
25.2-28.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
28.6-35.9
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
35.9+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td
|
|
||||||
class="border border-gray-300 p-1 font-medium text-center"
|
|
||||||
>
|
|
||||||
60-69
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
13.4-16.5
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
16.5-18.9
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
18.9-21.2
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
21.2-24.6
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
24.6-29.4
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-300 p-1 text-center">
|
|
||||||
29.4+
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -0,0 +1,474 @@
|
|||||||
|
<div class="w-full page bg-white">
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="p-8">
|
||||||
|
<!-- Body Fat Percent Master Chart Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="text-2xl font-bold mb-4 text-center">
|
||||||
|
Body Fat Percent Master Chart
|
||||||
|
</h1>
|
||||||
|
<div class="w-full max-w-5xl mx-auto">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64,{{ body_fat_percentage_chart }}"
|
||||||
|
alt="Body Fat Percentage"
|
||||||
|
class="w-full h-auto object-contain chart-large"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Resting Heart Rate Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-xl font-bold mb-4 text-center">
|
||||||
|
Resting Heart Rate
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Male Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (M)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Below Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Above Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Athlete
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
18-25
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
85bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
79-84bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-78bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
61-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
40-60bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
26-35
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
83bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-82bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
69-72bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-68bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
42-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
36-45
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
85bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
79-84bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-78bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
45-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
46-55
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
78-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-77bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
61-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
48-60bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
56-65
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
78-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-77bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
50-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
65+
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
52-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Female Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (F)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Below Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Above Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Athlete
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
18-25
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
82bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
40-55bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
26-35
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
82bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
75-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
71-74bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-70bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
44-54bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
36-45
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
83bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-82bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
71-75bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
67-70bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
63-66bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
57-62bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
47-56bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
46-55
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
72-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
68-71bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
64-67bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
58-63bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
49-57bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
56-65
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
82bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
72-75bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
68-71bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-67bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
57-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
51-56bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
65+
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
80bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-79bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
52-55bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -15,7 +15,8 @@
|
|||||||
<!-- Lung Analysis -->
|
<!-- Lung Analysis -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
3
|
3
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +36,8 @@
|
|||||||
<!-- Cardio Metrics -->
|
<!-- Cardio Metrics -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
4
|
4
|
||||||
</div>
|
</div>
|
||||||
@@ -52,7 +54,8 @@
|
|||||||
<!-- Fuel Utilization -->
|
<!-- Fuel Utilization -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
5
|
5
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +69,8 @@
|
|||||||
<!-- Local Muscle Activity -->
|
<!-- Local Muscle Activity -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
9
|
9
|
||||||
</div>
|
</div>
|
||||||
@@ -80,7 +84,8 @@
|
|||||||
<!-- Training Recommendations -->
|
<!-- Training Recommendations -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
10
|
10
|
||||||
</div>
|
</div>
|
||||||
@@ -94,7 +99,8 @@
|
|||||||
<!-- Next Steps -->
|
<!-- Next Steps -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
12
|
12
|
||||||
</div>
|
</div>
|
||||||
@@ -111,7 +117,8 @@
|
|||||||
<!-- Glossary -->
|
<!-- Glossary -->
|
||||||
<div class="flex items-start bg-gray-200 h-24">
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
<div
|
<div
|
||||||
class="bg-black text-white text-2xl font-bold w-16 h-full flex items-center justify-center mr-8 flex-shrink-0"
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
>
|
>
|
||||||
13
|
13
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,814 @@
|
|||||||
|
<div class="w-full page bg-white">
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="p-6">
|
||||||
|
<h1 class="text-3xl font-bold mb-6">Glossary</h1>
|
||||||
|
|
||||||
|
<!-- Resting Heart Rate Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-xl font-bold mb-4 text-center">
|
||||||
|
Resting Heart Rate
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Male Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (M)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Below Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Above Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Athlete
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
18-25
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
85bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-84bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-78bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
61-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-60bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
26-35
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
83bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-82bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
69-72bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-68bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
36-45
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
85bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
79-84bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-78bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
46-55
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-77bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-72bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
61-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56-60bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
56-65
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
85bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
78-84bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-77bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
50-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
65+
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
65-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
60-64bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55-59bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Female Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (F)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Below Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Above Average
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Athlete
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
18-25
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
81bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
73-78bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
50-55bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
26-35
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
82bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
75-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
71-74bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-70bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
54-54bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
36-45
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
83bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-82bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
71-75bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
67-70bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
63-66bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
57-62bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
47-56bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
46-55
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
84bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
77-83bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
72-76bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
68-71bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
64-67bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
58-63bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
49-57bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
56-65
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
82bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
76-81bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
72-75bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
68-71bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-67bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
57-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
51-56bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
65+
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
80bpm +
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
74-79bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
70-73bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66-69bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
62-65bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56-61bpm
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
52-55bpm
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- VO2 Master Chart Section -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<h2 class="text-xl font-bold mb-4 text-center">
|
||||||
|
VO2 Master Chart
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Male VO2 Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (M)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Very Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Fair
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Superior
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
20-29
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
29.0-38.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
38.1-44.9
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
44.9-50.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
50.2-61.8
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
57.1-66.3
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
66.3+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
30-39
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
27.2-34.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
34.1-39.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
39.6-45.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
45.2-51.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
51.6-59.8
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
59.8+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
40-49
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
24.2-30.5
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
30.5-35.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
35.7-40.3
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
40.3-46.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
46.7-55.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
55.6+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
50-59
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
20.9-26.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
26.1-30.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
30.7-35.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
35.1-41.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
41.2-50.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
50.7+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
60-69
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
17.4-22.4
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
22.4-26.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
26.6-30.5
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
30.5-36.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
36.1-43.0
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
43.0+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Female VO2 Table -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<table
|
||||||
|
class="w-full border-collapse border border-gray-300 text-xs"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-blue-300">
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Age (F)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Very Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Poor
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Fair
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Good
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Excellent
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="border border-gray-300 p-1 font-bold text-center"
|
||||||
|
>
|
||||||
|
Superior
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
20-29
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
21.7-28.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
28.6-34.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
34.6-40.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
40.6-46.5
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
46.5-56.0
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
56.0+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
30-39
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
19.0-24.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
24.1-28.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
28.2-32.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
32.2-35.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
35.7-45.8
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
45.8+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
40-49
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
17.0-21.3
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
21.3-24.9
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
24.9-28.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
28.7-34.0
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
34.0-41.7
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
41.7+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
50-59
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
16.0-19.1
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
19.1-24.4
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
21.8-27.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
25.2-28.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
28.6-35.9
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
35.9+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="border border-gray-300 p-1 font-medium text-center"
|
||||||
|
>
|
||||||
|
60-69
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
13.4-16.5
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
16.5-18.9
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
18.9-21.2
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
21.2-24.6
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
24.6-29.4
|
||||||
|
</td>
|
||||||
|
<td class="border border-gray-300 p-1 text-center">
|
||||||
|
29.4+
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<div class="bg-white w-full page m-0 px-10">
|
||||||
|
<div class="px-16 py-10">
|
||||||
|
<!-- Table of Contents Header -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1
|
||||||
|
class="text-5xl font-bold text-black mb-6 tracking-wide border-b-4 border-blue-500 pb-2 text-center"
|
||||||
|
>
|
||||||
|
TABLE OF CONTENTS
|
||||||
|
</h1>
|
||||||
|
<div class="w-full h-1 bg-cyan-400"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table of Contents Items -->
|
||||||
|
<div class="flex flex-col justify-between space-y-6 py-6">
|
||||||
|
<!-- Nutrition Guidelines -->
|
||||||
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
|
<div
|
||||||
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
|
>
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col flex-1 py-1 justify-center h-full">
|
||||||
|
<h2 class="text-2xl font-semibold text-black">
|
||||||
|
Nutrition Guidelines
|
||||||
|
</h2>
|
||||||
|
<p class="text-gray-600 text-base">
|
||||||
|
Ultrasound & Body Composition
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600 text-base">
|
||||||
|
Resting Metabolic Rate Assessment
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Nutrition Recommendations -->
|
||||||
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
|
<div
|
||||||
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
|
>
|
||||||
|
4
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col py-1 flex-1 justify-center h-full">
|
||||||
|
<h2 class="text-2xl font-semibold text-black mb-3">
|
||||||
|
Nutrition Recommendations
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Next Steps -->
|
||||||
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
|
<div
|
||||||
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
|
>
|
||||||
|
5
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col h-full justify-center flex-1">
|
||||||
|
<h2 class="text-2xl font-semibold text-black">
|
||||||
|
Next Steps
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<!-- No sub-items -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Glossary -->
|
||||||
|
<div class="flex items-start bg-gray-200 h-24">
|
||||||
|
<div
|
||||||
|
class="bg-black text-white text-4xl font-extrabold w-24 h-24 flex items-center justify-center mr-8 flex-shrink-0"
|
||||||
|
style="border-radius: 0;"
|
||||||
|
>
|
||||||
|
6
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col h-full justify-center flex-1">
|
||||||
|
<h2 class="text-2xl font-semibold text-black">
|
||||||
|
Glossary
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<!-- No sub-items -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<div class="w-full bg-white">
|
||||||
|
<!-- Header Section -->
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-2">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-3">Nutrition Guidelines</h1>
|
||||||
|
|
||||||
|
<!-- Section Title -->
|
||||||
|
<h2 class="text-xl font-bold text-black mb-2">
|
||||||
|
Resting Metabolic Rate Assessment
|
||||||
|
</h2>
|
||||||
|
<p class="text-gray-700 text-sm mb-4">
|
||||||
|
The resting metabolic rate assessment determines the number of
|
||||||
|
calories that you burn at rest, and metabolic health. It is also an
|
||||||
|
indicator of overall health and well-being.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Slow vs Fast Metabolism Section -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64,{{ metabolism_chart }}"
|
||||||
|
alt="Slow vs Fast Metabolism Chart"
|
||||||
|
class="max-w-full h-auto max-h-40"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fuel Source Section -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64,{{ fuel_source_chart }}"
|
||||||
|
alt="Fuel Source Chart"
|
||||||
|
class="max-w-full h-auto max-h-40"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Caloric Intake Section -->
|
||||||
|
<div class="px-6 mb-6">
|
||||||
|
<h3 class="text-2xl font-bold text-black mb-4 text-center">
|
||||||
|
Caloric Intake
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<!-- Calculation Formula -->
|
||||||
|
<div class="flex items-center justify-center space-x-4 text-center">
|
||||||
|
<!-- Resting Metabolic -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg">
|
||||||
|
<div class="text-lg font-bold text-black">
|
||||||
|
{{ resting_calories }}kCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-600 mt-1">
|
||||||
|
<div>Resting</div>
|
||||||
|
<div>Metabolic</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Plus sign -->
|
||||||
|
<div class="text-2xl font-bold text-black">+</div>
|
||||||
|
|
||||||
|
<!-- NEAT -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg">
|
||||||
|
<div class="text-lg font-bold text-black">
|
||||||
|
{{ neat_calories }}kCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-600 mt-1">NEAT</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Minus sign -->
|
||||||
|
<div class="text-2xl font-bold text-black">-</div>
|
||||||
|
|
||||||
|
<!-- Weight Loss -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg">
|
||||||
|
<div class="text-lg font-bold text-black">
|
||||||
|
{{ weight_loss_calories }}kCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-gray-600 mt-1">
|
||||||
|
<div>to lose {{ weight_loss_rate }}lbs</div>
|
||||||
|
<div>per week</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Equals sign -->
|
||||||
|
<div class="text-2xl font-bold text-black">=</div>
|
||||||
|
|
||||||
|
<!-- Total -->
|
||||||
|
<div class="bg-gray-200 p-3 rounded-lg">
|
||||||
|
<div class="text-lg font-bold text-black">
|
||||||
|
~{{ total_calories }}kCals
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Resting Heart Rate Table Section -->
|
||||||
|
{% if rhr_table %}
|
||||||
|
<div class="mb-4">
|
||||||
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
|
Resting Heart Rate
|
||||||
|
</h2>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img
|
||||||
|
src="data:image/png;base64, {{ rhr_table }}"
|
||||||
|
alt="Resting Heart Rate Table"
|
||||||
|
class="table-image"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
+134
-213
@@ -1,219 +1,140 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
<!-- Header Section -->
|
<div class="px-1 py-6">
|
||||||
<!-- main content -->
|
<!-- Page Title -->
|
||||||
<div class="px-8 py-6">
|
<h1 class="text-2xl font-bold text-black mb-6 text-center">
|
||||||
<!-- Page Title -->
|
Weekly Meal Plan Breakdown
|
||||||
<h1 class="text-3xl font-bold text-black mb-8 text-center">Weekly Meal Plan Breakdown</h1>
|
</h1>
|
||||||
|
|
||||||
<!-- Caloric Deficit Example Section -->
|
|
||||||
<div class="mb-12">
|
|
||||||
<h2 class="text-2xl font-bold text-black mb-6 text-center">Caloric Deficit Example</h2>
|
|
||||||
|
|
||||||
<!-- Weekly Grid -->
|
|
||||||
<div class="grid grid-cols-7 gap-3 mb-8">
|
|
||||||
<!-- Monday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Monday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tuesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Tuesday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div class="text-xs text-black">{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Wednesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Wednesday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Thursday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Thursday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Friday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Friday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Saturday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Saturday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sunday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Sunday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ deficit_calories | default('1725KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
|
||||||
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
|
||||||
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Caloric Deficit with Maintenance/Refeed Example Section -->
|
<!-- Caloric Deficit Example Section -->
|
||||||
<div class="mb-12">
|
<div class="mb-8">
|
||||||
<h2 class="text-2xl font-bold text-black mb-6 text-center">Caloric Deficit with Maintenance/Refeed Example</h2>
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
|
Caloric Deficit Example
|
||||||
<!-- Weekly Grid -->
|
</h2>
|
||||||
<div class="grid grid-cols-7 gap-2 mb-8">
|
|
||||||
<!-- Monday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Monday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekday_calories | default('1615KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tuesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Tuesday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekday_calories | default('1615KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Wednesday -->
|
|
||||||
<div class="bg-cyan-300 p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Wednesday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekday_calories | default('1615KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Thursday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Thursday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekday_calories | default('1615KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Friday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Friday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekday_calories | default('1615KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Saturday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Saturday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekend_calories | default('2000KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekend_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekend_carbs | default('190g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekend_fat | default('84g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekend_fiber | default('30g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sunday -->
|
|
||||||
<div class="p-3 text-left rounded-lg">
|
|
||||||
<div class="font-bold text-black mb-2">Sunday</div>
|
|
||||||
<div class="text-lg font-bold text-black mb-2">{{ refeed_weekend_calories | default('2000KCals') }}</div>
|
|
||||||
<div class="text-xs text-black space-y-1">
|
|
||||||
<div>{{ refeed_weekend_protein | default('120g Protein') }}</div>
|
|
||||||
<div>{{ refeed_weekend_carbs | default('190g Carbs') }}</div>
|
|
||||||
<div>{{ refeed_weekend_fat | default('84g Fat') }}</div>
|
|
||||||
<div>{{ refeed_weekend_fiber | default('30g Fibre') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Macronutrients Recommendations Section -->
|
<!-- Weekly Grid -->
|
||||||
<div class="mb-8">
|
<div class="grid grid-cols-7 gap-0 mb-6">
|
||||||
<h2 class="text-2xl font-bold text-black mb-8 text-center">Macronutrients Recommendations</h2>
|
{% set days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] %}
|
||||||
|
{% for i in range(7) %}
|
||||||
<!-- Macronutrient Boxes -->
|
<div
|
||||||
<div class="flex justify-center space-x-12">
|
class="border border-gray-300 text-center
|
||||||
<!-- Protein -->
|
{% if i == 0 %} rounded-tl-lg rounded-bl-lg {% endif %}
|
||||||
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
{% if i == 6 %} rounded-tr-lg rounded-br-lg {% endif %}
|
||||||
<div class="text-3xl font-bold text-black mb-2">{{ protein_percentage | default('28%') }}</div>
|
{% if i < 5 %} bg-cyan-300 {% else %} bg-white {% endif %}"
|
||||||
<div class="text-lg font-semibold text-black">Protein</div>
|
style="padding: 0"
|
||||||
|
>
|
||||||
|
<!-- Day Row (Always blue) -->
|
||||||
|
<div class="bg-blue-300
|
||||||
|
{% if i == 0 %} rounded-tl-lg {% endif %}
|
||||||
|
{% if i == 6 %} rounded-tr-lg {% endif %}
|
||||||
|
text-black text-sm font-bold px-2 py-1"
|
||||||
|
style="border-top-left-radius: {% if i == 0 %}0.5rem{% else %}0{% endif %}; border-top-right-radius: {% if i == 6 %}0.5rem{% else %}0{% endif %};"
|
||||||
|
>
|
||||||
|
{{ days[i] }}
|
||||||
|
</div>
|
||||||
|
<!-- Macro Body (fills to the bottom, cyan or white) -->
|
||||||
|
<div class="flex flex-col items-center py-1 px-2">
|
||||||
|
<div class="font-bold text-sm text-black mb-1">
|
||||||
|
{{ deficit_calories | default('1725KCals') }} KCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black leading-tight text-left">
|
||||||
|
<div>{{ deficit_protein | default('120g Protein') }}</div>
|
||||||
|
<div>{{ deficit_carbs | default('155g Carbs') }}</div>
|
||||||
|
<div>{{ deficit_fat | default('69g Fat') }}</div>
|
||||||
|
<div>{{ deficit_fiber | default('25g Fibre') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Carbs -->
|
|
||||||
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
|
||||||
<div class="text-3xl font-bold text-black mb-2">{{ carbs_percentage | default('36%') }}</div>
|
|
||||||
<div class="text-lg font-semibold text-black">Carbs</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fats -->
|
|
||||||
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
|
||||||
<div class="text-3xl font-bold text-black mb-2">{{ fats_percentage | default('36%') }}</div>
|
|
||||||
<div class="text-lg font-semibold text-black">Fats</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- Caloric Deficit with Maintenance/Refeed Example Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-xl font-bold text-black mb-4 text-center">
|
||||||
|
Caloric Deficit with Maintenance/Refeed Example
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Weekly Grid -->
|
||||||
|
<div class="grid grid-cols-7 gap-0 mb-6">
|
||||||
|
{% for i in range(7) %}
|
||||||
|
<div class="border border-gray-300 text-center
|
||||||
|
{% if i == 0 %} rounded-tl-lg rounded-bl-lg {% endif %}
|
||||||
|
{% if i == 6 %} rounded-tr-lg rounded-br-lg {% endif %}
|
||||||
|
{% if i < 5 %} bg-cyan-300 {% else %} bg-white {% endif %}"
|
||||||
|
style="padding: 0"
|
||||||
|
>
|
||||||
|
<!-- Day Row (Always blue) -->
|
||||||
|
<div class="bg-blue-300
|
||||||
|
{% if i == 0 %} rounded-tl-lg {% endif %}
|
||||||
|
{% if i == 6 %} rounded-tr-lg {% endif %}
|
||||||
|
text-black text-sm font-bold px-2 py-1"
|
||||||
|
style="border-top-left-radius: {% if i == 0 %}0.5rem{% else %}0{% endif %}; border-top-right-radius: {% if i == 6 %}0.5rem{% else %}0{% endif %};"
|
||||||
|
>
|
||||||
|
{{ days[i] }}
|
||||||
|
</div>
|
||||||
|
<!-- Macro Body (fills to the bottom, cyan or white) -->
|
||||||
|
{% if i < 5 %}
|
||||||
|
<div class="flex flex-col items-center py-1 px-2">
|
||||||
|
<div class="font-bold text-sm text-black mb-1">
|
||||||
|
{{ refeed_weekday_calories | default('1615KCals') }} KCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black leading-tight text-left">
|
||||||
|
<div>{{ refeed_weekday_protein | default('120g Protein') }}</div>
|
||||||
|
<div>{{ refeed_weekday_carbs | default('142g Carbs') }}</div>
|
||||||
|
<div>{{ refeed_weekday_fat | default('63g Fat') }}</div>
|
||||||
|
<div>{{ refeed_weekday_fiber | default('24g Fibre') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="flex flex-col items-center py-1 px-2">
|
||||||
|
<div class="font-bold text-black mb-1">
|
||||||
|
{{ refeed_weekend_calories | default('2000KCals') }} KCals
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-black leading-tight text-left">
|
||||||
|
<div>{{ refeed_weekend_protein | default('120g Protein') }}</div>
|
||||||
|
<div>{{ refeed_weekend_carbs | default('190g Carbs') }}</div>
|
||||||
|
<div>{{ refeed_weekend_fat | default('84g Fat') }}</div>
|
||||||
|
<div>{{ refeed_weekend_fiber | default('30g Fibre') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Macronutrients Recommendations Section -->
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-black mb-8 text-center">
|
||||||
|
Macronutrients Recommendations
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- Macronutrient Boxes -->
|
||||||
|
<div class="flex justify-center space-x-12">
|
||||||
|
<!-- Protein -->
|
||||||
|
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
||||||
|
<div class="text-3xl font-bold text-black mb-2">
|
||||||
|
{{ protein_percentage | default('28%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-semibold text-black">Protein</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Carbs -->
|
||||||
|
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
||||||
|
<div class="text-3xl font-bold text-black mb-2">
|
||||||
|
{{ carbs_percentage | default('36%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-semibold text-black">Carbs</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fats -->
|
||||||
|
<div class="bg-gray-200 p-6 rounded-lg text-center">
|
||||||
|
<div class="text-3xl font-bold text-black mb-2">
|
||||||
|
{{ fats_percentage | default('36%') }}
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-semibold text-black">Fats</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<!-- Indications Box -->
|
<!-- Indications Box -->
|
||||||
<div class="bg-gray-200 rounded-lg p-4 text-center mb-2">
|
<div class="bg-gray-200 rounded-lg p-4 text-center mb-2">
|
||||||
<h3 class="font-semibold text-lg mb-2">Indications</h3>
|
<h3 class="font-semibold text-lg mb-2">Indications</h3>
|
||||||
<p class="text-gray-700">{{ indication }}</p>
|
<p >{{ indication | default('No Respiratory Capacity Limitation')}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+37
-193
@@ -1,198 +1,42 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="px-8 py-6">
|
||||||
|
<!-- Page Title -->
|
||||||
|
<h1 class="text-3xl font-bold text-black mb-6">Cardio Metrics</h1>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Active Metabolic Rate Assessment Section -->
|
||||||
<div class="px-8 py-6">
|
<h2 class="text-xl font-bold text-black mb-4">
|
||||||
<!-- Page Title -->
|
Active Metabolic Rate Assessment
|
||||||
<h1 class="text-3xl font-bold text-black mb-6">Cardio Metrics</h1>
|
</h2>
|
||||||
|
<p class="text-gray-700 text-sm mb-8">
|
||||||
<!-- Active Metabolic Rate Assessment Section -->
|
The active metabolic rate assessment is a key measure of aerobic
|
||||||
<h2 class="text-xl font-bold text-black mb-4">Active Metabolic Rate Assessment</h2>
|
fitness. It helps determine your specific heart rate zones and how
|
||||||
<p class="text-gray-700 text-sm mb-8">The active metabolic rate assessment is a key measure of aerobic fitness. It helps determine your specific heart rate zones and how well your body uses carbohydrates and fats as fuel while you exercise. It is also an indicator of overall health and wellbeing.</p>
|
well your body uses carbohydrates and fats as fuel while you
|
||||||
|
exercise. It is also an indicator of overall health and wellbeing.
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- VO2 Max Section -->
|
<!-- VO2 Max Section -->
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h3 class="text-xl font-bold text-black mb-4 text-center">VO2 Max - {{ vo2_max_value | default('49.5') }} ({{ vo2_max_percentile | default('100th percentile') }})</h3>
|
<!-- VO2 Max Table -->
|
||||||
|
<div class="mb-8 flex justify-center">
|
||||||
<!-- VO2 Max Table -->
|
<img
|
||||||
<div class="mb-8">
|
src="data:image/png;base64, {{ vo2_max_table }}"
|
||||||
<table class="w-full border-collapse">
|
alt="VO2 Max Table"
|
||||||
<thead>
|
class="table-image"
|
||||||
<tr>
|
/>
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Age (F)</th>
|
</div>
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Very Poor</th>
|
</div>
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Poor</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Fair</th>
|
<!-- Personalized Heart Rate Zones Section -->
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Good</th>
|
<div class="mb-8">
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold">Excellent</th>
|
<!-- Heart Rate Zones Table -->
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-3 text-black font-bold relative">
|
<div class="flex justify-center">
|
||||||
Superior
|
<img
|
||||||
<!-- Arrow indicator -->
|
src="data:image/png;base64, {{ hr_zones_table }}"
|
||||||
<div class="absolute -bottom-4 left-1/2 transform -translate-x-1/2">
|
alt="Heart Rate Zones Table"
|
||||||
<div class="w-0 h-0 border-l-4 border-r-4 border-t-8 border-transparent border-t-black"></div>
|
class="table-image"
|
||||||
</div>
|
/>
|
||||||
</th>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td class="bg-cyan-200 border border-gray-400 p-3 text-black font-semibold">{{ age_range | default('30-39') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center">{{ very_poor_range | default('19.0-24.1') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center">{{ poor_range | default('24.1-28.2') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center">{{ fair_range | default('28.2-32.2') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center">{{ good_range | default('32.2-35.7') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center">{{ excellent_range | default('35.7-45.8') }}</td>
|
|
||||||
<td class="bg-gray-100 border border-gray-400 p-3 text-black text-center font-bold">{{ superior_range | default('45.8+') }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Personalized Heart Rate Zones Section -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<h3 class="text-xl font-bold text-black mb-6 text-center">Personalized Heart Rate Zones</h3>
|
|
||||||
|
|
||||||
<!-- Heart Rate Zones Table -->
|
|
||||||
<table class="w-full border-collapse text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone 1</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone 2</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone 3</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone 4</th>
|
|
||||||
<th class="bg-cyan-300 border border-gray-400 p-2 text-black font-bold">Zone 5</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<!-- Zone Descriptions -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-3 text-center">
|
|
||||||
<div class="text-black font-semibold mb-1">Improves health and recovery capacity</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-3 text-center">
|
|
||||||
<div class="text-black font-semibold mb-1">Improves endurance and fat burning</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-3 text-center">
|
|
||||||
<div class="text-black font-semibold mb-1">Improves Aerobic fitness</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-3 text-center">
|
|
||||||
<div class="text-black font-semibold mb-1">Improves maximum performance capacity</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-3 text-center">
|
|
||||||
<div class="text-black font-semibold mb-1">Develops maximum performance and speed</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Heart Rate Percentages -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">{{ zone1_percentage | default('55-65% of Max Heart Rate') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">{{ zone2_percentage | default('65-75% of Max Heart Rate') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">{{ zone3_percentage | default('80-85% of Max Heart Rate') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">{{ zone4_percentage | default('85-88% of Max Heart Rate') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black font-semibold">{{ zone5_percentage | default('90% of Max Heart Rate') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Heart Rate BPM -->
|
|
||||||
<tr>
|
|
||||||
<td class="bg-red-200 border border-gray-400 p-2 text-center text-black font-bold">{{ zone1_bpm | default('81-96bpm') }}</td>
|
|
||||||
<td class="bg-red-200 border border-gray-400 p-2 text-center text-black font-bold">{{ zone2_bpm | default('96-100bpm') }}</td>
|
|
||||||
<td class="bg-yellow-200 border border-gray-400 p-2 text-center text-black font-bold">{{ zone3_bpm | default('100-178bpm') }}</td>
|
|
||||||
<td class="bg-green-200 border border-gray-400 p-2 text-center text-black font-bold">{{ zone4_bpm | default('178-188bpm') }}</td>
|
|
||||||
<td class="bg-green-200 border border-gray-400 p-2 text-center text-black font-bold">{{ zone5_bpm | default('188-198bpm') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Speed -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-semibold">{{ zone1_speed | default('3.5mph') }}</div>
|
|
||||||
<div class="text-black text-xs">{{ zone1_incline | default('2% Incline') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-semibold">{{ zone2_speed | default('3.5-4.0mph') }}</div>
|
|
||||||
<div class="text-black text-xs">{{ zone2_incline | default('2% Incline') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-semibold">{{ zone3_speed | default('4.0-6.5mph') }}</div>
|
|
||||||
<div class="text-black text-xs">{{ zone3_incline | default('2% Incline') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-semibold">{{ zone4_speed | default('6.5-7.0mph') }}</div>
|
|
||||||
<div class="text-black text-xs">{{ zone4_incline | default('2% Incline') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-semibold">{{ zone5_speed | default('7.0-8.0mph') }}</div>
|
|
||||||
<div class="text-black text-xs">{{ zone5_incline | default('2% Incline') }}</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Pace -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone1_pace | default('10:39min/km Pace') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone2_pace | default('10:39-9:19min/km Pace') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone3_pace | default('9:19-5:44min/km Pace') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone4_pace | default('5:44-5:20min/km Pace') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone5_pace | default('5:20-4:40min/km Pace') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Average Calories -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black text-xs">Avg:</div>
|
|
||||||
<div class="text-black font-semibold">{{ zone1_calories | default('4.4kcals/minute') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black text-xs">Avg:</div>
|
|
||||||
<div class="text-black font-semibold">{{ zone2_calories | default('5.9kcals/minute') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black text-xs">Avg:</div>
|
|
||||||
<div class="text-black font-semibold">{{ zone3_calories | default('9.4kcals/minute') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black text-xs">Avg:</div>
|
|
||||||
<div class="text-black font-semibold">{{ zone4_calories | default('12.5kcals/minute') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black text-xs">Avg:</div>
|
|
||||||
<div class="text-black font-semibold">{{ zone5_calories | default('12.8kcals/minute') }}</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Carb Utilization -->
|
|
||||||
<tr>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone1_carb | default('Avg: 0.4g/min Carb Utilization') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone2_carb | default('Avg: 0.6g/min Carb Utilization') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone3_carb | default('Avg: 1.9g/min Carb Utilization') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone4_carb | default('Avg: 2.9g/min Carb Utilization') }}</td>
|
|
||||||
<td class="border border-gray-400 p-2 text-center text-black">{{ zone5_carb | default('Avg: 3.1g/min Carb Utilization') }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<!-- Breathing -->
|
|
||||||
<tr>
|
|
||||||
<td class="bg-red-200 border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-bold">{{ zone1_breaths | default('Avg: 27 breaths') }}</div>
|
|
||||||
<div class="text-black text-xs italic">{{ zone1_breath_range | default('Ideal Range: 15-20 breaths') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="bg-red-200 border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-bold">{{ zone2_breaths | default('Avg: 28 breaths') }}</div>
|
|
||||||
<div class="text-black text-xs italic">{{ zone2_breath_range | default('Ideal Range: 20-25 breaths') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="bg-yellow-200 border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-bold">{{ zone3_breaths | default('Avg: 31 breaths') }}</div>
|
|
||||||
<div class="text-black text-xs italic">{{ zone3_breath_range | default('Ideal Range: 25-30 breaths') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="bg-green-200 border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-bold">{{ zone4_breaths | default('Avg: 42 breaths') }}</div>
|
|
||||||
<div class="text-black text-xs italic">{{ zone4_breath_range | default('Ideal Range: 30-35 breaths') }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="bg-green-200 border border-gray-400 p-2 text-center">
|
|
||||||
<div class="text-black font-bold">{{ zone5_breaths | default('Avg: 51 breaths') }}</div>
|
|
||||||
<div class="text-black text-xs italic">{{ zone5_breath_range | default('Ideal Range: 40+ breaths') }}</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<div class="w-full page bg-white">
|
<div class="w-full page bg-white">
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="flex flex-col items-center justify-center h-full">
|
<div class="flex flex-col items-center justify-center h-full">
|
||||||
|
<!-- Title -->
|
||||||
|
<h1 class="text-2xl font-bold text-center text-gray-800 mb-6">
|
||||||
|
Fuel Utilization Report - Institute of Science, Health and
|
||||||
|
Performance
|
||||||
|
</h1>
|
||||||
|
|
||||||
<!-- Fuel Utilization Chart -->
|
<!-- Fuel Utilization Chart -->
|
||||||
<div class="w-full max-w-5xl">
|
<div class="w-full max-w-5xl">
|
||||||
<img
|
<img
|
||||||
@@ -13,8 +19,8 @@
|
|||||||
<!-- Chart Information -->
|
<!-- Chart Information -->
|
||||||
<div class="mt-8 text-center">
|
<div class="mt-8 text-center">
|
||||||
<p class="text-gray-700 text-sm">
|
<p class="text-gray-700 text-sm">
|
||||||
Client: {{ client_name | default('Keirstyn Moran') }} |
|
Client: {{ client_name }} | Assessment Date: {{ assessment_date
|
||||||
Assessment Date: {{ assessment_date | default('July 29 2025') }}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
+833
-85
File diff suppressed because it is too large
Load Diff
@@ -151,7 +151,7 @@ class ReportGeneratorService:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generate_html(
|
def generate_html(
|
||||||
self, patient_info: Dict[str, Any], contexts: Dict[str, Dict[str, Any]]
|
self, patient_info: Dict[str, Any], contexts: Dict[str, Dict[str, Any]], report_type: str = "full"
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Generate HTML content for the report.
|
Generate HTML content for the report.
|
||||||
@@ -160,6 +160,7 @@ class ReportGeneratorService:
|
|||||||
patient_info: Dictionary containing patient information
|
patient_info: Dictionary containing patient information
|
||||||
(patient_name, age, height, weight, focus)
|
(patient_name, age, height, weight, focus)
|
||||||
contexts: Dictionary with keys 'page_1', 'page_2', etc., each containing context data
|
contexts: Dictionary with keys 'page_1', 'page_2', etc., each containing context data
|
||||||
|
report_type: Type of report to generate ("full" or "minimal")
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Complete HTML document as string
|
Complete HTML document as string
|
||||||
@@ -175,8 +176,28 @@ class ReportGeneratorService:
|
|||||||
"focus": patient_info.get("focus", "Endurance"),
|
"focus": patient_info.get("focus", "Endurance"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get total number of pages
|
# Define page mappings for full vs minimal reports
|
||||||
num_pages = len(contexts)
|
if report_type == "minimal":
|
||||||
|
# Minimal report: pages 1, 2, 4, 5, 6, 16, 17, 19, 20
|
||||||
|
# Map to minimal report pages 1-8
|
||||||
|
# Page mapping: (original_page_num, template_name, minimal_page_num)
|
||||||
|
page_mapping = [
|
||||||
|
(1, "page_1.html", 1),
|
||||||
|
(2, "page_2_minimal.html", 2),
|
||||||
|
(4, "page_4.html", 3),
|
||||||
|
(5, "page_5_minimal.html", 4),
|
||||||
|
(6, "page_6.html", 5),
|
||||||
|
(16, "page_16.html", 6),
|
||||||
|
(17, "page_17_minimal.html", 7),
|
||||||
|
(19, "page_19_20_minimal.html", 8), # Combined page
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# Full report: all pages 1-20
|
||||||
|
page_mapping = [
|
||||||
|
(i, f"page_{i}.html", i) for i in range(1, 21)
|
||||||
|
]
|
||||||
|
|
||||||
|
num_pages = len(page_mapping)
|
||||||
|
|
||||||
# Footer context
|
# Footer context
|
||||||
footer_context = [
|
footer_context = [
|
||||||
@@ -198,13 +219,20 @@ class ReportGeneratorService:
|
|||||||
for context in footer_context
|
for context in footer_context
|
||||||
]
|
]
|
||||||
|
|
||||||
# Render pages - iterate through pages in order
|
# Render pages based on mapping
|
||||||
for i in range(1, num_pages + 1):
|
for idx, (original_page_num, template_name, minimal_page_num) in enumerate(page_mapping):
|
||||||
page_key = f"page_{i}"
|
# For combined page_19_20_minimal, use the combined context
|
||||||
|
if template_name == "page_19_20_minimal.html":
|
||||||
|
page_key = "page_19_20_minimal"
|
||||||
|
else:
|
||||||
|
page_key = f"page_{original_page_num}"
|
||||||
context = contexts.get(page_key, {})
|
context = contexts.get(page_key, {})
|
||||||
template = self.env.get_template(f"page_{i}.html").render(context)
|
template = self.env.get_template(template_name).render(context)
|
||||||
|
|
||||||
if i > 2:
|
# Pages 1 and 2 don't have headers/footers in full report
|
||||||
|
# In minimal report, only page 1 doesn't have header/footer
|
||||||
|
page_num_in_report = minimal_page_num if report_type == "minimal" else original_page_num
|
||||||
|
if page_num_in_report > 2:
|
||||||
full_html = f"""
|
full_html = f"""
|
||||||
<div class="page flex flex-col justify-between">
|
<div class="page flex flex-col justify-between">
|
||||||
<div>
|
<div>
|
||||||
@@ -214,7 +242,7 @@ class ReportGeneratorService:
|
|||||||
{template}
|
{template}
|
||||||
</main>
|
</main>
|
||||||
<div class="border-t text-center text-sm text-gray-600">
|
<div class="border-t text-center text-sm text-gray-600">
|
||||||
{footer_html_list[i - 1]}
|
{footer_html_list[idx]}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
@@ -260,6 +288,13 @@ class ReportGeneratorService:
|
|||||||
.chart-large {{
|
.chart-large {{
|
||||||
max-height: 500px !important;
|
max-height: 500px !important;
|
||||||
}}
|
}}
|
||||||
|
.table-image {{
|
||||||
|
max-height: none !important;
|
||||||
|
width: auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto !important;
|
||||||
|
object-fit: contain;
|
||||||
|
}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="m-0 p-0">
|
<body class="m-0 p-0">
|
||||||
@@ -293,6 +328,7 @@ class ReportGeneratorService:
|
|||||||
output_filename: str = None,
|
output_filename: str = None,
|
||||||
metric_overrides: Optional[Dict[str, Any]] = None,
|
metric_overrides: Optional[Dict[str, Any]] = None,
|
||||||
oxygenation_csv_path: Optional[str] = None,
|
oxygenation_csv_path: Optional[str] = None,
|
||||||
|
report_type: str = "full",
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Generate complete medical report from uploaded files.
|
Generate complete medical report from uploaded files.
|
||||||
@@ -421,6 +457,21 @@ class ReportGeneratorService:
|
|||||||
)
|
)
|
||||||
graphs_dict["body_fat_percentage_master_chart"] = ""
|
graphs_dict["body_fat_percentage_master_chart"] = ""
|
||||||
|
|
||||||
|
# Load static fuelling analysis flowchart for page 10
|
||||||
|
flowchart_path = Path("app/estimated_carb_storage.png")
|
||||||
|
if flowchart_path.exists():
|
||||||
|
try:
|
||||||
|
with open(flowchart_path, "rb") as f:
|
||||||
|
graphs_dict["fuelling_analysis_flowchart"] = base64.b64encode(
|
||||||
|
f.read()
|
||||||
|
).decode("utf-8")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: Could not load fuelling analysis flowchart: {e}")
|
||||||
|
graphs_dict["fuelling_analysis_flowchart"] = ""
|
||||||
|
else:
|
||||||
|
print(f"Warning: Fuelling analysis flowchart not found at {flowchart_path}")
|
||||||
|
graphs_dict["fuelling_analysis_flowchart"] = ""
|
||||||
|
|
||||||
# Generate spirometry chart
|
# Generate spirometry chart
|
||||||
print("Step 4: Generating spirometry chart...")
|
print("Step 4: Generating spirometry chart...")
|
||||||
try:
|
try:
|
||||||
@@ -473,9 +524,36 @@ class ReportGeneratorService:
|
|||||||
}
|
}
|
||||||
rmr_metrics = temp_context_gen.calculate_rmr_and_fuel_source()
|
rmr_metrics = temp_context_gen.calculate_rmr_and_fuel_source()
|
||||||
|
|
||||||
# Generate metabolism chart
|
# Convert height to cm if available
|
||||||
|
height_cm = None
|
||||||
|
height_str = patient_info.get("height", "")
|
||||||
|
if height_str:
|
||||||
|
try:
|
||||||
|
# Try to parse height string (e.g., "5'4"", "165cm", "165")
|
||||||
|
import re
|
||||||
|
# Check if it's in feet'inches" format
|
||||||
|
feet_inches_match = re.match(r"(\d+)'(\d+)\"", height_str)
|
||||||
|
if feet_inches_match:
|
||||||
|
feet = int(feet_inches_match.group(1))
|
||||||
|
inches = int(feet_inches_match.group(2))
|
||||||
|
height_cm = (feet * 12 + inches) * 2.54
|
||||||
|
# Check if it ends with cm
|
||||||
|
elif "cm" in height_str.lower():
|
||||||
|
height_cm = float(re.sub(r"[^\d.]", "", height_str))
|
||||||
|
# Otherwise try to parse as number (assume cm)
|
||||||
|
else:
|
||||||
|
height_cm = float(re.sub(r"[^\d.]", "", height_str))
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Generate metabolism chart with ratio calculation if we have all parameters
|
||||||
metabolism_chart_b64 = self.graph_generator.generate_metabolism_chart(
|
metabolism_chart_b64 = self.graph_generator.generate_metabolism_chart(
|
||||||
rmr_metrics["rmr_kcal"], save_as_base64=True
|
rmr_metrics["rmr_kcal"],
|
||||||
|
weight_kg=weight_kg,
|
||||||
|
height_cm=height_cm,
|
||||||
|
age_years=patient_info.get("age", None),
|
||||||
|
sex=gender,
|
||||||
|
save_as_base64=True,
|
||||||
)
|
)
|
||||||
graphs_dict["metabolism_chart"] = metabolism_chart_b64
|
graphs_dict["metabolism_chart"] = metabolism_chart_b64
|
||||||
|
|
||||||
@@ -496,6 +574,7 @@ class ReportGeneratorService:
|
|||||||
pnoe_csv_path,
|
pnoe_csv_path,
|
||||||
str(spirometry_csv_path),
|
str(spirometry_csv_path),
|
||||||
None, # No SECA file
|
None, # No SECA file
|
||||||
|
oxygenation_csv_path, # Pass oxygenation CSV path
|
||||||
)
|
)
|
||||||
# Set patient info manually
|
# Set patient info manually
|
||||||
self.context_generator.patient_info = {
|
self.context_generator.patient_info = {
|
||||||
@@ -505,9 +584,14 @@ class ReportGeneratorService:
|
|||||||
"weight": weight_kg,
|
"weight": weight_kg,
|
||||||
"fat_percentage": fat_pct,
|
"fat_percentage": fat_pct,
|
||||||
"gender": gender,
|
"gender": gender,
|
||||||
|
"next_testing_date": patient_info.get("next_testing_date", "Contact us for scheduling"),
|
||||||
}
|
}
|
||||||
contexts = self.context_generator.generate_all_contexts(
|
contexts = self.context_generator.generate_all_contexts(
|
||||||
patient_name, graphs_dict, metric_overrides=metric_overrides
|
patient_name,
|
||||||
|
graphs_dict,
|
||||||
|
metric_overrides=metric_overrides,
|
||||||
|
graph_generator=self.graph_generator,
|
||||||
|
report_type=report_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Step 5: Calculate analysis metrics
|
# Step 5: Calculate analysis metrics
|
||||||
@@ -515,7 +599,7 @@ class ReportGeneratorService:
|
|||||||
analysis_data["graphs_count"] = len(graphs_generated)
|
analysis_data["graphs_count"] = len(graphs_generated)
|
||||||
|
|
||||||
# Step 6: Generate HTML
|
# Step 6: Generate HTML
|
||||||
html_content = self.generate_html(patient_info, contexts)
|
html_content = self.generate_html(patient_info, contexts, report_type=report_type)
|
||||||
|
|
||||||
# Step 7: Generate PDF
|
# Step 7: Generate PDF
|
||||||
if output_filename is None:
|
if output_filename is None:
|
||||||
|
|||||||
+163
-75
@@ -1,24 +1,32 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %} {% block title %}Report Preview - Report Generator{%
|
||||||
|
endblock %} {% block content %}
|
||||||
{% block title %}Report Preview - Report Generator{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="px-4 py-6 sm:px-0">
|
<div class="px-4 py-6 sm:px-0">
|
||||||
{% if not session.get('report_path') %}
|
{% if not session.get('report_path') %}
|
||||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
|
||||||
<p class="text-yellow-800">No report found. Please <a href="/" class="underline">upload files</a> first.</p>
|
<p class="text-yellow-800">
|
||||||
|
No report found. Please
|
||||||
|
<a href="/" class="underline">upload files</a> first.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
<div class="bg-white shadow rounded-lg mb-6">
|
<div class="bg-white shadow rounded-lg mb-6">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h2 class="text-2xl font-bold text-gray-900">Generated Report Preview</h2>
|
<h2 class="text-2xl font-bold text-gray-900">
|
||||||
|
Generated Report Preview
|
||||||
|
</h2>
|
||||||
<div class="flex space-x-3">
|
<div class="flex space-x-3">
|
||||||
<a href="/edit" class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
<a
|
||||||
|
href="/edit"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||||
|
>
|
||||||
Edit Metrics
|
Edit Metrics
|
||||||
</a>
|
</a>
|
||||||
<a href="/download-report/{{ session.report_path.split('/')[-1] }}" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700">
|
<a
|
||||||
|
href="/download-report/{{ session.report_path.split('/')[-1] }}"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700"
|
||||||
|
>
|
||||||
Download PDF
|
Download PDF
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,23 +34,33 @@
|
|||||||
|
|
||||||
<!-- Patient Information -->
|
<!-- Patient Information -->
|
||||||
<div class="border-b border-gray-200 pb-6 mb-6">
|
<div class="border-b border-gray-200 pb-6 mb-6">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Patient Information</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Patient Information
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-gray-500">Name</p>
|
<p class="text-sm text-gray-500">Name</p>
|
||||||
<p class="text-base font-medium text-gray-900">{{ session.patient_info['patient_name'] }}</p>
|
<p class="text-base font-medium text-gray-900">
|
||||||
|
{{ session.patient_info['patient_name'] }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-gray-500">Age</p>
|
<p class="text-sm text-gray-500">Age</p>
|
||||||
<p class="text-base font-medium text-gray-900">{{ session.patient_info['age'] }}</p>
|
<p class="text-base font-medium text-gray-900">
|
||||||
|
{{ session.patient_info['age'] }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-gray-500">Height</p>
|
<p class="text-sm text-gray-500">Height</p>
|
||||||
<p class="text-base font-medium text-gray-900">{{ session.patient_info['height'] }}</p>
|
<p class="text-base font-medium text-gray-900">
|
||||||
|
{{ session.patient_info['height'] }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm text-gray-500">Weight</p>
|
<p class="text-sm text-gray-500">Weight</p>
|
||||||
<p class="text-base font-medium text-gray-900">{{ session.patient_info['weight'] }}</p>
|
<p class="text-base font-medium text-gray-900">
|
||||||
|
{{ session.patient_info['weight'] }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,56 +70,113 @@
|
|||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Pnoe Metrics -->
|
<!-- Pnoe Metrics -->
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Pnoe Metrics</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
Pnoe Metrics
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
|
||||||
|
>
|
||||||
{% if session.metrics.pnoe.get('vo2_max') %}
|
{% if session.metrics.pnoe.get('vo2_max') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">VO2 Max</p>
|
<p class="text-sm text-gray-500">VO2 Max</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.pnoe['vo2_max']) }} ml/min</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
|
{{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['vo2_max'])
|
||||||
|
}} ml/min
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if
|
||||||
{% if session.metrics.pnoe.get('vo2_max_per_kg') %}
|
session.metrics.pnoe.get('vo2_max_per_kg') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">VO2 Max per kg</p>
|
<p class="text-sm text-gray-500">VO2 Max per kg</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.pnoe['vo2_max_per_kg']) }} ml/min/kg</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
|
{{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['vo2_max_per_kg'])
|
||||||
|
}} ml/min/kg
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if session.metrics.pnoe.get('peak_vt') %}
|
||||||
{% if session.metrics.pnoe.get('peak_vt') %}
|
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">Peak VT</p>
|
<p class="text-sm text-gray-500">Peak VT</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.pnoe['peak_vt']) }} L</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
<p class="text-sm text-gray-500 mt-1">HR: {{ "%.0f"|format(session.metrics.pnoe['peak_vt_hr']) }} bpm</p>
|
{{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['peak_vt'])
|
||||||
|
}} L
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
HR: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['peak_vt_hr'])
|
||||||
|
}} bpm
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if
|
||||||
{% if session.metrics.pnoe.get('fat_max_value') %}
|
session.metrics.pnoe.get('fat_max_value') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">Fat Max Value</p>
|
<p class="text-sm text-gray-500">Fat Max Value</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.pnoe['fat_max_value']) }} kcal/min</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
<p class="text-sm text-gray-500 mt-1">HR: {{ "%.0f"|format(session.metrics.pnoe['fat_max_hr']) }} bpm</p>
|
{{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['fat_max_value'])
|
||||||
|
}} kcal/min
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
HR: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['fat_max_hr'])
|
||||||
|
}} bpm
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VT1 and VT2 -->
|
<!-- VT1 and VT2 -->
|
||||||
{% if session.metrics.pnoe.get('vt1') or session.metrics.pnoe.get('vt2') %}
|
{% if session.metrics.pnoe.get('vt1') or
|
||||||
|
session.metrics.pnoe.get('vt2') %}
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Ventilatory Thresholds</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Ventilatory Thresholds
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
{% if session.metrics.pnoe.get('vt1') %}
|
{% if session.metrics.pnoe.get('vt1') %}
|
||||||
<div class="bg-blue-50 p-4 rounded-lg">
|
<div class="bg-blue-50 p-4 rounded-lg">
|
||||||
<p class="text-sm font-medium text-blue-900 mb-2">VT1</p>
|
<p class="text-sm font-medium text-blue-900 mb-2">
|
||||||
<p class="text-sm text-blue-700">Heart Rate: {{ "%.0f"|format(session.metrics.pnoe['vt1']['HeartRate']) }} bpm</p>
|
VT1
|
||||||
<p class="text-sm text-blue-700">Speed: {{ "%.2f"|format(session.metrics.pnoe['vt1']['Speed']) }} mph</p>
|
</p>
|
||||||
<p class="text-sm text-blue-700">Time: {{ "%.0f"|format(session.metrics.pnoe['vt1']['Time']) }} sec</p>
|
<p class="text-sm text-blue-700">
|
||||||
|
Heart Rate: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['vt1']['HeartRate'])
|
||||||
|
}} bpm
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-blue-700">
|
||||||
|
Speed: {{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['vt1']['Speed'])
|
||||||
|
}} mph
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-blue-700">
|
||||||
|
Time: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['vt1']['Time'])
|
||||||
|
}} sec
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if session.metrics.pnoe.get('vt2') %}
|
||||||
{% if session.metrics.pnoe.get('vt2') %}
|
|
||||||
<div class="bg-green-50 p-4 rounded-lg">
|
<div class="bg-green-50 p-4 rounded-lg">
|
||||||
<p class="text-sm font-medium text-green-900 mb-2">VT2</p>
|
<p class="text-sm font-medium text-green-900 mb-2">
|
||||||
<p class="text-sm text-green-700">Heart Rate: {{ "%.0f"|format(session.metrics.pnoe['vt2']['HeartRate']) }} bpm</p>
|
VT2
|
||||||
<p class="text-sm text-green-700">Speed: {{ "%.2f"|format(session.metrics.pnoe['vt2']['Speed']) }} mph</p>
|
</p>
|
||||||
<p class="text-sm text-green-700">Time: {{ "%.0f"|format(session.metrics.pnoe['vt2']['Time']) }} sec</p>
|
<p class="text-sm text-green-700">
|
||||||
|
Heart Rate: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['vt2']['HeartRate'])
|
||||||
|
}} bpm
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-green-700">
|
||||||
|
Speed: {{
|
||||||
|
"%.2f"|format(session.metrics.pnoe['vt2']['Speed'])
|
||||||
|
}} mph
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-green-700">
|
||||||
|
Time: {{
|
||||||
|
"%.0f"|format(session.metrics.pnoe['vt2']['Time'])
|
||||||
|
}} sec
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@@ -111,17 +186,20 @@
|
|||||||
<!-- Heart Rate Zones -->
|
<!-- Heart Rate Zones -->
|
||||||
{% if session.metrics.pnoe.get('zone1_bpm') %}
|
{% if session.metrics.pnoe.get('zone1_bpm') %}
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Heart Rate Zones</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Heart Rate Zones
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-5">
|
<div class="grid grid-cols-1 gap-2 sm:grid-cols-5">
|
||||||
{% for i in range(1, 6) %}
|
{% for i in range(1, 6) %} {% set zone_key = "zone" +
|
||||||
{% set zone_key = "zone" + i|string + "_bpm" %}
|
i|string + "_bpm" %} {% if
|
||||||
{% if session.metrics.pnoe.get(zone_key) %}
|
session.metrics.pnoe.get(zone_key) %}
|
||||||
<div class="bg-gray-50 p-3 rounded-lg text-center">
|
<div class="bg-gray-50 p-3 rounded-lg text-center">
|
||||||
<p class="text-xs text-gray-500">Zone {{ i }}</p>
|
<p class="text-xs text-gray-500">Zone {{ i }}</p>
|
||||||
<p class="text-sm font-medium text-gray-900">{{ session.metrics.pnoe[zone_key] }}</p>
|
<p class="text-sm font-medium text-gray-900">
|
||||||
|
{{ session.metrics.pnoe[zone_key] }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% endfor %}
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -129,27 +207,53 @@
|
|||||||
<!-- Spirometry Metrics -->
|
<!-- Spirometry Metrics -->
|
||||||
{% if session.metrics.spirometry %}
|
{% if session.metrics.spirometry %}
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Spirometry Metrics</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Spirometry Metrics
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||||
{% if session.metrics.spirometry.get('fvc_best') %}
|
{% if session.metrics.spirometry.get('fvc_best') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">FVC Best</p>
|
<p class="text-sm text-gray-500">FVC Best</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.spirometry['fvc_best']) }} L</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
<p class="text-sm text-gray-500 mt-1">{{ "%.1f"|format(session.metrics.spirometry['fvc_pred']) }}% predicted</p>
|
{{
|
||||||
|
"%.2f"|format(session.metrics.spirometry['fvc_best'])
|
||||||
|
}} L
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
{{
|
||||||
|
"%.1f"|format(session.metrics.spirometry['fvc_pred'])
|
||||||
|
}}% predicted
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if
|
||||||
{% if session.metrics.spirometry.get('fev1_best') %}
|
session.metrics.spirometry.get('fev1_best') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">FEV1 Best</p>
|
<p class="text-sm text-gray-500">FEV1 Best</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.spirometry['fev1_best']) }} L</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
<p class="text-sm text-gray-500 mt-1">{{ "%.1f"|format(session.metrics.spirometry['fev1_pred']) }}% predicted</p>
|
{{
|
||||||
|
"%.2f"|format(session.metrics.spirometry['fev1_best'])
|
||||||
|
}} L
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
{{
|
||||||
|
"%.1f"|format(session.metrics.spirometry['fev1_pred'])
|
||||||
|
}}% predicted
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% if
|
||||||
{% if session.metrics.spirometry.get('fev1_fvc_pct_best') %}
|
session.metrics.spirometry.get('fev1_fvc_pct_best') %}
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm text-gray-500">FEV1/FVC%</p>
|
<p class="text-sm text-gray-500">FEV1/FVC%</p>
|
||||||
<p class="text-2xl font-bold text-gray-900">{{ "%.2f"|format(session.metrics.spirometry['fev1_fvc_pct_best']) }}%</p>
|
<p class="text-2xl font-bold text-gray-900">
|
||||||
<p class="text-sm text-gray-500 mt-1">{{ "%.1f"|format(session.metrics.spirometry['fev1_fvc_pct_pred']) }}% predicted</p>
|
{{
|
||||||
|
"%.2f"|format(session.metrics.spirometry['fev1_fvc_pct_best'])
|
||||||
|
}}%
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">
|
||||||
|
{{
|
||||||
|
"%.1f"|format(session.metrics.spirometry['fev1_fvc_pct_pred'])
|
||||||
|
}}% predicted
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
@@ -157,24 +261,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Graphs Section -->
|
|
||||||
{% if session.graphs_generated %}
|
|
||||||
<div class="mt-8">
|
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Generated Graphs</h3>
|
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
||||||
{% for graph in session.graphs_generated %}
|
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">{{ graph.name|replace('_', ' ')|title }}</p>
|
|
||||||
<img src="/graphs/{{ graph.path.split('/')[-1] }}" alt="{{ graph.name }}" class="w-full h-auto rounded">
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
+316
-57
@@ -1,55 +1,117 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %} {% block title %}Upload Patient Data - Report
|
||||||
|
Generator{% endblock %} {% block content %}
|
||||||
{% block title %}Upload Patient Data - Report Generator{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="px-4 py-6 sm:px-0">
|
<div class="px-4 py-6 sm:px-0">
|
||||||
<div class="bg-white shadow rounded-lg">
|
<div class="bg-white shadow rounded-lg">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Upload Patient Data and Files</h2>
|
<h2 class="text-2xl font-bold text-gray-900 mb-6">
|
||||||
|
Upload Patient Data and Files
|
||||||
|
</h2>
|
||||||
|
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
|
<div class="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
|
||||||
<p class="text-red-800">{{ error }}</p>
|
<p class="text-red-800">{{ error }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form action="/upload" method="post" enctype="multipart/form-data" class="space-y-6">
|
<form
|
||||||
|
id="upload-form"
|
||||||
|
action="/upload"
|
||||||
|
method="post"
|
||||||
|
enctype="multipart/form-data"
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<!-- Patient Information Section -->
|
<!-- Patient Information Section -->
|
||||||
<div class="border-b border-gray-200 pb-6">
|
<div class="border-b border-gray-200 pb-6">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Patient Information</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Patient Information
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<label for="first_name" class="block text-sm font-medium text-gray-700">First Name</label>
|
<label
|
||||||
<input type="text" name="first_name" id="first_name" required
|
for="first_name"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
class="block text-sm font-medium text-gray-700"
|
||||||
</div>
|
>First Name</label
|
||||||
<div>
|
>
|
||||||
<label for="last_name" class="block text-sm font-medium text-gray-700">Last Name</label>
|
<input
|
||||||
<input type="text" name="last_name" id="last_name" required
|
type="text"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
name="first_name"
|
||||||
</div>
|
id="first_name"
|
||||||
<div>
|
required
|
||||||
<label for="age" class="block text-sm font-medium text-gray-700">Age</label>
|
|
||||||
<input type="number" name="age" id="age" required min="1" max="120"
|
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="height" class="block text-sm font-medium text-gray-700">Height (e.g., 5'4" or 165cm)</label>
|
|
||||||
<input type="text" name="height" id="height" required
|
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
placeholder="5'4"">
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="weight" class="block text-sm font-medium text-gray-700">Weight (e.g., 123lbs or 56kg)</label>
|
<label
|
||||||
<input type="text" name="weight" id="weight" required
|
for="last_name"
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Last Name</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="last_name"
|
||||||
|
id="last_name"
|
||||||
|
required
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
placeholder="123lbs">
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="gender" class="block text-sm font-medium text-gray-700">Gender</label>
|
<label
|
||||||
<select name="gender" id="gender" required
|
for="age"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Age</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
name="age"
|
||||||
|
id="age"
|
||||||
|
required
|
||||||
|
min="1"
|
||||||
|
max="120"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="height"
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Height (e.g., 5'4" or 165cm)</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="height"
|
||||||
|
id="height"
|
||||||
|
required
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
placeholder="5'4""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="weight"
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Weight (e.g., 123lbs or 56kg)</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="weight"
|
||||||
|
id="weight"
|
||||||
|
required
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
placeholder="123lbs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
for="gender"
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Gender</label
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
name="gender"
|
||||||
|
id="gender"
|
||||||
|
required
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
>
|
||||||
<option value="">Select...</option>
|
<option value="">Select...</option>
|
||||||
<option value="male">Male</option>
|
<option value="male">Male</option>
|
||||||
<option value="female">Female</option>
|
<option value="female">Female</option>
|
||||||
@@ -57,51 +119,249 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="focus" class="block text-sm font-medium text-gray-700">Training Focus</label>
|
<label
|
||||||
<input type="text" name="focus" id="focus" value="Endurance"
|
for="focus"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Training Focus</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="focus"
|
||||||
|
id="focus"
|
||||||
|
value="Endurance"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="session_id" class="block text-sm font-medium text-gray-700">Session ID</label>
|
<label
|
||||||
<input type="text" name="session_id" id="session_id" value="default"
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border">
|
>Report Type</label
|
||||||
|
>
|
||||||
|
<div class="mt-1 space-y-2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="report_type"
|
||||||
|
id="report_type_full"
|
||||||
|
value="full"
|
||||||
|
checked
|
||||||
|
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="report_type_full"
|
||||||
|
class="ml-2 block text-sm text-gray-700"
|
||||||
|
>
|
||||||
|
Full Report
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="report_type"
|
||||||
|
id="report_type_minimal"
|
||||||
|
value="minimal"
|
||||||
|
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="report_type_minimal"
|
||||||
|
class="ml-2 block text-sm text-gray-700"
|
||||||
|
>
|
||||||
|
Minimal Report
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Recommended Next Testing Date</label
|
||||||
|
>
|
||||||
|
<div class="mt-1 grid grid-cols-2 gap-3">
|
||||||
|
<select
|
||||||
|
id="next_testing_month"
|
||||||
|
required
|
||||||
|
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
>
|
||||||
|
<option value="">Month</option>
|
||||||
|
<option value="January">January</option>
|
||||||
|
<option value="February">February</option>
|
||||||
|
<option value="March">March</option>
|
||||||
|
<option value="April">April</option>
|
||||||
|
<option value="May">May</option>
|
||||||
|
<option value="June">June</option>
|
||||||
|
<option value="July">July</option>
|
||||||
|
<option value="August">August</option>
|
||||||
|
<option value="September">September</option>
|
||||||
|
<option value="October">October</option>
|
||||||
|
<option value="November">November</option>
|
||||||
|
<option value="December">December</option>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
id="next_testing_year"
|
||||||
|
required
|
||||||
|
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
|
>
|
||||||
|
<option value="">Year</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="next_testing_date"
|
||||||
|
id="next_testing_date"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// Populate year dropdown
|
||||||
|
(function () {
|
||||||
|
const yearSelect =
|
||||||
|
document.getElementById(
|
||||||
|
"next_testing_year"
|
||||||
|
);
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
for (
|
||||||
|
let i = currentYear;
|
||||||
|
i <= currentYear + 10;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
const option =
|
||||||
|
document.createElement("option");
|
||||||
|
option.value = i;
|
||||||
|
option.textContent = i;
|
||||||
|
yearSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine month and year into hidden input
|
||||||
|
const monthSelect =
|
||||||
|
document.getElementById(
|
||||||
|
"next_testing_month"
|
||||||
|
);
|
||||||
|
const dateInput =
|
||||||
|
document.getElementById(
|
||||||
|
"next_testing_date"
|
||||||
|
);
|
||||||
|
|
||||||
|
function updateDateInput() {
|
||||||
|
const month = monthSelect.value;
|
||||||
|
const year = yearSelect.value;
|
||||||
|
if (month && year) {
|
||||||
|
dateInput.value = month + " " + year;
|
||||||
|
} else {
|
||||||
|
dateInput.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
monthSelect.addEventListener(
|
||||||
|
"change",
|
||||||
|
updateDateInput
|
||||||
|
);
|
||||||
|
yearSelect.addEventListener(
|
||||||
|
"change",
|
||||||
|
updateDateInput
|
||||||
|
);
|
||||||
|
|
||||||
|
// Validate form submission
|
||||||
|
const form =
|
||||||
|
document.getElementById("upload-form");
|
||||||
|
form.addEventListener("submit", function (e) {
|
||||||
|
const month = monthSelect.value;
|
||||||
|
const year = yearSelect.value;
|
||||||
|
if (!month || !year) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert(
|
||||||
|
"Please select both month and year for the recommended next testing date."
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Ensure hidden input is set before submission
|
||||||
|
updateDateInput();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- File Upload Section -->
|
<!-- File Upload Section -->
|
||||||
<div class="border-b border-gray-200 pb-6">
|
<div class="border-b border-gray-200 pb-6">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Upload Files</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Upload Files
|
||||||
|
</h3>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label for="spirometry_pdf" class="block text-sm font-medium text-gray-700">Spirometry PDF</label>
|
<label
|
||||||
<input type="file" name="spirometry_pdf" id="spirometry_pdf" accept=".pdf" required
|
for="spirometry_pdf"
|
||||||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Spirometry PDF</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="spirometry_pdf"
|
||||||
|
id="spirometry_pdf"
|
||||||
|
accept=".pdf"
|
||||||
|
required
|
||||||
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="pnoe_csv" class="block text-sm font-medium text-gray-700">Pnoe CSV</label>
|
<label
|
||||||
<input type="file" name="pnoe_csv" id="pnoe_csv" accept=".csv" required
|
for="pnoe_csv"
|
||||||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Pnoe CSV</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="pnoe_csv"
|
||||||
|
id="pnoe_csv"
|
||||||
|
accept=".csv"
|
||||||
|
required
|
||||||
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="fat_percentage" class="block text-sm font-medium text-gray-700">Body Fat Percentage (%)</label>
|
<label
|
||||||
<input type="number" step="0.1" name="fat_percentage" id="fat_percentage" required min="0" max="100"
|
for="fat_percentage"
|
||||||
|
class="block text-sm font-medium text-gray-700"
|
||||||
|
>Body Fat Percentage (%)</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
step="0.1"
|
||||||
|
name="fat_percentage"
|
||||||
|
id="fat_percentage"
|
||||||
|
required
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-3 py-2 border"
|
||||||
placeholder="22.5">
|
placeholder="22.5"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="oxygenation_csv" class="block text-sm font-medium text-gray-700">Muscle Oxygenation CSV (Optional)</label>
|
<label
|
||||||
<input type="file" name="oxygenation_csv" id="oxygenation_csv" accept=".csv"
|
for="oxygenation_csv"
|
||||||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
|
class="block text-sm font-medium text-gray-700"
|
||||||
<p class="mt-1 text-xs text-gray-500">Upload NIRS muscle oxygen CSV file to generate TSI graph</p>
|
>Muscle Oxygenation CSV (Optional)</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
name="oxygenation_csv"
|
||||||
|
id="oxygenation_csv"
|
||||||
|
accept=".csv"
|
||||||
|
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100"
|
||||||
|
/>
|
||||||
|
<p class="mt-1 text-xs text-gray-500">
|
||||||
|
Upload NIRS muscle oxygen CSV file to generate
|
||||||
|
TSI graph
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button type="submit"
|
<button
|
||||||
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
type="submit"
|
||||||
|
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
Generate Report
|
Generate Report
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -110,4 +370,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
+22648
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+31
-28
@@ -2,7 +2,7 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 6,
|
"execution_count": 1,
|
||||||
"id": "b18c1027",
|
"id": "b18c1027",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 7,
|
"execution_count": 3,
|
||||||
"id": "56a9d655",
|
"id": "56a9d655",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -104,7 +104,10 @@
|
|||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"import pandas as pd\n",
|
"import pandas as pd\n",
|
||||||
"spirometry_df = pd.read_csv(\"data/spirometry_data.csv\")\n",
|
"import os\n",
|
||||||
|
"\n",
|
||||||
|
"base_dir = os.path.dirname(os.path.abspath('.'))\n",
|
||||||
|
"spirometry_df = pd.read_csv(f\"{base_dir}/data/spirometry_data.csv\")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"fvc_best = spirometry_df.loc[spirometry_df['Parameters'] == 'FVC', 'Best'].values[0]\n",
|
"fvc_best = spirometry_df.loc[spirometry_df['Parameters'] == 'FVC', 'Best'].values[0]\n",
|
||||||
"fvc_pred = spirometry_df.loc[spirometry_df['Parameters'] == 'FVC', '%Pred.'].values[0]\n",
|
"fvc_pred = spirometry_df.loc[spirometry_df['Parameters'] == 'FVC', '%Pred.'].values[0]\n",
|
||||||
@@ -122,7 +125,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 8,
|
"execution_count": 4,
|
||||||
"id": "990f4b4f",
|
"id": "990f4b4f",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -136,7 +139,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"df = pd.read_csv('data/Pnoe_20250729_1550-Moran_Keirstyn.csv', delimiter=';')\n",
|
"df = pd.read_csv(f'{base_dir}/data/Pnoe_20250729_1550-Moran_Keirstyn.csv', delimiter=';')\n",
|
||||||
"peak_vt = df['VT(l)'].max()\n",
|
"peak_vt = df['VT(l)'].max()\n",
|
||||||
"max_vt_row = df.loc[df['VT(l)'].idxmax()]\n",
|
"max_vt_row = df.loc[df['VT(l)'].idxmax()]\n",
|
||||||
"print(f\"Peak VT: {peak_vt}\")\n",
|
"print(f\"Peak VT: {peak_vt}\")\n",
|
||||||
@@ -146,7 +149,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 9,
|
"execution_count": 19,
|
||||||
"id": "041cbc3d",
|
"id": "041cbc3d",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -154,21 +157,21 @@
|
|||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Peak VT: 2.3770000000000002\n",
|
"Peak VT: 2.3844444444444446\n",
|
||||||
"HR at Peak VT: 171.525\n"
|
"HR at Peak VT: 172.80555555555554\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "stderr",
|
"name": "stderr",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"/tmp/ipykernel_69398/4157056299.py:3: FutureWarning: errors='ignore' is deprecated and will raise in a future version. Use to_numeric without passing `errors` and catch exceptions explicitly instead\n",
|
"/tmp/ipykernel_53922/361246798.py:3: FutureWarning: errors='ignore' is deprecated and will raise in a future version. Use to_numeric without passing `errors` and catch exceptions explicitly instead\n",
|
||||||
" df = df.apply(pd.to_numeric, errors='ignore')\n"
|
" df = df.apply(pd.to_numeric, errors='ignore')\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"df = pd.read_csv('data/Pnoe_20250729_1550-Moran_Keirstyn.csv', delimiter=';')\n",
|
"df = pd.read_csv(f'{base_dir}/data/Pnoe_20250729_1550-Moran_Keirstyn.csv', delimiter=';')\n",
|
||||||
"# Convert all columns to numeric where possible, coercing errors to NaN\n",
|
"# Convert all columns to numeric where possible, coercing errors to NaN\n",
|
||||||
"df = df.apply(pd.to_numeric, errors='ignore')\n",
|
"df = df.apply(pd.to_numeric, errors='ignore')\n",
|
||||||
"df['VO2 Pulse'] = df['VO2(ml/min)'] / df['HR(bpm)'] # VO2 Pulse in mL/beat\n",
|
"df['VO2 Pulse'] = df['VO2(ml/min)'] / df['HR(bpm)'] # VO2 Pulse in mL/beat\n",
|
||||||
@@ -176,7 +179,7 @@
|
|||||||
"df['CHO'] = df['EE(kcal/min)'] * df['CARBS(%)']/100\n",
|
"df['CHO'] = df['EE(kcal/min)'] * df['CARBS(%)']/100\n",
|
||||||
"df['FAT'] = df['EE(kcal/min)'] * df['FAT(%)']/100\n",
|
"df['FAT'] = df['EE(kcal/min)'] * df['FAT(%)']/100\n",
|
||||||
"# Smooth key columns using rolling window\n",
|
"# Smooth key columns using rolling window\n",
|
||||||
"window_size = 10\n",
|
"window_size = 9\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# List of columns to smooth\n",
|
"# List of columns to smooth\n",
|
||||||
"columns_to_smooth = ['VO2(ml/min)', 'VCO2(ml/min)', 'HR(bpm)', 'VT(l)', 'BF(bpm)', 'VE(l/min)', 'VO2 Pulse', 'VO2 Breath', 'CHO', 'FAT']\n",
|
"columns_to_smooth = ['VO2(ml/min)', 'VCO2(ml/min)', 'HR(bpm)', 'VT(l)', 'BF(bpm)', 'VE(l/min)', 'VO2 Pulse', 'VO2 Breath', 'CHO', 'FAT']\n",
|
||||||
@@ -195,7 +198,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 10,
|
"execution_count": 20,
|
||||||
"id": "de7cadd1",
|
"id": "de7cadd1",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -203,7 +206,7 @@
|
|||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"Percent FEV: 72.91411042944786\n"
|
"Percent FEV: 73.14246762099523\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -214,7 +217,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 11,
|
"execution_count": 21,
|
||||||
"id": "cb972ed3",
|
"id": "cb972ed3",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -311,13 +314,13 @@
|
|||||||
"[1 rows x 147 columns]"
|
"[1 rows x 147 columns]"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"execution_count": 11,
|
"execution_count": 21,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"output_type": "execute_result"
|
"output_type": "execute_result"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"personal_df = pd.read_excel('data/SECA body comp for all patients.xlsx')\n",
|
"personal_df = pd.read_excel(f'{base_dir}/data/SECA body comp for all patients.xlsx')\n",
|
||||||
"\n",
|
"\n",
|
||||||
"keirstyn_data = personal_df[personal_df['LastName'].str.contains('Moran', case=False, na=False)]\n",
|
"keirstyn_data = personal_df[personal_df['LastName'].str.contains('Moran', case=False, na=False)]\n",
|
||||||
"keirstyn_data"
|
"keirstyn_data"
|
||||||
@@ -325,7 +328,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 12,
|
"execution_count": 22,
|
||||||
"id": "98d9295a",
|
"id": "98d9295a",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -333,7 +336,7 @@
|
|||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"VO2 Max: 47.906290322580645\n"
|
"VO2 Max: 48.19062126642772\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -345,7 +348,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 13,
|
"execution_count": null,
|
||||||
"id": "cdfeb309",
|
"id": "cdfeb309",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -398,7 +401,7 @@
|
|||||||
"optimal_fat_idx = df['fat_carb_ratio'].idxmax()\n",
|
"optimal_fat_idx = df['fat_carb_ratio'].idxmax()\n",
|
||||||
"optimal_row = df.loc[optimal_fat_idx]\n",
|
"optimal_row = df.loc[optimal_fat_idx]\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(f\"Optimal Fat Burning Zone (highest fat:carb ratio):\")\n",
|
"print(\"Optimal Fat Burning Zone (highest fat:carb ratio):\")\n",
|
||||||
"print(f\"Time: {optimal_row['T(sec)']} seconds\")\n",
|
"print(f\"Time: {optimal_row['T(sec)']} seconds\")\n",
|
||||||
"print(f\"Fat burn rate: {optimal_row['FAT_smoothed']:.3f} kcal/min\")\n",
|
"print(f\"Fat burn rate: {optimal_row['FAT_smoothed']:.3f} kcal/min\")\n",
|
||||||
"print(f\"Carb burn rate: {optimal_row['CHO_smoothed']:.3f} kcal/min\")\n",
|
"print(f\"Carb burn rate: {optimal_row['CHO_smoothed']:.3f} kcal/min\")\n",
|
||||||
@@ -409,7 +412,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 14,
|
"execution_count": null,
|
||||||
"id": "4420cfea",
|
"id": "4420cfea",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -467,7 +470,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 21,
|
"execution_count": null,
|
||||||
"id": "62803668",
|
"id": "62803668",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -552,7 +555,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 16,
|
"execution_count": null,
|
||||||
"id": "07593b56",
|
"id": "07593b56",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -590,7 +593,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 17,
|
"execution_count": null,
|
||||||
"id": "c90415b2",
|
"id": "c90415b2",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -653,7 +656,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 18,
|
"execution_count": null,
|
||||||
"id": "c3b2cc59",
|
"id": "c3b2cc59",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -742,7 +745,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 19,
|
"execution_count": null,
|
||||||
"id": "672d68f3",
|
"id": "672d68f3",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@@ -823,7 +826,7 @@
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "report_generation",
|
"display_name": ".venv",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
"name": "python3"
|
"name": "python3"
|
||||||
},
|
},
|
||||||
@@ -837,7 +840,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.3"
|
"version": "3.12.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
@@ -0,0 +1,249 @@
|
|||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
|
def mifflin_st_jeor(weight_kg, height_cm, age_years, sex):
|
||||||
|
"""
|
||||||
|
Compute predicted RMR with Mifflin St Jeor.
|
||||||
|
sex: 'male' or 'female'
|
||||||
|
"""
|
||||||
|
base = 10.0 * weight_kg + 6.25 * height_cm - 5.0 * age_years
|
||||||
|
if sex.lower().startswith("m"):
|
||||||
|
return base + 5.0
|
||||||
|
else:
|
||||||
|
return base - 161.0
|
||||||
|
|
||||||
|
|
||||||
|
def classify_metabolism(measured_kcal_day, predicted_kcal_day):
|
||||||
|
"""
|
||||||
|
Classify metabolic rate relative to prediction.
|
||||||
|
Returns (label, ratio).
|
||||||
|
"""
|
||||||
|
ratio = measured_kcal_day / predicted_kcal_day
|
||||||
|
|
||||||
|
if ratio < 0.70:
|
||||||
|
label = "very slow"
|
||||||
|
elif ratio < 0.90:
|
||||||
|
label = "slow"
|
||||||
|
elif ratio <= 1.10:
|
||||||
|
label = "average"
|
||||||
|
elif ratio <= 1.30:
|
||||||
|
label = "fast"
|
||||||
|
else:
|
||||||
|
label = "very fast"
|
||||||
|
|
||||||
|
return label, ratio
|
||||||
|
|
||||||
|
|
||||||
|
def find_sampling_window(df):
|
||||||
|
"""
|
||||||
|
Derive number of samples that represent about 2 minutes.
|
||||||
|
"""
|
||||||
|
dt = df["T(sec)"].diff().median()
|
||||||
|
if dt is None or dt <= 0:
|
||||||
|
raise ValueError("Invalid time step in T(sec)")
|
||||||
|
|
||||||
|
samples = int(round(120.0 / dt))
|
||||||
|
if samples < 1:
|
||||||
|
samples = 1
|
||||||
|
return samples
|
||||||
|
|
||||||
|
|
||||||
|
def rolling_stable_window(df, window_samples):
|
||||||
|
"""
|
||||||
|
Find the most stable 2-minute window using rolling standard deviation.
|
||||||
|
Returns:
|
||||||
|
means_series, t_start, t_end
|
||||||
|
"""
|
||||||
|
cols_mean = [
|
||||||
|
"VO2(ml/min)",
|
||||||
|
"VCO2(ml/min)",
|
||||||
|
"VE(l/min)",
|
||||||
|
"VT(l)",
|
||||||
|
"BF(bpm)",
|
||||||
|
"EE(kcal/min)",
|
||||||
|
"RER",
|
||||||
|
"CARBS(%)",
|
||||||
|
"FAT(%)",
|
||||||
|
]
|
||||||
|
|
||||||
|
cols_std = [
|
||||||
|
"VO2(ml/min)",
|
||||||
|
"VCO2(ml/min)",
|
||||||
|
"VE(l/min)",
|
||||||
|
"VT(l)",
|
||||||
|
"BF(bpm)",
|
||||||
|
]
|
||||||
|
|
||||||
|
roll_mean = df[cols_mean].rolling(window_samples, min_periods=window_samples).mean()
|
||||||
|
roll_std = df[cols_std].rolling(window_samples, min_periods=window_samples).std()
|
||||||
|
|
||||||
|
# Sum std devs to get stability score; use skipna=False to preserve NaN for incomplete windows
|
||||||
|
stability_score = roll_std.sum(axis=1, skipna=False)
|
||||||
|
|
||||||
|
# Find index with lowest stability score (dropna to ignore incomplete windows)
|
||||||
|
best_idx = stability_score.dropna().idxmin()
|
||||||
|
|
||||||
|
means_series = roll_mean.loc[best_idx].copy()
|
||||||
|
|
||||||
|
start_idx = max(best_idx - window_samples + 1, 0)
|
||||||
|
end_idx = best_idx
|
||||||
|
|
||||||
|
t_start = float(df["T(sec)"].iloc[start_idx])
|
||||||
|
t_end = float(df["T(sec)"].iloc[end_idx])
|
||||||
|
|
||||||
|
return means_series, t_start, t_end
|
||||||
|
|
||||||
|
|
||||||
|
def manual_window_means(df, t_start, t_end):
|
||||||
|
"""
|
||||||
|
Compute mean values inside a user-selected time window.
|
||||||
|
"""
|
||||||
|
mask = (df["T(sec)"] >= t_start) & (df["T(sec)"] <= t_end)
|
||||||
|
slice_df = df.loc[mask].copy()
|
||||||
|
|
||||||
|
if slice_df.empty:
|
||||||
|
raise ValueError("Manual window has no rows inside T(sec) range")
|
||||||
|
|
||||||
|
cols = [
|
||||||
|
"VO2(ml/min)",
|
||||||
|
"VCO2(ml/min)",
|
||||||
|
"VE(l/min)",
|
||||||
|
"VT(l)",
|
||||||
|
"BF(bpm)",
|
||||||
|
"EE(kcal/min)",
|
||||||
|
"RER",
|
||||||
|
"CARBS(%)",
|
||||||
|
"FAT(%)",
|
||||||
|
]
|
||||||
|
|
||||||
|
means = slice_df[cols].mean()
|
||||||
|
return means, float(t_start), float(t_end)
|
||||||
|
|
||||||
|
|
||||||
|
def load_pnoe_csv(path):
|
||||||
|
"""
|
||||||
|
Load and clean a PNOE CSV file.
|
||||||
|
"""
|
||||||
|
df = pd.read_csv(path, sep=";")
|
||||||
|
|
||||||
|
numeric_cols = [
|
||||||
|
"T(sec)",
|
||||||
|
"VO2(ml/min)",
|
||||||
|
"VCO2(ml/min)",
|
||||||
|
"RER",
|
||||||
|
"VE(l/min)",
|
||||||
|
"VT(l)",
|
||||||
|
"BF(bpm)",
|
||||||
|
"EE(kcal/min)",
|
||||||
|
"CARBS(%)",
|
||||||
|
"FAT(%)",
|
||||||
|
]
|
||||||
|
|
||||||
|
for col in numeric_cols:
|
||||||
|
df[col] = pd.to_numeric(df[col], errors="coerce")
|
||||||
|
|
||||||
|
df = df.dropna(subset=["VO2(ml/min)", "EE(kcal/min)"]).reset_index(drop=True)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_pnoe_rmr(
|
||||||
|
path,
|
||||||
|
weight_kg,
|
||||||
|
height_cm,
|
||||||
|
age_years,
|
||||||
|
sex,
|
||||||
|
subject_name=None,
|
||||||
|
test_date=None,
|
||||||
|
manual_window=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Analyze resting RMR from a PNOE CSV file.
|
||||||
|
|
||||||
|
manual_window:
|
||||||
|
None for automatic stable window
|
||||||
|
or (t_start_sec, t_end_sec) for user-chosen window
|
||||||
|
"""
|
||||||
|
df = load_pnoe_csv(path)
|
||||||
|
window_samples = find_sampling_window(df)
|
||||||
|
|
||||||
|
# Automatic stable window
|
||||||
|
auto_means, auto_t_start, auto_t_end = rolling_stable_window(df, window_samples)
|
||||||
|
|
||||||
|
# Manual override if provided
|
||||||
|
manual_means = None
|
||||||
|
manual_t_start = None
|
||||||
|
manual_t_end = None
|
||||||
|
|
||||||
|
if manual_window is not None:
|
||||||
|
t_start_manual, t_end_manual = manual_window
|
||||||
|
manual_means, manual_t_start, manual_t_end = manual_window_means(
|
||||||
|
df, t_start_manual, t_end_manual
|
||||||
|
)
|
||||||
|
chosen_source = "manual"
|
||||||
|
chosen_means = manual_means
|
||||||
|
chosen_t_start = manual_t_start
|
||||||
|
chosen_t_end = manual_t_end
|
||||||
|
else:
|
||||||
|
chosen_source = "auto"
|
||||||
|
chosen_means = auto_means
|
||||||
|
chosen_t_start = auto_t_start
|
||||||
|
chosen_t_end = auto_t_end
|
||||||
|
|
||||||
|
kcal_per_min = float(chosen_means["EE(kcal/min)"])
|
||||||
|
rmr_kcal_day = kcal_per_min * 1440.0
|
||||||
|
|
||||||
|
predicted_kcal_day = mifflin_st_jeor(weight_kg, height_cm, age_years, sex)
|
||||||
|
label, ratio = classify_metabolism(rmr_kcal_day, predicted_kcal_day)
|
||||||
|
|
||||||
|
def pack_metrics(prefix, means, t_start, t_end):
|
||||||
|
if means is None:
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
f"{prefix}_window_start_sec": t_start,
|
||||||
|
f"{prefix}_window_end_sec": t_end,
|
||||||
|
f"{prefix}_VO2_L_min": float(means["VO2(ml/min)"]) / 1000.0,
|
||||||
|
f"{prefix}_VCO2_L_min": float(means["VCO2(ml/min)"]) / 1000.0,
|
||||||
|
f"{prefix}_VE_L_min": float(means["VE(l/min)"]),
|
||||||
|
f"{prefix}_VT_L": float(means["VT(l)"]),
|
||||||
|
f"{prefix}_BF_bpm": float(means["BF(bpm)"]),
|
||||||
|
f"{prefix}_RER": float(means["RER"]),
|
||||||
|
f"{prefix}_Fat_percent": float(means["FAT(%)"]),
|
||||||
|
f"{prefix}_Carb_percent": float(means["CARBS(%)"]),
|
||||||
|
f"{prefix}_kcal_per_min": float(means["EE(kcal/min)"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"subject_name": subject_name,
|
||||||
|
"test_date": test_date,
|
||||||
|
"sex": sex,
|
||||||
|
"weight_kg": weight_kg,
|
||||||
|
"height_cm": height_cm,
|
||||||
|
"age_years": age_years,
|
||||||
|
"chosen_window_source": chosen_source,
|
||||||
|
"chosen_window_start_sec": chosen_t_start,
|
||||||
|
"chosen_window_end_sec": chosen_t_end,
|
||||||
|
"RMR_kcal_day": rmr_kcal_day,
|
||||||
|
"Mifflin_kcal_day": predicted_kcal_day,
|
||||||
|
"Measured_to_Mifflin_ratio": ratio,
|
||||||
|
"Metabolic_classification": label,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.update(pack_metrics("auto", auto_means, auto_t_start, auto_t_end))
|
||||||
|
result.update(pack_metrics("manual", manual_means, manual_t_start, manual_t_end))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
result = analyze_pnoe_rmr(
|
||||||
|
path="/home/oluwasanmi/Documents/Work/MKD/report_generation/data/Pnoe_20250729_1550-Moran_Keirstyn.csv",
|
||||||
|
weight_kg=56,
|
||||||
|
height_cm=162,
|
||||||
|
age_years=34,
|
||||||
|
sex="female",
|
||||||
|
subject_name="Cullen Pacas",
|
||||||
|
test_date="2025-11-12",
|
||||||
|
manual_window=None, # or (t_start_sec, t_end_sec)
|
||||||
|
)
|
||||||
|
|
||||||
|
for key, value in result.items():
|
||||||
|
print(f"{key}: {value}")
|
||||||
+2476
-125
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
|
|||||||
|
Metric,Value
|
||||||
|
Left Baseline SmO2 (%),75.37
|
||||||
|
Right Baseline SmO2 (%),82.91
|
||||||
|
Left Minimum SmO2 (%),69.34
|
||||||
|
Right Minimum SmO2 (%),73.65
|
||||||
|
Left Maximum SmO2 (%),78.24
|
||||||
|
Right Maximum SmO2 (%),82.59
|
||||||
|
Left Recovery SmO2 (%),82.47
|
||||||
|
Right Recovery SmO2 (%),80.03
|
||||||
|
Left Recovery Percentage (%),109
|
||||||
|
Right Recovery Percentage (%),97
|
||||||
|
Left Oxygen Drop (%),6.03
|
||||||
|
Right Oxygen Drop (%),9.26
|
||||||
|
Warmup HR (bpm),93.2
|
||||||
|
Maximum HR (bpm),168.2
|
||||||
|
Recovery HR (bpm),107.7
|
||||||
|
Test Duration (seconds),1287
|
||||||
|
Recovery Duration (seconds),159
|
||||||
|
@@ -0,0 +1,192 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# --- CONFIGURATION TABLES (From your PDFs) ---
|
||||||
|
|
||||||
|
# From deficit.pdf
|
||||||
|
ACTIVITY_MULTIPLIERS = {
|
||||||
|
"Sedentary": 1.2, "Light": 1.375, "Moderate": 1.55, "Active": 1.7, "Extreme": 1.9
|
||||||
|
}
|
||||||
|
|
||||||
|
# From deficit.pdf (Weight Loss kg -> Calorie Deficit)
|
||||||
|
DEFICIT_TABLE = {
|
||||||
|
0.1: 85, 0.2: 169, 0.3: 254, 0.4: 339, 0.5: 423,
|
||||||
|
0.6: 508, 0.7: 593, 0.8: 677, 0.9: 762, 1.0: 847,
|
||||||
|
1.1: 931, 1.2: 1016
|
||||||
|
}
|
||||||
|
|
||||||
|
# From no_deficit.pdf (Protein Multipliers g/kg of Lean Body Mass)
|
||||||
|
PROTEIN_GUIDELINES = {
|
||||||
|
(0, 30): {'maintenance': 1.9, 'deficit': 2.3},
|
||||||
|
(30, 40): {'maintenance': 2.15, 'deficit': 2.6},
|
||||||
|
(40, 50): {'maintenance': 2.45, 'deficit': 2.95},
|
||||||
|
(50, 60): {'maintenance': 2.75, 'deficit': 3.3},
|
||||||
|
(60, 100): {'maintenance': 3.05, 'deficit': 3.65}
|
||||||
|
}
|
||||||
|
|
||||||
|
def analyze_pnoe_data(csv_path):
|
||||||
|
"""
|
||||||
|
Parses PNOE CSV. FIX: Uses MEDIAN instead of MEAN to avoid outliers.
|
||||||
|
"""
|
||||||
|
df = pd.read_csv(csv_path, delimiter=';')
|
||||||
|
df.columns = df.columns.str.strip()
|
||||||
|
|
||||||
|
# Filter for RMR window (assumed T=60s to T=300s, 4 minutes of stable rest)
|
||||||
|
df_stable = df[(df['T(sec)'] >= 60) & (df['T(sec)'] <= 300)].copy()
|
||||||
|
|
||||||
|
# Ensure data columns are numeric
|
||||||
|
for col in ['EE(kcal/day)', 'RER', 'T(sec)']:
|
||||||
|
df_stable.loc[:, col] = pd.to_numeric(df_stable[col], errors='coerce')
|
||||||
|
|
||||||
|
df_stable.dropna(subset=['EE(kcal/day)', 'RER'], inplace=True)
|
||||||
|
|
||||||
|
if not df_stable.empty:
|
||||||
|
# **CRITICAL CHANGE: Use Median instead of Mean**
|
||||||
|
rmr_measured = df_stable['EE(kcal/day)'].median()
|
||||||
|
rer = df_stable['RER'].median()
|
||||||
|
else:
|
||||||
|
# Fallback if window is empty
|
||||||
|
rmr_measured = 1386.0
|
||||||
|
rer = 0.85
|
||||||
|
|
||||||
|
# Calculate Fuel Source
|
||||||
|
clamped_rer = max(0.7, min(1.0, rer))
|
||||||
|
percent_carbs = (clamped_rer - 0.7) / 0.3
|
||||||
|
percent_fat = 1.0 - percent_carbs
|
||||||
|
|
||||||
|
return {
|
||||||
|
"measured_rmr": int(round(rmr_measured)),
|
||||||
|
"rer": round(rer, 2),
|
||||||
|
"fuel_source": {
|
||||||
|
"fat_percent": round(percent_fat * 100, 1),
|
||||||
|
"carb_percent": round(percent_carbs * 100, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def assess_metabolic_health(measured_rmr, weight_kg, height_cm, age, sex):
|
||||||
|
"""
|
||||||
|
Calculates Predicted RMR (Mifflin-St Jeor) and compares to Measured RMR.
|
||||||
|
"""
|
||||||
|
# Mifflin-St Jeor Formula
|
||||||
|
if sex.lower() == 'male':
|
||||||
|
predicted_rmr = (10 * weight_kg) + (6.25 * height_cm) - (5 * age) + 5
|
||||||
|
else:
|
||||||
|
predicted_rmr = (10 * weight_kg) + (6.25 * height_cm) - (5 * age) - 161
|
||||||
|
|
||||||
|
variance = ((measured_rmr - predicted_rmr) / predicted_rmr) * 100
|
||||||
|
|
||||||
|
# Interpretation
|
||||||
|
if variance > 10:
|
||||||
|
metabolism_type = "Fast"
|
||||||
|
elif variance < -10:
|
||||||
|
metabolism_type = "Slow"
|
||||||
|
else:
|
||||||
|
metabolism_type = "Normal"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"predicted_rmr_mifflin": int(round(predicted_rmr)),
|
||||||
|
"variance_percent": round(variance, 1),
|
||||||
|
"metabolism_type": metabolism_type
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_nutrition_plan(measured_rmr, weight_kg, body_fat_percent, age, activity_level, weekly_weight_loss_goal_kg):
|
||||||
|
"""
|
||||||
|
Calculates TDEE, applies Deficit, and calculates Macros based on uploaded PDFs.
|
||||||
|
"""
|
||||||
|
# 1. TDEE (Maintenance Calories)
|
||||||
|
multiplier = ACTIVITY_MULTIPLIERS.get(activity_level, 1.2)
|
||||||
|
maintenance_calories = measured_rmr * multiplier
|
||||||
|
|
||||||
|
# 2. Daily Calorie Target
|
||||||
|
daily_deficit = DEFICIT_TABLE.get(weekly_weight_loss_goal_kg, 0)
|
||||||
|
target_calories = maintenance_calories - daily_deficit
|
||||||
|
is_deficit = daily_deficit > 0
|
||||||
|
|
||||||
|
# 3. Protein Needs (Based on Lean Body Mass and age/deficit status)
|
||||||
|
lean_mass_kg = weight_kg * (1 - (body_fat_percent / 100))
|
||||||
|
|
||||||
|
protein_multiplier = 1.8 # default fallback
|
||||||
|
for (min_age, max_age), values in PROTEIN_GUIDELINES.items():
|
||||||
|
if min_age <= age < max_age:
|
||||||
|
protein_multiplier = values['deficit'] if is_deficit else values['maintenance']
|
||||||
|
break
|
||||||
|
|
||||||
|
daily_protein_grams = lean_mass_kg * protein_multiplier
|
||||||
|
protein_calories = daily_protein_grams * 4
|
||||||
|
|
||||||
|
# 4. Remaining Macros (Fats and Carbs)
|
||||||
|
FAT_PERCENT_OF_TOTAL_CALORIES = 0.28 # Standard 25-30% fat allocation
|
||||||
|
|
||||||
|
fat_calories = target_calories * FAT_PERCENT_OF_TOTAL_CALORIES
|
||||||
|
fat_grams = fat_calories / 9
|
||||||
|
|
||||||
|
carb_calories = target_calories - protein_calories - fat_calories
|
||||||
|
carb_grams = carb_calories / 4
|
||||||
|
|
||||||
|
if carb_calories < 0:
|
||||||
|
carb_calories = 0
|
||||||
|
carb_grams = 0
|
||||||
|
|
||||||
|
return {
|
||||||
|
"tdee_maintenance": int(round(maintenance_calories)),
|
||||||
|
"daily_deficit": daily_deficit,
|
||||||
|
"target_calories": int(round(target_calories)),
|
||||||
|
"macros": {
|
||||||
|
"protein_g": int(round(daily_protein_grams)),
|
||||||
|
"fats_g": int(round(fat_grams)),
|
||||||
|
"carbs_g": int(round(carb_grams))
|
||||||
|
},
|
||||||
|
"caloric_breakdown": {
|
||||||
|
"protein_kcal": int(round(protein_calories)),
|
||||||
|
"fats_kcal": int(round(fat_calories)),
|
||||||
|
"carbs_kcal": int(round(carb_calories))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- EXECUTION EXAMPLE ---
|
||||||
|
|
||||||
|
# 1. Run Analysis on the CSV
|
||||||
|
# Replace with your actual file path
|
||||||
|
csv_result = analyze_pnoe_data('/home/oluwasanmi/Documents/Work/MKD/report_generation/data/Pnoe_20250729_1550-Moran_Keirstyn.csv')
|
||||||
|
|
||||||
|
# 2. Inputs for the Calculation (These would come from your UI/Form)
|
||||||
|
user_weight = 85.0 # kg
|
||||||
|
user_height = 180.0 # cm
|
||||||
|
user_age = 35
|
||||||
|
user_sex = 'male'
|
||||||
|
user_body_fat = 20.0 # %
|
||||||
|
user_activity = 'Moderate' # From the PDF list
|
||||||
|
user_goal_loss = 0.5 # kg per week
|
||||||
|
|
||||||
|
# 3. Assess Health
|
||||||
|
health_assessment = assess_metabolic_health(
|
||||||
|
measured_rmr=csv_result['measured_rmr'],
|
||||||
|
weight_kg=user_weight,
|
||||||
|
height_cm=user_height,
|
||||||
|
age=user_age,
|
||||||
|
sex=user_sex
|
||||||
|
)
|
||||||
|
|
||||||
|
# 4. Get Nutrition Plan
|
||||||
|
nutrition_plan = generate_nutrition_plan(
|
||||||
|
measured_rmr=csv_result['measured_rmr'],
|
||||||
|
weight_kg=user_weight,
|
||||||
|
body_fat_percent=user_body_fat,
|
||||||
|
age=user_age,
|
||||||
|
activity_level=user_activity,
|
||||||
|
weekly_weight_loss_goal_kg=user_goal_loss
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- OUTPUT ---
|
||||||
|
print("--- METABOLIC REPORT ---")
|
||||||
|
print(f"Measured RMR: {csv_result['measured_rmr']} kcal/day")
|
||||||
|
print(f"Predicted RMR: {health_assessment['predicted_rmr_mifflin']} kcal/day")
|
||||||
|
print(f"Metabolism Status: {health_assessment['metabolism_type']} ({health_assessment['variance_percent']}%)")
|
||||||
|
print(f"Fuel Source: {csv_result['fuel_source']['fat_percent']}% Fat, {csv_result['fuel_source']['carb_percent']}% Carbs")
|
||||||
|
print("\n--- NUTRITION PLAN ---")
|
||||||
|
print(f"Goal: Lose {user_goal_loss} kg/week")
|
||||||
|
print(f"Daily Calorie Target: {nutrition_plan['target_calories']} kcal (Deficit: {nutrition_plan['daily_deficit']})")
|
||||||
|
print("\nDaily Macros:")
|
||||||
|
print(f"Protein: {nutrition_plan['macros']['protein_g']}g")
|
||||||
|
print(f"Fats: {nutrition_plan['macros']['fats_g']}g")
|
||||||
|
print(f"Carbs: {nutrition_plan['macros']['carbs_g']}g")
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
"""
|
||||||
|
Test script for Page 6 - Meal Plan Calculations
|
||||||
|
Using Keirstyn Moran's actual data
|
||||||
|
|
||||||
|
Expected values from PDF (Page 6):
|
||||||
|
Row 1 (Caloric Deficit - 7 days same):
|
||||||
|
- Calories: 1725 kCals
|
||||||
|
- Protein: 120g (28%)
|
||||||
|
- Carbs: 155g (36%)
|
||||||
|
- Fat: 69g (36%)
|
||||||
|
- Fiber: 25g
|
||||||
|
|
||||||
|
Row 2 (Caloric Deficit with Refeed - 5 weekdays low, 2 weekend high):
|
||||||
|
Weekdays (5 days):
|
||||||
|
- Calories: 1615 kCals
|
||||||
|
- Protein: 120g
|
||||||
|
- Carbs: 142g
|
||||||
|
- Fat: 63g
|
||||||
|
- Fiber: 24g
|
||||||
|
|
||||||
|
Weekends (2 days):
|
||||||
|
- Calories: 2000 kCals
|
||||||
|
- Protein: 120g
|
||||||
|
- Carbs: 190g
|
||||||
|
- Fat: 84g
|
||||||
|
- Fiber: 30g
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, '/Users/macbook/bio-performx')
|
||||||
|
|
||||||
|
from app.services.context_generator import ContextGenerator
|
||||||
|
|
||||||
|
# Keirstyn Moran's patient data from PDF
|
||||||
|
PATIENT_DATA = {
|
||||||
|
"name": "Keirstyn Moran",
|
||||||
|
"first_name": "Keirstyn",
|
||||||
|
"last_name": "Moran",
|
||||||
|
"age": 34,
|
||||||
|
"height": "5'4\"", # 162.56 cm
|
||||||
|
"weight": 55.79, # 123 lbs = 55.79 kg
|
||||||
|
"gender": "female",
|
||||||
|
"fat_percentage": 20.0, # Estimated
|
||||||
|
"activity_level": "moderate",
|
||||||
|
}
|
||||||
|
|
||||||
|
# RMR metrics from Page 5 (using expected PDF values)
|
||||||
|
RMR_METRICS_EXPECTED = {
|
||||||
|
"total_calories": 1725,
|
||||||
|
"resting_calories": 1386,
|
||||||
|
"neat_calories": 762,
|
||||||
|
"weight_loss_calories": 423,
|
||||||
|
}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("=" * 80)
|
||||||
|
print("PAGE 6 - MEAL PLAN CALCULATION TEST")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"\nPatient: {PATIENT_DATA['name']}")
|
||||||
|
print(f"Weight: {PATIENT_DATA['weight']}kg ({PATIENT_DATA['weight'] * 2.20462:.1f}lbs)")
|
||||||
|
print(f"Body Fat: {PATIENT_DATA['fat_percentage']}%")
|
||||||
|
|
||||||
|
# Create context generator
|
||||||
|
gen = ContextGenerator()
|
||||||
|
|
||||||
|
# Set patient info manually
|
||||||
|
gen.patient_info = PATIENT_DATA.copy()
|
||||||
|
|
||||||
|
# Calculate fat mass and lean mass
|
||||||
|
weight_kg = PATIENT_DATA["weight"]
|
||||||
|
fat_pct = PATIENT_DATA["fat_percentage"]
|
||||||
|
lean_mass_kg = weight_kg * (1 - fat_pct / 100)
|
||||||
|
lean_mass_lbs = lean_mass_kg * 2.20462
|
||||||
|
|
||||||
|
gen.patient_info["fat_mass_lbs"] = weight_kg * fat_pct / 100 * 2.20462
|
||||||
|
gen.patient_info["lean_mass_lbs"] = lean_mass_lbs
|
||||||
|
|
||||||
|
print(f"Lean Mass: {lean_mass_lbs:.2f} lbs ({lean_mass_kg:.2f} kg)")
|
||||||
|
print(f"Fat Mass: {gen.patient_info['fat_mass_lbs']:.2f} lbs")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("CALCULATING MEAL PLAN (using our formula)")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"\nTotal Daily Calories (from Page 5): {RMR_METRICS_EXPECTED['total_calories']} kcal")
|
||||||
|
|
||||||
|
# Calculate meal plan using our formula
|
||||||
|
try:
|
||||||
|
meal_metrics = gen.calculate_meal_plan_breakdown(RMR_METRICS_EXPECTED)
|
||||||
|
|
||||||
|
print("\n--- Protein Calculation (Bio-PerformX Formula) ---")
|
||||||
|
print(f"Formula: Total Body Weight (kg) × 2.15 g/kg")
|
||||||
|
print(f" = {weight_kg:.2f} × 2.15")
|
||||||
|
protein_grams = weight_kg * 2.15
|
||||||
|
print(f" = {protein_grams:.0f}g protein")
|
||||||
|
protein_calories = protein_grams * 4
|
||||||
|
print(f" = {protein_calories:.0f} kcal from protein")
|
||||||
|
|
||||||
|
print("\n--- Carbs and Fats (50/50 split of remaining calories) ---")
|
||||||
|
remaining = RMR_METRICS_EXPECTED['total_calories'] - protein_calories
|
||||||
|
print(f"Remaining calories: {RMR_METRICS_EXPECTED['total_calories']} - {protein_calories:.0f} = {remaining:.0f} kcal")
|
||||||
|
print(f"Carbs (50%): {remaining * 0.5:.0f} kcal ÷ 4 = {remaining * 0.5 / 4:.0f}g")
|
||||||
|
print(f"Fats (50%): {remaining * 0.5:.0f} kcal ÷ 9 = {remaining * 0.5 / 9:.0f}g")
|
||||||
|
|
||||||
|
print("\n--- Fiber Calculation ---")
|
||||||
|
print(f"Formula: 15g per 1000 calories")
|
||||||
|
print(f" = {RMR_METRICS_EXPECTED['total_calories']} ÷ 1000 × 15")
|
||||||
|
print(f" = {RMR_METRICS_EXPECTED['total_calories'] / 1000 * 15:.0f}g")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("ROW 1: CALORIC DEFICIT (7 days same)")
|
||||||
|
print("=" * 80)
|
||||||
|
print(f"Calories: {meal_metrics['deficit_calories']} kcal")
|
||||||
|
print(f"Protein: {meal_metrics['deficit_protein']}g ({meal_metrics['protein_percentage']}%)")
|
||||||
|
print(f"Carbs: {meal_metrics['deficit_carbs']}g ({meal_metrics['carbs_percentage']}%)")
|
||||||
|
print(f"Fat: {meal_metrics['deficit_fat']}g ({meal_metrics['fats_percentage']}%)")
|
||||||
|
print(f"Fiber: {meal_metrics['deficit_fiber']}g")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("ROW 2: CALORIC DEFICIT WITH REFEED (5 weekdays + 2 weekends)")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
print("\nWeekdays (5 days):")
|
||||||
|
print(f"Calories: {meal_metrics['refeed_weekday_calories']} kcal")
|
||||||
|
print(f"Protein: {meal_metrics['refeed_weekday_protein']}g")
|
||||||
|
print(f"Carbs: {meal_metrics['refeed_weekday_carbs']}g")
|
||||||
|
print(f"Fat: {meal_metrics['refeed_weekday_fat']}g")
|
||||||
|
print(f"Fiber: {meal_metrics['refeed_weekday_fiber']}g")
|
||||||
|
|
||||||
|
print("\nWeekends (2 days):")
|
||||||
|
print(f"Calories: {meal_metrics['refeed_weekend_calories']} kcal")
|
||||||
|
print(f"Protein: {meal_metrics['refeed_weekend_protein']}g")
|
||||||
|
print(f"Carbs: {meal_metrics['refeed_weekend_carbs']}g")
|
||||||
|
print(f"Fat: {meal_metrics['refeed_weekend_fat']}g")
|
||||||
|
print(f"Fiber: {meal_metrics['refeed_weekend_fiber']}g")
|
||||||
|
|
||||||
|
print("\n--- Weekly Total Verification ---")
|
||||||
|
weekly_total_row1 = meal_metrics['deficit_calories'] * 7
|
||||||
|
weekly_total_row2 = (meal_metrics['refeed_weekday_calories'] * 5) + (meal_metrics['refeed_weekend_calories'] * 2)
|
||||||
|
print(f"Row 1 Weekly Total: {meal_metrics['deficit_calories']} × 7 = {weekly_total_row1} kcal")
|
||||||
|
print(f"Row 2 Weekly Total: ({meal_metrics['refeed_weekday_calories']} × 5) + ({meal_metrics['refeed_weekend_calories']} × 2) = {weekly_total_row2} kcal")
|
||||||
|
print(f"Difference: {abs(weekly_total_row1 - weekly_total_row2)} kcal (should be ~0)")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("EXPECTED VALUES (From PDF Page 6)")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
print("\nRow 1 (Deficit - 7 days):")
|
||||||
|
print("Calories: 1725 kcal")
|
||||||
|
print("Protein: 120g (28%)")
|
||||||
|
print("Carbs: 155g (36%)")
|
||||||
|
print("Fat: 69g (36%)")
|
||||||
|
print("Fiber: 25g")
|
||||||
|
|
||||||
|
print("\nRow 2 Weekdays:")
|
||||||
|
print("Calories: 1615 kcal")
|
||||||
|
print("Protein: 120g")
|
||||||
|
print("Carbs: 142g")
|
||||||
|
print("Fat: 63g")
|
||||||
|
print("Fiber: 24g")
|
||||||
|
|
||||||
|
print("\nRow 2 Weekends:")
|
||||||
|
print("Calories: 2000 kcal")
|
||||||
|
print("Protein: 120g")
|
||||||
|
print("Carbs: 190g")
|
||||||
|
print("Fat: 84g")
|
||||||
|
print("Fiber: 30g")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("COMPARISON")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
expected_row1 = {
|
||||||
|
"calories": 1725,
|
||||||
|
"protein": 120,
|
||||||
|
"carbs": 155,
|
||||||
|
"fat": 69,
|
||||||
|
"fiber": 25
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_weekday = {
|
||||||
|
"calories": 1615,
|
||||||
|
"protein": 120,
|
||||||
|
"carbs": 142,
|
||||||
|
"fat": 63,
|
||||||
|
"fiber": 24
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_weekend = {
|
||||||
|
"calories": 2000,
|
||||||
|
"protein": 120,
|
||||||
|
"carbs": 190,
|
||||||
|
"fat": 84,
|
||||||
|
"fiber": 30
|
||||||
|
}
|
||||||
|
|
||||||
|
def compare(label, expected_val, actual_val, unit=""):
|
||||||
|
diff = actual_val - expected_val
|
||||||
|
pct_diff = (diff / expected_val * 100) if expected_val != 0 else 0
|
||||||
|
status = "✓" if abs(pct_diff) < 5 else "✗"
|
||||||
|
print(f"{status} {label:25} Expected: {expected_val:5}{unit} Actual: {actual_val:5}{unit} Diff: {diff:+5.0f} ({pct_diff:+.1f}%)")
|
||||||
|
|
||||||
|
print("\nRow 1 (Deficit - 7 days):")
|
||||||
|
compare("Calories", expected_row1['calories'], meal_metrics['deficit_calories'], " kcal")
|
||||||
|
compare("Protein", expected_row1['protein'], meal_metrics['deficit_protein'], "g")
|
||||||
|
compare("Carbs", expected_row1['carbs'], meal_metrics['deficit_carbs'], "g")
|
||||||
|
compare("Fat", expected_row1['fat'], meal_metrics['deficit_fat'], "g")
|
||||||
|
compare("Fiber", expected_row1['fiber'], meal_metrics['deficit_fiber'], "g")
|
||||||
|
|
||||||
|
print("\nRow 2 Weekdays:")
|
||||||
|
compare("Calories", expected_weekday['calories'], meal_metrics['refeed_weekday_calories'], " kcal")
|
||||||
|
compare("Protein", expected_weekday['protein'], meal_metrics['refeed_weekday_protein'], "g")
|
||||||
|
compare("Carbs", expected_weekday['carbs'], meal_metrics['refeed_weekday_carbs'], "g")
|
||||||
|
compare("Fat", expected_weekday['fat'], meal_metrics['refeed_weekday_fat'], "g")
|
||||||
|
compare("Fiber", expected_weekday['fiber'], meal_metrics['refeed_weekday_fiber'], "g")
|
||||||
|
|
||||||
|
print("\nRow 2 Weekends:")
|
||||||
|
compare("Calories", expected_weekend['calories'], meal_metrics['refeed_weekend_calories'], " kcal")
|
||||||
|
compare("Protein", expected_weekend['protein'], meal_metrics['refeed_weekend_protein'], "g")
|
||||||
|
compare("Carbs", expected_weekend['carbs'], meal_metrics['refeed_weekend_carbs'], "g")
|
||||||
|
compare("Fat", expected_weekend['fat'], meal_metrics['refeed_weekend_fat'], "g")
|
||||||
|
compare("Fiber", expected_weekend['fiber'], meal_metrics['refeed_weekend_fiber'], "g")
|
||||||
|
|
||||||
|
# Overall assessment
|
||||||
|
row1_match = all([
|
||||||
|
abs(meal_metrics['deficit_calories'] - expected_row1['calories']) <= 5,
|
||||||
|
abs(meal_metrics['deficit_protein'] - expected_row1['protein']) <= 5,
|
||||||
|
abs(meal_metrics['deficit_carbs'] - expected_row1['carbs']) <= 5,
|
||||||
|
abs(meal_metrics['deficit_fat'] - expected_row1['fat']) <= 5,
|
||||||
|
])
|
||||||
|
|
||||||
|
weekday_match = all([
|
||||||
|
abs(meal_metrics['refeed_weekday_calories'] - expected_weekday['calories']) <= 10,
|
||||||
|
abs(meal_metrics['refeed_weekday_protein'] - expected_weekday['protein']) <= 5,
|
||||||
|
abs(meal_metrics['refeed_weekday_carbs'] - expected_weekday['carbs']) <= 5,
|
||||||
|
abs(meal_metrics['refeed_weekday_fat'] - expected_weekday['fat']) <= 5,
|
||||||
|
])
|
||||||
|
|
||||||
|
weekend_match = all([
|
||||||
|
abs(meal_metrics['refeed_weekend_calories'] - expected_weekend['calories']) <= 10,
|
||||||
|
abs(meal_metrics['refeed_weekend_protein'] - expected_weekend['protein']) <= 5,
|
||||||
|
abs(meal_metrics['refeed_weekend_carbs'] - expected_weekend['carbs']) <= 10,
|
||||||
|
abs(meal_metrics['refeed_weekend_fat'] - expected_weekend['fat']) <= 5,
|
||||||
|
])
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
if row1_match and weekday_match and weekend_match:
|
||||||
|
print("✓ SUCCESS: Our formula produces values matching the PDF!")
|
||||||
|
else:
|
||||||
|
print("✗ WARNING: Significant differences found. Check:")
|
||||||
|
if not row1_match:
|
||||||
|
print(" - Row 1 calculations (daily deficit)")
|
||||||
|
if not weekday_match:
|
||||||
|
print(" - Weekday calculations (10% reduction)")
|
||||||
|
if not weekend_match:
|
||||||
|
print(" - Weekend calculations (maintaining weekly total)")
|
||||||
|
print("\nNote: Protein formula is Bio-PerformX specific: Lean Mass (lbs) × 2.2")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n✗ Error calculating metrics: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[project]
|
||||||
|
name = "report-generation"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi[all]>=0.121.3",
|
||||||
|
"matplotlib>=3.10.7",
|
||||||
|
"openpyxl>=3.1.5",
|
||||||
|
"pandas>=2.3.3",
|
||||||
|
"playwright>=1.56.0",
|
||||||
|
"requests>=2.32.5",
|
||||||
|
"seaborn>=0.13.2",
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user