diff options
author | Marius Peter <marius.peter@tutanota.com> | 2025-03-15 19:17:14 +0100 |
---|---|---|
committer | Marius Peter <marius.peter@tutanota.com> | 2025-03-15 19:17:14 +0100 |
commit | 346d17a1f4c78a05fb1fe010eb1a9e646c8b04a3 (patch) | |
tree | f1151c0e5bb1649158735a219e0744e11f3015b3 | |
parent | 55993c4d0857aec8a372aee989aaeef61ea37b3c (diff) |
Great work today, again!
-rw-r--r-- | bin/main.ml | 14 | ||||
-rw-r--r-- | lib/dune | 2 | ||||
-rw-r--r-- | lib/handlers.ml | 28 | ||||
-rw-r--r-- | lib/static/styles.css | 54 | ||||
-rw-r--r-- | lib/views.ml | 121 |
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 @@ -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 |