Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 314 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,163 @@ class VitruvianApp {
}
}
}
// --- BEGIN Exercise Library with Demos ---

const EXERCISES = {
chest: ["Bench Press","Incline Press","Chest Fly","Push-Ups","Cable Crossover","Dips","Decline Press"],
back: ["Pull-Ups","Lat Pulldown","Bent Row","Seated Row","Deadlift","Face Pulls","T-Bar Row"],
legs: ["Squats","Lunges","Leg Press","Leg Curl","Leg Extension","Calf Raises","Bulgarian Split Squat"],
shoulders: ["Overhead Press","Lateral Raise","Front Raise","Rear Delt Fly","Arnold Press","Upright Row"],
arms: ["Bicep Curl","Tricep Extension","Hammer Curl","Skull Crushers","Preacher Curl","Tricep Pushdown"],
core: ["Plank","Crunches","Russian Twist","Leg Raises","Cable Woodchop","Bicycle Crunches","Mountain Climbers"]
};

const EXERCISE_EMOJIS = {
'Bench Press': '🏋️',
'Incline Press': '🏋️',
'Chest Fly': '💪',
'Push-Ups': '💪',
'Pull-Ups': '🤸',
'Lat Pulldown': '💪',
'Squats': '🦵',
'Lunges': '🏃',
'Bicep Curl': '💪',
'Tricep Extension': '💪',
'Overhead Press': '🏋️',
'Plank': '🧘'
};

let selectedExercise = null;
let personalBests = JSON.parse(localStorage.getItem('vitruvian_pbs') || '{}');
let leaderboard = JSON.parse(localStorage.getItem('vitruvian_leaderboard') || '[]');

function initSidebarFeatures() {
if (!document.getElementById('exerciseList')) return; // Skip if sidebar not in HTML
renderExercises();
renderPersonalBests();
renderLeaderboard();

document.getElementById('exerciseSearch').oninput = renderExercises;
document.getElementById('muscleFilter').onchange = renderExercises;
if (document.getElementById('startBtn')) {
document.getElementById('startBtn').onclick = startWorkoutFromSidebar;
}
}

function renderExercises() {
const search = document.getElementById('exerciseSearch').value.toLowerCase();
const muscle = document.getElementById('muscleFilter').value;
const listEl = document.getElementById('exerciseList');
let exercises = [];

if (muscle === 'all') {
Object.values(EXERCISES).forEach(list => exercises.push(...list));
} else {
exercises = EXERCISES[muscle] || [];
}
exercises = exercises.filter(ex => ex.toLowerCase().includes(search));

listEl.innerHTML = exercises.map(ex => {
const emoji = EXERCISE_EMOJIS[ex] || '🏃';
return `<div class="exercise-item" onclick="selectExercise('${ex}')" style="display:flex;align-items:center;padding:8px;margin:5px 0;background:#f5f5f5;border-radius:5px;cursor:pointer;">
<span style="font-size:32px;margin-right:10px;">${emoji}</span>
<span>${ex}</span>
</div>`;
}).join('');
}

window.selectExercise = function(name) {
selectedExercise = name;
if (document.getElementById('selectedExercise')) {
document.getElementById('selectedExercise').textContent = `Selected: ${name}`;
}
document.querySelectorAll('.exercise-item').forEach(item => {
const exerciseName = item.querySelector('span:last-child').textContent;
if (exerciseName === name) {
item.style.background = '#667eea';
item.style.color = 'white';
} else {
item.style.background = '#f5f5f5';
item.style.color = 'black';
}
});
updateMuscleHeatmap(name);
};

function startWorkoutFromSidebar() {
if (!document.getElementById('mode')) return;
let mode = document.getElementById('mode').value;
let weight = parseFloat(document.getElementById('weight').value);
let reps = parseInt(document.getElementById('reps').value, 10);

localStorage.setItem('vitruvian_lastworkout',
JSON.stringify({ exercise: selectedExercise, mode, weight, reps })
);

console.log('Workout started:', { exercise: selectedExercise, mode, weight, reps });
}

function renderPersonalBests() {
const pbList = document.getElementById('pbList');
if (!pbList) return;
const pbs = Object.entries(personalBests).slice(0, 5);
if (pbs.length === 0) {
pbList.innerHTML = '<p style="color:#999;font-size:0.9em">Complete workouts to track PRs</p>';
return;
}
pbList.innerHTML = pbs.map(([exercise, weight]) =>
`<div style="display:flex;justify-content:space-between;padding:8px;border-bottom:1px solid #eee">
<span style="font-size:0.9em">${exercise}</span>
<strong style="color:#667eea">${weight}kg</strong>
</div>`
).join('');
}

function renderLeaderboard() {
const lbList = document.getElementById('leaderboardList');
if (!lbList) return;
const sorted = leaderboard.sort((a,b) => b.score - a.score).slice(0,5);
if (sorted.length === 0) {
lbList.innerHTML = '<p style="color:#999;font-size:0.9em">No entries yet</p>';
return;
}
lbList.innerHTML = sorted.map((entry, i) =>
`<div style="display:flex;gap:10px;padding:8px;background:#f5f5f5;margin:5px 0;border-radius:5px">
<span style="font-weight:bold;width:30px;color:${i===0?'gold':i===1?'silver':i===2?'#cd7f32':'#667eea'}">${i+1}</span>
<span style="flex:1">${entry.name}</span>
<span style="font-weight:bold">${entry.score}</span>
</div>`
).join('');
}

function updateMuscleHeatmap(selected) {
['chest','shoulders-l','shoulders-r','arms-l','arms-r','core','legs-l','legs-r'].forEach(id => {
let el = document.getElementById('m-'+id);
if (el) el.setAttribute('fill', '#ddd');
});
if (!selected) return;

const ex = selected.toLowerCase();
if (ex.match(/chest|press|fly|push/)) highlight(['chest']);
else if (ex.match(/shoulder|overhead|lateral|arnold/)) highlight(['shoulders-l','shoulders-r']);
else if (ex.match(/bicep|tricep|curl|skull|hammer/)) highlight(['arms-l','arms-r']);
else if (ex.match(/core|plank|crunch|twist|woodchop/)) highlight(['core']);
else if (ex.match(/squat|lunge|leg|calf/)) highlight(['legs-l','legs-r']);
else if (ex.match(/pull|row|deadlift/)) highlight(['shoulders-l','shoulders-r','arms-l','arms-r']);

function highlight(ids) {
ids.forEach(id => {
let el = document.getElementById('m-'+id);
if (el) el.setAttribute('fill', '#f88');
});
}
}

window.addEventListener('DOMContentLoaded', () => {
initSidebarFeatures();
});

// --- END Exercise Library with Demos ---

// Create global app instance
const app = new VitruvianApp();
Expand All @@ -1334,3 +1491,160 @@ app.addLogEntry("Requirements:", "info");
app.addLogEntry("- Chrome, Edge, or Opera browser", "info");
app.addLogEntry("- HTTPS connection (or localhost)", "info");
app.addLogEntry("- Bluetooth enabled on your device", "info");
// --- BEGIN Exercise Library with Demos ---

const EXERCISES = {
chest: ["Bench Press","Incline Press","Chest Fly","Push-Ups","Cable Crossover","Dips","Decline Press"],
back: ["Pull-Ups","Lat Pulldown","Bent Row","Seated Row","Deadlift","Face Pulls","T-Bar Row"],
legs: ["Squats","Lunges","Leg Press","Leg Curl","Leg Extension","Calf Raises","Bulgarian Split Squat"],
shoulders: ["Overhead Press","Lateral Raise","Front Raise","Rear Delt Fly","Arnold Press","Upright Row"],
arms: ["Bicep Curl","Tricep Extension","Hammer Curl","Skull Crushers","Preacher Curl","Tricep Pushdown"],
core: ["Plank","Crunches","Russian Twist","Leg Raises","Cable Woodchop","Bicycle Crunches","Mountain Climbers"]
};

const EXERCISE_EMOJIS = {
'Bench Press': '🏋️',
'Incline Press': '🏋️',
'Chest Fly': '💪',
'Push-Ups': '💪',
'Pull-Ups': '🤸',
'Lat Pulldown': '💪',
'Squats': '🦵',
'Lunges': '🏃',
'Bicep Curl': '💪',
'Tricep Extension': '💪',
'Overhead Press': '🏋️',
'Plank': '🧘'
};

let selectedExercise = null;
let personalBests = JSON.parse(localStorage.getItem('vitruvian_pbs') || '{}');
let leaderboard = JSON.parse(localStorage.getItem('vitruvian_leaderboard') || '[]');

function initSidebarFeatures() {
if (!document.getElementById('exerciseList')) return; // Skip if sidebar not in HTML
renderExercises();
renderPersonalBests();
renderLeaderboard();

document.getElementById('exerciseSearch').oninput = renderExercises;
document.getElementById('muscleFilter').onchange = renderExercises;
if (document.getElementById('startBtn')) {
document.getElementById('startBtn').onclick = startWorkoutFromSidebar;
}
}

function renderExercises() {
const search = document.getElementById('exerciseSearch').value.toLowerCase();
const muscle = document.getElementById('muscleFilter').value;
const listEl = document.getElementById('exerciseList');
let exercises = [];

if (muscle === 'all') {
Object.values(EXERCISES).forEach(list => exercises.push(...list));
} else {
exercises = EXERCISES[muscle] || [];
}
exercises = exercises.filter(ex => ex.toLowerCase().includes(search));

listEl.innerHTML = exercises.map(ex => {
const emoji = EXERCISE_EMOJIS[ex] || '🏃';
return `<div class="exercise-item" onclick="selectExercise('${ex}')" style="display:flex;align-items:center;padding:8px;margin:5px 0;background:#f5f5f5;border-radius:5px;cursor:pointer;">
<span style="font-size:32px;margin-right:10px;">${emoji}</span>
<span>${ex}</span>
</div>`;
}).join('');
}

window.selectExercise = function(name) {
selectedExercise = name;
if (document.getElementById('selectedExercise')) {
document.getElementById('selectedExercise').textContent = `Selected: ${name}`;
}
document.querySelectorAll('.exercise-item').forEach(item => {
const exerciseName = item.querySelector('span:last-child').textContent;
if (exerciseName === name) {
item.style.background = '#667eea';
item.style.color = 'white';
} else {
item.style.background = '#f5f5f5';
item.style.color = 'black';
}
});
updateMuscleHeatmap(name);
};

function startWorkoutFromSidebar() {
if (!document.getElementById('mode')) return;
let mode = document.getElementById('mode').value;
let weight = parseFloat(document.getElementById('weight').value);
let reps = parseInt(document.getElementById('reps').value, 10);

localStorage.setItem('vitruvian_lastworkout',
JSON.stringify({ exercise: selectedExercise, mode, weight, reps })
);

console.log('Workout started:', { exercise: selectedExercise, mode, weight, reps });
}

function renderPersonalBests() {
const pbList = document.getElementById('pbList');
if (!pbList) return;
const pbs = Object.entries(personalBests).slice(0, 5);
if (pbs.length === 0) {
pbList.innerHTML = '<p style="color:#999;font-size:0.9em">Complete workouts to track PRs</p>';
return;
}
pbList.innerHTML = pbs.map(([exercise, weight]) =>
`<div style="display:flex;justify-content:space-between;padding:8px;border-bottom:1px solid #eee">
<span style="font-size:0.9em">${exercise}</span>
<strong style="color:#667eea">${weight}kg</strong>
</div>`
).join('');
}

function renderLeaderboard() {
const lbList = document.getElementById('leaderboardList');
if (!lbList) return;
const sorted = leaderboard.sort((a,b) => b.score - a.score).slice(0,5);
if (sorted.length === 0) {
lbList.innerHTML = '<p style="color:#999;font-size:0.9em">No entries yet</p>';
return;
}
lbList.innerHTML = sorted.map((entry, i) =>
`<div style="display:flex;gap:10px;padding:8px;background:#f5f5f5;margin:5px 0;border-radius:5px">
<span style="font-weight:bold;width:30px;color:${i===0?'gold':i===1?'silver':i===2?'#cd7f32':'#667eea'}">${i+1}</span>
<span style="flex:1">${entry.name}</span>
<span style="font-weight:bold">${entry.score}</span>
</div>`
).join('');
}

function updateMuscleHeatmap(selected) {
['chest','shoulders-l','shoulders-r','arms-l','arms-r','core','legs-l','legs-r'].forEach(id => {
let el = document.getElementById('m-'+id);
if (el) el.setAttribute('fill', '#ddd');
});
if (!selected) return;

const ex = selected.toLowerCase();
if (ex.match(/chest|press|fly|push/)) highlight(['chest']);
else if (ex.match(/shoulder|overhead|lateral|arnold/)) highlight(['shoulders-l','shoulders-r']);
else if (ex.match(/bicep|tricep|curl|skull|hammer/)) highlight(['arms-l','arms-r']);
else if (ex.match(/core|plank|crunch|twist|woodchop/)) highlight(['core']);
else if (ex.match(/squat|lunge|leg|calf/)) highlight(['legs-l','legs-r']);
else if (ex.match(/pull|row|deadlift/)) highlight(['shoulders-l','shoulders-r','arms-l','arms-r']);

function highlight(ids) {
ids.forEach(id => {
let el = document.getElementById('m-'+id);
if (el) el.setAttribute('fill', '#f88');
});
}
}

window.addEventListener('DOMContentLoaded', () => {
initSidebarFeatures();
});

// --- END Exercise Library with Demos ---
11 changes: 11 additions & 0 deletions images/images_bench-press_Version3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions images/images_bicep-curl_Version2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions images/images_chest-fly_Version2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions images/images_incline-press_Version2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions images/images_lat-pulldown_Version1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions images/images_lateral-raise_Version1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading