Compare commits
6 Commits
793689e29c
...
main
Author | SHA1 | Date | |
---|---|---|---|
f96143757a
|
|||
fb4acf962f
|
|||
6cfce18819
|
|||
c46b37756a
|
|||
115728fe58
|
|||
7d7c89a0c9
|
11
App.js
11
App.js
@@ -1,9 +1,14 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('routine.json')
|
||||
fetch('collection.json')
|
||||
.then(response => response.json())
|
||||
.then(workout_json => {
|
||||
// Use the JSON workout_json here
|
||||
.then(collection_json => {
|
||||
// Generate Exercise plan
|
||||
const egen = new ExerciseGenerator(collection_json);
|
||||
|
||||
// 2 sets of 4 exercises each, 3 reps per set
|
||||
let workout_json = egen.generate_build_and_burn(2, 4, 3);
|
||||
console.log(workout_json);
|
||||
|
||||
const wo = new Workout(document.getElementById("content-wrapper"),
|
||||
workout_json);
|
||||
wo.render();
|
||||
|
132
ExerciseGenerator.js
Normal file
132
ExerciseGenerator.js
Normal file
@@ -0,0 +1,132 @@
|
||||
class ExerciseGenerator {
|
||||
|
||||
// ----------
|
||||
constructor(collection) {
|
||||
this.collection = collection;
|
||||
|
||||
// console.log(this.collection);
|
||||
this.used_exercise_ids = new Array;
|
||||
|
||||
this.ex_nxt;
|
||||
this.ex_last = null;
|
||||
}
|
||||
|
||||
// ----------
|
||||
exercise_id_used(ex) {
|
||||
return (this.used_exercise_ids.filter(function(v) { return (v == ex.id) }).length > 0);
|
||||
}
|
||||
|
||||
// ----------
|
||||
exercise_related_to(ex) {
|
||||
let related = false;
|
||||
let gen = this;
|
||||
|
||||
if (gen.ex_last == null) {
|
||||
return related;
|
||||
}
|
||||
|
||||
ex.focus.forEach(function(e) {
|
||||
related |= gen.ex_last.focus.includes(e);
|
||||
});
|
||||
|
||||
return related;
|
||||
}
|
||||
|
||||
// ----------
|
||||
get_next_exercise() {
|
||||
let scope = this.collection.exercises;
|
||||
let gen = this;
|
||||
|
||||
scope = this.collection.exercises.filter(function(e) {
|
||||
let pick = true;
|
||||
|
||||
// Pick if exercise is not already used
|
||||
pick &= (gen.exercise_id_used(e) == false);
|
||||
|
||||
// Pick if nor related to the previous one
|
||||
pick &= (gen.exercise_related_to(e) == false);
|
||||
|
||||
return pick
|
||||
});
|
||||
gen.shuffle_exercise_array(scope);
|
||||
// gen.show_exercise_array(scope);
|
||||
|
||||
return scope[0];
|
||||
}
|
||||
|
||||
// ----------
|
||||
show_exercise_array(arr) {
|
||||
let gen = this;
|
||||
|
||||
arr.map(function(it) {
|
||||
gen.show_exercise(it);
|
||||
});
|
||||
}
|
||||
|
||||
// ----------
|
||||
show_exercise(ex) {
|
||||
console.log(`${ex.id} : ${ex.name} [` + ex.focus.join(", ") + ']');
|
||||
}
|
||||
|
||||
// ----------
|
||||
// From answer on https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
|
||||
shuffle_exercise_array(arr) {
|
||||
let currentIndex = arr.length;
|
||||
|
||||
// While there remain elements to shuffle...
|
||||
while (currentIndex != 0) {
|
||||
// Pick a remaining element...
|
||||
let randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex--;
|
||||
|
||||
// And swap it with the current element.
|
||||
[arr[currentIndex], arr[randomIndex]] = [
|
||||
arr[randomIndex], arr[currentIndex]];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
generate_set(size) {
|
||||
let set_exercises = Array();
|
||||
let lim = size;
|
||||
|
||||
this.ex_last = null;
|
||||
|
||||
do {
|
||||
this.ex_nxt = this.get_next_exercise();
|
||||
if (this.ex_nxt == null) {
|
||||
break;
|
||||
}
|
||||
this.used_exercise_ids.push(this.ex_nxt.id);
|
||||
set_exercises.push(this.ex_nxt);
|
||||
this.ex_last = this.ex_nxt;
|
||||
lim--;
|
||||
} while ((this.ex_nxt != null) && (lim > 0));
|
||||
|
||||
this.show_exercise_array(set_exercises);
|
||||
console.log(this.used_exercise_ids);
|
||||
|
||||
return set_exercises;
|
||||
}
|
||||
|
||||
// ----------
|
||||
generate_build_and_burn(sets, exercises, reps) {
|
||||
let wo_plan = {
|
||||
"name": "Daily Build and Burn",
|
||||
"set": [
|
||||
]
|
||||
}
|
||||
|
||||
for (let i = 1; i <= sets; i ++) {
|
||||
let set = {
|
||||
"name": `Set ${i}`,
|
||||
"count": reps,
|
||||
"exercise": this.generate_set(exercises)
|
||||
}
|
||||
wo_plan.set.push(set);
|
||||
}
|
||||
|
||||
return wo_plan;
|
||||
}
|
||||
|
||||
}
|
23
Workout.js
23
Workout.js
@@ -7,6 +7,7 @@ constructor(cont, plan) {
|
||||
cont.appendChild(wo_cont);
|
||||
|
||||
// Inputs to the class. Workout plan and container to display it in
|
||||
this.arena = cont;
|
||||
this.container = wo_cont;
|
||||
this.plan = plan;
|
||||
|
||||
@@ -52,8 +53,6 @@ progress_indicator(id) {
|
||||
// ----------
|
||||
render_workout_header() {
|
||||
const hdr = this.text_element("h1", this.plan.name);
|
||||
const wo_indicator = this.progress_indicator("wo-indicator");
|
||||
hdr.appendChild(wo_indicator);
|
||||
this.container.appendChild(hdr);
|
||||
}
|
||||
|
||||
@@ -251,9 +250,19 @@ update_active_item() {
|
||||
|
||||
// Mark workout done
|
||||
if (this.workout_done == 1) {
|
||||
const wo_indicator = this.container.querySelector("#wo-indicator");
|
||||
wo_indicator.classList.remove("pending");
|
||||
wo_indicator.classList.add("done");
|
||||
const wo_h1 = this.container.querySelector(".workout-wrapper h1");
|
||||
wo_h1.classList.add("done");
|
||||
this.container.classList.add("done");
|
||||
let buttons = this.container.querySelectorAll("button");
|
||||
buttons.forEach(function(bttn, bidx) {
|
||||
bttn.disabled = true;
|
||||
});
|
||||
const wo_done = this.text_element("div", "");
|
||||
wo_done.setAttribute("id", "workout-done");
|
||||
const wo_done_txt = this.text_element("div", "Workout done!");
|
||||
wo_done_txt.classList.add("workout-done-txt");
|
||||
wo_done.appendChild(wo_done_txt);
|
||||
this.arena.appendChild(wo_done);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,10 +410,10 @@ render_fab() {
|
||||
const fab_wrapper = document.createElement("div");
|
||||
fab_wrapper.setAttribute("id", "fab-wrapper");
|
||||
|
||||
const fab_regress = this.text_element("button", "<< Regress");
|
||||
const fab_regress = this.text_element("button", " ");
|
||||
fab_regress.classList.add("fab-button");
|
||||
fab_regress.setAttribute("id", "fab-regress");
|
||||
const fab_advance = this.text_element("button", "Advance >>");
|
||||
const fab_advance = this.text_element("button", " ");
|
||||
fab_advance.classList.add("fab-button");
|
||||
fab_advance.setAttribute("id", "fab-advance");
|
||||
|
||||
|
65
collection.json
Normal file
65
collection.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "Collection of exercises",
|
||||
"exercises": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Leg triads with dumbell",
|
||||
"count": 10,
|
||||
"pattern": "each side",
|
||||
"focus": ["legs"]},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Forward lunge with dumbell twist",
|
||||
"count": 10,
|
||||
"pattern": "each side",
|
||||
"focus": ["legs"]},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "A and Y core on floor",
|
||||
"count": 10,
|
||||
"pattern": "each end",
|
||||
"focus": ["core"]},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Bow and arrow pull with bands",
|
||||
"count": 10,
|
||||
"pattern": "each side",
|
||||
"focus": ["arms"]},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Push ups",
|
||||
"count": 10,
|
||||
"pattern": "",
|
||||
"focus": ["arms", "chest"]},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Bicep curls",
|
||||
"count": 10,
|
||||
"pattern": "each side",
|
||||
"focus": ["arms"]},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Russian twists",
|
||||
"count": 10,
|
||||
"pattern": "",
|
||||
"focus": ["core"]},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Chin up core",
|
||||
"count": 10,
|
||||
"pattern": "",
|
||||
"focus": ["arms", "core"]},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Tricep curls on the floor",
|
||||
"count": 15,
|
||||
"pattern": "",
|
||||
"focus": ["arms"]},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Leg curl on floor",
|
||||
"count": 10,
|
||||
"pattern": "each leg",
|
||||
"focus": ["legs"]}
|
||||
]
|
||||
}
|
@@ -10,6 +10,7 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Boldonse&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<script type="text/javascript" src="ExerciseGenerator.js"></script>
|
||||
<script type="text/javascript" src="Workout.js"></script>
|
||||
<script type="text/javascript" src="App.js"></script>
|
||||
|
||||
|
39
routine.json
39
routine.json
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "Daily Build and Burn",
|
||||
"set": [
|
||||
{ "name": "Build",
|
||||
"count": 3,
|
||||
"exercise": [
|
||||
{ "name": "Forward lunge with dumbell twist",
|
||||
"count": 10,
|
||||
"pattern": "each side"},
|
||||
{ "name": "A and Y core on floor",
|
||||
"count": 10,
|
||||
"pattern": "each end"},
|
||||
{ "name": "Bow and arrow pull with bands",
|
||||
"count": 10,
|
||||
"pattern": "each side"},
|
||||
{ "name": "Push ups",
|
||||
"count": 10,
|
||||
"pattern": ""}
|
||||
]
|
||||
},
|
||||
{ "name": "Burn",
|
||||
"count": 3,
|
||||
"exercise": [
|
||||
{ "name": "Bicep curls",
|
||||
"count": 10,
|
||||
"pattern": "each side"},
|
||||
{ "name": "Russian twists",
|
||||
"count": 10,
|
||||
"pattern": ""},
|
||||
{ "name": "Chin up core",
|
||||
"count": 10,
|
||||
"pattern": ""},
|
||||
{ "name": "Tricep curls on the floor",
|
||||
"count": 15,
|
||||
"pattern": ""}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
83
style.css
83
style.css
@@ -27,6 +27,10 @@ html {
|
||||
.workout-wrapper {
|
||||
width: 90%;
|
||||
}
|
||||
.workout-wrapper.done {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.workout-wrapper table {
|
||||
width: 97%;
|
||||
}
|
||||
@@ -57,8 +61,11 @@ html {
|
||||
font-family: "Boldonse", system-ui;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
|
||||
text-align: center;
|
||||
text-decoration: underline var(--indicator-pending) solid 0.2em;
|
||||
}
|
||||
.workout-wrapper h1.done {
|
||||
text-decoration: underline var(--indicator-done) solid 0.2em;
|
||||
}
|
||||
.workout-wrapper table {
|
||||
margin-left: auto;
|
||||
@@ -119,9 +126,10 @@ html {
|
||||
display: inline-block;
|
||||
white-space: pre-wrap;
|
||||
width: 1em;
|
||||
line-height: 1em;
|
||||
border: thin solid gray;
|
||||
border-radius: 0.5em;
|
||||
font-size: 0.3em;
|
||||
border-radius: 0.7em;
|
||||
font-size: 0.5em;
|
||||
vertical-align: middle;
|
||||
margin-left: 1em;
|
||||
}
|
||||
@@ -147,23 +155,82 @@ html {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
/* Workout done sheet that covers everything */
|
||||
#workout-done {
|
||||
position: fixed;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(200,200,200,0.5);
|
||||
z-index: 2000;
|
||||
backdrop-filter: blur(0.5em);
|
||||
}
|
||||
|
||||
#workout-done .workout-done-txt {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-family: "Boldonse", system-ui;
|
||||
font-weight: 400;
|
||||
font-size: xx-large;
|
||||
color: white;
|
||||
text-shadow: var(--indicator-done-grade) 0.5em 0.5em 1em;
|
||||
}
|
||||
|
||||
/* Floating Action Buttons */
|
||||
#fab-wrapper {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#fab-wrapper .fab-button {
|
||||
display: inline-block;
|
||||
white-space: pre-wrap;
|
||||
border: thin solid gray;
|
||||
border-radius: 0.5em;
|
||||
border-radius: 50%;
|
||||
font-size: 1em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#fab-wrapper #fab-regress {
|
||||
border: 0.4em solid gray;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
}
|
||||
#fab-wrapper #fab-regress:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 0.8em;
|
||||
height: 0.8em;
|
||||
margin-top: 0.2em;
|
||||
margin-left: 0.2em;
|
||||
border-top: 0.4em solid gray;
|
||||
border-right: 0.4em solid gray;
|
||||
transform: rotate(-135deg);
|
||||
}
|
||||
|
||||
#fab-wrapper #fab-advance {
|
||||
border: 0.4em solid gray;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
#fab-wrapper #fab-advance:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
margin-bottom: -0.2em;
|
||||
margin-right: 0.6em;
|
||||
border-top: 0.4em solid gray;
|
||||
border-right: 0.4em solid gray;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
Reference in New Issue
Block a user