Skip to content
Snippets Groups Projects
Commit 58745a44 authored by Stephen D's avatar Stephen D
Browse files

add opengraph to posts and pages

parent ebdc964d
No related branches found
No related tags found
1 merge request!2add opengraph to posts and pages
...@@ -58,7 +58,7 @@ impl Blog { ...@@ -58,7 +58,7 @@ impl Blog {
content.push_str("</table>"); content.push_str("</table>");
Ok(self.dress_page(None, &content)) Ok(self.dress_page(None, &content, None))
} }
fn rss(&self) -> anyhow::Result<String> { fn rss(&self) -> anyhow::Result<String> {
...@@ -85,7 +85,7 @@ impl Blog { ...@@ -85,7 +85,7 @@ impl Blog {
Ok(out) Ok(out)
} }
fn dress_page(&self, title: Option<&str>, content: &str) -> String { fn dress_page(&self, title: Option<&str>, content: &str, head: Option<&str>) -> String {
let title = match title { let title = match title {
Some(title) => format!("{} | {}", title.trim(), self.config.name.trim()), Some(title) => format!("{} | {}", title.trim(), self.config.name.trim()),
None => self.config.name.trim().to_string(), None => self.config.name.trim().to_string(),
...@@ -109,8 +109,10 @@ impl Blog { ...@@ -109,8 +109,10 @@ impl Blog {
page_links.push_str(&p.link_short()); page_links.push_str(&p.link_short());
} }
let head = head.unwrap_or("");
format!( format!(
r#"<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/style.css" />{favicons}<title>{title}</title></head><body><div><a href="/">Home</a>{page_links}{logo}</div><hr>{content}</body></html>"# r#"<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/style.css" />{favicons}<title>{title}</title>{head}</head><body><div><a href="/">Home</a>{page_links}{logo}</div><hr>{content}</body></html>"#
) )
} }
} }
...@@ -145,13 +147,21 @@ impl TryFrom<Blog> for RenderedBlog { ...@@ -145,13 +147,21 @@ impl TryFrom<Blog> for RenderedBlog {
let mut pages = FnvHashMap::default(); let mut pages = FnvHashMap::default();
for p in &b.posts { for p in &b.posts {
let body = b.dress_page(Some(&p.title), &p.html()?); let body = b.dress_page(
Some(&p.title),
&p.html()?,
Some(p.open_graph(&b.config.root, &b.config.logo)?.as_ref()),
);
insert_path(&mut pages, &p.url, Response::html(body))?; insert_path(&mut pages, &p.url, Response::html(body))?;
} }
for p in &b.pages { for p in &b.pages {
let body = b.dress_page(Some(&p.title), &p.html()?); let body = b.dress_page(
Some(&p.title),
&p.html()?,
Some(p.open_graph(&b.config.root, &b.config.logo)?.as_ref()),
);
insert_path(&mut pages, &p.url, Response::html(body))?; insert_path(&mut pages, &p.url, Response::html(body))?;
} }
...@@ -184,8 +194,11 @@ impl TryFrom<Blog> for RenderedBlog { ...@@ -184,8 +194,11 @@ impl TryFrom<Blog> for RenderedBlog {
Response::svg(include_bytes!("assets/rss.svg").to_vec()), Response::svg(include_bytes!("assets/rss.svg").to_vec()),
)?; )?;
let not_found = let not_found = Response::html(b.dress_page(
Response::html(b.dress_page(Some("Page not found"), include_str!("assets/404.html"))); Some("Page not found"),
include_str!("assets/404.html"),
None,
));
if let Some(fav) = b.favicon { if let Some(fav) = b.favicon {
for (p, r) in fav.responses { for (p, r) in fav.responses {
......
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
#[derive(Eq, PartialEq, Hash, Debug)] #[derive(Eq, PartialEq, Hash, Debug, Clone)]
pub struct UrlPath { pub struct UrlPath {
parts: Vec<String>, parts: Vec<String>,
} }
......
...@@ -5,6 +5,7 @@ use chrono::{DateTime, NaiveDate, Utc}; ...@@ -5,6 +5,7 @@ use chrono::{DateTime, NaiveDate, Utc};
use orgize::{elements::Keyword, export::HtmlHandler, Element}; use orgize::{elements::Keyword, export::HtmlHandler, Element};
use crate::{ use crate::{
config::Logo,
date::parse_org_date, date::parse_org_date,
load::Loadable, load::Loadable,
parser::{parse, CustomHtmlHandler, Parser}, parser::{parse, CustomHtmlHandler, Parser},
...@@ -20,6 +21,7 @@ pub struct Post { ...@@ -20,6 +21,7 @@ pub struct Post {
pub index: u32, pub index: u32,
pub content: String, pub content: String,
pub url: String, pub url: String,
pub primary_photo: Option<String>,
} }
impl Post { impl Post {
...@@ -65,6 +67,45 @@ impl Post { ...@@ -65,6 +67,45 @@ impl Post {
)) ))
} }
pub fn open_graph(&self, root_url: &str, logo: &Option<Logo>) -> anyhow::Result<String> {
let root = UrlPath::new_from_raw(root_url.to_string());
let og_image = match self
.primary_photo
.as_ref()
.or_else(|| logo.as_ref().map(|l| &l.path))
{
Some(l) => format!(
r#"<meta property="og:image" content="{}" />"#,
root.clone().join(l)
),
None => String::new(),
};
let date = match self.date {
Some(d) => {
format!(
r#"<meta property="og:article:published_time" content="{}" />"#,
DateTime::<Utc>::from_utc(
d.and_hms_opt(0, 0, 0)
.context("Could not convert date to datetime")?,
Utc
)
.to_rfc3339()
)
}
None => "".to_string(),
};
Ok(format!(
r#"<meta property="og:title" content="{}" /><meta property="og:type" content="article" />{}<meta property="og:url" content="{}" />{}"#,
self.title,
og_image,
root.join(&self.url),
date,
))
}
pub fn link(&self) -> anyhow::Result<String> { pub fn link(&self) -> anyhow::Result<String> {
let link = match self.date_f()? { let link = match self.date_f()? {
Some(date_f) => format!( Some(date_f) => format!(
...@@ -147,6 +188,7 @@ struct PostParser { ...@@ -147,6 +188,7 @@ struct PostParser {
url: String, url: String,
content: Vec<u8>, content: Vec<u8>,
handler: CustomHtmlHandler, handler: CustomHtmlHandler,
primary_photo: Option<String>,
} }
impl PostParser { impl PostParser {
...@@ -159,6 +201,7 @@ impl PostParser { ...@@ -159,6 +201,7 @@ impl PostParser {
url, url,
content: vec![], content: vec![],
handler: CustomHtmlHandler::new(base_path)?, handler: CustomHtmlHandler::new(base_path)?,
primary_photo: None,
}) })
} }
} }
...@@ -178,6 +221,14 @@ impl Parser<Post> for PostParser { ...@@ -178,6 +221,14 @@ impl Parser<Post> for PostParser {
self.title = Some(value.to_string()); self.title = Some(value.to_string());
} }
Element::Keyword(Keyword { key, value, .. }) if key == "PREVIEW" => {
if self.primary_photo.is_some() {
bail!("Post has more than one preview");
}
self.primary_photo = Some(format!("/thumb/{value}"));
}
Element::Keyword(Keyword { key, value, .. }) if key == "DATE" => { Element::Keyword(Keyword { key, value, .. }) if key == "DATE" => {
if self.date.is_some() { if self.date.is_some() {
bail!("Post has more than one date"); bail!("Post has more than one date");
...@@ -215,6 +266,7 @@ impl Parser<Post> for PostParser { ...@@ -215,6 +266,7 @@ impl Parser<Post> for PostParser {
let index = self.index.unwrap_or(u32::MAX); let index = self.index.unwrap_or(u32::MAX);
let content = String::from_utf8(self.content)?; let content = String::from_utf8(self.content)?;
let url = self.url; let url = self.url;
let primary_photo = self.primary_photo;
Ok(Post { Ok(Post {
hidden, hidden,
...@@ -223,6 +275,7 @@ impl Parser<Post> for PostParser { ...@@ -223,6 +275,7 @@ impl Parser<Post> for PostParser {
index, index,
content, content,
url, url,
primary_photo,
}) })
} }
} }
pub struct Wrapper {
//
}
impl Wrapper {
fn new() {}
fn before() {}
fn after() {}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment