Added opengraph/meta tags
This commit is contained in:
parent
981bc757e4
commit
f88c5b46fc
8 changed files with 160 additions and 13 deletions
|
@ -1,7 +1,7 @@
|
|||
import gleam/option
|
||||
import gloss/paths.{type PathConfiguration}
|
||||
import gloss/rendering/views.{
|
||||
type BaseView, type FeedView, type ListPageView, type PageView,
|
||||
type BaseView, type FeedView, type ListPageView, type MetaView, type PageView,
|
||||
type SinglePostView,
|
||||
}
|
||||
import gloss/compiler.{type CompileDatabase, type Compiler}
|
||||
|
@ -13,6 +13,7 @@ import gloss/rendering/database.{type RenderDatabase} as _
|
|||
pub type Views {
|
||||
Views(
|
||||
base: fn(Database, Configuration) -> BaseView,
|
||||
meta: fn(Database, Configuration) -> MetaView,
|
||||
single_post_full: fn(Database, Configuration) -> SinglePostView,
|
||||
single_post_list: fn(Database, Configuration) -> SinglePostView,
|
||||
page: fn(Database, Configuration) -> PageView,
|
||||
|
|
|
@ -4,6 +4,7 @@ import gloss/rendering/views/base
|
|||
import gloss/rendering/views/list_page
|
||||
import gloss/rendering/views/page
|
||||
import gloss/rendering/views/feed
|
||||
import gloss/rendering/views/meta
|
||||
import gloss/renderer
|
||||
import gloss/paths
|
||||
import gloss/parser
|
||||
|
@ -12,6 +13,7 @@ import gloss/compiler
|
|||
|
||||
const default_views = config.Views(
|
||||
base: base.generate,
|
||||
meta: meta.generate,
|
||||
single_post_full: single_post.full_view,
|
||||
single_post_list: single_post.list_view,
|
||||
page: page.generate,
|
||||
|
|
|
@ -61,3 +61,10 @@ pub fn comparator(a: Post, b: Post) -> Order {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_iso8601(post: Post) -> String {
|
||||
case post.date {
|
||||
JustDate(d) -> date.format_iso(d)
|
||||
DateTime(luxon: l, ..) -> luxon.to_iso(l)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import gleam/result
|
|||
import gleam/int
|
||||
import lustre/element.{type Element}
|
||||
import gloss/rendering/views.{
|
||||
type BaseView, type FeedView, type ListPageView, type PageView,
|
||||
type BaseView, type FeedView, type ListPageView, type MetaView, type PageView,
|
||||
type SinglePostView, ListInfo,
|
||||
}
|
||||
import gloss/rendering/database.{
|
||||
|
@ -22,6 +22,7 @@ import gloss/utils/date
|
|||
pub type Views {
|
||||
Views(
|
||||
base: BaseView,
|
||||
meta: MetaView,
|
||||
single_post_full: SinglePostView,
|
||||
page: PageView,
|
||||
list_page: ListPageView,
|
||||
|
@ -37,6 +38,7 @@ pub fn render(
|
|||
let views =
|
||||
Views(
|
||||
base: config.rendering.views.base(db, config),
|
||||
meta: config.rendering.views.meta(db, config),
|
||||
single_post_full: config.rendering.views.single_post_full(db, config),
|
||||
page: config.rendering.views.page(db, config),
|
||||
list_page: config.rendering.views.list_page(db, config),
|
||||
|
@ -76,7 +78,11 @@ pub fn render_posts(
|
|||
|> list.map(fn(post_with_id) {
|
||||
let assert Ok(content) = dict.get(post_contents, post_with_id.id)
|
||||
let rendered =
|
||||
views.base(views.single_post_full(content), post_with_id.post.title)
|
||||
views.base(
|
||||
views.single_post_full(content),
|
||||
views.meta(views.Post(post_with_id.post)),
|
||||
post_with_id.post.title,
|
||||
)
|
||||
RenderedSinglePost(post_with_id.post, rendered)
|
||||
})
|
||||
}
|
||||
|
@ -87,7 +93,12 @@ pub fn render_pages(
|
|||
views: Views,
|
||||
) {
|
||||
list.map(compiled_pages, fn(page) {
|
||||
let rendered = views.base(views.page(page), page.orig.title)
|
||||
let rendered =
|
||||
views.base(
|
||||
views.page(page),
|
||||
views.meta(views.Page(page.orig)),
|
||||
page.orig.title,
|
||||
)
|
||||
RenderedPage(page.orig, rendered)
|
||||
})
|
||||
}
|
||||
|
@ -233,7 +244,12 @@ fn pageify_posts(
|
|||
extra_header: extra_header,
|
||||
)
|
||||
|
||||
let page_content = views.base(views.list_page(info), title_prefix)
|
||||
let page_content =
|
||||
views.base(
|
||||
views.list_page(info),
|
||||
views.meta(views.Other(title_prefix, "")),
|
||||
title_prefix,
|
||||
)
|
||||
ListPage(page: page, content: page_content)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
import lustre/element.{type Element}
|
||||
import gloss/compiler.{type CompiledPage, type CompiledPost}
|
||||
import gloss/models/post
|
||||
import gloss/models/page
|
||||
|
||||
pub type BaseView =
|
||||
fn(Element(Nil), String) -> Element(Nil)
|
||||
fn(Element(Nil), List(Element(Nil)), String) -> Element(Nil)
|
||||
|
||||
pub type PageType {
|
||||
Post(post.Post)
|
||||
Page(page.Page)
|
||||
Other(title: String, description: String)
|
||||
}
|
||||
|
||||
pub type MetaView =
|
||||
fn(PageType) -> List(Element(Nil))
|
||||
|
||||
pub type SinglePostView =
|
||||
fn(CompiledPost) -> Element(Nil)
|
||||
|
|
|
@ -26,8 +26,8 @@ pub type PreRendered {
|
|||
|
||||
pub fn generate(db: Database, config: Configuration) {
|
||||
let pre_rendered = pre_render(db, config)
|
||||
fn(inner: Element(Nil), title_prefix: String) {
|
||||
view(db, config, pre_rendered, inner, title_prefix)
|
||||
fn(inner: Element(Nil), extra_meta: List(Element(Nil)), title_prefix: String) {
|
||||
view(db, config, pre_rendered, inner, extra_meta, title_prefix)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ fn view(
|
|||
config: Configuration,
|
||||
pre_rendered: PreRendered,
|
||||
inner: Element(Nil),
|
||||
extra_meta: List(Element(Nil)),
|
||||
title_prefix: String,
|
||||
) {
|
||||
let title_text = case title_prefix {
|
||||
|
@ -71,6 +72,7 @@ fn view(
|
|||
option.Some(url) -> link([rel("me"), value(url)])
|
||||
_ -> element.none()
|
||||
},
|
||||
..extra_meta
|
||||
]),
|
||||
body([], [
|
||||
header([id("title"), role("banner")], [
|
||||
|
|
|
@ -11,7 +11,6 @@ import gloss/models/post
|
|||
import gloss/config.{type Configuration}
|
||||
import gloss/compiler.{type CompiledPost}
|
||||
import gloss/utils/luxon
|
||||
import gloss/utils/date
|
||||
|
||||
pub fn generate(_db: Database, config: Configuration) {
|
||||
fn(posts: List(CompiledPost)) {
|
||||
|
@ -43,10 +42,7 @@ pub fn generate(_db: Database, config: Configuration) {
|
|||
),
|
||||
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)
|
||||
}
|
||||
let date_str = post.to_iso8601(post.orig)
|
||||
|
||||
entry([
|
||||
title(post.orig.title),
|
||||
|
|
112
src/gloss/rendering/views/meta.gleam
Normal file
112
src/gloss/rendering/views/meta.gleam
Normal file
|
@ -0,0 +1,112 @@
|
|||
import gleam/dict
|
||||
import gleam/list
|
||||
import gleam/option
|
||||
import gleam/result
|
||||
import lustre/element/html
|
||||
import lustre/attribute
|
||||
import gloss/rendering/views.{type PageType, Other, Page, Post}
|
||||
import gloss/models/post
|
||||
import gloss/models/page
|
||||
import gloss/config.{type Configuration}
|
||||
import gloss/models/database.{type Database}
|
||||
|
||||
pub fn generate(_db: Database, config: Configuration) {
|
||||
fn(page_type: PageType) {
|
||||
list.flatten([
|
||||
[
|
||||
name_meta("author", config.author.name),
|
||||
name_meta("description", description(page_type)),
|
||||
// Schema.org
|
||||
itemprop_meta("name", title(page_type)),
|
||||
itemprop_meta("author", config.author.name),
|
||||
itemprop_meta("headline", title(page_type)),
|
||||
itemprop_meta("description", description(page_type)),
|
||||
// Twitter/X card
|
||||
name_meta("twitter:card", "summary_large_image"),
|
||||
name_meta("twitter:site", ""),
|
||||
name_meta("twitter:title", title(page_type)),
|
||||
name_meta("twitter:description", description(page_type)),
|
||||
name_meta("twitter:creator", ""),
|
||||
// Open Graph
|
||||
property_meta("og:title", title(page_type)),
|
||||
property_meta("og:type", case page_type {
|
||||
Post(..) | Page(..) -> "article"
|
||||
_ -> "website"
|
||||
}),
|
||||
property_meta("og:description", description(page_type)),
|
||||
property_meta("og:site_name", config.blog_name),
|
||||
],
|
||||
case page_type {
|
||||
Post(post) -> {
|
||||
let timestamp = post.to_iso8601(post)
|
||||
|
||||
let image =
|
||||
post.headers
|
||||
|> dict.from_list()
|
||||
|> dict.get("image")
|
||||
|> option.from_result()
|
||||
|
||||
[
|
||||
property_meta("article:published_time", timestamp),
|
||||
itemprop_meta("datePublished", timestamp),
|
||||
property_meta(
|
||||
"og:url",
|
||||
config.blog_url <> config.paths.single_post(post),
|
||||
),
|
||||
..case image {
|
||||
option.Some(image) -> [
|
||||
name_meta("twitter:image", image),
|
||||
property_meta("og:image", image),
|
||||
itemprop_meta("image", image),
|
||||
]
|
||||
option.None -> []
|
||||
}
|
||||
]
|
||||
}
|
||||
Page(page) -> [
|
||||
property_meta("og:url", config.blog_url <> config.paths.page(page)),
|
||||
]
|
||||
_ -> []
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
fn name_meta(name: String, content: String) {
|
||||
meta("name", name, content)
|
||||
}
|
||||
|
||||
fn itemprop_meta(itemprop: String, content: String) {
|
||||
meta("itemprop", itemprop, content)
|
||||
}
|
||||
|
||||
fn property_meta(property: String, content: String) {
|
||||
meta("property", property, content)
|
||||
}
|
||||
|
||||
fn meta(attr_name: String, attr_value: String, content: String) {
|
||||
html.meta([
|
||||
attribute.attribute(attr_name, attr_value),
|
||||
attribute.attribute("content", content),
|
||||
])
|
||||
}
|
||||
|
||||
fn description(page_type: PageType) {
|
||||
case page_type {
|
||||
Post(post.Post(headers: headers, ..))
|
||||
| Page(page.Page(headers: headers, ..)) ->
|
||||
headers
|
||||
|> dict.from_list()
|
||||
|> dict.get("description")
|
||||
|> result.unwrap("")
|
||||
Other(description: description, ..) -> description
|
||||
}
|
||||
}
|
||||
|
||||
fn title(page_type: PageType) {
|
||||
case page_type {
|
||||
Post(post.Post(title: title, ..))
|
||||
| Page(page.Page(title: title, ..))
|
||||
| Other(title: title, ..) -> title
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue