feat preview the upcoming workout's exercises on the card

Show the prescribed exercises of the next workout beneath its name on the Home card, so the trainee sees what is coming rather than just a workout label. Adds next_exercises to the Home view model, phrased the same way as the routine page.

Commit
1204a3c10600b65046f43a077cf07b6e23519c4c
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/presenter/pages_routine.ml
index edfbddfd..50d00445 100644..100644
@@ -139,6 +139,13 @@
139 139 ([
140 140 tag "h1" [] [ txt "%s" vm.routine_name ];
141 141 tag "p" [ class_ "ledger-meta" ] [ txt "Next: %s" vm.next_workout ];
142 Added: (if vm.next_exercises = [] then txt ""
143 Added: else
144 Added: tag "ul"
145 Added: [ class_ "next-workout-preview" ]
146 Added: (List.map
147 Added: (fun name -> tag "li" [] [ txt "%s" name ])
148 Added: vm.next_exercises));
142 149 tag "p" [ class_ "ledger-meta" ] [ txt "%s" status ];
143 150 ]
144 151 @ gate)
lib/presenter/view_model.ml
index ed406cfc..56e1b0c8 100644..100644
@@ -67,6 +67,9 @@
67 67 routine_id : string; (** For the begin/override forms. *)
68 68 routine_name : string;
69 69 next_workout : string;
70 Added: next_exercises : string list;
71 Added: (** The prescribed exercises of the upcoming workout, phrased, in order.
72 Added: Shown on the card to preview what is coming. *)
70 73 gate : gate;
71 74 }
72 75 (** The overview while no workout is in progress. The recovery policy has
lib/web/assets/hito.css
index 1552e21d..90d4a644 100644..100644
@@ -360,6 +360,15 @@
360 360 font-variant-numeric: tabular-nums;
361 361 }
362 362
363 Added: /* The upcoming workout's exercises, previewed on the Home card. A tight ledger
364 Added: of what is coming, so the next session reads at a glance. */
365 Added: .next-workout-preview {
366 Added: margin: 0.5rem 0 1rem;
367 Added: padding-left: 1.1rem;
368 Added: color: var(--ink);
369 Added: }
370 Added: .next-workout-preview li { padding: 0.2rem 0; }
371 Added:
363 372 fieldset {
364 373 margin: 1rem 0 0;
365 374 padding: 0.875rem;
lib/web/handlers_overview.ml
index e98729d9..4235335e 100644..100644
@@ -51,6 +51,8 @@
51 51 routine_id = (routine :> string);
52 52 routine_name;
53 53 next_workout = Prescription.Workout.name next;
54 Added: next_exercises =
55 Added: List.map exercise_string (Prescription.Workout.stimuli next);
54 56 gate =
55 57 (match readiness with
56 58 | Recovery.Ready -> View_model.Home.Ready
test/web/overview.ml
index 7f1091c4..c04c970d 100644..100644
@@ -33,6 +33,22 @@
33 33 Alcotest.(check int)
34 34 "the redirected GET is 200" 200
35 35 (status (get c "/")) );
36 Added: ( "the home card previews the upcoming workout's exercises",
37 Added: `Quick,
38 Added: fun () ->
39 Added: let c = client () in
40 Added: let _ = sign_in_new c in
41 Added: let token = Option.get (csrf_token (body (get c "/"))) in
42 Added: let _ = post c "/routines/ideal/select" [ ("dream.csrf", token) ] in
43 Added: let page = body (get c "/") in
44 Added: Alcotest.(check bool)
45 Added: "the exercise preview list is present" true
46 Added: (Option.is_some
47 Added: (index_from ~needle:"next-workout-preview" page 0));
48 Added: (* Day 1 opens with the flyes/incline-press pre-exhaust pair. *)
49 Added: Alcotest.(check bool)
50 Added: "an upcoming exercise is shown" true
51 Added: (Option.is_some (index_from ~needle:"Incline Presses" page 0)) );
36 52 ( "the routine page is served once a routine is selected",
37 53 `Quick,
38 54 fun () ->