From 44b6bdfea23e1d663c27618166cd9559c6b7698a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Engl=C3=B6f=20Ytterstr=C3=B6m?= Date: Sun, 20 Apr 2025 19:32:38 +0200 Subject: [PATCH] Design overhoul --- README.md | 72 ++++++++-------- src/App.svelte | 57 +++++-------- src/app.css | 105 ++++++------------------ src/lib/ArmyFatPercentage.svelte | 130 ----------------------------- src/lib/Counter.svelte | 10 --- src/lib/Display.svelte | 119 +++++++++++++++++++++++++++ src/lib/Keypad.svelte | 132 ++++++++++++++++++++++++++++++ src/lib/NavyFatPercentage.svelte | 136 ------------------------------- src/lib/OneRepMax.svelte | 56 ------------- src/lib/common.ts | 5 -- src/lib/formulaes.ts | 101 +++++++++++++++++++++++ src/lib/store.ts | 4 +- 12 files changed, 435 insertions(+), 492 deletions(-) delete mode 100644 src/lib/ArmyFatPercentage.svelte delete mode 100644 src/lib/Counter.svelte create mode 100644 src/lib/Display.svelte create mode 100644 src/lib/Keypad.svelte delete mode 100644 src/lib/NavyFatPercentage.svelte delete mode 100644 src/lib/OneRepMax.svelte delete mode 100644 src/lib/common.ts create mode 100644 src/lib/formulaes.ts diff --git a/README.md b/README.md index e6cd94f..99209b8 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,43 @@ -# Svelte + TS + Vite +# Kalkylatorer -This template should help get you started developing with Svelte and TypeScript in Vite. +This is 2 things: -## Recommended IDE Setup +- A set of formulaes for speedy calculation for +those times when a spreadsheet is to overwhelming. Basically related to strength training and body fat. +- An personal exercise to learn CSS subgrids, as well +as grinding code with Svelte. -[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). +## How it works -## Need an official Svelte framework? +- Choose a formula (top row), and set the values +with the keypad. +- Separate the values using semicolons. +- Add decimals by using a comma (sorry not sorry). +- Get result by pressing "=" button. -Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. -## Technical considerations +## Built-in calculators -**Why use this over SvelteKit?** +### 1 repetition max calculator -- It brings its own routing solution which might not be preferable for some users. -- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. - -This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. - -Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. - -**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** - -Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. - -**Why include `.vscode/extensions.json`?** - -Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. - -**Why enable `allowJs` in the TS template?** - -While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. - -**Why is HMR not preserving my local component state?** - -HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). - -If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. - -```ts -// store.ts -// An extremely simple external store -import { writable } from 'svelte/store' -export default writable(0) +``` +1rm(weight: number, reps: number, variant: "lower" | "upper") +``` + +### KG to LBS converter + +``` +lbs(weight: number) +``` + +### Army body fat composition calculator + +``` +abf(length: number, neck: number, waist: number, hips?: number, gender: "male" | "female", metric: boolean) +``` + +### Navy body fat composition calculator + +``` +nbf(length: number, neck: number, waist: number, hips?: number, gender: "male" | "female", metric: boolean) ``` diff --git a/src/App.svelte b/src/App.svelte index ea9c222..e5a583d 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,42 +1,29 @@ -{#if $currentView === "armyfatcalc"} - -{/if} -{#if $currentView === "navyfatcalc"} - -{/if} -{#if $currentView === "onerepmax"} - -{/if} -{#if $currentView === "start"} -
- -
-{/if} +
+ + +
+ diff --git a/src/app.css b/src/app.css index 395a0a3..6f59ae9 100644 --- a/src/app.css +++ b/src/app.css @@ -5,7 +5,13 @@ color-scheme: light dark; color: rgba(255, 255, 255, 0.87); - background-color: #242424; + background-color: #333; + background-image: linear-gradient( + hsl(0 25% 10%), + hsl(90 25% 10%), + hsl(180 25% 10%), + hsl(270 25% 10%) + ); font-synthesis: none; text-rendering: optimizeLegibility; @@ -14,90 +20,27 @@ } body { + min-height: 100vh; + min-width: 100vw; 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; -} - -h1, -h2, -h2 { - font-size: 1em; - margin: 0; - text-wrap: balance; + display: flex; + justify-content: center; + align-items: center; } main { - min-width: 100vw; - min-height: 100vh; + width: 14rem; + height: 14rem; + max-width: 97%; + max-height: 97%; + background: #543; + padding: 0.5em; + border: 3px solid #000; + background-image: linear-gradient(135deg, #432, #654, #432); + border-radius: 5px; display: grid; - gap: 1em; - padding: 1em; + gap: 0.2em; 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; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: repeat(8, 1fr); } diff --git a/src/lib/ArmyFatPercentage.svelte b/src/lib/ArmyFatPercentage.svelte deleted file mode 100644 index c85056d..0000000 --- a/src/lib/ArmyFatPercentage.svelte +++ /dev/null @@ -1,130 +0,0 @@ - - -
-
- - - -

Kroppsfettkalkylator, Army

