diff --git a/src/gloss/models/database.gleam b/src/gloss/models/database.gleam index f51a9b1..0fa1a1a 100644 --- a/src/gloss/models/database.gleam +++ b/src/gloss/models/database.gleam @@ -4,6 +4,7 @@ import gleam/option.{None, Some} import gleam/order.{type Order} import gloss/models/post.{type Post, type Tag} import gloss/models/page.{type Page} +import gloss/models/menu.{type MenuItem} import gloss/utils/date.{type Month} import gloss/utils/ordered_tree.{type OrderedTree} import gloss/utils/uniqid.{type Generator, type UniqID} @@ -28,6 +29,7 @@ pub opaque type Database { Database( posts: OrderedTree(PostWithID), pages: List(Page), + menu: List(MenuItem), tags: TagPosts, years: YearPosts, posts_by_id: Dict(PostID, Post), @@ -39,6 +41,7 @@ pub fn new() -> Database { Database( posts: new_tree(), pages: [], + menu: [], tags: dict.new(), years: dict.new(), posts_by_id: dict.new(), @@ -101,6 +104,10 @@ pub fn add_page(db: Database, page: Page) -> Database { Database(..db, pages: [page, ..db.pages]) } +pub fn set_menu(db: Database, menu: List(MenuItem)) -> Database { + Database(..db, menu: menu) +} + pub fn tags(db: Database) { db.tags } @@ -120,6 +127,10 @@ pub fn pages(db: Database) { db.pages } +pub fn menu(db: Database) { + db.menu +} + fn new_tree() -> OrderedTree(PostWithID) { ordered_tree.new(comparator) } diff --git a/src/gloss/models/menu.gleam b/src/gloss/models/menu.gleam new file mode 100644 index 0000000..727586d --- /dev/null +++ b/src/gloss/models/menu.gleam @@ -0,0 +1,3 @@ +pub type MenuItem { + MenuItem(url: String, name: String) +} diff --git a/src/gloss/parser.gleam b/src/gloss/parser.gleam index 3611e72..5ec1616 100644 --- a/src/gloss/parser.gleam +++ b/src/gloss/parser.gleam @@ -6,6 +6,7 @@ import gloss/models/database.{type Database} import gloss/parser/common import gloss/parser/post import gloss/parser/page +import gloss/parser/menu const default_data_path = "./data" @@ -15,11 +16,13 @@ pub type Parser = pub type ParseError { FileError(path: String, err: fs.FSError) PostParseError(filename: String, err: common.ParseError) + MenuParseError } pub fn default_parse() -> Result(Database, ParseError) { parse_posts(database.new(), post_path()) |> result.try(parse_pages(_, page_path())) + |> result.try(parse_menu(_, menu_path())) } pub fn parse_posts(db: Database, path: String) -> Result(Database, ParseError) { @@ -77,6 +80,26 @@ pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) { Ok(list.fold(pages, db, database.add_page)) } +pub fn parse_menu(db: Database, file: String) -> Result(Database, ParseError) { + case fs.exists(file) { + Ok(True) -> { + use contents <- result.try( + fs.read_file(file) + |> result.map_error(fn(err) { FileError(file, err) }), + ) + + use menu <- result.try( + menu.parse(contents) + |> result.replace_error(MenuParseError), + ) + + Ok(database.set_menu(db, menu)) + } + + _ -> Ok(db) + } +} + fn post_path() { default_data_path <> "/posts" } @@ -84,3 +107,7 @@ fn post_path() { fn page_path() { default_data_path <> "/pages" } + +fn menu_path() { + default_data_path <> "/menu" +} diff --git a/src/gloss/parser/menu.gleam b/src/gloss/parser/menu.gleam new file mode 100644 index 0000000..4fa727e --- /dev/null +++ b/src/gloss/parser/menu.gleam @@ -0,0 +1,14 @@ +import gleam/list +import gleam/string +import gleam/result +import gloss/models/menu.{MenuItem} + +pub fn parse(content: String) { + string.split(content, "\n") + |> list.filter(fn(line) { string.length(line) != 0 }) + |> list.map(fn(line) { + use #(url, name) <- result.try(string.split_once(line, " ")) + Ok(MenuItem(url: url, name: name)) + }) + |> result.all() +} diff --git a/src/gloss/rendering/views/base.gleam b/src/gloss/rendering/views/base.gleam index ed18c65..9121912 100644 --- a/src/gloss/rendering/views/base.gleam +++ b/src/gloss/rendering/views/base.gleam @@ -11,6 +11,7 @@ import lustre/element/html.{ } import lustre/attribute.{attribute, href, id, name, rel, role, style, value} import gloss/models/database.{type Database} +import gloss/models/menu.{type MenuItem} import gloss/utils/ordered_tree import gloss/utils/date import gloss/config.{type Configuration} @@ -37,7 +38,7 @@ fn pre_render(db, config) -> PreRendered { } fn view( - _db: Database, + db: Database, config: Configuration, pre_rendered: PreRendered, inner: Element(Nil), @@ -71,6 +72,10 @@ fn view( text(config.blog_name), ]), ]), + case database.menu(db) { + [] -> element.none() + m -> menu(m) + }, ]), main([], [inner]), section([id("sidebar")], [ @@ -192,3 +197,14 @@ fn archives(db: Database, config: Configuration) { }) |> ul([], _) } + +fn menu(menu: List(MenuItem)) { + nav([], [ + ul( + [], + list.map(menu, fn(item) { + li([], [a([href(item.url)], [text(item.name)])]) + }), + ), + ]) +}