[OCaml] High Intensity Training Online
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.
Changed files
ENHANCEMENTS.org
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 () ->