forked from robur/blog.robur.coop
Merge pull request 'Implement tags' (#4) from yocaml2-tags into main
Reviewed-on: robur/blog.robur.coop#4
This commit is contained in:
commit
33ef4926e2
6 changed files with 122 additions and 23 deletions
96
bin/blog.ml
96
bin/blog.ml
|
@ -1,5 +1,7 @@
|
||||||
open Yocaml
|
open Yocaml
|
||||||
|
|
||||||
|
module SM = Map.Make(String)
|
||||||
|
|
||||||
let is_empty_list = function [] -> true | _ -> false
|
let is_empty_list = function [] -> true | _ -> false
|
||||||
|
|
||||||
module Date = struct
|
module Date = struct
|
||||||
|
@ -414,6 +416,69 @@ module Articles = struct
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Tag = struct
|
||||||
|
type t = {
|
||||||
|
name : string;
|
||||||
|
articles : (Path.t * Article.t) list;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make ~name ~articles =
|
||||||
|
{ name; articles }
|
||||||
|
|
||||||
|
let normalize_article (ident, article) =
|
||||||
|
let open Data in
|
||||||
|
record (("url", string @@ Path.to_string ident) :: Article.normalize article)
|
||||||
|
|
||||||
|
let normalize { name; articles } =
|
||||||
|
let open Data in
|
||||||
|
[
|
||||||
|
("name", string name);
|
||||||
|
("articles", (list_of normalize_article) articles);
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
module Tags = struct
|
||||||
|
class type t = object ('self)
|
||||||
|
inherit Articles.t
|
||||||
|
method tags : Tag.t list
|
||||||
|
end
|
||||||
|
|
||||||
|
class tags ?title ?description articles =
|
||||||
|
object
|
||||||
|
inherit Articles.articles ?title ?description articles as super
|
||||||
|
method tags =
|
||||||
|
let tags =
|
||||||
|
let update article sm tag =
|
||||||
|
SM.update tag
|
||||||
|
(function
|
||||||
|
| None -> Some [article]
|
||||||
|
| Some urls -> Some (article :: urls))
|
||||||
|
sm
|
||||||
|
in
|
||||||
|
List.fold_left
|
||||||
|
(fun sm (url, article) ->
|
||||||
|
List.fold_left (update (url, article)) sm article#tags)
|
||||||
|
SM.empty
|
||||||
|
super#articles
|
||||||
|
|> SM.bindings
|
||||||
|
in
|
||||||
|
List.map (fun (tag, articles) ->
|
||||||
|
Tag.make ~name:tag ~articles)
|
||||||
|
tags
|
||||||
|
end
|
||||||
|
|
||||||
|
let of_articles articles =
|
||||||
|
new tags ?title:articles#title ?description:articles#description articles#articles
|
||||||
|
|
||||||
|
let normalize_tag tag =
|
||||||
|
let open Data in
|
||||||
|
record (Tag.normalize tag)
|
||||||
|
|
||||||
|
let normalize tags =
|
||||||
|
let open Data in
|
||||||
|
("all_tags", (list_of normalize_tag tags#tags)) :: Articles.normalize tags
|
||||||
|
end
|
||||||
|
|
||||||
module Make_with_target (S : sig
|
module Make_with_target (S : sig
|
||||||
val source : Path.t
|
val source : Path.t
|
||||||
val target : Path.t
|
val target : Path.t
|
||||||
|
@ -427,6 +492,7 @@ struct
|
||||||
let images = Path.(source_root / "images")
|
let images = Path.(source_root / "images")
|
||||||
let articles = Path.(source_root / "articles")
|
let articles = Path.(source_root / "articles")
|
||||||
let index = Path.(source_root / "pages" / "index.md")
|
let index = Path.(source_root / "pages" / "index.md")
|
||||||
|
let tags = Path.(source_root / "pages" / "tags.md")
|
||||||
let templates = Path.(source_root / "templates")
|
let templates = Path.(source_root / "templates")
|
||||||
let template file = Path.(templates / file)
|
let template file = Path.(templates / file)
|
||||||
let binary = Path.rel [ Sys.argv.(0) ]
|
let binary = Path.rel [ Sys.argv.(0) ]
|
||||||
|
@ -507,6 +573,35 @@ struct
|
||||||
>>> drop_first ()
|
>>> drop_first ()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let process_tags ~host =
|
||||||
|
let file = Source.tags in
|
||||||
|
let file_target = Target.(as_html pages file) in
|
||||||
|
|
||||||
|
let open Task in
|
||||||
|
let compute_index =
|
||||||
|
Articles.compute_index
|
||||||
|
(module Yocaml_yaml)
|
||||||
|
~where:(Path.has_extension "md")
|
||||||
|
~compute_link:(Target.as_html @@ Path.abs [ "articles" ])
|
||||||
|
Source.articles
|
||||||
|
in
|
||||||
|
|
||||||
|
Action.write_static_file file_target
|
||||||
|
begin
|
||||||
|
Pipeline.track_files [ Source.binary; Source.articles ]
|
||||||
|
>>> Yocaml_yaml.Pipeline.read_file_with_metadata (module Page) file
|
||||||
|
>>> Yocaml_cmarkit.content_to_html ()
|
||||||
|
>>> first compute_index
|
||||||
|
>>* (fun (obj, str) -> Eff.return (Tags.of_articles (obj#with_host host), str))
|
||||||
|
>>> Yocaml_jingoo.Pipeline.as_template ~strict:true
|
||||||
|
(module Tags)
|
||||||
|
(Source.template "tags.html")
|
||||||
|
>>> Yocaml_jingoo.Pipeline.as_template ~strict:true
|
||||||
|
(module Tags)
|
||||||
|
(Source.template "layout.html")
|
||||||
|
>>> drop_first ()
|
||||||
|
end
|
||||||
|
|
||||||
let feed_title = "The Robur's blog"
|
let feed_title = "The Robur's blog"
|
||||||
let site_url = "https://blog.robur.coop/"
|
let site_url = "https://blog.robur.coop/"
|
||||||
let feed_description = "The Robur cooperative blog"
|
let feed_description = "The Robur cooperative blog"
|
||||||
|
@ -624,6 +719,7 @@ struct
|
||||||
let open Eff in
|
let open Eff in
|
||||||
Action.restore_cache ~on:`Source Source.cache
|
Action.restore_cache ~on:`Source Source.cache
|
||||||
>>= process_css_files >>= process_js_files >>= process_images_files
|
>>= process_css_files >>= process_js_files >>= process_images_files
|
||||||
|
>>= process_tags ~host
|
||||||
>>= process_articles ~host >>= process_index ~host >>= rss1 >>= rss2 >>= atom
|
>>= process_articles ~host >>= process_index ~host >>= rss1 >>= rss2 >>= atom
|
||||||
>>= Action.store_cache ~on:`Source Source.cache
|
>>= Action.store_cache ~on:`Source Source.cache
|
||||||
end
|
end
|
||||||
|
|
|
@ -197,6 +197,10 @@ article code {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-box:target > h3 > span {
|
||||||
|
background-color: #c2410c;
|
||||||
|
}
|
||||||
|
|
||||||
.tag-box > h3 > span::before {
|
.tag-box > h3 > span::before {
|
||||||
content: "#";
|
content: "#";
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
<ul class="tags-list">
|
<ul class="tags-list">
|
||||||
{%- for tag in tags -%}
|
{%- for tag in tags -%}
|
||||||
<li>{{ tag }}</li>
|
<li><a href="{{ host }}/tags.html#tag-{{ tag }}">{{ tag }}</a></li>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</ul>
|
</ul>
|
||||||
{%- autoescape false -%}
|
{%- autoescape false -%}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<ul class="tags-list">
|
<ul class="tags-list">
|
||||||
{%- for tag in article.tags -%}
|
{%- for tag in article.tags -%}
|
||||||
<li>{{ tag }}</li>
|
<li><a href="{{ host }}/tags.html#tag-{{ tag }}">{{ tag }}</a></li>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
<a href="/index.html">Back to index</a>
|
|
||||||
|
|
||||||
<ul class="tags-list aeration">
|
|
||||||
{%- for tag in tags -%}
|
|
||||||
<li><a href="/{{ tag.link }}">{{ tag.name }} ({{ tag.number }})</a></li>
|
|
||||||
{%- endfor -%}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="tag-box" id="tag-{{ tag }}">
|
|
||||||
{%- set nb_tags = length (articles) -%}
|
|
||||||
<h3>
|
|
||||||
<span>{{ tag }}</span>
|
|
||||||
{{ nb_tags }}
|
|
||||||
{%- if nb_tags > 1 %} entries{%- else %} entry{%- endif -%}
|
|
||||||
</h3>
|
|
||||||
<ul>
|
|
||||||
{%- for article in articles -%}
|
|
||||||
<li><a href="/{{ article.url }}">{{ article.metadata.title }}</a></li>
|
|
||||||
{%- endfor -%}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
20
templates/tags.html
Normal file
20
templates/tags.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<a href="/index.html">Back to index</a>
|
||||||
|
|
||||||
|
<ul class="tags-list aeration">
|
||||||
|
{%- for tag in all_tags -%}
|
||||||
|
<li><a href="#tag-{{ tag.name }}">{{ tag.name }}</a></li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{%- for tag in all_tags -%}
|
||||||
|
<div class="tag-box" id="tag-{{ tag.name }}">
|
||||||
|
<h3>
|
||||||
|
<span>{{ tag.name }}</span>
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
{%- for article in tag.articles -%}
|
||||||
|
<li><a href="{{ host }}{{ article.url }}">{{ article.title }}</a></li>
|
||||||
|
{%- endfor -%}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{%- endfor -%}
|
Loading…
Reference in a new issue