Commit Graph

20 Commits

Author SHA1 Message Date
Alexander e7293ac496 feat(fitness/active): rail + focus card layout
Redesign the active-workout page around a left-rail timeline and a
focus card on the right. The rail owns the workout title, pause,
elapsed time, sync indicator, progress bar, and a reorderable chip
per exercise (drag to reorder, × to delete, starting-weight hint so
you know what to rack, green checkmark when complete). Main stage
holds a hero focus card for the active exercise plus its SetTable.

- New WorkoutRail.svelte and WorkoutFocusCard.svelte
- Active exercise pinned to top of the scrollable rail (mobile only)
- Desktop: rail grows freely; mobile: compact vertical stack
- Finish + cancel share one row; cancel is a ghost action
- Drop the old sticky bottombar; its controls moved into the rail
- ExerciseName gains `plain` prop to opt out of the detail link
- Active workout route joins the 1400px max-width whitelist
2026-04-23 22:35:05 +02:00
Alexander 504a6f410f style(fitness/exercises): wrap muscle filter in card, widen layout
Align the muscle picker with the site card language (matches
/fitness/check-in and /fitness/stats) and unlock the full desktop
width via the 1400px container used by nutrition/check-in.

- Sidebar card layout at ≥900px (200/620 grid, sticky)
- Larger sidebar at ≥1180px (460/720) with figures uncapped
- Tablet tier (900–1179px) stacks figures vertically inside the card
- Below 900px the card sits on top of the content column
2026-04-23 21:33:05 +02:00
Alexander abb59f46a6 perf: Lucide subpath imports to split 748 KB icon chunk
Barrel `from '@lucide/svelte'` imports pulled every referenced icon into
one shared 748 KB client chunk. Switch every call site to per-icon
subpaths (`@lucide/svelte/icons/<kebab-name>`) so Vite tree-shakes each
icon independently. Also logs the TODO list for the perf audit so we
don't lose track.

- 46 files, 106 unique icons
- single `Minus as MinusIcon` alias preserved
- Lucide-internal aliases (`AlertTriangle`, `BarChart3`) resolve through
  Lucide's own re-export shims; no behavioral change
2026-04-23 14:52:39 +02:00
Alexander 9a15779a44 feat(fitness): rename Measure route to Check-in / Erfassung (NotebookPen icon)
CI / update (push) Successful in 3m47s
Route slugs and nav label rename only — storage, API endpoints
(`/api/fitness/measurements`), and the `BodyMeasurement` Mongo model
keep their technical names.

- `/fitness/measure` → `/fitness/check-in` (EN)
- `/fitness/messen` → `/fitness/erfassung` (DE)
- Folder `[measure=fitnessMeasure]` → `[checkin=fitnessCheckIn]`
  (git rename; history preserved).
- Param matcher `fitnessMeasure.ts` → `fitnessCheckIn.ts`, accepts
  `check-in` / `erfassung`.
- `fitnessSlugs(lang).measure` and `fitnessLabels(lang).measure` code
  keys are unchanged — value returns "check-in"/"erfassung" and
  "Check-in"/"Erfassung" respectively, so no call site needs touching.
- slugMap language-detection updated to `erfassung ↔ check-in`.
- Service-worker cache list + the layout regex that gates the wider
  content width now reference the new slugs.
- Nav icon swapped from `Ruler` to `NotebookPen` — reads as "logging
  entries" and spans weight / composition / period better.

Bookmarks on the old URLs will 404; no redirect added.
2026-04-23 14:12:54 +02:00
Alexander e9ebe492fb chore: clear all svelte-check errors and warnings repo-wide (454 → 0)
Mostly additive JSDoc/TS type annotations and null/undefined guards —
no runtime behavior changes. Starting baseline: 454 errors + 1 warning
across ~50 files. After: 0/0, build is clean.

Highlights:
- Duplicate object-literal keys fixed: 11 in cospendI18n.ts, 2 in
  fitnessI18n.ts (dropped second `loading`; renamed `protein_per_kg`
  stats-card label to reuse `protein`), 1 in shoppingCategorizer.
- `bind:this` state declared with `HTMLDivElement | null` across
  DatePicker + Muscle{Map,Filter,Heatmap}.
- SaveFab's required `onclick` made optional (type="submit" handles
  form submission in most callsites).
- Implicit any on ~200 callback parameters replaced with concrete
  JSDoc/TS types. Chart.js generics and one mongoose query chain cast
  are the only `any` / `unknown as any[]` uses introduced.
- Stats history discriminated union (`paired: true | false`) lets the
  template narrow `series` and `stats` properly.
- Food page server guards use `throw new Error('unreachable')` after
  `errorWithVerse(...)` awaits so TS narrows `entry`/`recipe`/`meal`
  below. Same pattern applied to cospend payments, calendar detail,
  and prayers server loads.
- Mongo `Date → string` serialization helper in cospend list so
  `IShoppingItem[]` fits `ShoppingItem[]` at the boundary.
- Recipe category/tag pages use a local `RecipeItem` alias (derived
  from `BriefRecipeType`) so `rand_array`/filter callbacks type.
- `web-haptics/svelte` has no bundled `.d.ts`; added a local
  `@ts-expect-error` shim on the one import line.

Files touched: ~50 across fitness, cospend, faith, recipe, and shared
lib components / API routes.
2026-04-23 13:12:07 +02:00
Alexander def176db4d feat(fitness): redesign measure page with muscle-man map, inline edit, and desktop 2-col layout
- Weight + body fat cards share a unified .metric-card component with wheel
  + keyboard (Arrow/Shift+Arrow) stepping. Side-by-side on tablet and up.
- Replaced body-parts accordion with a prominent card showing a cropped
  muscle-front silhouette and overlay dots/bands marking which regions
  have measurements. Shoulders + chest render as dotted tape-measure
  bands; other parts as dots. "Last measured" now relative (N days ago).
- Desktop layout: .main-col (form + period tracker) left, history on
  right. Two columns center together at wider widths instead of drifting
  apart. Fitness layout detects measure index and bumps max-width to
  1400px, matching nutrition.
- Inline history edit: pencil swaps the row for a compact date/kg/%
  form (Enter saves, Escape cancels) via PUT /api/fitness/measurements.
  Full-edit link preserved for body-parts tweaks.
- Body-parts history heading renamed to "Past measurements" /
  "Frühere Messungen" to avoid collision with the period tracker's
  own history.
- "Profil bearbeiten" moved to the top-left of the main column.
- Same-sides toggle in the body-parts flow now uses the shared Toggle
  component.
2026-04-23 11:08:41 +02:00
Alexander 9c119b8df2 feat(fitness): add guided body-parts measurement wizard
New /fitness/measure/body-parts route with step-by-step tape-measure
flow, per-step tips, L/R paired inputs, inline history chart, and
review-before-save summary. Measure page replaces the old body-parts
accordion with a launch button. Fitness layout goes full-bleed and
hides the site footer for this route via a :has() attribute selector,
and the desktop 3-column grid now extends rail and side panel up past
the floating nav while the middle column compensates with padding.
2026-04-20 16:28:09 +02:00
Alexander 768c09eeb1 feat: use path-based date URLs for nutrition page
Migrate /fitness/nutrition?date=YYYY-MM-DD to /fitness/nutrition/YYYY-MM-DD
using SvelteKit optional param [[date=fitnessDate]]. Replace date nav
buttons with anchor tags for native browser navigation. Today resolves to
the clean /fitness/nutrition path without a date segment.
2026-04-10 08:47:48 +02:00
Alexander d8ae18ec5a fix: SSR improvements for nutrition desktop layout
Move favorites and recent foods fetching to server load (parallel with
existing queries). Replace client-side $effect DOM manipulation for
fitness-content max-width with reactive CSS variable in layout via
route detection. Removes client-side fetch-on-mount pattern.
2026-04-08 20:42:46 +02:00
Alexander 1fa2e350d7 feat: major dependency upgrades, remove Redis, fix mongoose 9 types
Dependencies upgraded:
- svelte 5.38→5.55, @sveltejs/kit 2.37→2.56, adapter-node 5.3→5.5
- mongoose 8→9, sharp 0.33→0.34, typescript 5→6
- lucide-svelte → @lucide/svelte 1.7 (Svelte 5 native package)
- vite 7→8 with rolldown (build time 33s→14s)
- Removed terser (esbuild/oxc default minifier is 20-100x faster)

Infrastructure:
- Removed Redis/ioredis cache layer — MongoDB handles caching natively
- Deleted src/lib/server/cache.ts and all cache.get/set/invalidate usage
- Removed redis-cli from deploy workflow, Redis env vars from .env.example

