From a00a808618aedc9c7980fc2506c919839b2d9a72 Mon Sep 17 00:00:00 2001 From: Mikko Ahlroth Date: Mon, 6 May 2024 19:35:17 +0300 Subject: [PATCH] Split tags and archives into their own components --- .../rendering/views/archives.gleam | 70 ++++++++++ src/scriptorium/rendering/views/base.gleam | 121 ++---------------- src/scriptorium/rendering/views/tags.gleam | 58 +++++++++ 3 files changed, 140 insertions(+), 109 deletions(-) create mode 100644 src/scriptorium/rendering/views/archives.gleam create mode 100644 src/scriptorium/rendering/views/tags.gleam diff --git a/src/scriptorium/rendering/views/archives.gleam b/src/scriptorium/rendering/views/archives.gleam new file mode 100644 index 0000000..7cecf64 --- /dev/null +++ b/src/scriptorium/rendering/views/archives.gleam @@ -0,0 +1,70 @@ +//// The archives component renders all the years and months where there are +//// posts as nested unordered lists. + +import gleam/dict +import gleam/int +import gleam/list +import lustre/attribute.{href} +import lustre/element.{text} +import lustre/element/html.{a, li, ul} +import scriptorium/config.{type Configuration} +import scriptorium/models/database.{type Database} +import scriptorium/utils/date +import scriptorium/utils/ordered_tree + +pub fn view(db: Database, config: Configuration) { + db + |> database.years() + |> dict.to_list() + |> list.sort(fn(a, b) { int.compare(a.0, b.0) }) + |> list.fold([], fn(year_archive, year) { + let #(year, months) = year + [ + li([], [ + a( + [ + href(config.paths.html( + config.paths.root + <> config.paths.list_page(config.paths.year(year), 1), + )), + ], + [text(int.to_string(year))], + ), + ul( + [], + list.fold(date.months, [], fn(month_archive, month) { + case dict.get(months, month) { + Ok(posts) -> [ + li([], [ + a( + [ + href(config.paths.html( + config.paths.root + <> config.paths.list_page( + config.paths.month(year, month), + 1, + ), + )), + ], + [ + text( + date.month_to_string(month) + <> " (" + <> int.to_string(ordered_tree.length(posts)) + <> ")", + ), + ], + ), + ]), + ..month_archive + ] + Error(_) -> month_archive + } + }), + ), + ]), + ..year_archive + ] + }) + |> ul([], _) +} diff --git a/src/scriptorium/rendering/views/base.gleam b/src/scriptorium/rendering/views/base.gleam index 47b8e33..f99c537 100644 --- a/src/scriptorium/rendering/views/base.gleam +++ b/src/scriptorium/rendering/views/base.gleam @@ -1,10 +1,7 @@ import gleam/dict -import gleam/float -import gleam/int import gleam/list import gleam/option -import gleam/string -import lustre/attribute.{attribute, href, id, name, rel, role, style, type_} +import lustre/attribute.{attribute, href, id, name, rel, role, type_} import lustre/element.{type Element, text} import lustre/element/html.{ a, body, footer, h1, head, header, html, li, link, main, meta, nav, p, section, @@ -13,10 +10,8 @@ import lustre/element/html.{ import scriptorium/config.{type Configuration} import scriptorium/models/database.{type Database} import scriptorium/models/menu.{type MenuItem} -import scriptorium/utils/date -import scriptorium/utils/ordered_tree - -const tag_min_size = 0.5 +import scriptorium/rendering/views/archives +import scriptorium/rendering/views/tags /// The base view pre-renders some content once, so that it can be reused for every render. pub type PreRendered { @@ -24,13 +19,20 @@ pub type PreRendered { } pub fn generate(db: Database, config: Configuration) { - let pre_rendered = pre_render(db, config) + let pre_rendered = pre_render(db, config, tags.view, archives.view) fn(inner: Element(Nil), extra_meta: List(Element(Nil)), title_prefix: String) { view(db, config, pre_rendered, inner, extra_meta, title_prefix) } } -fn pre_render(db, config) -> PreRendered { +/// Pre-render the tag and archive elements using the given tags and archives +/// components. +pub fn pre_render( + db: Database, + config: Configuration, + tags: fn(Database, Configuration) -> Element(Nil), + archives: fn(Database, Configuration) -> Element(Nil), +) -> PreRendered { PreRendered(tags: tags(db, config), archives: archives(db, config)) } @@ -110,105 +112,6 @@ fn view( ]) } -fn tags(db: Database, config: Configuration) { - let tags = - db - |> database.tags() - |> dict.map_values(fn(_key, posts) { - int.to_float(ordered_tree.length(posts)) - }) - - let most_posts = - tags - |> dict.values() - |> list.fold(0.0, float.max) - - tags - |> dict.to_list() - |> list.sort(fn(a, b) { - string.compare(string.lowercase(a.0), string.lowercase(b.0)) - }) - |> list.map(fn(item) { - let #(tag, post_count) = item - let percentage = - float.round( - { - { { post_count /. most_posts } *. { 1.0 -. tag_min_size } } - +. tag_min_size - } - *. 100.0, - ) - - li([], [ - a( - [ - href(config.paths.html(config.paths.root <> config.paths.tag(tag))), - style([#("font-size", int.to_string(percentage) <> "%")]), - ], - [text(tag)], - ), - ]) - }) - |> ul([], _) -} - -fn archives(db: Database, config: Configuration) { - db - |> database.years() - |> dict.to_list() - |> list.sort(fn(a, b) { int.compare(a.0, b.0) }) - |> list.fold([], fn(year_archive, year) { - let #(year, months) = year - [ - li([], [ - a( - [ - href(config.paths.html( - config.paths.root - <> config.paths.list_page(config.paths.year(year), 1), - )), - ], - [text(int.to_string(year))], - ), - ul( - [], - list.fold(date.months, [], fn(month_archive, month) { - case dict.get(months, month) { - Ok(posts) -> [ - li([], [ - a( - [ - href(config.paths.html( - config.paths.root - <> config.paths.list_page( - config.paths.month(year, month), - 1, - ), - )), - ], - [ - text( - date.month_to_string(month) - <> " (" - <> int.to_string(ordered_tree.length(posts)) - <> ")", - ), - ], - ), - ]), - ..month_archive - ] - Error(_) -> month_archive - } - }), - ), - ]), - ..year_archive - ] - }) - |> ul([], _) -} - fn menu(menu: List(MenuItem)) { nav([], [ ul( diff --git a/src/scriptorium/rendering/views/tags.gleam b/src/scriptorium/rendering/views/tags.gleam new file mode 100644 index 0000000..3282824 --- /dev/null +++ b/src/scriptorium/rendering/views/tags.gleam @@ -0,0 +1,58 @@ +//// The tags component renders tags of the database as a tag cloud with tags of +//// varying sizes as an unordered list. + +import gleam/dict +import gleam/float +import gleam/int +import gleam/list +import gleam/string +import lustre/attribute.{href, style} +import lustre/element.{text} +import lustre/element/html.{a, li, ul} +import scriptorium/config.{type Configuration} +import scriptorium/models/database.{type Database} +import scriptorium/utils/ordered_tree + +const tag_min_size = 0.5 + +pub fn view(db: Database, config: Configuration) { + let tags = + db + |> database.tags() + |> dict.map_values(fn(_key, posts) { + int.to_float(ordered_tree.length(posts)) + }) + + let most_posts = + tags + |> dict.values() + |> list.fold(0.0, float.max) + + tags + |> dict.to_list() + |> list.sort(fn(a, b) { + string.compare(string.lowercase(a.0), string.lowercase(b.0)) + }) + |> list.map(fn(item) { + let #(tag, post_count) = item + let percentage = + float.round( + { + { { post_count /. most_posts } *. { 1.0 -. tag_min_size } } + +. tag_min_size + } + *. 100.0, + ) + + li([], [ + a( + [ + href(config.paths.html(config.paths.root <> config.paths.tag(tag))), + style([#("font-size", int.to_string(percentage) <> "%")]), + ], + [text(tag)], + ), + ]) + }) + |> ul([], _) +}