open Yocaml module Metaformat = Yocaml_yaml module Markup = Yocaml_cmark module Template = Yocaml_jingoo let css_target target = "css" |> into target let images_target target = "images" |> into target let js_target target = "js" |> into target let audio_target target = "audio" |> into target let index_html target = "index.html" |> into target let about_html target = "about.html" |> into target let contact_html target = "contact.html" |> into target let archive_html target = "archive.html" |> into target let article_target file target = Model.article_path file |> into target let move_css target = process_files [ "css" ] File.is_css (Build.copy_file ~into:(css_target target)) let move_images target = process_files [ "images" ] File.is_image (Build.copy_file ~into:(images_target target)) let move_js target = process_files [ "js" ] File.is_javascript (Build.copy_file ~into:(js_target target)) let move_audio target = process_files [ "audio" ] (with_extension "ogg") (Build.copy_file ~into:(audio_target target)) let with_layout (type a) (module M : Metadata.INJECTABLE with type t = a) (read_model : (_, a) Build.t) page target = let open Build in let module M = Model.With_layout(M) in let apply_template_from_string (v, content) = let values = M.inject (module Template) v in let content = Template.to_string ~strict:true values content in (v, content) in create_file target (watch Sys.argv.(0) >>> Metaformat.read_file_with_metadata (module Model.Page) page &&& read_model >>^ (fun (({ Model.Page.title; head_extra }, content), v) -> M.merge ~title ~head_extra v, content) >>^ apply_template_from_string >>> Markup.content_to_html ~strict:false () >>> Template.apply_as_template (module M) "templates/layout.html" >>^ Stdlib.snd) let process_articles target = let open Build in process_files [ "posts" ] File.is_markdown (fun article_file -> create_file (article_target article_file target) (Metaformat.read_file_with_metadata (module Model.Article) article_file >>> Markup.content_to_html ~strict:false () >>> Template.apply_as_template (module Model.Article) "templates/article.html" >>> Template.apply_as_template (module Model.Article) "templates/layout.html" >>^ Stdlib.snd)) let articles = let open Build in collection (read_child_files "posts" File.is_markdown) (fun path -> Metaformat.read_file_with_metadata (module Model.Article) path >>^ fun (meta, _data) -> (Model.article_path path, meta)) (fun articles () -> Model.Articles.sort articles) let generate_archive target = let* articles = articles in with_layout (module Model.Articles) articles "pages/archive.md" (archive_html target) let page page_file target = let open Build in create_file target (watch Sys.argv.(0) >>> Metaformat.read_file_with_metadata (module Model.Page) page_file >>> Markup.content_to_html ~strict:false () >>> Template.apply_as_template (module Model.Page) "templates/layout.html" >>^ Stdlib.snd) let generate_about target = page "pages/about.md" (about_html target) let generate_contact target = page "pages/contact.md" (contact_html target) let generate_index target = let* articles = articles in let rec take n xs = match n, xs with | 0, _ | _, [] -> [] | _, x :: xs -> x :: take (pred n) xs in let open Build in let articles = articles >>^ take 3 in with_layout (module Model.Articles) articles "pages/index.md" (index_html target)