Add some docs and rip out unused stuff
This commit is contained in:
parent
992d000fac
commit
dca56d1053
17 changed files with 104 additions and 51 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
//// The database contains all the parsed data from the input files, but not
|
||||||
|
//// processed content.
|
||||||
|
|
||||||
import gleam/dict.{type Dict}
|
import gleam/dict.{type Dict}
|
||||||
import gleam/list
|
import gleam/list
|
||||||
import gleam/option.{None, Some}
|
import gleam/option.{None, Some}
|
||||||
|
@ -9,6 +12,7 @@ import gloss/utils/date.{type Month}
|
||||||
import gloss/utils/ordered_tree.{type OrderedTree}
|
import gloss/utils/ordered_tree.{type OrderedTree}
|
||||||
import gloss/utils/uniqid.{type Generator, type UniqID}
|
import gloss/utils/uniqid.{type Generator, type UniqID}
|
||||||
|
|
||||||
|
/// Internal post ID, generated automatically.
|
||||||
pub type PostID =
|
pub type PostID =
|
||||||
UniqID
|
UniqID
|
||||||
|
|
||||||
|
@ -16,12 +20,15 @@ pub type PostWithID {
|
||||||
PostWithID(id: PostID, post: Post)
|
PostWithID(id: PostID, post: Post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All tags and their posts.
|
||||||
pub type TagPosts =
|
pub type TagPosts =
|
||||||
Dict(Tag, OrderedTree(PostWithID))
|
Dict(Tag, OrderedTree(PostWithID))
|
||||||
|
|
||||||
|
/// Posts organised by month. This is used inside `YearPosts`.
|
||||||
pub type MonthPosts =
|
pub type MonthPosts =
|
||||||
Dict(Month, OrderedTree(PostWithID))
|
Dict(Month, OrderedTree(PostWithID))
|
||||||
|
|
||||||
|
/// Posts organised by year, containing posts organised by month.
|
||||||
pub type YearPosts =
|
pub type YearPosts =
|
||||||
Dict(Int, MonthPosts)
|
Dict(Int, MonthPosts)
|
||||||
|
|
||||||
|
@ -37,6 +44,7 @@ pub opaque type Database {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new empty database.
|
||||||
pub fn new() -> Database {
|
pub fn new() -> Database {
|
||||||
Database(
|
Database(
|
||||||
posts: new_tree(),
|
posts: new_tree(),
|
||||||
|
@ -49,6 +57,7 @@ pub fn new() -> Database {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a post into the database.
|
||||||
pub fn add_post(db: Database, post: Post) -> Database {
|
pub fn add_post(db: Database, post: Post) -> Database {
|
||||||
let post_date = post.get_date(post)
|
let post_date = post.get_date(post)
|
||||||
let #(id, id_generator) = uniqid.get(db.id_generator)
|
let #(id, id_generator) = uniqid.get(db.id_generator)
|
||||||
|
@ -100,22 +109,27 @@ pub fn add_post(db: Database, post: Post) -> Database {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a page into the database.
|
||||||
pub fn add_page(db: Database, page: Page) -> Database {
|
pub fn add_page(db: Database, page: Page) -> Database {
|
||||||
Database(..db, pages: [page, ..db.pages])
|
Database(..db, pages: [page, ..db.pages])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the menu items of the database, replacing any old ones.
|
||||||
pub fn set_menu(db: Database, menu: List(MenuItem)) -> Database {
|
pub fn set_menu(db: Database, menu: List(MenuItem)) -> Database {
|
||||||
Database(..db, menu: menu)
|
Database(..db, menu: menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get posts organised by tags.
|
||||||
pub fn tags(db: Database) {
|
pub fn tags(db: Database) {
|
||||||
db.tags
|
db.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get posts organised by years and months.
|
||||||
pub fn years(db: Database) {
|
pub fn years(db: Database) {
|
||||||
db.years
|
db.years
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all posts in the given order.
|
||||||
pub fn get_posts_with_ids(
|
pub fn get_posts_with_ids(
|
||||||
db: Database,
|
db: Database,
|
||||||
order: ordered_tree.WalkOrder,
|
order: ordered_tree.WalkOrder,
|
||||||
|
@ -123,10 +137,12 @@ pub fn get_posts_with_ids(
|
||||||
ordered_tree.to_list(db.posts, order)
|
ordered_tree.to_list(db.posts, order)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get pages.
|
||||||
pub fn pages(db: Database) {
|
pub fn pages(db: Database) {
|
||||||
db.pages
|
db.pages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get menu items.
|
||||||
pub fn menu(db: Database) {
|
pub fn menu(db: Database) {
|
||||||
db.menu
|
db.menu
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
/// A post or page header: a string key and a string value.
|
||||||
pub type Header =
|
pub type Header =
|
||||||
#(String, String)
|
#(String, String)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// A menu item that points to some URL (relative or absolute) and has a name.
|
||||||
pub type MenuItem {
|
pub type MenuItem {
|
||||||
MenuItem(url: String, name: String)
|
MenuItem(url: String, name: String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//// A static page in the blog that is not part of any post lists or archives.
|
||||||
|
|
||||||
import gloss/models/header.{type Header}
|
import gloss/models/header.{type Header}
|
||||||
|
|
||||||
pub type Page {
|
pub type Page {
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
|
//// A post in the blog.
|
||||||
|
|
||||||
|
import gleam/int
|
||||||
import gleam/option.{type Option}
|
import gleam/option.{type Option}
|
||||||
import gleam/order.{type Order, Eq, Gt, Lt}
|
import gleam/order.{type Order, Eq}
|
||||||
import gloss/utils/date.{type Date}
|
import gloss/utils/date.{type Date}
|
||||||
import gloss/utils/time.{type Time, Time}
|
import gloss/utils/time.{type Time, Time}
|
||||||
import gloss/utils/luxon.{type DateTime}
|
import gloss/utils/luxon.{type DateTime}
|
||||||
import gloss/models/header.{type Header}
|
import gloss/models/header.{type Header}
|
||||||
|
|
||||||
pub type PostedAt {
|
pub type PostedAt {
|
||||||
|
/// The post only had date information.
|
||||||
JustDate(Date)
|
JustDate(Date)
|
||||||
|
|
||||||
|
/// The post had date, time, and timezone information.
|
||||||
DateTime(date: Date, time: Time, tz: String, luxon: DateTime)
|
DateTime(date: Date, time: Time, tz: String, luxon: DateTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A tag is any string of lowercase characters, numbers, dashes, or underscores.
|
||||||
pub type Tag =
|
pub type Tag =
|
||||||
String
|
String
|
||||||
|
|
||||||
|
@ -20,12 +27,15 @@ pub type Post {
|
||||||
tags: List(Tag),
|
tags: List(Tag),
|
||||||
headers: List(Header),
|
headers: List(Header),
|
||||||
content: String,
|
content: String,
|
||||||
|
/// The content before the split, if any
|
||||||
short_content: Option(String),
|
short_content: Option(String),
|
||||||
date: PostedAt,
|
date: PostedAt,
|
||||||
|
/// The post's order during that day, if there are multiple posts on the same day.
|
||||||
order: Int,
|
order: Int,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the date of the post.
|
||||||
pub fn get_date(post: Post) -> Date {
|
pub fn get_date(post: Post) -> Date {
|
||||||
case post.date {
|
case post.date {
|
||||||
JustDate(date) -> date
|
JustDate(date) -> date
|
||||||
|
@ -33,6 +43,7 @@ pub fn get_date(post: Post) -> Date {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the time of the post, if it exists.
|
||||||
pub fn get_time(post: Post) -> Option(Time) {
|
pub fn get_time(post: Post) -> Option(Time) {
|
||||||
case post.date {
|
case post.date {
|
||||||
JustDate(..) -> option.None
|
JustDate(..) -> option.None
|
||||||
|
@ -40,6 +51,7 @@ pub fn get_time(post: Post) -> Option(Time) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the Luxon datetime of the post, if it exists.
|
||||||
pub fn get_luxon(post: Post) -> Option(luxon.DateTime) {
|
pub fn get_luxon(post: Post) -> Option(luxon.DateTime) {
|
||||||
case post.date {
|
case post.date {
|
||||||
JustDate(..) -> option.None
|
JustDate(..) -> option.None
|
||||||
|
@ -47,21 +59,25 @@ pub fn get_luxon(post: Post) -> Option(luxon.DateTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compare two posts and get an order between them.
|
||||||
pub fn comparator(a: Post, b: Post) -> Order {
|
pub fn comparator(a: Post, b: Post) -> Order {
|
||||||
let a_date = get_date(a)
|
let a_date = get_date(a)
|
||||||
let b_date = get_date(b)
|
let b_date = get_date(b)
|
||||||
|
|
||||||
case date.compare(a_date, b_date) {
|
case date.compare(a_date, b_date) {
|
||||||
Lt -> Lt
|
|
||||||
Gt -> Gt
|
|
||||||
Eq -> {
|
Eq -> {
|
||||||
let a_time = option.lazy_unwrap(get_time(a), time.nil_time)
|
let a_time = option.lazy_unwrap(get_time(a), time.nil_time)
|
||||||
let b_time = option.lazy_unwrap(get_time(b), time.nil_time)
|
let b_time = option.lazy_unwrap(get_time(b), time.nil_time)
|
||||||
time.compare(a_time, b_time)
|
case time.compare(a_time, b_time) {
|
||||||
|
Eq -> int.compare(a.order, b.order)
|
||||||
|
other -> other
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
other -> other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the post's date or datetime formatted as an ISO 8601 formatted string.
|
||||||
pub fn to_iso8601(post: Post) -> String {
|
pub fn to_iso8601(post: Post) -> String {
|
||||||
case post.date {
|
case post.date {
|
||||||
JustDate(d) -> date.format_iso(d)
|
JustDate(d) -> date.format_iso(d)
|
||||||
|
|
|
@ -4,10 +4,12 @@ import gleam/list
|
||||||
import gleam/bool
|
import gleam/bool
|
||||||
import gloss/models/header.{type Header}
|
import gloss/models/header.{type Header}
|
||||||
|
|
||||||
|
/// The default file extension for source files.
|
||||||
pub const filename_postfix = ".md"
|
pub const filename_postfix = ".md"
|
||||||
|
|
||||||
const header_separator = ":"
|
const header_separator = ":"
|
||||||
|
|
||||||
|
/// An error that occurred when parsing content.
|
||||||
pub type ParseError {
|
pub type ParseError {
|
||||||
EmptyFile
|
EmptyFile
|
||||||
HeaderMissing
|
HeaderMissing
|
||||||
|
@ -19,16 +21,19 @@ pub type ParseError {
|
||||||
MalformedHeader(header: String)
|
MalformedHeader(header: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the `value` is `Ok`, run `if_ok`, otherwise return `error`.
|
||||||
pub fn try(value: Result(a, b), error: c, if_ok: fn(a) -> Result(d, c)) {
|
pub fn try(value: Result(a, b), error: c, if_ok: fn(a) -> Result(d, c)) {
|
||||||
result.try(result.replace_error(value, error), if_ok)
|
result.try(result.replace_error(value, error), if_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse given lines as headers.
|
||||||
pub fn parse_headers(headers: List(String)) -> Result(List(Header), ParseError) {
|
pub fn parse_headers(headers: List(String)) -> Result(List(Header), ParseError) {
|
||||||
headers
|
headers
|
||||||
|> list.map(parse_header)
|
|> list.map(parse_header)
|
||||||
|> result.all()
|
|> result.all()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse given line as a header.
|
||||||
pub fn parse_header(header: String) -> Result(Header, ParseError) {
|
pub fn parse_header(header: String) -> Result(Header, ParseError) {
|
||||||
let header_parts = string.split(header, header_separator)
|
let header_parts = string.split(header, header_separator)
|
||||||
let parts_amount = list.length(header_parts)
|
let parts_amount = list.length(header_parts)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import gleam/string
|
||||||
import gleam/result
|
import gleam/result
|
||||||
import gloss/models/menu.{MenuItem}
|
import gloss/models/menu.{MenuItem}
|
||||||
|
|
||||||
|
/// Parse the content and return menu items.
|
||||||
pub fn parse(content: String) {
|
pub fn parse(content: String) {
|
||||||
string.split(content, "\n")
|
string.split(content, "\n")
|
||||||
|> list.filter(fn(line) { string.length(line) != 0 })
|
|> list.filter(fn(line) { string.length(line) != 0 })
|
||||||
|
|
|
@ -4,6 +4,7 @@ import gleam/list
|
||||||
import gloss/models/page.{type Page, Page}
|
import gloss/models/page.{type Page, Page}
|
||||||
import gloss/parser/common.{type ParseError, EmptyFile, HeaderMissing, try}
|
import gloss/parser/common.{type ParseError, EmptyFile, HeaderMissing, try}
|
||||||
|
|
||||||
|
/// Parse page from file data.
|
||||||
pub fn parse(filename: String, contents: String) -> Result(Page, ParseError) {
|
pub fn parse(filename: String, contents: String) -> Result(Page, ParseError) {
|
||||||
let lines = string.split(contents, "\n")
|
let lines = string.split(contents, "\n")
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import gloss/parser/common.{
|
||||||
MalformedFilename, MalformedHeader, MonthNotInt, YearNotInt, try,
|
MalformedFilename, MalformedHeader, MonthNotInt, YearNotInt, try,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Post filenames must match this regex.
|
||||||
pub const filename_regex = "^\\d{4}-\\d\\d-\\d\\d-.*\\.md$"
|
pub const filename_regex = "^\\d{4}-\\d\\d-\\d\\d-.*\\.md$"
|
||||||
|
|
||||||
const filename_separator = "-"
|
const filename_separator = "-"
|
||||||
|
@ -28,6 +29,7 @@ type FilenameMeta {
|
||||||
FilenameMeta(date: PostedAt, order: Int, slug: String)
|
FilenameMeta(date: PostedAt, order: Int, slug: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse post from file data.
|
||||||
pub fn parse(filename: String, contents: String) -> Result(Post, ParseError) {
|
pub fn parse(filename: String, contents: String) -> Result(Post, ParseError) {
|
||||||
let filename =
|
let filename =
|
||||||
string.slice(
|
string.slice(
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import gleam/string
|
import gleam/string
|
||||||
|
import gleam/list
|
||||||
import gloss/models/post.{type Post}
|
import gloss/models/post.{type Post}
|
||||||
import gloss/models/page.{type Page}
|
import gloss/models/page.{type Page}
|
||||||
import gloss/paths/post as post_paths
|
|
||||||
import gloss/utils/date.{type Month}
|
import gloss/utils/date.{type Month}
|
||||||
|
import gloss/utils/ints/day
|
||||||
|
|
||||||
pub const default_root = ""
|
pub const default_root = ""
|
||||||
|
|
||||||
|
@ -44,9 +45,18 @@ pub const defaults = PathConfiguration(
|
||||||
)
|
)
|
||||||
|
|
||||||
pub fn default_single_post(post: Post) {
|
pub fn default_single_post(post: Post) {
|
||||||
let post_path = post_paths.post_to_path(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,
|
||||||
|
)
|
||||||
|
|
||||||
"/" <> post_path.date_path <> "/" <> post_path.slug
|
"/" <> string.join(date_parts, "/") <> "/" <> post.slug
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_page(page: Page) {
|
pub fn default_page(page: Page) {
|
||||||
|
@ -81,3 +91,9 @@ pub fn default_list_page(path: String, page: Int) {
|
||||||
pub fn default_html(path: String) {
|
pub fn default_html(path: String) {
|
||||||
path <> ".html"
|
path <> ".html"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pad_int(number: Int) -> String {
|
||||||
|
number
|
||||||
|
|> int.to_string()
|
||||||
|
|> string.pad_left(to: 2, with: "0")
|
||||||
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import gleam/string
|
|
||||||
import gleam/int
|
|
||||||
import gleam/list
|
|
||||||
import gloss/models/post.{type Post}
|
|
||||||
import gloss/utils/date
|
|
||||||
import gloss/utils/ints/day
|
|
||||||
|
|
||||||
pub type PostPath {
|
|
||||||
PostPath(date_path: String, slug: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn post_to_path(post: Post) -> PostPath {
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
PostPath(date_path: string.join(date_parts, "/"), slug: post.slug)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pad_int(number: Int) -> String {
|
|
||||||
number
|
|
||||||
|> int.to_string()
|
|
||||||
|> string.pad_left(to: 2, with: "0")
|
|
||||||
}
|
|
|
@ -55,9 +55,7 @@ pub fn render(
|
||||||
let feed = render_feed(all_posts, compiled.posts, views)
|
let feed = render_feed(all_posts, compiled.posts, views)
|
||||||
|
|
||||||
RenderDatabase(
|
RenderDatabase(
|
||||||
orig: db,
|
|
||||||
single_posts: posts,
|
single_posts: posts,
|
||||||
index: [],
|
|
||||||
pages: pages,
|
pages: pages,
|
||||||
index_pages: index_pages,
|
index_pages: index_pages,
|
||||||
tag_pages: tag_pages,
|
tag_pages: tag_pages,
|
||||||
|
|
|
@ -1,35 +1,41 @@
|
||||||
|
//// The render database stores the rendered posts and pages.
|
||||||
|
|
||||||
import gleam/dict.{type Dict}
|
import gleam/dict.{type Dict}
|
||||||
import lustre/element.{type Element}
|
import lustre/element.{type Element}
|
||||||
import gloss/models/database.{type Database, type PostID} as _
|
|
||||||
import gloss/models/post.{type Post}
|
import gloss/models/post.{type Post}
|
||||||
import gloss/models/page.{type Page}
|
import gloss/models/page.{type Page}
|
||||||
import gloss/utils/date.{type Month}
|
import gloss/utils/date.{type Month}
|
||||||
|
|
||||||
pub type PostList =
|
/// A post and its rendered content.
|
||||||
List(PostID)
|
|
||||||
|
|
||||||
pub type RenderedSinglePost {
|
pub type RenderedSinglePost {
|
||||||
RenderedSinglePost(orig: Post, content: Element(Nil))
|
RenderedSinglePost(orig: Post, content: Element(Nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A page and its rendered content.
|
||||||
pub type RenderedPage {
|
pub type RenderedPage {
|
||||||
RenderedPage(page: Page, content: Element(Nil))
|
RenderedPage(page: Page, content: Element(Nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A list page's page number and the page's content.
|
||||||
pub type RenderedListPage {
|
pub type RenderedListPage {
|
||||||
ListPage(page: Int, content: Element(Nil))
|
ListPage(page: Int, content: Element(Nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type RenderDatabase {
|
pub type RenderDatabase {
|
||||||
RenderDatabase(
|
RenderDatabase(
|
||||||
orig: Database,
|
/// Individual posts.
|
||||||
single_posts: List(RenderedSinglePost),
|
single_posts: List(RenderedSinglePost),
|
||||||
index: PostList,
|
/// Individual pages.
|
||||||
pages: List(RenderedPage),
|
pages: List(RenderedPage),
|
||||||
|
/// "Index" list pages, meaning the main post flow.
|
||||||
index_pages: List(RenderedListPage),
|
index_pages: List(RenderedListPage),
|
||||||
|
/// Tag list pages.
|
||||||
tag_pages: Dict(String, List(RenderedListPage)),
|
tag_pages: Dict(String, List(RenderedListPage)),
|
||||||
|
/// Year list pages.
|
||||||
year_pages: Dict(Int, List(RenderedListPage)),
|
year_pages: Dict(Int, List(RenderedListPage)),
|
||||||
|
/// Month list pages.
|
||||||
month_pages: Dict(#(Int, Month), List(RenderedListPage)),
|
month_pages: Dict(#(Int, Month), List(RenderedListPage)),
|
||||||
|
/// The feed (corresponding to the main post flow).
|
||||||
feed: Element(Nil),
|
feed: Element(Nil),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,36 +3,57 @@ import gloss/compiler.{type CompiledPage, type CompiledPost}
|
||||||
import gloss/models/post
|
import gloss/models/post
|
||||||
import gloss/models/page
|
import gloss/models/page
|
||||||
|
|
||||||
|
/// The base view renders the base page layout.
|
||||||
|
///
|
||||||
|
/// The three arguments are:
|
||||||
|
/// - The inner content to render in the layout.
|
||||||
|
/// - Extra elements to put inside `<head>`.
|
||||||
|
/// - Text to add as a prefix to the `<title>` element.
|
||||||
pub type BaseView =
|
pub type BaseView =
|
||||||
fn(Element(Nil), List(Element(Nil)), String) -> Element(Nil)
|
fn(Element(Nil), List(Element(Nil)), String) -> Element(Nil)
|
||||||
|
|
||||||
|
/// Types of pages in the blog.
|
||||||
pub type PageType {
|
pub type PageType {
|
||||||
|
/// Individual post.
|
||||||
Post(post.Post)
|
Post(post.Post)
|
||||||
|
/// Individual page.
|
||||||
Page(page.Page)
|
Page(page.Page)
|
||||||
|
/// Any other page.
|
||||||
Other(title: String, description: String)
|
Other(title: String, description: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The meta view renders meta tags such as OpenGraph based on the page information.
|
||||||
pub type MetaView =
|
pub type MetaView =
|
||||||
fn(PageType) -> List(Element(Nil))
|
fn(PageType) -> List(Element(Nil))
|
||||||
|
|
||||||
|
/// View to render an individual post.
|
||||||
pub type SinglePostView =
|
pub type SinglePostView =
|
||||||
fn(CompiledPost) -> Element(Nil)
|
fn(CompiledPost) -> Element(Nil)
|
||||||
|
|
||||||
|
/// View to render an individual page.
|
||||||
pub type PageView =
|
pub type PageView =
|
||||||
fn(CompiledPage) -> Element(Nil)
|
fn(CompiledPage) -> Element(Nil)
|
||||||
|
|
||||||
|
/// View to render the RSS or Atom feed.
|
||||||
pub type FeedView =
|
pub type FeedView =
|
||||||
fn(List(CompiledPost)) -> Element(Nil)
|
fn(List(CompiledPost)) -> Element(Nil)
|
||||||
|
|
||||||
|
/// Information passed for list pages.
|
||||||
pub type ListInfo {
|
pub type ListInfo {
|
||||||
ListInfo(
|
ListInfo(
|
||||||
|
/// The path to prefix before the page number. E.g. `/index` and the resulting path would then be `/index/2`.
|
||||||
root_path: String,
|
root_path: String,
|
||||||
|
/// The page number of the current page being rendered.
|
||||||
current_page: Int,
|
current_page: Int,
|
||||||
|
/// The amount of pages in the current list.
|
||||||
total_pages: Int,
|
total_pages: Int,
|
||||||
|
/// Posts on this page.
|
||||||
posts: List(CompiledPost),
|
posts: List(CompiledPost),
|
||||||
|
/// Any extra content to put on top of the page before the posts.
|
||||||
extra_header: Element(Nil),
|
extra_header: Element(Nil),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View to render a list page. A list page is a page with many posts in a list.
|
||||||
pub type ListPageView =
|
pub type ListPageView =
|
||||||
fn(ListInfo) -> Element(Nil)
|
fn(ListInfo) -> Element(Nil)
|
||||||
|
|
|
@ -18,6 +18,7 @@ import gloss/config.{type Configuration}
|
||||||
|
|
||||||
const tag_min_size = 0.5
|
const tag_min_size = 0.5
|
||||||
|
|
||||||
|
/// The base view pre-renders some content once, so that it can be reused for every render.
|
||||||
pub type PreRendered {
|
pub type PreRendered {
|
||||||
PreRendered(pages: Element(Nil), tags: Element(Nil), archives: Element(Nil))
|
PreRendered(pages: Element(Nil), tags: Element(Nil), archives: Element(Nil))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,12 @@ import gloss/utils/date
|
||||||
import gloss/utils/time
|
import gloss/utils/time
|
||||||
import gloss/utils/luxon
|
import gloss/utils/luxon
|
||||||
|
|
||||||
|
/// Generate a view that renders a full post.
|
||||||
pub fn full_view(db: Database, config: Configuration) {
|
pub fn full_view(db: Database, config: Configuration) {
|
||||||
view(_, True, db, config)
|
view(_, True, db, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a view that renders a post that's inside of a list.
|
||||||
pub fn list_view(db: Database, config: Configuration) {
|
pub fn list_view(db: Database, config: Configuration) {
|
||||||
view(_, False, db, config)
|
view(_, False, db, config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,8 @@ import lustre/ssg
|
||||||
import lustre/ssg/xml
|
import lustre/ssg/xml
|
||||||
import lustre/element
|
import lustre/element
|
||||||
import gloss/rendering/database.{type RenderDatabase} as _
|
import gloss/rendering/database.{type RenderDatabase} as _
|
||||||
import gloss/models/post.{type Post}
|
|
||||||
import gloss/paths/post.{type PostPath} as _
|
|
||||||
import gloss/config.{type Configuration, WriteError}
|
import gloss/config.{type Configuration, WriteError}
|
||||||
|
|
||||||
pub type PostPathGenerator =
|
|
||||||
fn(Post) -> PostPath
|
|
||||||
|
|
||||||
pub fn write(db: RenderDatabase, config: Configuration) {
|
pub fn write(db: RenderDatabase, config: Configuration) {
|
||||||
let site =
|
let site =
|
||||||
ssg.new(config.output_path)
|
ssg.new(config.output_path)
|
||||||
|
|
Loading…
Reference in a new issue