[OCaml] High Intensity Training Online
feat Add workout date and refine type
Changed files
lib/presenter/pages_workout.ml
@@ -356,7 +356,10 @@
356
356
Dream_html.attr "data-hito-workout-content";
357
357
]
358
358
else [])
359
Removed:
([ tag "h1" [] [ txt "%s" vm.name ] ]
359
Added:
([
360
Added:
tag "h1" [] [ txt "%s" vm.name ];
361
Added:
tag "h2" [ class_ "workout-date" ] [ txt "%s" vm.date ];
362
Added:
]
360
363
@ slots @ complete_note @ finish_section
361
364
@
362
365
if enhanced then
lib/presenter/view_model.ml
@@ -131,6 +131,8 @@
131
131
132
132
type t = {
133
133
name : string; (** The workout (prescription) name, for the page title. *)
134
Added:
date : string;
135
Added:
(** Workout start date, pre-formatted as "day month year" in UTC. *)
134
136
slots : slot list;
135
137
active_slot : int;
136
138
started_at_unix : int; (** Workout start, for the elapsed timer. *)
lib/web/assets/hito.css
@@ -930,6 +930,12 @@
930
930
.in-progress h1 { margin: 0.35rem 0; }
931
931
.in-progress p { margin: 0; }
932
932
933
Added:
.workout-date {
934
Added:
margin: 0 0 1.25rem;
935
Added:
color: var(--ink);
936
Added:
font: 500 var(--font-size-h2)/1.25 var(--sans);
937
Added:
}
938
Added:
933
939
/* The exercise accordion uses one <details> per prescription slot. They share
934
940
a [name], so the browser keeps exactly one open without script. The summary
935
941
holds the slot's level-two heading and a plus or minus marker. The heading
@@ -969,6 +975,9 @@
969
975
align-items: baseline;
970
976
gap: 0.6rem;
971
977
margin: 0;
978
Added:
font-size: var(--font-size-h3);
979
Added:
line-height: 1.25;
980
Added:
font-weight: 600;
972
981
}
973
982
.slot-heading .slot-number { color: var(--muted-ink); }
974
983
.slot-heading .slot-label-done {
lib/web/handlers_kit.ml
@@ -83,6 +83,32 @@
83
83
Printf.sprintf "%04d-%02d-%02d" (tm.Unix.tm_year + 1900)
84
84
(tm.Unix.tm_mon + 1) tm.Unix.tm_mday
85
85
86
Added:
let ordinal_suffix day =
87
Added:
if day mod 100 >= 11 && day mod 100 <= 13 then "th"
88
Added:
else match day mod 10 with 1 -> "st" | 2 -> "nd" | 3 -> "rd" | _ -> "th"
89
Added:
90
Added:
let month_name = function
91
Added:
| 1 -> "January"
92
Added:
| 2 -> "February"
93
Added:
| 3 -> "March"
94
Added:
| 4 -> "April"
95
Added:
| 5 -> "May"
96
Added:
| 6 -> "June"
97
Added:
| 7 -> "July"
98
Added:
| 8 -> "August"
99
Added:
| 9 -> "September"
100
Added:
| 10 -> "October"
101
Added:
| 11 -> "November"
102
Added:
| 12 -> "December"
103
Added:
| _ -> ""
104
Added:
105
Added:
let utc_long_date seconds =
106
Added:
let tm = Unix.gmtime (float_of_int seconds) in
107
Added:
let day = tm.Unix.tm_mday in
108
Added:
Printf.sprintf "%d%s %s %d" day (ordinal_suffix day)
109
Added:
(month_name (tm.Unix.tm_mon + 1))
110
Added:
(tm.Unix.tm_year + 1900)
111
Added:
86
112
let utc_datetime seconds =
87
113
let tm = Unix.gmtime (float_of_int seconds) in
88
114
Printf.sprintf "%04d-%02d-%02d %02d:%02d" (tm.Unix.tm_year + 1900)
@@ -449,6 +475,10 @@
449
475
in
450
476
{
451
477
name = Prescription.Workout.name prescription;
478
Added:
date =
479
Added:
utc_long_date
480
Added:
(Recovery.timestamp_to_unix_seconds
481
Added:
(Evidence.Workout.started_at workout));
452
482
slots = List.mapi slot_view prescribed_slots;
453
483
active_slot;
454
484
started_at_unix =
test/web/workout.ml
@@ -8,7 +8,8 @@
8
8
( "a signed-in trainee selects a routine and begins a workout",
9
9
`Quick,
10
10
fun () ->
11
Removed:
let c, repo = client_with_repo () in
11
Added:
let c, now, repo = clocked_client () in
12
Added:
now := day 10;
12
13
let _ = register c ~username:"lifter" ~password:"heavyduty1" in
13
14
let trainee = the_trainee repo ~username:"lifter" in
14
15
let token = Option.get (csrf_token (body (get c "/"))) in
@@ -30,6 +31,11 @@
30
31
Alcotest.(check int)
31
32
"the workout view is served" 200
32
33
(status (get c "/workout"));
34
Added:
let workout_page = body (get c "/workout") in
35
Added:
Alcotest.(check bool)
36
Added:
"the workout date is shown" true
37
Added:
(Option.is_some
38
Added:
(index_from ~needle:"11th January 1970" workout_page 0));
33
39
(* The static workout client asset is served. *)
34
40
let asset = get c "/assets/workout-client.js" in
35
41
Alcotest.(check int) "serves the workout client" 200 (status asset)