-
- - {#if fatPercentage > 0} - {Math.round(fatPercentage * 100) / 100} - {/if} - -
-
- - -
- - - {#if gender == "female"} - - {/if} - -
-
- - diff --git a/src/lib/Counter.svelte b/src/lib/Counter.svelte deleted file mode 100644 index 37d75ce..0000000 --- a/src/lib/Counter.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/lib/Display.svelte b/src/lib/Display.svelte new file mode 100644 index 0000000..8342f4e --- /dev/null +++ b/src/lib/Display.svelte @@ -0,0 +1,119 @@ + + +
+
+ {#if $formula} + {$formula} + {#if $formula === "1rm"} + 0 ? "done" : ""}>weight + 1 ? "done" : ""}>reps + {/if} + {#if $formula === "lbs"} + 0 ? "done" : ""}>weight + {/if} + {#if $formula === "akf" || $formula === "nkf"} + 0 ? "done" : ""}>hgt + 1 ? "done" : ""}>nck + 2 ? "done" : ""}>wst + 3 ? "done" : ""}>hps? + {/if} + {/if} +
+
{$display}
+ copyToClipboard()}> + {#if $calculated}= + {/if} + {$calculated} + +
+ + diff --git a/src/lib/Keypad.svelte b/src/lib/Keypad.svelte new file mode 100644 index 0000000..e3d8f1e --- /dev/null +++ b/src/lib/Keypad.svelte @@ -0,0 +1,132 @@ + + + + + diff --git a/src/lib/NavyFatPercentage.svelte b/src/lib/NavyFatPercentage.svelte deleted file mode 100644 index ff2a9ff..0000000 --- a/src/lib/NavyFatPercentage.svelte +++ /dev/null @@ -1,136 +0,0 @@ - - -
-
- - - -

Kroppsfettkalkylator, Navy

-
- - {#if fatPercentage > 0} - {Math.round(fatPercentage * 100) / 100} - {/if} - -
-
- - -
- - - {#if gender == "female"} - - {/if} - -
-
- - diff --git a/src/lib/OneRepMax.svelte b/src/lib/OneRepMax.svelte deleted file mode 100644 index 43aba57..0000000 --- a/src/lib/OneRepMax.svelte +++ /dev/null @@ -1,56 +0,0 @@ - - -
-
- - - -

1RM

-
- - {#if oneRepMax > 0} - {Math.round(oneRepMax * 100) / 100} - {/if} - -
- - -
-
- - diff --git a/src/lib/common.ts b/src/lib/common.ts deleted file mode 100644 index 74a557c..0000000 --- a/src/lib/common.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { currentView } from "./store"; - -export const navigate = ( - page: "start" | "armyfatcalc" | "navyfatcalc" | "onerepmax", -) => currentView.update((_) => page); diff --git a/src/lib/formulaes.ts b/src/lib/formulaes.ts new file mode 100644 index 0000000..bcddcad --- /dev/null +++ b/src/lib/formulaes.ts @@ -0,0 +1,101 @@ +type Gender = "male" | "female"; +type Formula = "akf" | "nkf" | "1rm" | "lbs"; + +export const calculate = (f: Formula, params: string[]) => { + let G: Gender = "male"; + let H = undefined; + switch (f) { + case "1rm": + return round(oneRepMax(parseFloat(params[0]), parseInt(params[1], 10))); + case "lbs": + return round(kg2lbs(parseFloat(params[0].replace(",", ".")))); + case "akf": + if (params.length > 3) { + H = parseFloat(params[3].replace(",", ".")); + G = "female"; + } + return round( + armyBodyFatComposition( + G, + parseFloat(params[0].replace(",", ".")), + parseFloat(params[1].replace(",", ".")), + parseFloat(params[2].replace(",", ".")), + H, + ), + ); + case "nkf": + if (params.length > 3) { + H = parseFloat(params[3].replace(",", ".")); + G = "female"; + } + return round( + navyBodyFatComposition( + G, + parseFloat(params[0].replace(",", ".")), + parseFloat(params[1].replace(",", ".")), + parseFloat(params[2].replace(",", ".")), + H, + ), + ); + } +}; + +// https://www.athlegan.com/calculate-1rm +const oneRepMax = (weight: number, reps: number) => { + return weight / (1.0278 - 0.0278 * reps); +}; + +// https://www.gigacalculator.com/calculators/army-body-fat-calculator.php +const armyBodyFatComposition = ( + gender: Gender, + height: number, + neck: number, + waist: number, + hips?: number, +) => { + if (gender == "male") { + return ( + 86.01 * Math.log10(waist - neck) - 70.041 * Math.log10(height) + 30.3 + ); + } else { + return ( + 163.205 * Math.log10(waist + hips! - neck) - + 97.684 * Math.log10(height) - + 104.912 + ); + } +}; + +// https://www.omnicalculator.com/health/navy-body-fat +const navyBodyFatComposition = ( + gender: Gender, + height: number, + neck: number, + waist: number, + hips?: number, +) => { + if (gender == "male") { + return ( + 495 / + (1.0324 - + 0.19077 * Math.log10(waist - neck) + + 0.15456 * Math.log10(height)) - + 450 + ); + } else { + return ( + 495 / + (1.29579 - + 0.35004 * Math.log10(waist + hips! - neck) + + 0.221 * Math.log10(height)) - + 450 + ); + } +}; + +// https://www.unitconverters.net/weight-and-mass/kg-to-lbs.htm +const kg2lbs = (weight: number) => 2.2046226218 * weight; + +const round = (i: number) => { + return Math.round(i * 1000) / 1000; +}; diff --git a/src/lib/store.ts b/src/lib/store.ts index 9f91db0..5301372 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -1,3 +1,5 @@ import { writable } from "svelte/store"; -export const currentView = writable("start"); +export const calculated = writable(""); +export const formula = writable(""); +export const display = writable("hi.");