Mongoose 9 migration:
- Replaced deprecated `new: true` with `returnDocument: 'after'` (16 files)
- Fixed strict query filter types for ObjectId/paymentId fields
- Fixed season param type (string→number) in recipe API
- Removed unused @ts-expect-error in WorkoutSession model
2026-04-06 12:21:26 +02:00
Alexander 23b45abc5a feat: add nutrition/food logging to fitness section
Daily food log with calorie and macro tracking against configurable diet
goals (presets: WHO balanced, cut, bulk, keto, etc.). Includes USDA/BLS
food search with portion-based units, favorite ingredients, custom
reusable meals, per-food micronutrient detail pages, and recipe-to-log
integration via AddToFoodLogButton. Extends FitnessGoal with nutrition
targets and adds birth year to user profile for BMR calculation.
2026-04-04 14:34:47 +02:00
Alexander 68e3a3e1e9 fix: precache __data.json for offline client-side navigation
The fitness pages were only precaching HTML shells, but SvelteKit
client-side navigation fetches __data.json instead. Without these
cached, navigating to workout/training while offline would fail.
2026-03-23 22:28:39 +01:00
Alexander 19ac60c6f2 fitness: add offline support with session queue and shell caching
Cache fitness page shells and data routes in the service worker so
pages load offline. Queue finished workouts in IndexedDB when the
POST fails and auto-flush them on reconnect. Show an offline banner
on the completion screen so the user knows their workout will sync.
2026-03-23 22:15:42 +01:00
Alexander 0fae3d6d14 fitness: add bilingual EN/DE support for all fitness routes and components
Use SvelteKit param matchers for bilingual URL routing (e.g. /fitness/stats
and /fitness/statistik). Add centralized i18n module with translation
dictionary, language detection from URL, and path conversion utilities.
Translate all UI text across pages, components, and navigation.
2026-03-22 21:25:03 +01:00
Alexander bc6096b44e fitness: move workout controls to FAB, track rest timer position in store 2026-03-22 19:44:25 +01:00
Alexander de55e51301 fitness: add per-exercise metrics, cardio support, and stats page
- Add metrics system (weight/reps/rpe/distance/duration) per exercise type
  so cardio exercises show distance+duration instead of weight+reps
- Add 8 new cardio exercises: swimming, hiking, rowing outdoor, cycling
  outdoor, elliptical, stair climber, jump rope, walking
- Add bilateral flag to dumbbell exercises for accurate tonnage calculation
- Make SetTable, SessionCard, history detail, template editor, and exercise
  stats API all render/compute dynamically based on exercise metrics
- Rename Profile to Stats with lifetime cards: workouts, tonnage, cardio km
- Move route /fitness/profile -> /fitness/stats, API /stats/profile -> /stats/overview
2026-03-19 18:57:52 +01:00
Alexander dff67c7059 fitness: add multi-device workout sync via SSE and rest timer improvements
Enables real-time workout synchronization across devices using
Server-Sent Events and an ephemeral MongoDB document (24h TTL).
Rest timers now use absolute timestamps instead of interval-based
countdown for accurate cross-device sync. Adds +/-30s rest timer
adjust buttons.
2026-03-19 09:44:24 +01:00
Alexander c5e3719a0c fitness: add complete fitness tracker frontend
- 5-tab layout (Profile, History, Workout, Exercises, Measure) with shared header nav
- Workout system: template CRUD, active workout on /fitness/workout/active with localStorage persistence, pause/resume timer, rest timer, RPE input
- Shared workout singleton (getWorkout) so active workout state is accessible across all fitness routes
- Floating workout FAB indicator on all /fitness routes when workout is active
- AddActionButton component for button-based FABs (measure + template creation)
- Profile page with workouts-per-week bar chart and weight line chart with SMA trend line + ±1σ confidence band
- Exercise detail with history, charts, and records tabs using static exercise data
- Session history with grouped-by-month list, session detail with stats/PRs
- Body measurements with latest values, body part display, add form
- Card styling matching rosary/prayer route patterns (accent-dark, nord5 light, box-shadow, hover lift)
- FitnessChart: fix SSR hang by moving Chart.register to client-side, remove redundant $effect
- Exercise API: use static in-repo data instead of empty MongoDB collection
- Workout finish: include exercise name for WorkoutSession model validation
2026-03-19 08:17:55 +01:00
Alexander 69e5b80795 fix: resolve Svelte 5 migration warnings and improve accessibility
- Fix state_referenced_locally warnings by extracting initial values to constants
- Remove unused CSS selectors (subheading, header-actions, back-actions)
- Add ARIA roles and keyboard handlers to settlement options
- Add a11y ignore comment for custom checkbox implementation
2026-01-10 17:05:39 +01:00
Alexander 283aaa19d9 refactor: consolidate formatting utilities and add testing infrastructure
- Replace 8 duplicate formatCurrency functions with shared utility
- Add comprehensive formatter utilities (currency, date, number, etc.)
- Set up Vitest for unit testing with 38 passing tests
- Set up Playwright for E2E testing
- Consolidate database connection to single source (src/utils/db.ts)
- Add auth middleware helpers to reduce code duplication
- Fix display bug: remove spurious minus sign in recent activity amounts
- Add path aliases for cleaner imports ($utils, $models)
- Add project documentation (CODEMAP.md, REFACTORING_PLAN.md)

Test coverage: 38 unit tests passing
Build: successful with no breaking changes
2025-11-18 15:24:22 +01:00