summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Peter <marius.peter@tutanota.com>2025-03-15 19:17:14 +0100
committerMarius Peter <marius.peter@tutanota.com>2025-03-15 19:17:14 +0100
commit346d17a1f4c78a05fb1fe010eb1a9e646c8b04a3 (patch)
treef1151c0e5bb1649158735a219e0744e11f3015b3
parent55993c4d0857aec8a372aee989aaeef61ea37b3c (diff)
Great work today, again!
-rw-r--r--bin/main.ml14
-rw-r--r--lib/dune2
-rw-r--r--lib/handlers.ml28
-rw-r--r--lib/static/styles.css54
-rw-r--r--lib/views.ml121
5 files changed, 99 insertions, 120 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 74712e1..5fcd6cf 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -1,13 +1 @@
-let () =
- Dream.run @@ Dream.logger
- @@ Dream.router
- [
- Dream.get "/" (fun _req -> Ogit.Handlers.ogit_root _req);
- Dream.get "/:repo_name" (fun req ->
- let repo_name = Dream.param req "repo_name" in
- Ogit.Handlers.repo_root repo_name);
- Dream.get "/:repo_name/tree" (fun req ->
- let repo_name = Dream.param req "repo_name" in
- Ogit.Handlers.repo_tree repo_name);
- Dream.get "/static/**" (Dream.static "./lib/static");
- ]
+let () = Dream.run @@ Dream.logger @@ Dream.router Ogit.Handlers.all_handlers
diff --git a/lib/dune b/lib/dune
index 076d7c6..3963ffd 100644
--- a/lib/dune
+++ b/lib/dune
@@ -1,5 +1,5 @@
(library
(name ogit)
- (libraries unix dream dream-html git git-unix)
+ (libraries dream dream-html git git-unix)
(preprocess
(pps lwt_ppx)))
diff --git a/lib/handlers.ml b/lib/handlers.ml
index 46df354..3211929 100644
--- a/lib/handlers.ml
+++ b/lib/handlers.ml
@@ -1,3 +1,25 @@
-let ogit_root _ = Views.Ogit_root.render () |> Dream_html.respond
-let repo_root repo_name = Views.Repo_root.render repo_name |> Dream_html.respond
-let repo_tree repo_name = Views.Repo_tree.render repo_name |> Dream_html.respond
+(* Handlers for different routes *)
+let ogit_root _req = Views.Ogit_root.render () |> Dream_html.respond
+
+let repo_root req =
+ let repo_name = Dream.param req "repo_name" in
+ Views.Repo_root.render repo_name |> Dream_html.respond
+
+let repo_tree req =
+ let repo_name = Dream.param req "repo_name" in
+ let dir_path = Dream.param req "**" in
+ Views.Repo_tree.render repo_name dir_path |> Dream_html.respond
+
+let repo_blob req =
+ let repo_name = Dream.param req "repo_name" in
+ let blob_name = Dream.param req "blob_name" in
+ Views.Repo_blob.render repo_name blob_name |> Dream_html.respond
+
+(* Route definitions *)
+let all_handlers = [
+ Dream.get "/" ogit_root;
+ Dream.get "/:repo_name" repo_root;
+ Dream.get "/:repo_name/tree/**" repo_tree;
+ Dream.get "/:repo_name/blob/:blob_name" repo_blob;
+ Dream.get "/static/**" (Dream.static "./lib/static");
+]
diff --git a/lib/static/styles.css b/lib/static/styles.css
index de2c3db..680a6b1 100644
--- a/lib/static/styles.css
+++ b/lib/static/styles.css
@@ -1,29 +1,18 @@
-@import url("fonts/Inter-4.1/web/inter.css");
-
body {
- font-family: Inter, sans-serif;
- max-width: 50em;
- margin: auto;
- padding: 0 1em;
- background-color: #181818;
- color: white;
+ font-family: sans-serif;
}
nav#top {
- background-color: black;
- border-radius: 0.25rem;
+ background-color: dimgray;
}
nav#top ul {
- display: flex;
- flex-wrap: wrap;
+ display: flex;
list-style-type: none;
- padding: 0;
}
nav#top ul li {
- padding: 0.5em 0;
- border-radius: 0.25rem;
+ padding: 1em 0;
}
nav#top ul li a {
@@ -33,39 +22,6 @@ nav#top ul li a {
}
nav#top ul li a:hover {
- background-color: white;
- color: black;
-}
-
-nav#top ul li#active {
- border-radius: 0.25rem;
- background-color: rgb(194, 79, 30);
-}
-
-nav#top ul li#active a:hover {
- border-radius: 0.25rem;
- background-color: rgb(132, 40, 0);
- color: white;
-}
-
-div#main ul {
- padding-left: 0;
- list-style: none;
-}
-
-div#main ul li {
- border: 1px solid #303030;
-}
-
-div#main ul li a {
- display: block;
- color: white;
- text-decoration: none;
- padding: 0.5em;
-}
-
-div#main a:hover {
- background-color: white;
- color: black;
+ background-color: #555;
text-decoration: revert;
}
diff --git a/lib/views.ml b/lib/views.ml
index 2d11674..d09892b 100644
--- a/lib/views.ml
+++ b/lib/views.ml
@@ -29,6 +29,7 @@ module Layout = struct
[
title [] "%s" head_data.page_title;
link [ rel "stylesheet"; href "/static/styles.css" ];
+ link [ rel "icon"; type_ "image/x-icon"; href "/static/git_icon.svg"];
];
body []
[
@@ -68,30 +69,6 @@ module Topnav = struct
("diff", "diff");
];
]
-
- (* let li_of_a (path, text) = *)
- (* let is_active = path = current_path in *)
- (* li (if is_active then [ id "active" ] else []) in *)
- (* let link_of_path = *)
- (* if String.length path = 0 then Printf.sprintf "/%s" repo_path *)
- (* else Printf.sprintf "/%s/%s" repo_path path *)
- (* in *)
- (* li [ id "active" ] [ a [ href "%s" link_of_path ] [ txt text ] ] *)
- (* in *)
- (* nav *)
- (* [ id "top" ] *)
- (* [ *)
- (* ul [] *)
- (* @@ List.map li_of_a *)
- (* [ *)
- (* ("", "summary"); *)
- (* ("refs", "refs"); *)
- (* ("log", "log"); *)
- (* ("tree", "tree"); *)
- (* ("commit", "commit"); *)
- (* ("diff", "diff"); *)
- (* ]; *)
- (* ] *)
end
module Ogit_root = struct
@@ -123,13 +100,6 @@ module Repo_root = struct
open Dream_html
open HTML
- (* let href_for_git_object kind identifier = *)
- (* let open Printf in *)
- (* href "%s" @@ *)
- (* match kind with *)
- (* | `Branch -> sprintf "/tree/%s" identifier *)
- (* | `Commit -> sprintf "/commit/%s" identifier *)
-
let render repo_path =
let title = repo_path in
let subtitle = Filename.concat Config.git_directory repo_path in
@@ -159,41 +129,84 @@ module Repo_tree = struct
open Dream_html
open HTML
- let full_path repo_path = Filename.concat Config.git_directory repo_path
+ let full_path repo_path dir_path =
+ Filename.concat (Filename.concat Config.git_directory repo_path) dir_path
- (* Helper function to list top-level files and directories *)
- let ls_repo repo_path =
+ (* Helper function to list contents of a given directory *)
+ let ls_dir repo_path dir_path =
+ let dir_full_path = full_path repo_path dir_path in
try
- Sys.readdir (full_path repo_path)
+ Sys.readdir dir_full_path
|> Array.to_list
|> List.filter (fun name -> name <> ".git") (* Exclude .git *)
- |> List.sort String.compare
+ |> List.map (fun entry ->
+ let entry_rel_path = Filename.concat dir_path entry in
+ let full_entry_path = Filename.concat dir_full_path entry in
+ (entry, entry_rel_path, Sys.is_directory full_entry_path))
+ |> List.sort (fun (a, _, is_dir_a) (b, _, is_dir_b) ->
+ match (is_dir_a, is_dir_b) with
+ | true, false -> -1 (* Directories first *)
+ | false, true -> 1
+ | _ -> String.compare a b)
with Sys_error _ -> []
(* Function to create a link based on file type *)
- let link_for_entry repo_path entry =
- let entry_path = Filename.concat (full_path repo_path) entry in
- if Sys.is_directory entry_path then
- a
- [ href "%s" @@ Printf.sprintf "/%s/tree/%s" repo_path entry ]
- [ txt "%s" (entry ^ "/") ]
- else
- a
- [ href "%s" @@ Printf.sprintf "/%s/blob/%s" repo_path entry ]
- [ txt "%s" entry ]
-
- let li_of_entry repo_path entry = li [] [ link_for_entry repo_path entry ]
+ let link_for_entry repo_path (entry, entry_rel_path, is_dir) =
+ let link =
+ if is_dir then Printf.sprintf "/%s/tree/%s" repo_path entry_rel_path
+ else Printf.sprintf "/%s/blob/%s" repo_path entry_rel_path
+ in
+ li [] [ a [ href "%s" link ] [ txt "%s" entry ] ]
- (* Render function *)
- let render repo_path =
- let title = repo_path in
- let subtitle = "Files" in
+ (* Render function, now supporting nested directories *)
+ let render repo_path dir_path =
+ let title = Filename.concat repo_path dir_path in
+ let subtitle = "Repository Files" in
- let repo_entries = ls_repo repo_path in
- let content = [ ul [] (List.map (li_of_entry repo_path) repo_entries) ] in
+ let repo_entries = ls_dir repo_path dir_path in
+ let content =
+ [
+ h3 [] [ txt "%s" (Printf.sprintf "Contents of /%s" dir_path) ];
+ ul [] (List.map (link_for_entry repo_path) repo_entries);
+ ]
+ in
let body_data =
{ title; subtitle; topnav = Topnav.repo repo_path "tree"; content }
in
Layout.application body_data
end
+
+module Repo_blob = struct
+ open Dream_html
+ open HTML
+
+ let full_path repo_path = Filename.concat Config.git_directory repo_path
+
+ (* Read the contents of a file *)
+ let read_blob repo_path blob_name =
+ let file_path = Filename.concat (full_path repo_path) blob_name in
+ try Some (In_channel.with_open_text file_path In_channel.input_all)
+ with _ -> None (* Handle cases where the file doesn't exist or can't be read *)
+
+ (* Render function *)
+ let render repo_path blob_name =
+ let title = blob_name in
+ let subtitle = "File Contents" in
+
+ match read_blob repo_path blob_name with
+ | Some content ->
+ let content_display =
+ pre [] [ code [] [ txt "%s" content ] ] (* Render as code block *)
+ in
+ let body_data =
+ { title; subtitle; topnav = Topnav.repo repo_path "blob"; content = [content_display] }
+ in
+ Layout.application body_data
+ | None ->
+ let error_message = p [] [ txt "Error: Unable to read file." ] in
+ let body_data =
+ { title; subtitle; topnav = Topnav.repo repo_path "blob"; content = [error_message] }
+ in
+ Layout.application body_data
+end
Copyright 2019--2025 Marius PETER