Add Atom feed
This commit is contained in:
parent
ace0b8b453
commit
bc92b53483
15 changed files with 250 additions and 19 deletions
|
@ -15,7 +15,7 @@ target = "javascript"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gleam_stdlib = "~> 0.36 or ~> 1.0"
|
gleam_stdlib = "~> 0.36 or ~> 1.0"
|
||||||
lustre = "~> 4.0"
|
lustre = "~> 4.1"
|
||||||
lustre_ssg = { path = "../ssg" }
|
lustre_ssg = { path = "../ssg" }
|
||||||
gleam_javascript = "~> 0.8"
|
gleam_javascript = "~> 0.8"
|
||||||
ranged_int = "~> 1.0"
|
ranged_int = "~> 1.0"
|
||||||
|
|
|
@ -3,26 +3,27 @@
|
||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
{ name = "bigi", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "bigi", source = "hex", outer_checksum = "B6F7CAF319F13F32DB4331A750534912A9AEE1C195DD8E5DA83A42A4AD390274" },
|
{ name = "bigi", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "bigi", source = "hex", outer_checksum = "B6F7CAF319F13F32DB4331A750534912A9AEE1C195DD8E5DA83A42A4AD390274" },
|
||||||
|
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
|
||||||
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
|
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
|
||||||
{ name = "gleam_javascript", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8" },
|
{ name = "gleam_javascript", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8" },
|
||||||
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
|
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
|
||||||
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
|
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
|
||||||
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
|
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
|
||||||
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
|
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
|
||||||
{ name = "jot", version = "0.3.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "574A2DACA106E9B4826C9F3F2D3911844C7826D554C08E404696CC16F85E0392" },
|
{ name = "jot", version = "0.3.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "574A2DACA106E9B4826C9F3F2D3911844C7826D554C08E404696CC16F85E0392" },
|
||||||
{ name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" },
|
{ name = "lustre", version = "4.1.5", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "C90B3DC868D346C49E98C8A62F2E594AE559D5FF25A46269D60FAA5939FCE827" },
|
||||||
{ name = "lustre_ssg", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "jot", "lustre", "simplifile", "tom"], source = "local", path = "../ssg" },
|
{ name = "lustre_ssg", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "jot", "lustre", "simplifile", "tom"], source = "local", path = "../ssg" },
|
||||||
{ name = "ranged_int", version = "1.0.0", build_tools = ["gleam"], requirements = ["bigi", "gleam_stdlib"], otp_app = "ranged_int", source = "hex", outer_checksum = "8AACD49213E87BC6E7CE5F80038C1989966CF8187382760B6168E5EA9F364B09" },
|
{ name = "ranged_int", version = "1.0.0", build_tools = ["gleam"], requirements = ["bigi", "gleam_stdlib"], otp_app = "ranged_int", source = "hex", outer_checksum = "8AACD49213E87BC6E7CE5F80038C1989966CF8187382760B6168E5EA9F364B09" },
|
||||||
{ name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" },
|
{ name = "simplifile", version = "1.6.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "B75D3C64E526D9D7EDEED5F3BA31DAAF5F2B4D80A4183FE17FDB02ED526E4E96" },
|
||||||
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
|
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
|
||||||
{ name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" },
|
{ name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[requirements]
|
[requirements]
|
||||||
bigi = { version = "~> 2.1"}
|
bigi = { version = "~> 2.1" }
|
||||||
gleam_javascript = { version = "~> 0.8" }
|
gleam_javascript = { version = "~> 0.8" }
|
||||||
gleam_stdlib = { version = "~> 0.36 or ~> 1.0" }
|
gleam_stdlib = { version = "~> 0.36 or ~> 1.0" }
|
||||||
gleeunit = { version = "~> 1.0" }
|
gleeunit = { version = "~> 1.0" }
|
||||||
lustre = { version = "~> 4.0" }
|
lustre = { version = "~> 4.1" }
|
||||||
lustre_ssg = { path = "../ssg" }
|
lustre_ssg = { path = "../ssg" }
|
||||||
ranged_int = { version = "~> 1.0" }
|
ranged_int = { version = "~> 1.0" }
|
||||||
|
|
|
@ -12,6 +12,10 @@ export function dateTimeInZone(dtStr, tz) {
|
||||||
return new Ok(dt);
|
return new Ok(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function utcNow() {
|
||||||
|
return DateTime.utc();
|
||||||
|
}
|
||||||
|
|
||||||
export function toDate(dt) {
|
export function toDate(dt) {
|
||||||
return new Date(
|
return new Date(
|
||||||
dt.year,
|
dt.year,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import gleam/option
|
||||||
import gloss/paths.{type PathConfiguration}
|
import gloss/paths.{type PathConfiguration}
|
||||||
import gloss/rendering/templates.{
|
import gloss/rendering/templates.{
|
||||||
type BaseRenderer, type ListPageRenderer, type PostContentRenderer,
|
type BaseRenderer, type FeedRenderer, type ListPageRenderer,
|
||||||
type SinglePostRenderer,
|
type PostContentRenderer, type SinglePostRenderer,
|
||||||
}
|
}
|
||||||
import gloss/parser.{type Parser}
|
import gloss/parser.{type Parser}
|
||||||
import gloss/writer.{type Writer}
|
import gloss/writer.{type Writer}
|
||||||
|
@ -13,6 +14,7 @@ pub type Templates {
|
||||||
single_post_full: fn(Database, Configuration) -> SinglePostRenderer,
|
single_post_full: fn(Database, Configuration) -> SinglePostRenderer,
|
||||||
single_post_list: fn(Database, Configuration) -> SinglePostRenderer,
|
single_post_list: fn(Database, Configuration) -> SinglePostRenderer,
|
||||||
list_page: fn(Database, Configuration) -> ListPageRenderer,
|
list_page: fn(Database, Configuration) -> ListPageRenderer,
|
||||||
|
feed: fn(Database, Configuration) -> FeedRenderer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +24,19 @@ pub type Rendering {
|
||||||
copyright: String,
|
copyright: String,
|
||||||
content_renderer: PostContentRenderer,
|
content_renderer: PostContentRenderer,
|
||||||
posts_per_page: Int,
|
posts_per_page: Int,
|
||||||
|
posts_in_feed: Int,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Author {
|
||||||
|
Author(name: String, email: option.Option(String), url: option.Option(String))
|
||||||
|
}
|
||||||
|
|
||||||
pub type Configuration {
|
pub type Configuration {
|
||||||
Configuration(
|
Configuration(
|
||||||
blog_name: String,
|
blog_name: String,
|
||||||
|
blog_url: String,
|
||||||
|
author: Author,
|
||||||
rendering: Rendering,
|
rendering: Rendering,
|
||||||
paths: PathConfiguration,
|
paths: PathConfiguration,
|
||||||
parser: Parser,
|
parser: Parser,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import gloss/config.{type Configuration, Configuration, Rendering}
|
||||||
import gloss/rendering/templates/single_post
|
import gloss/rendering/templates/single_post
|
||||||
import gloss/rendering/templates/base
|
import gloss/rendering/templates/base
|
||||||
import gloss/rendering/templates/list_page
|
import gloss/rendering/templates/list_page
|
||||||
|
import gloss/rendering/templates/feed
|
||||||
import gloss/paths
|
import gloss/paths
|
||||||
import gloss/parser
|
import gloss/parser
|
||||||
import gloss/writer
|
import gloss/writer
|
||||||
|
@ -11,16 +12,25 @@ const default_templates = config.Templates(
|
||||||
single_post_full: single_post.full_view,
|
single_post_full: single_post.full_view,
|
||||||
single_post_list: single_post.list_view,
|
single_post_list: single_post.list_view,
|
||||||
list_page: list_page.generate,
|
list_page: list_page.generate,
|
||||||
|
feed: feed.generate,
|
||||||
)
|
)
|
||||||
|
|
||||||
pub fn default_config() -> Configuration {
|
pub fn default_config(
|
||||||
|
blog_name: String,
|
||||||
|
blog_url: String,
|
||||||
|
author: config.Author,
|
||||||
|
copyright: String,
|
||||||
|
) -> Configuration {
|
||||||
Configuration(
|
Configuration(
|
||||||
blog_name: "",
|
blog_name: blog_name,
|
||||||
|
blog_url: blog_url,
|
||||||
|
author: author,
|
||||||
rendering: Rendering(
|
rendering: Rendering(
|
||||||
templates: default_templates,
|
templates: default_templates,
|
||||||
copyright: "",
|
copyright: copyright,
|
||||||
content_renderer: single_post.content_renderer,
|
content_renderer: single_post.content_renderer,
|
||||||
posts_per_page: 10,
|
posts_per_page: 10,
|
||||||
|
posts_in_feed: 20,
|
||||||
),
|
),
|
||||||
paths: paths.conf(
|
paths: paths.conf(
|
||||||
paths.default_index,
|
paths.default_index,
|
||||||
|
|
|
@ -4,8 +4,8 @@ import gleam/result
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import lustre/element.{type Element}
|
import lustre/element.{type Element}
|
||||||
import gloss/rendering/templates.{
|
import gloss/rendering/templates.{
|
||||||
type BaseRenderer, type ListPageRenderer, type PostContentRenderer,
|
type BaseRenderer, type FeedRenderer, type ListPageRenderer,
|
||||||
type SinglePostRenderer, ListInfo,
|
type PostContentRenderer, type SinglePostRenderer, ListInfo,
|
||||||
}
|
}
|
||||||
import gloss/rendering/database.{
|
import gloss/rendering/database.{
|
||||||
type Database as RenderDatabase, type RenderedPost, type RenderedSinglePost,
|
type Database as RenderDatabase, type RenderedPost, type RenderedSinglePost,
|
||||||
|
@ -21,6 +21,7 @@ pub type Renderers {
|
||||||
base: BaseRenderer,
|
base: BaseRenderer,
|
||||||
single_post_full: SinglePostRenderer,
|
single_post_full: SinglePostRenderer,
|
||||||
list_page: ListPageRenderer,
|
list_page: ListPageRenderer,
|
||||||
|
feed: FeedRenderer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ pub fn render(db: Database, config: Configuration) -> RenderDatabase {
|
||||||
base: config.rendering.templates.base(db, config),
|
base: config.rendering.templates.base(db, config),
|
||||||
single_post_full: config.rendering.templates.single_post_full(db, config),
|
single_post_full: config.rendering.templates.single_post_full(db, config),
|
||||||
list_page: config.rendering.templates.list_page(db, config),
|
list_page: config.rendering.templates.list_page(db, config),
|
||||||
|
feed: config.rendering.templates.feed(db, config),
|
||||||
)
|
)
|
||||||
|
|
||||||
let all_posts = database.get_posts_with_ids(db, ordered_tree.Desc)
|
let all_posts = database.get_posts_with_ids(db, ordered_tree.Desc)
|
||||||
|
@ -41,6 +43,7 @@ pub fn render(db: Database, config: Configuration) -> RenderDatabase {
|
||||||
let tag_pages = render_tag_pages(config, db, post_contents, renderers)
|
let tag_pages = render_tag_pages(config, db, post_contents, renderers)
|
||||||
let year_pages = render_year_pages(config, db, post_contents, renderers)
|
let year_pages = render_year_pages(config, db, post_contents, renderers)
|
||||||
let month_pages = render_month_pages(config, db, post_contents, renderers)
|
let month_pages = render_month_pages(config, db, post_contents, renderers)
|
||||||
|
let feed = render_feed(all_posts, post_contents, renderers)
|
||||||
|
|
||||||
render_database.Database(
|
render_database.Database(
|
||||||
orig: db,
|
orig: db,
|
||||||
|
@ -51,6 +54,7 @@ pub fn render(db: Database, config: Configuration) -> RenderDatabase {
|
||||||
tag_pages: tag_pages,
|
tag_pages: tag_pages,
|
||||||
year_pages: year_pages,
|
year_pages: year_pages,
|
||||||
month_pages: month_pages,
|
month_pages: month_pages,
|
||||||
|
feed: feed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +193,19 @@ fn render_month_pages(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_feed(
|
||||||
|
posts: List(database.PostWithID),
|
||||||
|
posts_with_contents: Dict(PostID, RenderedPost),
|
||||||
|
renderers: Renderers,
|
||||||
|
) {
|
||||||
|
let posts =
|
||||||
|
list.map(posts, fn(post) {
|
||||||
|
let assert Ok(rendered) = dict.get(posts_with_contents, post.id)
|
||||||
|
rendered
|
||||||
|
})
|
||||||
|
renderers.feed(posts)
|
||||||
|
}
|
||||||
|
|
||||||
fn pageify_posts(
|
fn pageify_posts(
|
||||||
posts: List(PostWithID),
|
posts: List(PostWithID),
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
|
|
|
@ -34,5 +34,6 @@ pub type Database {
|
||||||
tag_pages: Dict(String, List(RenderedPage)),
|
tag_pages: Dict(String, List(RenderedPage)),
|
||||||
year_pages: Dict(Int, List(RenderedPage)),
|
year_pages: Dict(Int, List(RenderedPage)),
|
||||||
month_pages: Dict(#(Int, Month), List(RenderedPage)),
|
month_pages: Dict(#(Int, Month), List(RenderedPage)),
|
||||||
|
feed: Element(Nil),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ pub type BaseRenderer =
|
||||||
pub type SinglePostRenderer =
|
pub type SinglePostRenderer =
|
||||||
fn(RenderedPost) -> Element(Nil)
|
fn(RenderedPost) -> Element(Nil)
|
||||||
|
|
||||||
|
pub type FeedRenderer =
|
||||||
|
fn(List(RenderedPost)) -> Element(Nil)
|
||||||
|
|
||||||
pub type ListInfo {
|
pub type ListInfo {
|
||||||
ListInfo(
|
ListInfo(
|
||||||
root_path: String,
|
root_path: String,
|
||||||
|
|
|
@ -3,12 +3,13 @@ import gleam/list
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import gleam/float
|
import gleam/float
|
||||||
import gleam/string
|
import gleam/string
|
||||||
|
import gleam/option
|
||||||
import lustre/element.{type Element, text}
|
import lustre/element.{type Element, text}
|
||||||
import lustre/element/html.{
|
import lustre/element/html.{
|
||||||
a, body, footer, h1, head, header, html, li, link, main, meta, nav, p, section,
|
a, body, footer, h1, head, header, html, li, link, main, meta, nav, p, section,
|
||||||
title, ul,
|
title, ul,
|
||||||
}
|
}
|
||||||
import lustre/attribute.{attribute, href, id, name, rel, role, style}
|
import lustre/attribute.{attribute, href, id, name, rel, role, style, value}
|
||||||
import gloss/models/database.{type Database}
|
import gloss/models/database.{type Database}
|
||||||
import gloss/utils/ordered_tree
|
import gloss/utils/ordered_tree
|
||||||
import gloss/utils/date
|
import gloss/utils/date
|
||||||
|
@ -58,6 +59,10 @@ fn view(
|
||||||
link([href("./css/normalize.css"), rel("stylesheet")]),
|
link([href("./css/normalize.css"), rel("stylesheet")]),
|
||||||
link([href("./css/magick.css"), rel("stylesheet")]),
|
link([href("./css/magick.css"), rel("stylesheet")]),
|
||||||
link([href("./css/custom.css"), rel("stylesheet")]),
|
link([href("./css/custom.css"), rel("stylesheet")]),
|
||||||
|
case config.author.url {
|
||||||
|
option.Some(url) -> link([rel("me"), value(url)])
|
||||||
|
_ -> element.none()
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
body([], [
|
body([], [
|
||||||
header([id("title"), role("banner")], [
|
header([id("title"), role("banner")], [
|
||||||
|
@ -73,13 +78,14 @@ fn view(
|
||||||
nav([id("archives")], [pre_rendered.archives]),
|
nav([id("archives")], [pre_rendered.archives]),
|
||||||
]),
|
]),
|
||||||
footer([], [
|
footer([], [
|
||||||
p([], [text(config.rendering.copyright)]),
|
|
||||||
p([], [
|
p([], [
|
||||||
|
text(config.rendering.copyright),
|
||||||
|
text(" · "),
|
||||||
text("Powered by: "),
|
text("Powered by: "),
|
||||||
a([href("https://gleam.run/")], [text("Gleam")]),
|
a([href("https://gleam.run/")], [text("Gleam")]),
|
||||||
text(" · "),
|
text(", "),
|
||||||
a([href("https://hexdocs.pm/lustre")], [text("Lustre")]),
|
a([href("https://hexdocs.pm/lustre")], [text("Lustre")]),
|
||||||
text(" · "),
|
text(", "),
|
||||||
a([href("https://gitlab.com/Nicd/gloss")], [text("Gloss")]),
|
a([href("https://gitlab.com/Nicd/gloss")], [text("Gloss")]),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
|
67
src/gloss/rendering/templates/feed.gleam
Normal file
67
src/gloss/rendering/templates/feed.gleam
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import gleam/list
|
||||||
|
import gleam/option
|
||||||
|
import lustre/element
|
||||||
|
import lustre/attribute.{attribute}
|
||||||
|
import lustre/ssg/atom.{
|
||||||
|
author, content, email, entry, feed, generator, id, link, name, rights,
|
||||||
|
summary, title, updated, uri,
|
||||||
|
}
|
||||||
|
import gloss/models/database.{type Database}
|
||||||
|
import gloss/models/post
|
||||||
|
import gloss/config.{type Configuration}
|
||||||
|
import gloss/rendering/database.{type RenderedPost} as _
|
||||||
|
import gloss/utils/luxon
|
||||||
|
import gloss/utils/date
|
||||||
|
|
||||||
|
pub fn generate(_db: Database, config: Configuration) {
|
||||||
|
fn(posts: List(RenderedPost)) {
|
||||||
|
let now = luxon.utc_now()
|
||||||
|
let #(posts, _) = list.split(posts, config.rendering.posts_in_feed)
|
||||||
|
|
||||||
|
feed([
|
||||||
|
title(config.blog_name),
|
||||||
|
updated(luxon.to_iso(now)),
|
||||||
|
link([attribute("href", config.blog_url)]),
|
||||||
|
id(config.blog_url),
|
||||||
|
author([
|
||||||
|
name(config.author.name),
|
||||||
|
case config.author.email {
|
||||||
|
option.Some(e) -> email(e)
|
||||||
|
option.None -> element.none()
|
||||||
|
},
|
||||||
|
case config.author.url {
|
||||||
|
option.Some(u) -> uri(u)
|
||||||
|
option.None -> element.none()
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
generator(
|
||||||
|
[
|
||||||
|
attribute("uri", "https://gitlab.com/Nicd/gloss"),
|
||||||
|
attribute("version", "1.0.0"),
|
||||||
|
],
|
||||||
|
"Gloss",
|
||||||
|
),
|
||||||
|
rights(config.rendering.copyright),
|
||||||
|
..list.map(posts, fn(post) {
|
||||||
|
let date_str = case post.orig.date {
|
||||||
|
post.JustDate(d) -> date.format_iso(d)
|
||||||
|
post.DateTime(luxon: l, ..) -> luxon.to_iso(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
entry([
|
||||||
|
title(post.orig.title),
|
||||||
|
id(
|
||||||
|
config.blog_url
|
||||||
|
<> config.paths.html(config.paths.single_post(post.orig)),
|
||||||
|
),
|
||||||
|
updated(date_str),
|
||||||
|
content(post.content.full),
|
||||||
|
case post.content.short {
|
||||||
|
option.Some(s) -> summary(s)
|
||||||
|
option.None -> element.none()
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ pub fn date_time_in_zone(date: Date, time: Time, tz: String) {
|
||||||
do_date_time_in_zone(datetime_str, tz)
|
do_date_time_in_zone(datetime_str, tz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@external(javascript, "../../ffi_luxon.mjs", "utcNow")
|
||||||
|
pub fn utc_now() -> DateTime
|
||||||
|
|
||||||
@external(javascript, "../../ffi_luxon.mjs", "dateTimeInZone")
|
@external(javascript, "../../ffi_luxon.mjs", "dateTimeInZone")
|
||||||
fn do_date_time_in_zone(
|
fn do_date_time_in_zone(
|
||||||
datetime_str: String,
|
datetime_str: String,
|
||||||
|
|
|
@ -2,6 +2,8 @@ import gleam/list
|
||||||
import gleam/dict
|
import gleam/dict
|
||||||
import gleam/result
|
import gleam/result
|
||||||
import lustre/ssg
|
import lustre/ssg
|
||||||
|
import lustre/ssg/xml
|
||||||
|
import lustre/element
|
||||||
import gloss/rendering/database.{type Database} as _
|
import gloss/rendering/database.{type Database} as _
|
||||||
import gloss/models/post.{type Post}
|
import gloss/models/post.{type Post}
|
||||||
import gloss/paths/post.{type PostPath} as _
|
import gloss/paths/post.{type PostPath} as _
|
||||||
|
@ -67,6 +69,13 @@ pub fn write(db: Database, path_conf: PathConfiguration) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let site =
|
||||||
|
ssg.add_static_asset(
|
||||||
|
site,
|
||||||
|
"/feed.xml",
|
||||||
|
element.to_string(xml.declaration()) <> element.to_string(db.feed),
|
||||||
|
)
|
||||||
|
|
||||||
site
|
site
|
||||||
|> ssg.add_dynamic_route("/", single_posts, fn(c) { c })
|
|> ssg.add_dynamic_route("/", single_posts, fn(c) { c })
|
||||||
|> ssg.build()
|
|> ssg.build()
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
import gleam/result
|
import gleam/result
|
||||||
|
import gleam/option
|
||||||
import gleam/io
|
import gleam/io
|
||||||
import gloss/builder
|
import gloss/builder
|
||||||
import gloss/config.{type Configuration, Configuration}
|
import gloss/config.{type Configuration, Configuration}
|
||||||
import gloss/defaults
|
import gloss/defaults
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let config = defaults.default_config()
|
let config =
|
||||||
let config = Configuration(..config, blog_name: "Random Notes")
|
defaults.default_config(
|
||||||
|
"Random Notes",
|
||||||
|
"http://localhost:61055",
|
||||||
|
config.Author(
|
||||||
|
"Mikko Ahlroth",
|
||||||
|
option.Some("mikko@ahlroth.fi"),
|
||||||
|
option.Some("https://social.ahlcode.fi/@nicd"),
|
||||||
|
),
|
||||||
|
"© Mikko Ahlroth",
|
||||||
|
)
|
||||||
io.debug(build(config))
|
io.debug(build(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
86
src/lustre/ssg/atom.gleam
Normal file
86
src/lustre/ssg/atom.gleam
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import lustre/element.{type Element, advanced, element, namespaced, text}
|
||||||
|
import lustre/attribute.{attribute}
|
||||||
|
|
||||||
|
pub fn feed(children: List(Element(a))) {
|
||||||
|
element("feed", [attribute("xmlns", "http://www.w3.org/2005/Atom")], children)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entry(children: List(Element(a))) {
|
||||||
|
element("entry", [], children)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(uri: String) {
|
||||||
|
element("id", [], [text(uri)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(title: String) {
|
||||||
|
element("title", [attribute("type", "html")], [text(title)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updated(iso_timestamp: String) {
|
||||||
|
element("updated", [], [text(iso_timestamp)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn published(iso_timestamp: String) {
|
||||||
|
element("published", [], [text(iso_timestamp)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn author(children: List(Element(a))) {
|
||||||
|
element("author", [], children)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contributor(children: List(Element(a))) {
|
||||||
|
element("contributor", [], children)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source(children: List(Element(a))) {
|
||||||
|
namespaced("", "source", [], children)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link(attributes: List(attribute.Attribute(a))) {
|
||||||
|
advanced("", "link", attributes, [], True, False)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(name: String) {
|
||||||
|
element("name", [], [text(name)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn email(email: String) {
|
||||||
|
element("email", [], [text(email)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uri(uri: String) {
|
||||||
|
element("uri", [], [text(uri)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn category(attributes: List(attribute.Attribute(a))) {
|
||||||
|
advanced("", "category", attributes, [], True, False)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generator(attributes: List(attribute.Attribute(a)), name: String) {
|
||||||
|
element("generator", attributes, [text(name)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn icon(path: String) {
|
||||||
|
element("icon", [], [text(path)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn logo(path: String) {
|
||||||
|
element("logo", [], [text(path)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rights(rights: String) {
|
||||||
|
element("rights", [], [text(rights)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtitle(subtitle: String) {
|
||||||
|
element("subtitle", [attribute("type", "html")], [text(subtitle)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn summary(summary: String) {
|
||||||
|
element("summary", [attribute("type", "html")], [text(summary)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content(content: String) {
|
||||||
|
element("content", [attribute("type", "html")], [text(content)])
|
||||||
|
}
|
5
src/lustre/ssg/xml.gleam
Normal file
5
src/lustre/ssg/xml.gleam
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import lustre/element.{advanced}
|
||||||
|
|
||||||
|
pub fn declaration() {
|
||||||
|
advanced("", "?xml version=\"1.0\" encoding=\"utf-8\"?", [], [], False, True)
|
||||||
|
}
|
Loading…
Reference in a new issue