[OCaml] High Intensity Training Online
feat add App Feedback Home affordance
Make application feedback explicit and discoverable without mixing it with the primary training navigation.
Changed files
lib/presenter/pages_app_feedback.ml
@@ -178,9 +178,9 @@
178
178
]
179
179
in
180
180
html_page ~viewer ~request ~active:"app-feedback" ?workout_started
181
Removed:
"App feedback"
181
Added:
"App Feedback"
182
182
([
183
Removed:
tag "h1" [] [ txt "App feedback" ];
183
Added:
tag "h1" [] [ txt "App Feedback" ];
184
184
tag "p" [] [ txt "Help us improve hito by sharing your experience." ];
185
185
tag "nav"
186
186
[
lib/presenter/pages_profile.ml
@@ -265,7 +265,7 @@
265
265
tag "section"
266
266
[ class_ "profile-section profile-link-section" ]
267
267
[
268
Removed:
tag "h2" [] [ txt "Feedback" ];
268
Added:
tag "h2" [] [ txt "App Feedback" ];
269
269
tag "p" [] [ txt "Share feedback about the application." ];
270
270
tag "a"
271
271
[
lib/presenter/pages_routine.ml
@@ -2,6 +2,36 @@
2
2
open Page_kit
3
3
open Page_shell
4
4
5
Added:
let home_utility_sections viewer =
6
Added:
[
7
Added:
tag "section"
8
Added:
[ class_ "home-utility-section" ]
9
Added:
[
10
Added:
tag "h2" [ class_ "home-utility-title" ] [ txt "Account" ];
11
Added:
tag "p" [] [ txt "%s" viewer.View_model.Viewer.username ];
12
Added:
tag "a"
13
Added:
[
14
Added:
href Routes.profile;
15
Added:
class_ "button secondary";
16
Added:
Dream_html.attr "data-hito-app-link";
17
Added:
]
18
Added:
[ txt "Account" ];
19
Added:
];
20
Added:
tag "section"
21
Added:
[ class_ "home-utility-section" ]
22
Added:
[
23
Added:
tag "h2" [ class_ "home-utility-title" ] [ txt "App Feedback" ];
24
Added:
tag "p" [] [ txt "Help improve hito by sharing your experience." ];
25
Added:
tag "a"
26
Added:
[
27
Added:
href Routes.app_feedback;
28
Added:
class_ "button secondary";
29
Added:
Dream_html.attr "data-hito-app-link";
30
Added:
]
31
Added:
[ txt "Give feedback" ];
32
Added:
];
33
Added:
]
34
Added:
5
35
let choose_routine request ~workout_started ~viewer
6
36
~(routines : View_model.Routine_choice.t list) =
7
37
html_page ~viewer ~request ~active:"home" ?workout_started "Choose a routine"
@@ -25,20 +55,7 @@
25
55
];
26
56
])
27
57
routines
28
Removed:
@ [
29
Removed:
tag "section"
30
Removed:
[ class_ "home-account" ]
31
Removed:
[
32
Removed:
tag "p" [] [ txt "Account · %s" viewer.View_model.Viewer.username ];
33
Removed:
tag "a"
34
Removed:
[
35
Removed:
href Routes.profile;
36
Removed:
class_ "button secondary";
37
Removed:
Dream_html.attr "data-hito-app-link";
38
Removed:
]
39
Removed:
[ txt "Account" ];
40
Removed:
];
41
Removed:
])
58
Added:
@ home_utility_sections viewer)
42
59
43
60
let begin_form request ~routine_id ~override label =
44
61
tag "form"
@@ -174,20 +191,7 @@
174
191
tag "p" [] [ txt "%s" status ];
175
192
]
176
193
@ gate
177
Removed:
@ [
178
Removed:
tag "section"
179
Removed:
[ class_ "home-account" ]
180
Removed:
[
181
Removed:
tag "p" [] [ txt "Account · %s" viewer.View_model.Viewer.username ];
182
Removed:
tag "a"
183
Removed:
[
184
Removed:
href Routes.profile;
185
Removed:
class_ "button secondary";
186
Removed:
Dream_html.attr "data-hito-app-link";
187
Removed:
]
188
Removed:
[ txt "Account" ];
189
Removed:
];
190
Removed:
])
194
Added:
@ home_utility_sections viewer)
191
195
192
196
(* Home while a workout is in progress. Rather than the recovery gate or the
193
197
routine chooser, Home shows a single card: the workout is under way and one
lib/web/assets/hito.css
@@ -267,22 +267,20 @@
267
267
padding: 0.2rem 0;
268
268
}
269
269
270
Removed:
/* Account is a global utility, not a primary training action. */
271
Removed:
.home-account {
272
Removed:
display: flex;
273
Removed:
align-items: center;
274
Removed:
justify-content: space-between;
275
Removed:
gap: 1rem;
270
Added:
/* Account and application feedback are low-frequency Home utilities. Keep them
271
Added:
separate from the primary workout content and from each other. */
272
Added:
.home-utility-section {
276
273
margin-top: 2rem;
277
274
padding-top: 0.85rem;
278
275
border-top: 1px solid var(--rule);
279
276
}
280
Removed:
.home-account p {
277
Added:
.home-utility-title {
281
278
margin: 0;
282
Removed:
font-size: var(--font-size-small);
279
Added:
font-size: var(--font-size-lead);
283
280
}
284
Removed:
.home-account .button {
285
Removed:
flex: 0 0 auto;
281
Added:
.home-utility-section p {
282
Added:
margin: 0.35rem 0 0.75rem;
283
Added:
font-size: var(--font-size-small);
286
284
}
287
285
288
286
/* Keep one page action beside the title without creating a button strip. */
test/web/app_feedback.ml
@@ -13,6 +13,10 @@
13
13
Alcotest.(check int)
14
14
"write tab served" 200
15
15
(status (get c "/app-feedback"));
16
Added:
let page = body (get c "/app-feedback") in
17
Added:
Alcotest.(check bool)
18
Added:
"page names the App Feedback affordance" true
19
Added:
(Option.is_some (index_from ~needle:"App Feedback" page 0));
16
20
Alcotest.(check int)
17
21
"submitted tab served" 200
18
22
(status (get c "/app-feedback?tab=submitted")) );
test/web/overview.ml
@@ -47,6 +47,9 @@
47
47
Alcotest.(check bool)
48
48
"Home offers the Account affordance" true
49
49
(Option.is_some (index_from ~needle:"Account" home 0));
50
Added:
Alcotest.(check bool)
51
Added:
"Home offers the App Feedback affordance" true
52
Added:
(Option.is_some (index_from ~needle:"App Feedback" home 0));
50
53
let trainee = the_trainee repo ~username:"lifter" in
51
54
let token = Option.get (csrf_token (body (get c "/"))) in
52
55
let _ = post c "/routines/ideal/select" [ ("dream.csrf", token) ] in