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 | ]
|
---|