[OCaml] High Intensity Training Online
feat Replace routine table with accordions
Present each workout as a summary/description accordion. The summary names the workout, and the description lists its exercises with numeric rep bands. Remove the literal "reps" label from displayed values while keeping the exercise and prescription data unchanged.
lib/web/assets/hito.css
@@ -894,38 +894,54 @@
894
894
}
895
895
li li { color: var(--muted-ink); font-size: 0.92rem; }
896
896
897
Removed:
/* The routine's workouts as a basic table: one row per workout of the cycle,
898
Removed:
with its name, prescribed-stimuli count, and the prescription. The row header
899
Removed:
names the workout; the prescription cell lists each stimulus. */
900
Removed:
.routine-table {
901
Removed:
width: 100%;
897
Added:
/* The routine's workouts as summary/description accordions. Each summary
898
Added:
names one workout. Its description lists the prescribed exercises and numeric
899
Added:
rep bands. */
900
Added:
.routine-accordions {
901
Added:
display: grid;
902
Added:
gap: 0.65rem;
902
903
margin: 1.25rem 0 0;
903
Removed:
border-collapse: collapse;
904
904
}
905
Removed:
906
Removed:
.routine-table th,
907
Removed:
.routine-table td {
908
Removed:
padding: 0.6rem 0.7rem;
909
Removed:
border-bottom: 1px solid var(--rule);
910
Removed:
text-align: left;
911
Removed:
vertical-align: top;
905
Added:
.routine-accordion {
906
Added:
border: 1px solid var(--rule);
907
Added:
border-radius: var(--radius);
908
Added:
background: var(--paper-raised);
909
Added:
overflow: hidden;
912
910
}
913
Removed:
914
Removed:
.routine-table thead th {
911
Added:
.routine-accordion > summary {
912
Added:
padding: 0.8rem 1rem;
915
913
color: var(--ink);
916
Removed:
font: 700 var(--font-size-small)/1.2 var(--sans);
917
Removed:
letter-spacing: 0.02em;
918
Removed:
border-bottom: 2px solid var(--rule-strong);
919
Removed:
}
920
Removed:
921
Removed:
.routine-table tbody th {
922
Removed:
color: var(--ink);
923
914
font-weight: 700;
915
Added:
cursor: pointer;
916
Added:
list-style: none;
924
917
}
925
Removed:
926
Removed:
.routine-table ul {
927
Removed:
margin: 0;
928
Removed:
padding-left: 1.1rem;
918
Added:
.routine-accordion > summary::-webkit-details-marker { display: none; }
919
Added:
.routine-accordion > summary::marker { content: ""; }
920
Added:
.routine-accordion > summary::after {
921
Added:
float: right;
922
Added:
content: "+";
923
Added:
color: var(--muted-ink);
924
Added:
}
925
Added:
.routine-accordion[open] > summary::after { content: "−"; }
926
Added:
.routine-description {
927
Added:
padding: 0 1rem 0.8rem;
928
Added:
border-top: 1px solid var(--rule);
929
Added:
}
930
Added:
.routine-description ul {
931
Added:
margin: 0.7rem 0 0;
932
Added:
padding-left: 1.2rem;
933
Added:
}
934
Added:
.routine-description li {
935
Added:
display: flex;
936
Added:
justify-content: space-between;
937
Added:
gap: 1rem;
938
Added:
padding: 0.35rem 0;
939
Added:
}
940
Added:
.routine-exercise { color: var(--ink); }
941
Added:
.routine-reps {
942
Added:
color: var(--muted-ink);
943
Added:
font-family: var(--mono);
944
Added:
white-space: nowrap;
929
945
}
930
946
931
947
@media (max-width: 42rem) {
lib/web/handlers.ml
@@ -422,7 +422,7 @@
422
422
Prescription.Rep_range.bounds
423
423
(Prescription.Stimulus.rep_range prescription)
424
424
in
425
Removed:
Printf.sprintf "%d-%d reps" min_reps max_reps
425
Added:
Printf.sprintf "%d-%d" min_reps max_reps
426
426
427
427
let routine_view r : View_model.Routine.t =
428
428
{
lib/web/pages.ml
@@ -551,54 +551,33 @@
551
551
html_page ~viewer ~request ~active:"routine" ~logging "Routine"
552
552
[
553
553
tag "h1" [] [ txt "%s" vm.name ];
554
Removed:
tag "table"
555
Removed:
[ class_ "routine-table" ]
556
Removed:
[
557
Removed:
tag "thead" []
558
Removed:
[
559
Removed:
tag "tr" []
560
Removed:
[
561
Removed:
tag "th"
562
Removed:
[ Dream_html.string_attr "scope" "col" ]
563
Removed:
[ txt "Workout" ];
564
Removed:
tag "th"
565
Removed:
[ Dream_html.string_attr "scope" "col" ]
566
Removed:
[ txt "Exercise" ];
567
Removed:
tag "th"
568
Removed:
[ Dream_html.string_attr "scope" "col" ]
569
Removed:
[ txt "Reps" ];
570
Removed:
];
571
Removed:
];
572
Removed:
(* One sub-row per prescribed exercise. The workout name spans its
573
Removed:
exercises through a row-group heading, so each exercise gets its
574
Removed:
own name and rep-band cells and no stimuli count is shown. *)
575
Removed:
tag "tbody" []
576
Removed:
(List.concat_map
577
Removed:
(fun (workout : View_model.Routine.workout) ->
578
Removed:
List.mapi
579
Removed:
(fun index (exercise : View_model.Routine.exercise) ->
580
Removed:
let workout_cell =
581
Removed:
if index = 0 then
582
Removed:
[
583
Removed:
tag "th"
584
Removed:
[
585
Removed:
Dream_html.string_attr "scope" "rowgroup";
586
Removed:
Dream_html.string_attr "rowspan" "%d"
587
Removed:
(List.length workout.exercises);
588
Removed:
]
589
Removed:
[ txt "%s" workout.name ];
590
Removed:
]
591
Removed:
else []
592
Removed:
in
593
Removed:
tag "tr" []
594
Removed:
(workout_cell
595
Removed:
@ [
596
Removed:
tag "td" [] [ txt "%s" exercise.name ];
597
Removed:
tag "td" [] [ txt "%s" exercise.reps ];
598
Removed:
]))
599
Removed:
workout.exercises)
600
Removed:
vm.workouts);
601
Removed:
];
554
Added:
tag "div"
555
Added:
[ class_ "routine-accordions" ]
556
Added:
(List.map
557
Added:
(fun (workout : View_model.Routine.workout) ->
558
Added:
tag "details"
559
Added:
[ class_ "routine-accordion" ]
560
Added:
[
561
Added:
tag "summary" [] [ txt "%s" workout.name ];
562
Added:
tag "div"
563
Added:
[ class_ "routine-description" ]
564
Added:
[
565
Added:
tag "ul" []
566
Added:
(List.map
567
Added:
(fun (exercise : View_model.Routine.exercise) ->
568
Added:
tag "li" []
569
Added:
[
570
Added:
tag "span"
571
Added:
[ class_ "routine-exercise" ]
572
Added:
[ txt "%s" exercise.name ];
573
Added:
tag "span"
574
Added:
[ class_ "routine-reps" ]
575
Added:
[ txt "%s" exercise.reps ];
576
Added:
])
577
Added:
workout.exercises);
578
Added:
];
579
Added:
])
580
Added:
vm.workouts);
602
581
]
603
582
604
583
let error_for ~input_id (field : string) (errors : (string * string) list) =
lib/web/view_model.ml
@@ -50,8 +50,8 @@
50
50
type workout = { name : string; exercises : exercise list }
51
51
52
52
type t = { name : string; workouts : workout list }
53
Removed:
(** A routine as the table renders it: names, rep bands, and grouping only. No
54
Removed:
[Prescription] entity. *)
53
Added:
(** A routine as the accordion descriptions render it: names, numeric rep
54
Added:
bands, and workout grouping only. No [Prescription] entity. *)
55
55
end
56
56
57
57
module Routine_choice = struct