[OCaml] Mobile-friendly clone of cgit.
feat consistent navbar on all pages, configurable root title
- Add box-sizing: border-box to .nav-logo and .nav-home so they match the height/hover behavior of nav ul li a items. - Show a navbar on the root '/' page with the logo and a nav-home span displaying 'Repositories for <user>' (or a custom title). - Add an optional 'title' field to config that overrides the default root page heading when set. - Remove the old page-header from the root page in favor of the unified navigation bar.
Changed files
lib/config.ml
@@ -7,6 +7,7 @@
7
7
default_branch : string;
8
8
git_project_root : string;
9
9
commits_max_displayed : int;
10
Added:
title : string;
10
11
host : string;
11
12
port : int;
12
13
}
@@ -30,6 +31,7 @@
30
31
default_branch = "main";
31
32
git_project_root = Filename.concat home "git";
32
33
commits_max_displayed = 10;
34
Added:
title = "";
33
35
host = "127.0.0.1";
34
36
port = 8081;
35
37
}
@@ -52,6 +54,7 @@
52
54
("default_branch", TString t.default_branch);
53
55
("git_project_root", TString t.git_project_root);
54
56
("commits_max_displayed", TInt t.commits_max_displayed);
57
Added:
("title", TString t.title);
55
58
("host", TString t.host);
56
59
("port", TInt t.port);
57
60
]
@@ -92,6 +95,7 @@
92
95
let* user = find_string table "user" in
93
96
let* default_branch = find_string table "default_branch" in
94
97
let* commits_max_displayed = find_int table "commits_max_displayed" in
98
Added:
let* title = find_string_opt table "title" ~default:default.title in
95
99
let* host = find_string_opt table "host" ~default:default.host in
96
100
let* port = find_int_opt table "port" ~default:default.port in
97
101
if commits_max_displayed <= 0 then
@@ -105,6 +109,7 @@
105
109
user;
106
110
default_branch;
107
111
commits_max_displayed;
112
Added:
title;
108
113
host;
109
114
port;
110
115
}
lib/handlers.ml
@@ -11,9 +11,15 @@
11
11
let message = Format.asprintf "%a" Resolvers.pp_error error in
12
12
Views.error_page ~status ~title message
13
13
14
Added:
let root_title config =
15
Added:
if config.Config.title = "" then "Repositories for " ^ config.Config.user
16
Added:
else config.Config.title
17
Added:
14
18
let root config _request =
15
19
match Resolvers.repositories config with
16
Removed:
| Ok repositories -> Views.root ~user:config.Config.user repositories
20
Added:
| Ok repositories ->
21
Added:
Views.root ~user:config.Config.user ~root_title:(root_title config)
22
Added:
repositories
17
23
| Error error -> error_response error
18
24
19
25
module Repo = struct
@@ -23,7 +29,7 @@
23
29
| Error error -> error_response error
24
30
25
31
let view_context config repository =
26
Removed:
Views.Repo.context ~user:config.Config.user
32
Added:
Views.Repo.context ~user:config.Config.user ~root_title:(root_title config)
27
33
~repo:(Resolvers.repository_name repository)
28
34
~description:(Resolvers.repository_description repository)
29
35
lib/static/styles.css
@@ -101,6 +101,7 @@
101
101
min-height: 44px;
102
102
border-radius: 0.25rem;
103
103
font-family: monospace;
104
Added:
box-sizing: border-box;
104
105
}
105
106
106
107
.nav-home:hover {
@@ -114,6 +115,7 @@
114
115
padding: 0.5em;
115
116
min-height: 44px;
116
117
border-radius: 0.25rem;
118
Added:
box-sizing: border-box;
117
119
}
118
120
119
121
.nav-logo:hover {
lib/views/layout.ml
@@ -20,6 +20,17 @@
20
20
| Tags -> (Routes.Tags repo, "Tags", Tags)
21
21
| Readme -> (Routes.Readme repo, "README", Readme)
22
22
23
Added:
let rootnav ~title:nav_title =
24
Added:
HTML.(
25
Added:
nav
26
Added:
[ id "top"; Aria.label "Site navigation" ]
27
Added:
[
28
Added:
Routes.link_to Root
29
Added:
~other_attrs:[ class_ "nav-logo" ]
30
Added:
(img [ src "/static/git_icon.svg"; alt "Home"; class_ "site-logo" ]);
31
Added:
span [ class_ "nav-home" ] [ txt "%s" nav_title ];
32
Added:
])
33
Added:
23
34
let topnav ?(active = Summary) repo =
24
35
let nav_items =
25
36
List.map (page_to_nav_item repo)
@@ -87,23 +98,25 @@
87
98
link [ rel "icon"; type_ "image/x-icon"; href "/static/git_icon.svg" ];
88
99
]
89
100
90
Removed:
let body ~user page_data =
101
Added:
let body ~user ~root_title page_data =
91
102
let open HTML in
92
103
body []
93
104
[
94
105
a [ href "#main"; class_ "skip-link" ] [ txt "Skip to content" ];
106
Added:
(match page_data.repo with
107
Added:
| None -> rootnav ~title:root_title
108
Added:
| Some repo -> topnav ~active:page_data.active repo);
95
109
page_header
96
110
~has_repo:(Option.is_some page_data.repo)
97
111
page_data.title page_data.subtitle;
98
Removed:
(match page_data.repo with
99
Removed:
| None -> HTML.null []
100
Removed:
| Some repo -> topnav ~active:page_data.active repo);
101
112
div [ id "main" ] page_data.content;
102
113
page_footer user;
103
114
]
104
115
105
Removed:
let render ?(page_title = "Ogit") ~user body_data =
106
Removed:
HTML.html [ HTML.lang "en" ] [ head page_title; body ~user body_data ]
116
Added:
let render ?(page_title = "Ogit") ~user ~root_title body_data =
117
Added:
HTML.html
118
Added:
[ HTML.lang "en" ]
119
Added:
[ head page_title; body ~user ~root_title body_data ]
107
120
108
121
let error_page ?(title = "Request failed") ?(status = `Internal_Server_Error)
109
122
message =
lib/views/repo.ml
@@ -2,15 +2,24 @@
2
2
3
3
open Dream_html
4
4
5
Removed:
type context = { repo : string; description : string; user : string }
5
Added:
type context = {
6
Added:
repo : string;
7
Added:
description : string;
8
Added:
user : string;
9
Added:
root_title : string;
10
Added:
}
11
Added:
6
12
type commit_message = { summary : string; body : string }
7
13
8
Removed:
let context ~user ~repo ~description = { repo; description; user }
14
Added:
let context ~user ~root_title ~repo ~description =
15
Added:
{ repo; description; user; root_title }
16
Added:
9
17
let page_title context = context.repo ^ " — " ^ context.description
10
18
11
19
let render_page ?heading context ~active content =
12
20
respond
13
Removed:
@@ Layout.render ~user:context.user ~page_title:(page_title context)
21
Added:
@@ Layout.render ~user:context.user ~root_title:context.root_title
22
Added:
~page_title:(page_title context)
14
23
{
15
24
repo = Some context.repo;
16
25
title = Option.value heading ~default:context.repo;
lib/views/root.ml
@@ -2,7 +2,7 @@
2
2
3
3
open Dream_html
4
4
5
Removed:
let render ~user repositories =
5
Added:
let render ~user ~root_title repositories =
6
6
let li_of_repo repo =
7
7
HTML.li [] [ Routes.link_to (Routes.Repo repo) (txt "%s" repo) ]
8
8
in
@@ -11,11 +11,11 @@
11
11
div [ id "repositories" ] [ ul [] (List.map li_of_repo repositories) ])
12
12
in
13
13
respond
14
Removed:
@@ Layout.render ~user
14
Added:
@@ Layout.render ~user ~root_title
15
15
{
16
Removed:
title = "Ogit";
16
Added:
title = root_title;
17
17
repo = None;
18
Removed:
subtitle = "Repositories for " ^ user;
18
Added:
subtitle = "";
19
19
active = Summary;
20
20
content = [ all_repositories ];
21
21
}
test/test_config.ml
@@ -11,6 +11,7 @@
11
11
default_branch = "main";
12
12
git_project_root = "/srv/git";
13
13
commits_max_displayed = 25;
14
Added:
title = "";
14
15
host = "127.0.0.1";
15
16
port = 9000;
16
17
}