[OCaml] Mobile-friendly clone of cgit.
feat add commit pill filtering with toolbar component
Clicking a commit pill navigates to the commits list filtered by that conventional commit type via a ?type= query parameter. A persistent toolbar component appears in both the commits and files views. In commits, it displays the active filter pill with an adjacent small round dismiss button. In files, it wraps the breadcrumbs. The filter dismiss button is a small grey circle (×) close to the pill, with an expanded touch target via pseudo-element for accessibility.
Changed files
lib/handlers.ml
@@ -44,6 +44,10 @@
44
44
45
45
let handle config handler _request name = with_repository config name handler
46
46
47
Added:
let handle_request config handler request name =
48
Added:
with_repository config name (fun repository context ->
49
Added:
handler request repository context)
50
Added:
47
51
let handle_id config handler _request name id =
48
52
with_repository config name (fun repository context ->
49
53
handler repository context id)
@@ -55,11 +59,39 @@
55
59
in
56
60
Views.Repo.summary context branches commits
57
61
58
Removed:
let commits config repository context =
62
Added:
let filter_commits filter_type commits =
63
Added:
match filter_type with
64
Added:
| None -> commits
65
Added:
| Some ct ->
66
Added:
List.filter
67
Added:
(fun (commit : Resolvers.Commit.t) ->
68
Added:
match commit.message with
69
Added:
| None -> false
70
Added:
| Some message -> (
71
Added:
let summary =
72
Added:
match String.split_on_char '\n' message with
73
Added:
| [] -> ""
74
Added:
| s :: _ -> s
75
Added:
in
76
Added:
match String.index_opt summary ':' with
77
Added:
| None -> false
78
Added:
| Some colon_pos ->
79
Added:
let prefix = String.sub summary 0 colon_pos in
80
Added:
let type_name =
81
Added:
match String.index_opt prefix '(' with
82
Added:
| Some paren_pos -> String.sub prefix 0 paren_pos
83
Added:
| None -> prefix
84
Added:
in
85
Added:
String.lowercase_ascii type_name = ct))
86
Added:
commits
87
Added:
88
Added:
let commits config request repository context =
89
Added:
let filter_type = Dream.query request "type" in
59
90
let* commits =
60
91
Resolvers.Commit.recent repository config.Config.commits_max_displayed
61
92
in
62
Removed:
Views.Repo.commits context commits
93
Added:
let commits = filter_commits filter_type commits in
94
Added:
Views.Repo.commits ?filter_type context commits
63
95
64
96
let commits_branch config repository context branch =
65
97
let* reference = Resolvers.Reference.of_id repository branch in
@@ -115,7 +147,7 @@
115
147
get Routes.root_path (root config);
116
148
get Routes.repo_root_path (Repo.handle config (Repo.summary config));
117
149
get Routes.repo_path (Repo.handle config (Repo.summary config));
118
Removed:
get Routes.commits_path (Repo.handle config (Repo.commits config));
150
Added:
get Routes.commits_path (Repo.handle_request config (Repo.commits config));
119
151
get Routes.commits_branch_path
120
152
(Repo.handle_id config (Repo.commits_branch config));
121
153
get Routes.commit_path (Repo.handle_id config Repo.commit_id);
lib/static/styles.css
@@ -337,6 +337,52 @@
337
337
color: #fbb6d0;
338
338
}
339
339
340
Added:
/* Toolbar — persistent bar between navbar and content in commits/files views */
341
Added:
342
Added:
.toolbar {
343
Added:
display: flex;
344
Added:
align-items: center;
345
Added:
gap: 0.75em;
346
Added:
min-height: 44px;
347
Added:
box-sizing: border-box;
348
Added:
}
349
Added:
350
Added:
.toolbar-filter {
351
Added:
display: inline-flex;
352
Added:
align-items: center;
353
Added:
gap: 0.35em;
354
Added:
}
355
Added:
356
Added:
.toolbar-dismiss {
357
Added:
position: relative;
358
Added:
display: inline-flex;
359
Added:
align-items: center;
360
Added:
justify-content: center;
361
Added:
width: 1.2em;
362
Added:
height: 1.2em;
363
Added:
padding: 0;
364
Added:
color: #b0b0b0;
365
Added:
background-color: #3a3a3a;
366
Added:
text-decoration: none;
367
Added:
font-size: 0.8em;
368
Added:
line-height: 1;
369
Added:
border-radius: 50%;
370
Added:
box-sizing: border-box;
371
Added:
}
372
Added:
373
Added:
.toolbar-dismiss::before {
374
Added:
content: "";
375
Added:
position: absolute;
376
Added:
inset: -10px;
377
Added:
min-width: 44px;
378
Added:
min-height: 44px;
379
Added:
}
380
Added:
381
Added:
.toolbar-dismiss:hover {
382
Added:
background-color: #555;
383
Added:
color: white;
384
Added:
}
385
Added:
340
386
h1 {
341
387
padding: 0;
342
388
}
lib/views/repo.ml
@@ -123,7 +123,7 @@
123
123
HTML.(
124
124
span
125
125
[ class_ "commit-pill commit-pill-%s" ct ]
126
Removed:
[ Routes.link_to commit_route (txt "%s" ct) ])
126
Added:
[ a [ href "/%s/commits/?type=%s" repo ct ] [ txt "%s" ct ] ])
127
127
in
128
128
let title_span =
129
129
HTML.(
@@ -161,9 +161,40 @@
161
161
ul [] (List.map (li_of_commit context.repo) commits);
162
162
]
163
163
164
Removed:
let commits context commits =
164
Added:
let toolbar ?(filter : (string * string) option) content =
165
Added:
let filter_el =
166
Added:
match filter with
167
Added:
| None -> HTML.null []
168
Added:
| Some (commit_type, dismiss_href) ->
169
Added:
HTML.(
170
Added:
span
171
Added:
[ class_ "toolbar-filter" ]
172
Added:
[
173
Added:
span
174
Added:
[ class_ "commit-pill commit-pill-%s" commit_type ]
175
Added:
[ txt "%s" commit_type ];
176
Added:
a
177
Added:
[
178
Added:
href "%s" dismiss_href;
179
Added:
class_ "toolbar-dismiss";
180
Added:
Aria.label "Remove filter";
181
Added:
]
182
Added:
[ txt "\xc3\x97" ];
183
Added:
])
184
Added:
in
185
Added:
let children = content @ [ filter_el ] in
186
Added:
HTML.(
187
Added:
div [ class_ "toolbar"; role `toolbar; Aria.label "View toolbar" ] children)
188
Added:
189
Added:
let commits ?filter_type context commits =
190
Added:
let filter =
191
Added:
match filter_type with
192
Added:
| None -> None
193
Added:
| Some ct -> Some (ct, Printf.sprintf "/%s/commits/" context.repo)
194
Added:
in
195
Added:
let tb = toolbar ?filter [] in
165
196
render_page context ~active:Commits
166
Removed:
HTML.[ ul [] (List.map (li_of_commit context.repo) commits) ]
197
Added:
HTML.[ tb; ul [] (List.map (li_of_commit context.repo) commits) ]
167
198
168
199
let breadcrumbs repo (trail : (string * string) list) =
169
200
let root_link = HTML.li [] [ Routes.link_to (Files repo) (txt "Home") ] in
@@ -179,12 +210,10 @@
179
210
[ ul [] (root_link :: crumbs) ])
180
211
181
212
let files context trail (tree : Resolvers.Tree.t) =
213
Added:
let bc = breadcrumbs context.repo trail in
214
Added:
let tb = toolbar [ bc ] in
182
215
render_page context ~active:Files
183
Removed:
HTML.
184
Removed:
[
185
Removed:
breadcrumbs context.repo trail;
186
Removed:
ul [] (List.map (li_of_entry context.repo) tree.entries);
187
Removed:
]
216
Added:
HTML.[ tb; ul [] (List.map (li_of_entry context.repo) tree.entries) ]
188
217
189
218
let file ?(active = Layout.Files) context trail (blob : Resolvers.Blob.t) =
190
219
let to_numbered_line number line =
@@ -207,7 +236,11 @@
207
236
|> List.mapi to_numbered_line |> List.concat
208
237
in
209
238
render_page context ~active
210
Removed:
HTML.[ breadcrumbs context.repo trail; div [ id "blob" ] formatted_blob ]
239
Added:
HTML.
240
Added:
[
241
Added:
toolbar [ breadcrumbs context.repo trail ];
242
Added:
div [ id "blob" ] formatted_blob;
243
Added:
]
211
244
212
245
let commit context (commit : Resolvers.Commit.t) diff =
213
246
let message = parse_commit_message commit.message in