Skip to main content

Frontend

There's no client-side framework, bundler, or transpiler in this app — every page is a server-rendered EJS template, and interactivity is plain JavaScript loaded via <script> tags. This page catalogs what each script does; see Using the App for what the features actually look like to use.

Build

package.json has exactly two frontend-relevant scripts, both Sass-only:

  • build-css — compiles public/scss/main.scsspublic/css/main.css once.
  • watch-css — the same, in watch mode, for local development.

JavaScript ships as-is, one file per concern, included directly by whichever EJS views need it. Each script is written as a self-contained IIFE that checks for the DOM elements it needs before doing anything, so it's safe to include a shared script (like nav.js or theme.js) on every page without guarding inclusion per-route.

Scripts (public/js/)

FilePurpose
nav.jsHamburger menu open/close, including outside-click and Escape to close.
theme.jsLight/dark mode toggle button; persists the choice to localStorage.
about.jsOpens/closes the "About" info popup (build info, version).
muscleDiagram.jswindow.buildMuscleDiagram(primary, secondary) — builds two inline front/back-body SVGs with muscle regions highlighted, from a hardcoded muscle-name-to-SVG-region map. No external image assets — the body outlines are drawn entirely in code.
exercisePopup.jswindow.openExercisePopup(exercise) and window.openPlanUsagePopup(name, plans) — the shared modal for viewing an exercise's full detail (built on top of muscleDiagram.js) or seeing which plans reference it.
exerciseChart.jswindow.buildExerciseChart(container, data, type) — renders a Chart.js line chart of an exercise's logged reps/weight/duration history, reading theme colors from CSS custom properties so it matches light/dark mode automatically.
license.jsThe public /license page — handles both the trial-request form (posts to /api/license/trial, then swaps in a "check your email" message and reveals the key-entry form) and the activation form (posts to /api/license/activate, redirects home on success).
adminLicense.jsThe admin license screen's activation form — same /api/license/activate endpoint, reloads the page on success to reflect the newly-cached status.
planBuilder.jsThe plan create/edit UI. Maintains an in-memory days array of exercises and supersets, serializes it into a hidden daysJson field on form submit, and includes the exercise picker modal plus an inline "quick-create exercise" flow (POST /exercises/api/quick-create) so you never have to leave the plan you're building.
dayEditor.jsThe "Edit Day" modal available mid-workout to a plan's owner or an admin — add/remove/reorder exercises or supersets for the day currently being executed. Saves via PUT /plans/:id/days/:dayIdx and hands the updated day back to workout.js via window.WorkoutExec.refreshDay. Shares its exercise-picker pattern with planBuilder.js.
workout.jsThe guided workout execution state machine (idle → exercise → rest → complete) — the largest script in the app. Handles both regular exercises (sequential sets) and supersets (rounds across multiple exercises); tracks elapsed time; autosaves progress to POST /plans/:id/save-progress; builds completed-set log entries split by distinct rep count (mirroring how plansController.js#complete and ExerciseHistory's bucketing work server-side); supports ad-hoc "Add Set" (with an option to save it back to the plan permanently); an Auto-Advance preference persisted to localStorage; and resuming or discarding an in-progress WorkoutProgress document.

Styles (public/scss/)

Hand-rolled — no CSS framework. Structured as Sass partials compiled into one stylesheet:

  • abstracts/_variables.scss — shared Sass variables.
  • layout/_base.scss — base layout and the CSS custom properties that a user's themeColors overrides (see Data Model → User) target directly, so per-user appearance customization works by overriding CSS variables rather than generating per-user stylesheets.
  • components/*.scss — one partial per UI area (_admin, _buttons, _cards, _dashboard, _exercise-chart, _forms, _muscle-viz, _nav, _planbuilder, _profile, _timer, _about-popup), all pulled together by main.scss.