Skip to content
Snippets Groups Projects
paths.gleam 3.88 KiB
Newer Older
Mikko Ahlroth's avatar
Mikko Ahlroth committed
//// Path configuration controls where files are generated and how links are
//// formed.

import gleam/int
import gleam/list
Mikko Ahlroth's avatar
Mikko Ahlroth committed
import gleam/string
Mikko Ahlroth's avatar
Mikko Ahlroth committed
import scriptorium/models/page.{type Page}
import scriptorium/models/post.{type Post}
import scriptorium/utils/date.{type Month}
import scriptorium/utils/ints/day
Mikko Ahlroth's avatar
Mikko Ahlroth committed
const default_root = ""
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// The default index path.
pub const default_index = "/index"

Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// The default filename where the feed is written.
pub const default_feed_file = "/feed"
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// The default path where the feed is accessible when hosted.
pub const default_feed = default_feed_file

Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// The path configuration controls where files will be located and where links
/// will point to.
pub type PathConfiguration {
  PathConfiguration(
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// The root path where the blog will be accessible. With starting slash but
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// without trailing slash, e.g. `/scriptorium_blog`. Note that if the blog is
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// accessible without a subpath, this value should be `""`.
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// The index path. Note that the first page of the index is always written
    /// into `"/"`, meaning `index.html`. This path is used for the rest of the
    /// pages, e.g. `"/wibble"` would result in `/wibble/2.html`,
    /// `/wibble/3.html` and so on.
    index: String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to a single post.
    single_post: fn(Post) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to a page.
    page: fn(Page) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to a tag archive.
    tag: fn(String) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to a year archive.
    year: fn(Int) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to a month archive of a given year.
    month: fn(Int, Month) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// List page path: given the original path such as `/tag/wibble` as a
    /// string and the page number, forms the final path.
    list_page: fn(String, Int) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// HTML path: Append (or don't) the `.html` extension to the given path.
    /// If you are using fancy URLs without extensions, override this to do
    /// nothing.
    html: fn(String) -> String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    /// Path to the feed as it is accessible from the browser.
    feed: String,
    /// Path and file name of the feed file that will be written, _without_ the
    /// file extension! E.g. `/feed` will create a file `/feed.xml`.
    feed_file: String,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Default path configuration.
pub const defaults = PathConfiguration(
  index: default_index,
  single_post: default_single_post,
  page: default_page,
  tag: default_tag,
  year: default_year_archive,
  month: default_month_archive,
  list_page: default_list_page,
  html: default_html,
  feed: default_feed,
  feed_file: default_feed_file,
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Post path in the format `/2024/12/31/slug`.
pub fn default_single_post(post: Post) {
  let post_date = post.get_date(post)
  let date_parts =
    list.map(
      [
        post_date.year,
        date.month_to_int(post_date.month),
        day.to_int(post_date.day),
      ],
      pad_int,
    )
  "/" <> string.join(date_parts, "/") <> "/" <> post.slug
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Page path in the format `/slug`.
pub fn default_page(page: Page) {
  "/" <> page.slug
}

Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Tag path in the format `/tag/tag`.
pub fn default_tag(tag: String) {
Mikko Ahlroth's avatar
Mikko Ahlroth committed
  "/tag/" <> tag
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Year archive path in the format `/archive/2024`.
pub fn default_year_archive(year: Int) {
Mikko Ahlroth's avatar
Mikko Ahlroth committed
  "/archive" <> "/" <> int.to_string(year)
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Month archive path in the format `/archive/2024/05`.
pub fn default_month_archive(year: Int, month: Month) {
  default_year_archive(year)
Mikko Ahlroth's avatar
Mikko Ahlroth committed
  <> "/"
  <> string.pad_left(int.to_string(date.month_to_int(month)), 2, "0")
}

/// Get the given list path with a page number.
///
/// The first page does not get any appended page number.
pub fn default_list_page(path: String, page: Int) {
  case page {
    1 -> path
Mikko Ahlroth's avatar
Mikko Ahlroth committed
    other -> path <> "/" <> int.to_string(other)
Mikko Ahlroth's avatar
Mikko Ahlroth committed
/// Get path with the .html extension.
pub fn default_html(path: String) {
  path <> ".html"
}

fn pad_int(number: Int) -> String {
  number
  |> int.to_string()
  |> string.pad_left(to: 2, with: "0")
}