Commit a1fc79e2 authored by Dario Pinto's avatar Dario Pinto
Browse files

Add blog homepage and article metadata display

parent da5e58cb
type article =
{ date : int * int * int
; title : string
; authors : string list
; tags : string list
; category : string
; content : string
; url : string
}
let string_of_file file =
let chan = open_in ("src/content/" ^ file) in
let rec aux acc chan =
match input_line chan with
| exception End_of_file -> acc
| line -> aux (acc ^ "\n" ^ line) chan
in
let res = aux "" chan in
close_in chan;
res
let get_value field = List.hd (List.rev (String.split_on_char ':' field)) let get_value field = List.hd (List.rev (String.split_on_char ':' field))
let post_header t a d c tg = let extract_date date =
let title = get_value t in match String.split_on_char '-' date with
let authors = get_value a in | [ year; month; day ] ->
let date = get_value d in (int_of_string year, int_of_string month, int_of_string day)
let category = get_value c in | _ -> (0, 0, 0)
let tags = get_value tg in
let article_of_string post url =
match String.split_on_char '\n' post with
| title :: authors :: date :: category :: tags :: r ->
Some
{ date = extract_date (get_value date)
; title = get_value title
; authors =
(let authors = get_value authors in
match String.split_on_char ',' authors with
| [] -> [ "Unspecified authors!" ]
| auth -> auth )
; tags =
(let tags = get_value tags in
match String.split_on_char ',' tags with
| [] -> [ "Unspecified tags!" ]
| tags -> tags )
; category = get_value category
; content = String.concat "\n" r
; url
}
| _ -> None
let post_header title authors (year, month, day) category tags =
Format.asprintf Format.asprintf
{|<h1 id="page-title">%s</h1> {|<h1 id="page-title">%s</h1>
<div class="row"> <div class="row">
<div class="col-lg-3"> <div class="col-lg-3">
<img src="/blog/assets/img/icon_person.svg" style="max-width:1em"/> <img src="/blog/assets/img/icon_person.svg" style="max-width:1em"/>
Authors: %s Authors: %a
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<img src="/blog/assets/img/icon_calendar.svg" style="max-width:1em"/> <img src="/blog/assets/img/icon_calendar.svg" style="max-width:1em"/>
Date: %s Date: %4d-%2d-%2d
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<img src="/blog/assets/img/icon_category.svg" style="max-width:1em"/> <img src="/blog/assets/img/icon_category.svg" style="max-width:1em"/>
...@@ -23,9 +67,48 @@ let post_header t a d c tg = ...@@ -23,9 +67,48 @@ let post_header t a d c tg =
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<img src="/blog/assets/img/icon_tags.svg" style="max-width:1em"/> <img src="/blog/assets/img/icon_tags.svg" style="max-width:1em"/>
Tags: %s Tags: %a
</div> </div>
</div> </div>
<hr class="featurette-divider"/> <hr class="featurette-divider"/>
|} |}
title authors date category tags title
(Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
Format.pp_print_string )
authors year month day category
(Format.pp_print_list
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
Format.pp_print_string )
tags
let pp_articles fmt articles_data_list =
List.iter
(fun article ->
Format.fprintf fmt {|<a href="%s">%s</a>@.<br />|} article.url
article.title )
articles_data_list
let home_page home =
let articles =
List.find_all
(fun file ->
(String.length file >= 5 && String.equal (String.sub file 0 5) "blog/")
&& Filename.check_suffix file ".md" )
Content.file_list
in
let articles_data =
List.map
(fun article ->
match Content.read article with
| None -> failwith "invalid article data"
| Some data -> (
match article_of_string data (Filename.chop_suffix article ".md") with
| None -> failwith "invalid article data"
| Some data -> data ) )
articles
in
let articles_by_date =
List.sort (fun a1 a2 -> compare a2.date a1.date) articles_data
in
Format.asprintf "%s%a" home pp_articles articles_by_date
<h1 id="page-title">Blog</h1> <h1 id="page-title">Blog</h1>
This is our blog
title: opam 2.1.0 is released! title:opam 2.1.0 is released!
authors: rjbou authors:rjbou
date: 2021-08-05 date:2021-08-05
category: tooling category:tooling
tags: opam tags:opam
<div class="row"> <div class="row">
<div class="col-lg-12" align="center"> <div class="col-lg-12" align="center">
......
...@@ -14,18 +14,24 @@ let blog_asset_loader _root path _request = ...@@ -14,18 +14,24 @@ let blog_asset_loader _root path _request =
let page path = let page path =
match Content.read (path ^ ".md") with match Content.read (path ^ ".md") with
| None -> None | None -> None
| Some page -> Some (Omd.of_string page |> Omd.to_html) | Some page -> (
match path with
| "blog" -> Some (Omd.of_string (Blog.home_page page) |> Omd.to_html)
| _any_other_page -> Some (Omd.of_string page |> Omd.to_html) )
let article path = let article path =
match Content.read ("blog/" ^ path ^ ".md") with match Content.read ("blog/" ^ path ^ ".md") with
| None -> None | None -> None
| Some blog_article -> ( | Some blog_article -> begin
match String.split_on_char '\n' blog_article with match Blog.article_of_string blog_article path with
| title :: authors :: date :: category :: tags :: article -> | None -> None
let header = Blog.post_header title authors date category tags in | Some article ->
let header =
Some (header ^ (Omd.of_string (String.concat "\n" article) |> Omd.to_html)) Blog.post_header article.title article.authors article.date
| _ -> None ) article.category article.tags
in
Some (header ^ (Omd.of_string article.content |> Omd.to_html))
end
let () = let () =
Dream.run @@ Dream.logger Dream.run @@ Dream.logger
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment