Add calcylators: 1rm, Navy fat

This commit is contained in:
Anders Englöf Ytterström 2025-03-14 10:37:21 +01:00
parent 4d9a4fc7f9
commit f66cf85eb8
6 changed files with 299 additions and 67 deletions

View file

@ -3,15 +3,40 @@
import viteLogo from "/vite.svg";
import { navigate } from "./lib/common";
import { currentView } from "./lib/store";
import FatPercentage from "./lib/FatPercentage.svelte";
import ArmyFatPercentage from "./lib/ArmyFatPercentage.svelte";
import NavyFatPercentage from "./lib/NavyFatPercentage.svelte";
import OneRepMax from "./lib/OneRepMax.svelte";
</script>
{#if $currentView === "fatcalc"}
<FatPercentage />
{#if $currentView === "armyfatcalc"}
<ArmyFatPercentage />
{/if}
{#if $currentView === "navyfatcalc"}
<NavyFatPercentage />
{/if}
{#if $currentView === "onerepmax"}
<OneRepMax />
{/if}
{#if $currentView === "start"}
<button onclick={() => navigate("fatcalc")}>Kroppsfettkalkylator</button>
<main>
<nav>
<button onclick={() => navigate("armyfatcalc")}
>Kroppsfettkalkylator, Army</button
>
<button onclick={() => navigate("navyfatcalc")}
>Kroppsfettkalkylator, Navy</button
>
<button onclick={() => navigate("onerepmax")}>1RM-kalkylator</button
>
</nav>
</main>
{/if}
<style>
nav {
display: grid;
grid-template: subgrid / subgrid;
grid-column: 2 / 2;
grid-row: 2 / 6;
}
</style>

View file

@ -17,6 +17,19 @@ body {
margin: 0;
}
button {
border: 5px solid crimson;
background-color: transparent;
border-radius: 0;
color: inherit;
&:hover,
&:focus {
border-color: #fff;
background-color: rgba(255, 255, 255, 0.1);
}
}
header {
background-color: crimson;
}
@ -26,4 +39,65 @@ h2,
h2 {
font-size: 1em;
margin: 0;
text-wrap: balance;
}
main {
min-width: 100vw;
min-height: 100vh;
display: grid;
gap: 1em;
padding: 1em;
box-sizing: border-box;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(7, 1fr);
}
output {
background: rgba(0, 0, 0, 0.25);
display: grid;
grid-column: 1 / 4;
grid-row: 2 / 4;
grid-template: subgrid / subgrid;
font-size: 2em;
> span {
grid-column: 1 / 6;
grid-row: 1 / 2;
text-align: right;
&::before {
content: "=";
color: #888;
}
&::after {
content: "%";
color: #888;
}
}
}
form {
background: rgba(255, 255, 255, 0.25);
display: grid;
grid-column: 1 / 4;
grid-row: 4 / 8;
grid-template: subgrid / subgrid;
}
input {
max-width: 4em;
display: block;
}
header {
display: grid;
grid-column: 1 / 4;
grid-row: 1 / 1;
grid-template: subgrid / subgrid;
}
h1 {
grid-column: 2 / 4;
}

View file

@ -43,7 +43,7 @@
<span>
<button onclick={() => navigate("start")}>Tillbaka</button>
</span>
<h1>Kroppsfettkalkylator</h1>
<h1>Kroppsfettkalkylator, Army</h1>
</header>
<output>
{#if fatPercentage > 0}
@ -123,68 +123,8 @@
</main>
<style>
main {
min-width: 100vw;
min-height: 100vh;
display: grid;
gap: 1em;
padding: 1em;
box-sizing: border-box;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(7, 1fr);
}
output {
background: rgba(0, 0, 0, 0.25);
display: grid;
grid-column: 1 / 4;
grid-row: 2 / 4;
grid-template-columns: subgrid;
font-size: 2em;
> span {
grid-column: 1 / 6;
grid-row: 1 / 2;
text-align: right;
&::before {
content: "=";
color: #888;
}
&::after {
content: "%";
color: #888;
}
}
}
form {
background: rgba(255, 255, 255, 0.25);
display: grid;
grid-column: 1 / 4;
grid-row: 4 / 8;
grid-template-columns: subgrid;
}
.gender {
grid-column: 1 / 2;
grid-row: 1 / 4;
}
input {
max-width: 4em;
display: block;
}
header {
display: grid;
grid-column: 1 / 4;
grid-row: 1 / 1;
grid-template-columns: subgrid;
}
h1 {
grid-column: 2 / 4;
}
</style>

View file

@ -0,0 +1,136 @@
<script lang="ts">
import { navigate } from "./common";
let fatPercentage = $state(0);
let gender = $state("male");
let height = $state(null);
let waist = $state(null);
let neck = $state(null);
let hips = $state(null);
// https://www.omnicalculator.com/health/navy-body-fat
const male = (waist: number, neck: number, height: number) =>
495 /
(1.0324 -
0.19077 * Math.log10(waist - neck) +
0.15456 * Math.log10(height)) -
450;
const female = (
waist: number,
neck: number,
hips: number,
height: number,
) =>
495 /
(1.29579 -
0.35004 * Math.log10(waist + hips - neck) +
0.221 * Math.log10(height)) -
450;
const calculate = () => {
if (gender == "male") {
if (!waist || !neck || !height) {
return;
}
fatPercentage = male(waist, neck, height);
} else {
if (!waist || !neck || !height || !hips) {
return;
}
fatPercentage = female(waist, neck, hips, height);
}
};
</script>
<main>
<header>
<span>
<button onclick={() => navigate("start")}>Tillbaka</button>
</span>
<h1>Kroppsfettkalkylator, Navy</h1>
</header>
<output>
{#if fatPercentage > 0}
<span>{Math.round(fatPercentage * 100) / 100}</span>
{/if}
</output>
<form>
<div class="gender">
<label>
Man
<input
bind:group={gender}
type="radio"
name="gender"
value="male"
id="male"
/>
</label>
<label>
Kvinna
<input
bind:group={gender}
type="radio"
name="gender"
value="female"
id="female"
/>
</label>
</div>
<label>
Kroppslängd
<input
onchange={() => calculate()}
bind:value={height}
type="number"
id="height"
name="height"
size="5"
/>
</label>
<label>
Midja
<input
onchange={() => calculate()}
type="number"
bind:value={waist}
id="waist"
name="waist"
size="5"
/>
</label>
{#if gender == "female"}
<label>
Höft
<input
onchange={() => calculate()}
type="number"
bind:value={hips}
id="hips"
name="hips"
size="5"
/>
</label>
{/if}
<label>
Hals
<input
onchange={() => calculate()}
type="number"
bind:value={neck}
id="neck"
name="neck"
size="5"
/>
</label>
</form>
</main>
<style>
.gender {
grid-column: 1 / 2;
grid-row: 1 / 4;
}
</style>

56
src/lib/OneRepMax.svelte Normal file
View file

@ -0,0 +1,56 @@
<script lang="ts">
import { navigate } from "./common";
let oneRepMax = $state(0);
let reps = $state(null);
let weight = $state(null);
// https://www.athlegan.com/calculate-1rm
const calculate = () => {
if (weight && reps) {
oneRepMax = weight / (1.0278 - 0.0278 * reps);
}
};
</script>
<main>
<header>
<span>
<button onclick={() => navigate("start")}>Tillbaka</button>
</span>
<h1>1RM</h1>
</header>
<output>
{#if oneRepMax > 0}
<span>{Math.round(oneRepMax * 100) / 100}</span>
{/if}
</output>
<form>
<label>
Reps
<input
onchange={() => calculate()}
bind:value={reps}
type="number"
id="reps"
name="reps"
size="5"
/>
</label>
<label>
Vikt
<input
onchange={() => calculate()}
type="number"
bind:value={weight}
id="weight"
name="weight"
size="5"
/>
</label>
</form>
</main>
<style>
</style>

View file

@ -1,4 +1,5 @@
import { currentView } from "./store";
export const navigate = (page: "start" | "fatcalc") =>
currentView.update((_) => page);
export const navigate = (
page: "start" | "armyfatcalc" | "navyfatcalc" | "onerepmax",
) => currentView.update((_) => page);