Initial commit
This commit is contained in:
parent
084df08932
commit
26fff26fef
14
App.js
Normal file
14
App.js
Normal file
@ -0,0 +1,14 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('http://127.0.0.1:9898/routine.json')
|
||||
.then(response => response.json())
|
||||
.then(workout_json => {
|
||||
// Use the JSON workout_json here
|
||||
console.log(workout_json);
|
||||
const wo = new Workout(document.getElementById("content-wrapper"),
|
||||
workout_json);
|
||||
wo.render();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching JSON:', error);
|
||||
});
|
||||
});
|
244
Workout.js
Normal file
244
Workout.js
Normal file
@ -0,0 +1,244 @@
|
||||
class Workout {
|
||||
constructor(cont, plan) {
|
||||
const wo_cont = document.createElement("div");
|
||||
wo_cont.classList.add("workout-wrapper");
|
||||
cont.appendChild(wo_cont);
|
||||
this.cont = wo_cont;
|
||||
this.plan = plan;
|
||||
|
||||
this.action = "";
|
||||
this.set_idx = 0;
|
||||
this.exercise_idx = 0;
|
||||
this.workout_done = 0;
|
||||
|
||||
// this.show_debug_status = 1;
|
||||
}
|
||||
|
||||
text_element(typ, txt) {
|
||||
const ret_elem = document.createElement(typ);
|
||||
ret_elem.textContent = txt;
|
||||
|
||||
return ret_elem;
|
||||
}
|
||||
|
||||
render_workout_header() {
|
||||
this.cont.appendChild(this.text_element("h1", this.plan.name));
|
||||
}
|
||||
|
||||
render_debug_status() {
|
||||
const dbg_div = document.createElement("div");
|
||||
dbg_div.classList.add("app_debug");
|
||||
|
||||
const dt = document.createElement("p");
|
||||
dt.setAttribute("id", "app_debug_div");
|
||||
dbg_div.appendChild(dt);
|
||||
this.cont.appendChild(dbg_div);
|
||||
}
|
||||
|
||||
update_debug_info() {
|
||||
if (this.show_debug_status) {
|
||||
const dt = this.cont.querySelector("#app_debug_div");
|
||||
const done_str = (this.workout_done === 1) ? "Done " : "";
|
||||
dt.textContent = `${done_str}Action: ${this.action} Current: Set-${this.set_idx}/Exercise-${this.exercise_idx}`;
|
||||
}
|
||||
}
|
||||
|
||||
render_exercise(prnt, el, idx) {
|
||||
const tblr = document.createElement("tr");
|
||||
tblr.setAttribute("class", `exercise-row exercise-idx-${idx} exercise-pending`);
|
||||
|
||||
const sts_td = document.createElement("td");
|
||||
const sts_cb = document.createElement("input");
|
||||
sts_cb.setAttribute("type", "checkbox");
|
||||
sts_td.appendChild(sts_cb);
|
||||
sts_cb.setAttribute("disabled", true);
|
||||
|
||||
// Status
|
||||
let col = sts_td;
|
||||
col.classList.add("col-status");
|
||||
tblr.appendChild(col);
|
||||
// Name
|
||||
col = this.text_element("td", el.name);
|
||||
col.classList.add("col-name");
|
||||
tblr.appendChild(col);
|
||||
// Pattern/count
|
||||
col = this.text_element("td", `${el.pattern} x ${el.count}`);
|
||||
col.classList.add("col-pattern-count");
|
||||
tblr.appendChild(col);
|
||||
|
||||
prnt.appendChild(tblr);
|
||||
}
|
||||
|
||||
render_set(el, idx) {
|
||||
const wo = this;
|
||||
|
||||
// Table with one set
|
||||
const tbl = document.createElement("table");
|
||||
tbl.setAttribute("class", `set-table set-table-idx-${idx}`);
|
||||
|
||||
tbl.appendChild(this.text_element("caption", el.name));
|
||||
|
||||
let show_header = 0;
|
||||
if (show_header) {
|
||||
// Header of the table
|
||||
const tblh = document.createElement("thead");
|
||||
const tblhr = document.createElement("tr");
|
||||
|
||||
let col = this.text_element("th", "Status");
|
||||
col.classList.add("col-status");
|
||||
tblhr.appendChild(col);
|
||||
col = this.text_element("th", "Exercise");
|
||||
col.classList.add("col-name");
|
||||
tblhr.appendChild(col);
|
||||
col = this.text_element("th", "Pattern/Count");
|
||||
col.classList.add("col-pattern-count");
|
||||
tblhr.appendChild(col);
|
||||
|
||||
tblh.appendChild(tblhr);
|
||||
tbl.appendChild(tblh);
|
||||
}
|
||||
|
||||
// Content of table - exercises in the set
|
||||
const tblb = document.createElement("tbody");
|
||||
|
||||
el.exercise.forEach(function(el,idx) {
|
||||
wo.render_exercise(tblb, el, idx);
|
||||
});
|
||||
tbl.appendChild(tblb);
|
||||
|
||||
this.cont.appendChild(tbl);
|
||||
}
|
||||
|
||||
render_workout() {
|
||||
const wo = this;
|
||||
this.render_workout_header();
|
||||
if (this.show_debug_status) {
|
||||
this.render_debug_status();
|
||||
}
|
||||
this.plan.set.forEach(function(el,idx) {
|
||||
wo.render_set(el, idx);
|
||||
})
|
||||
|
||||
this.update_debug_info();
|
||||
}
|
||||
|
||||
update_active_item() {
|
||||
// Make current active exercise row inactive
|
||||
const curr_active_tr = this.cont.querySelector(".exercise-row.active");
|
||||
if (curr_active_tr != null) {
|
||||
curr_active_tr.classList.remove("active");
|
||||
}
|
||||
|
||||
// Set active exercise row
|
||||
let qstr = `table.set-table-idx-${this.set_idx} tr.exercise-idx-${this.exercise_idx}`;
|
||||
console.log(`Looking for ${qstr}`);
|
||||
const next_active_tr = this.cont.querySelector(qstr);
|
||||
console.log(next_active_tr);
|
||||
if (next_active_tr != null) {
|
||||
next_active_tr.classList.add("active");
|
||||
}
|
||||
|
||||
// Mark workout done
|
||||
qstr = `table tr.exercise-pending`;
|
||||
let pending_trs = this.cont.querySelectorAll(qstr);
|
||||
console.log(`Remaining to be done ${pending_trs.length}`);
|
||||
if (pending_trs.length === 0) {
|
||||
this.workout_done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
handle_exercise_advance() {
|
||||
const curr_exercise_max_idx = this.plan.set[this.set_idx].exercise.length-1;
|
||||
const curr_set_max_idx = this.plan.set.length-1;
|
||||
|
||||
console.log(`workout done ${this.workout_done} curr_exercise_max_idx = ${curr_exercise_max_idx} curr_set_max_idx = ${curr_set_max_idx}`);
|
||||
|
||||
if (this.exercise_idx === curr_exercise_max_idx) {
|
||||
if (this.set_idx === curr_set_max_idx) {
|
||||
if (this.workout_done === 1) {
|
||||
console.log("Exercise done");
|
||||
}
|
||||
} else {
|
||||
this.set_idx += 1;
|
||||
this.exercise_idx = 0;
|
||||
}
|
||||
} else {
|
||||
this.exercise_idx += 1;
|
||||
}
|
||||
|
||||
this.update_active_item();
|
||||
}
|
||||
|
||||
handle_exercise_regress() {
|
||||
const curr_set_max_idx = this.plan.set.length-1;
|
||||
|
||||
console.log(`workout done ${this.workout_done}`);
|
||||
|
||||
if (this.exercise_idx === 0) {
|
||||
if (this.set_idx === 0) {
|
||||
console.log("Exercise start");
|
||||
} else {
|
||||
this.set_idx -= 1;
|
||||
this.exercise_idx = this.plan.set[this.set_idx].exercise.length-1;
|
||||
}
|
||||
} else {
|
||||
this.exercise_idx -= 1;
|
||||
}
|
||||
|
||||
this.update_active_item();
|
||||
}
|
||||
|
||||
handle_exercise_done() {
|
||||
// Set active exercise row
|
||||
let qstr = `table.set-table-idx-${this.set_idx} tr.exercise-idx-${this.exercise_idx} input`;
|
||||
console.log(`Looking for ${qstr}`);
|
||||
const active_chkbox = this.cont.querySelector(qstr);
|
||||
|
||||
if (!active_chkbox.checked) {
|
||||
active_chkbox.checked = true;
|
||||
active_chkbox.disabled = true;
|
||||
qstr = `table.set-table-idx-${this.set_idx} tr.exercise-idx-${this.exercise_idx}`;
|
||||
const active_tr = this.cont.querySelector(qstr);
|
||||
active_tr.classList.remove("exercise-pending");
|
||||
}
|
||||
|
||||
this.update_active_item();
|
||||
}
|
||||
|
||||
|
||||
handle_key_press(app, ev) {
|
||||
if (this.workout_done) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Access the pressed key using ev.key
|
||||
const key = ev.key;
|
||||
|
||||
// Advance exercise
|
||||
if (key === 'n') {
|
||||
app.action = `Key-${ev.key}`;
|
||||
app.handle_exercise_advance();
|
||||
} else if (key === 'N') {
|
||||
app.action = `Key-${ev.key}`;
|
||||
app.handle_exercise_regress();
|
||||
} else if (key === ' ') {
|
||||
app.action = `Key-${ev.key}`;
|
||||
app.handle_exercise_done();
|
||||
} else {
|
||||
app.action = `UN Key-${ev.key}`;
|
||||
}
|
||||
|
||||
app.update_debug_info();
|
||||
}
|
||||
|
||||
render() {
|
||||
const app = this;
|
||||
this.render_workout();
|
||||
this.update_active_item();
|
||||
|
||||
document.addEventListener('keydown', function(ev) {
|
||||
app.handle_key_press(app, ev);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
17
index.html
Normal file
17
index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Workout</title>
|
||||
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<script type="text/javascript" src="http://127.0.0.1:9898/Workout.js"></script>
|
||||
<script type="text/javascript" src="http://127.0.0.1:9898/App.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="content-wrapper"></div>
|
||||
</body>
|
||||
</html>
|
4
launch.sh
Executable file
4
launch.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
npx http-server /home/mahesh/dev/js/workout -p 9898 --cors='Access-Control-Allow-Origin'
|
||||
|
37
routine.json
Normal file
37
routine.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "Daily Build and Burn",
|
||||
"set": [
|
||||
{ "name": "Build",
|
||||
"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",
|
||||
"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": ""}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
81
style.css
Normal file
81
style.css
Normal file
@ -0,0 +1,81 @@
|
||||
:root {
|
||||
--table-border: #ccc;
|
||||
--table-grade-top: #eee;
|
||||
--table-grade-bottom: #ddd;
|
||||
--table-shadow: #ccc;
|
||||
--table-active: #363;
|
||||
--table-active-grade: #474;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: "Iosevka", monospace;
|
||||
}
|
||||
|
||||
.workout-wrapper {
|
||||
width: 60em;
|
||||
margin: auto;
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.workout-wrapper h1 {
|
||||
text-align: center;
|
||||
}
|
||||
.workout-wrapper table {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
width: 95%;
|
||||
border-spacing: 0px;
|
||||
border-collapse: collapse;
|
||||
box-shadow: 1px 1px 7px var(--table-shadow);
|
||||
}
|
||||
.workout-wrapper table caption {
|
||||
font-size: large;
|
||||
text-align: left;
|
||||
padding: 7px 7px 7px 10px;
|
||||
font-weight: bold;
|
||||
border: thin solid var(--table-border);
|
||||
margin: 0;
|
||||
border-radius: 0.3em 0.3em 0 0;
|
||||
background: linear-gradient(var(--table-grade-top), var(--table-grade-bottom));
|
||||
box-shadow: 1px 1px 7px var(--table-shadow);
|
||||
}
|
||||
.workout-wrapper .set-table thead tr {
|
||||
border: thin solid var(--table-border);
|
||||
}
|
||||
.workout-wrapper .set-table tbody tr {
|
||||
border-bottom: thin solid var(--table-border-top);
|
||||
}
|
||||
.workout-wrapper .set-table tbody tr.active {
|
||||
background: linear-gradient(var(--table-active), var(--table-active-grade));
|
||||
color: white;
|
||||
border: 1px solid var(--table-active);
|
||||
box-shadow: 1px 1px 15px var(--table-active);
|
||||
}
|
||||
.workout-wrapper .set-table td,
|
||||
.workout-wrapper .set-table th {
|
||||
text-align: left;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.workout-wrapper .set-table th {
|
||||
background-color: var(--table-border);
|
||||
}
|
||||
|
||||
.workout-wrapper .set-table .col-status {
|
||||
width: 10%;
|
||||
}
|
||||
.workout-wrapper .set-table .col-name {
|
||||
width: 60%;
|
||||
}
|
||||
.workout-wrapper .set-table .col-pattern-count {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
/* Global */
|
||||
.workout-wrapper #app_debug_div {
|
||||
border: thin dotted blue;
|
||||
color: grey;
|
||||
font-size: x-small;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user