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 | 
