feat show an in-progress card on Home

While a workout is in progress, Home shows a single card that names the workout and links to the Current Workout tab, instead of rendering the workout form at the root. The middle navigation action already reads 'Current workout' in this mode; the card is the matching Home affordance.

Commit
61d82ffd3a36c85e897a89d35e31c8c8d758cd67
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
ENHANCEMENTS.org
index 9bd9f377..2ebb738e 100644..100644
@@ -34,7 +34,7 @@
34 34 Use Courier Prime Mono only for numerical inputs and outputs, and eventually for tabular data.
35 35 ** DONE Hide sign-out on mobile
36 36 Do not show the sign-out button on mobile.
37 Removed: ** TODO Show an in-progress workout card on Home
37 Added: ** DONE Show an in-progress workout card on Home
38 38 When the user is logging a current workout, show a Home card that indicates the workout is in progress and links to the Current Workout tab.
39 39 ** TODO Harmonize UI corner radii
40 40 Use uniformly rounded corners for all buttons, cards, and other UI elements.
@@ -42,3 +42,7 @@
42 42 When cancelling a workout, always leave the current workout view without showing an invalid-form response. Save the workout log as-is for later editing, then redirect the user to Home.
43 43 ** TODO Remove thick black bars from mobile bottom navigation
44 44 Remove the thick black bars visible in the mobile bottom navigation.
45 Added: ** TODO Add a sticky workout timer bar
46 Added: When logging a workout, show a sticky bar at the top of the screen with a workout timer.
47 Added: ** TODO Replace the exercise button group with a dropdown
48 Added: Use a dropdown menu to select the exercise instead of the exercise button group.
lib/web/assets/hito.css
index c96f5515..6a881a9f 100644..100644
@@ -290,6 +290,26 @@
290 290
291 291 .row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem; }
292 292
293 Added: /* The Home card shown while a workout is in progress. A full-width pressable
294 Added: panel that returns the user to the current workout. It reads as a raised
295 Added: surface with an oxblood accent, echoing the page surface. */
296 Added: .in-progress-card {
297 Added: display: block;
298 Added: margin: 1.25rem 0 0;
299 Added: border: 1px solid var(--rule-strong);
300 Added: border-left: 4px solid var(--oxblood);
301 Added: background: var(--paper);
302 Added: border-radius: 0.3rem;
303 Added: padding: 1rem 1.1rem;
304 Added: color: var(--ink);
305 Added: text-decoration: none;
306 Added: }
307 Added: .in-progress-card:hover {
308 Added: background: #ece4d5;
309 Added: }
310 Added: .in-progress-card h1 { margin: 0.35rem 0; }
311 Added: .in-progress-card p { margin: 0; }
312 Added:
293 313 /* The exercise button group. Server-rendered links, one per prescription slot,
294 314 carrying the slot in a query parameter. The active button reads as pressed; a
295 315 recorded slot is marked with a check. Buttons stack vertically and fill the
lib/web/handlers.ml
index d7edcff4..e144afda 100644..100644
@@ -223,10 +223,10 @@
223 223 let page t trainee request =
224 224 Service.in_progress t.service trainee.Trainee.id >>= function
225 225 | Some workout ->
226 Removed: Lwt.return
227 Removed: (Pages.workout request ~trainee ~record_id:None
228 Removed: ~active_slot:(active_slot request workout)
229 Removed: workout)
226 Added: let workout_name =
227 Added: Prescription.Workout.name (Evidence.Workout.prescription workout)
228 Added: in
229 Added: Lwt.return (Pages.workout_in_progress request ~trainee ~workout_name)
230 230 | None -> (
231 231 Service.active_routine t.service trainee.Trainee.id >>= function
232 232 | None ->
lib/web/pages.ml
index 7e785672..3dd02ea0 100644..100644
@@ -383,6 +383,26 @@
383 383 ]
384 384 @ gate)
385 385
386 Added: (* Home while a workout is in progress. Rather than the recovery gate or the
387 Added: routine chooser, Home shows a single card: the workout is under way and one
388 Added: tap returns to it. The middle navigation action already reads "Current
389 Added: workout" here, and this card is the matching Home affordance. *)
390 Added: let workout_in_progress request ~trainee ~workout_name =
391 Added: html_page ~trainee ~request ~active:"home" ~logging:true "Home"
392 Added: [
393 Added: tag "a"
394 Added: [
395 Added: class_ "in-progress-card";
396 Added: href Routes.workout;
397 Added: Dream_html.attr "data-hito-app-link";
398 Added: ]
399 Added: [
400 Added: tag "p" [ class_ "eyebrow" ] [ txt "Workout in progress" ];
401 Added: tag "h1" [] [ txt "%s" workout_name ];
402 Added: tag "p" [] [ txt "Return to the current workout to keep logging." ];
403 Added: ];
404 Added: ]
405 Added:
386 406 let routine request ?(logging = false) ~trainee routine =
387 407 html_page ~trainee ~request ~active:"routine" ~logging "Routine"
388 408 [
lib/web/pages.mli
index 10e5f218..d6c28221 100644..100644
@@ -24,6 +24,11 @@
24 24 readiness:Recovery.readiness ->
25 25 page
26 26
27 Added: val workout_in_progress :
28 Added: Dream.request -> trainee:Trainee.t -> workout_name:string -> page
29 Added: (** The Home card shown while a workout is in progress. Links to the current
30 Added: workout so it stays one tap away. *)
31 Added:
27 32 val routine :
28 33 Dream.request ->
29 34 ?logging:bool ->
test/test_web.ml
index 546c097e..4ef4bd41 100644..100644
@@ -274,7 +274,16 @@
274 274 (contains ~substring:">Current workout</a>" logging);
275 275 Alcotest.(check bool)
276 276 "drops the routine action while logging" false
277 Removed: (contains ~substring:">Routine</a>" logging) );
277 Added: (contains ~substring:">Routine</a>" logging);
278 Added: (* Home shows an in-progress card that links to the current
279 Added: workout, rather than the recovery gate or the workout form. *)
280 Added: let home_logging = body (get c "/") in
281 Added: Alcotest.(check bool)
282 Added: "home shows the in-progress card while logging" true
283 Added: (contains ~substring:"in-progress-card" home_logging);
284 Added: Alcotest.(check bool)
285 Added: "the in-progress card links to the current workout" true
286 Added: (contains ~substring:"href=\"/workout\"" home_logging) );
278 287 ( "only the app shell carries the page class, so active state is single",
279 288 `Quick,
280 289 fun () ->