feat fill the finish actions once every slot is recorded

While any prescribed slot is still outstanding, the Finish workout and Cancel logging controls read as a primary outline — present but not urging completion. Once every slot is recorded they fill solid oxblood to invite the finish. A finish-actions-complete class, toggled by all_recorded, carries the state.

Commit
9cfce28cf79f08287013579c35dc4d5df35a63e1
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/presenter/pages_workout.ml
index 44200655..7ee43c5a 100644..100644
@@ -359,7 +359,10 @@
359 359 | None ->
360 360 [
361 361 tag "div"
362 Removed: [ class_ "button-group" ]
362 Added: [
363 Added: Dream_html.string_attr "class" "button-group finish-actions%s"
364 Added: (if vm.all_recorded then " finish-actions-complete" else "");
365 Added: ]
363 366 [
364 367 tag "form"
365 368 [
lib/web/assets/hito.css
index a7231d1f..6fcbb095 100644..100644
@@ -616,6 +616,33 @@
616 616 background: var(--brass);
617 617 }
618 618
619 Added: /* The finish and cancel actions signal readiness by their fill. While any slot
620 Added: is still unrecorded, both read as a primary outline — present but not urging
621 Added: completion. Once every slot is recorded, both fill solid oxblood to invite
622 Added: the finish. The selectors name both group classes so they beat the generic
623 Added: solid-fill and the .secondary brass outline, which tie on specificity. */
624 Added: .button-group.finish-actions input[type="submit"],
625 Added: .button-group.finish-actions input[type="submit"].secondary {
626 Added: color: var(--oxblood);
627 Added: background: transparent;
628 Added: border: 2px solid var(--oxblood-dark);
629 Added: }
630 Added: .button-group.finish-actions input[type="submit"]:hover,
631 Added: .button-group.finish-actions input[type="submit"].secondary:hover {
632 Added: color: var(--on-primary);
633 Added: background: var(--oxblood);
634 Added: }
635 Added: .button-group.finish-actions-complete input[type="submit"],
636 Added: .button-group.finish-actions-complete input[type="submit"].secondary {
637 Added: color: var(--on-primary);
638 Added: background: var(--oxblood);
639 Added: border: 2px solid var(--oxblood-dark);
640 Added: }
641 Added: .button-group.finish-actions-complete input[type="submit"]:hover,
642 Added: .button-group.finish-actions-complete input[type="submit"].secondary:hover {
643 Added: background: var(--oxblood-hover);
644 Added: }
645 Added:
619 646 /* The logbook is one real table at every width. The columns — date, workout
620 647 name, duration, and the row menu — are few and narrow enough to share a
621 648 single table layout, so there is no mobile card reflow: the name column takes
test/web/workout.ml
index a795450e..2037d560 100644..100644
@@ -461,6 +461,31 @@
461 461 Alcotest.(check int)
462 462 "the saved workout is reachable" 200
463 463 (status (get c "/logbook/w1")) );
464 Added: ( "the finish actions read as an outline until every slot is recorded",
465 Added: `Quick,
466 Added: fun () ->
467 Added: (* While any slot is outstanding the finish and cancel controls carry
468 Added: only [finish-actions] (a primary outline). Once every slot is
469 Added: recorded the group also carries [finish-actions-complete], which
470 Added: fills them solid to invite the finish. *)
471 Added: let c, now, _repo = clocked_client () in
472 Added: now := day 10;
473 Added: let _ = register c ~username:"lifter" ~password:"heavyduty1" in
474 Added: let _ = start_day_one c in
475 Added: let page = body (get c "/workout") in
476 Added: Alcotest.(check bool)
477 Added: "the finish actions are an outline group" true
478 Added: (Option.is_some (index_from ~needle:"finish-actions" page 0));
479 Added: Alcotest.(check bool)
480 Added: "they are not yet the complete, solid group" true
481 Added: (Option.is_none
482 Added: (index_from ~needle:"finish-actions-complete" page 0));
483 Added: record_all_day_one_slots c;
484 Added: let page = body (get c "/workout") in
485 Added: Alcotest.(check bool)
486 Added: "once every slot is recorded the group is complete" true
487 Added: (Option.is_some
488 Added: (index_from ~needle:"finish-actions-complete" page 0)) );
464 489 ( "the recovery gate blocks the next workout until enough rest, then \
465 490 Day 2 begins",
466 491 `Quick,