[1] | 1 | open Tyxml.Html
|
---|
| 2 | open Logarion
|
---|
| 3 |
|
---|
| 4 | let to_string tyxml = Format.asprintf "%a" (Tyxml.Html.pp ()) tyxml
|
---|
| 5 |
|
---|
| 6 | let head ~style linker t =
|
---|
| 7 | head (title (pcdata t)) [
|
---|
| 8 | link ~rel:[`Stylesheet] ~href:(linker style) ();
|
---|
| 9 | link ~rel:[`Alternate] ~href:(linker "/feed.atom") ~a:[a_mime_type "application/atom+xml"] ();
|
---|
| 10 | meta ~a:[a_charset "utf-8"] ();
|
---|
| 11 | ]
|
---|
| 12 |
|
---|
| 13 | let default_style = "/static/main.css"
|
---|
| 14 |
|
---|
| 15 | let page ?(style=default_style) linker head_title header main =
|
---|
| 16 | html (head ~style linker head_title) (body [ header; main ])
|
---|
| 17 |
|
---|
| 18 | let anchor url content = a ~a:[ a_href (uri_of_string url) ] content
|
---|
| 19 |
|
---|
| 20 | let div ?(style_class="") content =
|
---|
| 21 | let a = if style_class <> "" then [a_class [style_class]] else [] in
|
---|
| 22 | div ~a content
|
---|
| 23 |
|
---|
| 24 | let main = main
|
---|
| 25 |
|
---|
| 26 | let unescaped_data = Unsafe.data
|
---|
| 27 | let data = pcdata
|
---|
| 28 | let title = h1
|
---|
| 29 | let header = header
|
---|
| 30 |
|
---|
| 31 | let pipe = span ~a:[a_class ["pipe"]] [pcdata " | "]
|
---|
| 32 |
|
---|
| 33 | let meta ~abstract ~authors ~date ~series ~topics ~keywords ~uuid =
|
---|
| 34 | let opt_span name value = if String.length value > 0 then (span [pipe; pcdata (name ^ value)]) else pcdata "" in
|
---|
| 35 | let authors = List.fold_left (fun acc x -> a ~a:[a_rel [`Author]] [pcdata x] :: acc) [] authors in
|
---|
| 36 | [ p ~a:[a_class ["abstract"]] [Unsafe.data abstract]; ]
|
---|
| 37 | @ authors
|
---|
| 38 | @ [
|
---|
| 39 | pipe;
|
---|
| 40 | time ~a:[a_datetime date] [pcdata date];
|
---|
| 41 | pipe;
|
---|
| 42 | opt_span "series: " series;
|
---|
| 43 | opt_span "topics: " topics;
|
---|
| 44 | opt_span "keywords: " keywords;
|
---|
| 45 | div [pcdata ("id: " ^ uuid)];
|
---|
| 46 | ]
|
---|
| 47 | |> div ~style_class:"meta"
|
---|
| 48 |
|
---|
| 49 | let note = article
|
---|
| 50 |
|
---|
| 51 | let text_item path meta =
|
---|
| 52 | let module Meta = Logarion.Meta in
|
---|
| 53 | tr [
|
---|
| 54 | td [ a ~a:[a_class ["title"]; a_href (path ^ Meta.alias meta ^ ".html")] [data meta.Meta.title] ];
|
---|
| 55 | td [ span [pcdata Meta.(stringset_csv meta.keywords)] ];
|
---|
| 56 | td [ time @@ [unescaped_data Meta.Date.(pretty_date (listing meta.Meta.date))] ];
|
---|
| 57 | ]
|
---|
| 58 |
|
---|
| 59 | let listing_texts path metas =
|
---|
| 60 | let item meta = text_item path meta in
|
---|
| 61 | table @@ List.map item metas
|
---|
| 62 |
|
---|
| 63 | let listing_index path metas =
|
---|
| 64 | let items topic =
|
---|
| 65 | List.fold_left Meta.(fun a e -> if StringSet.mem topic e.topics then text_item path e :: a else a)
|
---|
| 66 | [] metas
|
---|
| 67 | in
|
---|
| 68 | let item topic =
|
---|
| 69 | let module Meta = Logarion.Meta in
|
---|
| 70 | [ h3 ~a:[a_id topic] [pcdata topic]; table (items topic)]
|
---|
| 71 | in
|
---|
| 72 | List.fold_left (fun a e -> a @ item e) []
|
---|
| 73 | @@ Meta.StringSet.elements
|
---|
| 74 | @@ List.fold_left Meta.(fun a e -> unique_topics a e) Meta.StringSet.empty metas
|
---|
| 75 |
|
---|
| 76 | module Renderer = struct
|
---|
| 77 | let meta meta e =
|
---|
| 78 | let e = List.hd e in
|
---|
| 79 | match e with
|
---|
| 80 | | "urn_name" -> [unescaped_data @@ "/note/" ^ Logarion.Meta.alias meta]
|
---|
| 81 | | "date" | "date_created" | "date_edited" | "date_published" | "date_human" ->
|
---|
| 82 | [time @@ [unescaped_data @@ Logarion.Meta.value_with_name meta e]]
|
---|
| 83 | | tag -> [unescaped_data @@ Logarion.Meta.value_with_name meta tag]
|
---|
| 84 |
|
---|
| 85 | let note note e = match List.hd e with
|
---|
| 86 | | "body" -> [unescaped_data @@ Omd.to_html @@ Omd.of_string note.Logarion.Note.body]
|
---|
| 87 | | _ -> meta note.Logarion.Note.meta e
|
---|
| 88 |
|
---|
| 89 | let archive archive e = match List.hd e with
|
---|
| 90 | | "title" -> [h1 [anchor ("index.html") [data archive.Logarion.Archive.Configuration.title]]]
|
---|
| 91 | | tag -> prerr_endline ("unknown tag: " ^ tag); [unescaped_data ""]
|
---|
| 92 | end
|
---|
| 93 |
|
---|
| 94 | let form ymd =
|
---|
| 95 | let article_form =
|
---|
| 96 | let input_set title input = p [ label [ pcdata title; input ] ] in
|
---|
| 97 | let open Note in
|
---|
| 98 | let open Meta in
|
---|
| 99 | let authors = AuthorSet.to_string ymd.meta.authors in
|
---|
| 100 | [
|
---|
| 101 | input ~a:[a_name "uuid"; a_value (Id.to_string ymd.meta.uuid); a_input_type `Hidden] ();
|
---|
| 102 | input_set
|
---|
| 103 | "Title"
|
---|
| 104 | (input ~a:[a_name "title"; a_value ymd.meta.title; a_required ()] ());
|
---|
| 105 | input_set
|
---|
| 106 | "Authors"
|
---|
| 107 | (input ~a:[a_name "authors"; a_value authors] ());
|
---|
| 108 | input_set
|
---|
| 109 | "Topics"
|
---|
| 110 | (input ~a:[a_name "topics"; a_value (stringset_csv ymd.meta.topics)] ());
|
---|
| 111 | input_set
|
---|
| 112 | "Categories"
|
---|
| 113 | (input ~a:[a_name "categories"; a_value (CategorySet.to_csv ymd.meta.categories)] ());
|
---|
| 114 | input_set
|
---|
| 115 | "Keywords"
|
---|
| 116 | (input ~a:[a_name "keywords"; a_value (stringset_csv ymd.meta.keywords)] ());
|
---|
| 117 | input_set
|
---|
| 118 | "Series"
|
---|
| 119 | (input ~a:[a_name "series"; a_value (stringset_csv ymd.meta.series)] ());
|
---|
| 120 | input_set
|
---|
| 121 | "Abstract"
|
---|
| 122 | (input ~a:[a_name "abstract"; a_value ymd.meta.abstract] ());
|
---|
| 123 | input_set
|
---|
| 124 | "Text"
|
---|
| 125 | (textarea ~a:[a_name "body"] (pcdata ymd.body));
|
---|
| 126 | p [ button ~a:[a_button_type `Submit] [pcdata "Submit"] ];
|
---|
| 127 | ]
|
---|
| 128 | in
|
---|
| 129 | div
|
---|
| 130 | [ form
|
---|
| 131 | ~a:[a_method `Post; a_action (uri_of_string "/post.note"); a_accept_charset ["utf-8"]]
|
---|
| 132 | [ fieldset ~legend:(legend [pcdata "Article"]) article_form ]
|
---|
| 133 | ]
|
---|