Compare commits

..

3 Commits

7 changed files with 69 additions and 7 deletions

View File

@ -41,6 +41,7 @@ pub enum Thread {
#[derive(Debug, SimpleObject)] #[derive(Debug, SimpleObject)]
pub struct NewsPost { pub struct NewsPost {
pub thread_id: String, pub thread_id: String,
pub is_read: bool,
pub slug: String, pub slug: String,
pub site: String, pub site: String,
pub title: String, pub title: String,

View File

@ -9,7 +9,10 @@ use async_trait::async_trait;
use css_inline::{CSSInliner, InlineError, InlineOptions}; use css_inline::{CSSInliner, InlineError, InlineOptions};
use linkify::{LinkFinder, LinkKind}; use linkify::{LinkFinder, LinkKind};
use log::{error, info, warn}; use log::{error, info, warn};
use lol_html::{element, errors::RewritingError, rewrite_str, text, RewriteStrSettings}; use lol_html::{
element, errors::RewritingError, html_content::ContentType, rewrite_str, text,
RewriteStrSettings,
};
use maplit::{hashmap, hashset}; use maplit::{hashmap, hashset};
use scraper::{error::SelectorErrorKind, Html, Selector}; use scraper::{error::SelectorErrorKind, Html, Selector};
use thiserror::Error; use thiserror::Error;
@ -129,6 +132,36 @@ impl Transformer for InlineStyle {
} }
} }
/// Frame images will extract any alt or title tags on images and place them as labels below said
/// image.
struct FrameImages;
#[async_trait]
impl Transformer for FrameImages {
async fn transform(&self, link: &Option<Url>, html: &str) -> Result<String, TransformError> {
Ok(rewrite_str(
html,
RewriteStrSettings {
element_content_handlers: vec![element!("img[alt], img[title]", |el| {
info!("found image with alt or title {el:?}");
let src = el
.get_attribute("src")
.unwrap_or("https://placehold.co/600x400".to_string());
let alt = el.get_attribute("alt");
let title = el.get_attribute("title");
let mut frags = vec!["<figure>".to_string(), format!(r#"<img src="{src}">"#)];
alt.map(|t| frags.push(format!("<figcaption>Alt: {t}</figcaption>")));
title.map(|t| frags.push(format!("<figcaption>Title: {t}</figcaption>")));
frags.push("</figure>".to_string());
el.replace(&frags.join("\n"), ContentType::Html);
Ok(())
})],
..RewriteStrSettings::default()
},
)?)
}
}
struct AddOutlink; struct AddOutlink;
#[async_trait] #[async_trait]

View File

@ -15,7 +15,8 @@ use crate::{
compute_offset_limit, compute_offset_limit,
error::ServerError, error::ServerError,
graphql::{Body, Email, Html, Message, NewsPost, Tag, Thread, ThreadSummary}, graphql::{Body, Email, Html, Message, NewsPost, Tag, Thread, ThreadSummary},
AddOutlink, EscapeHtml, InlineStyle, SanitizeHtml, SlurpContents, StripHtml, Transformer, AddOutlink, EscapeHtml, FrameImages, InlineStyle, SanitizeHtml, SlurpContents, StripHtml,
Transformer,
}; };
pub fn is_newsreader_search(query: &str) -> bool { pub fn is_newsreader_search(query: &str) -> bool {
@ -193,6 +194,7 @@ pub async fn thread(pool: &PgPool, thread_id: String) -> Result<Thread, ServerEr
], ],
], ],
}), }),
Box::new(FrameImages),
Box::new(AddOutlink), Box::new(AddOutlink),
Box::new(EscapeHtml), Box::new(EscapeHtml),
Box::new(InlineStyle), Box::new(InlineStyle),
@ -207,6 +209,7 @@ pub async fn thread(pool: &PgPool, thread_id: String) -> Result<Thread, ServerEr
} }
} }
let title = clean_title(&r.title.unwrap_or("NO TITLE".to_string())).await?; let title = clean_title(&r.title.unwrap_or("NO TITLE".to_string())).await?;
let is_read = r.is_read.unwrap_or(false);
let timestamp = r let timestamp = r
.date .date
.expect("post missing date") .expect("post missing date")
@ -214,6 +217,7 @@ pub async fn thread(pool: &PgPool, thread_id: String) -> Result<Thread, ServerEr
.unix_timestamp(); .unix_timestamp();
Ok(Thread::News(NewsPost { Ok(Thread::News(NewsPost {
thread_id, thread_id,
is_read,
slug, slug,
site, site,
title, title,

View File

@ -878,6 +878,22 @@
} }
} }
}, },
{
"args": [],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "isRead",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
}
},
{ {
"args": [], "args": [],
"deprecationReason": null, "deprecationReason": null,

View File

@ -2,6 +2,7 @@ query ShowThreadQuery($threadId: String!) {
thread(threadId: $threadId) { thread(threadId: $threadId) {
__typename ... on NewsPost{ __typename ... on NewsPost{
threadId threadId
isRead
slug slug
site site
title title

View File

@ -1131,9 +1131,7 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg>
let avatar: Option<String> = None; let avatar: Option<String> = None;
//let avatar: Option<String> = Some(String::from("https://bulma.io/images/placeholders/64x64.png")); //let avatar: Option<String> = Some(String::from("https://bulma.io/images/placeholders/64x64.png"));
let id = post.thread_id.clone(); let id = post.thread_id.clone();
// TODO: plumb this through let is_unread = !post.is_read;
//let is_unread = has_unread(&msg.tags);
let is_unread = true;
let img = render_avatar(avatar, &from); let img = render_avatar(avatar, &from);
article![ article![
C!["media"], C!["media"],

View File

@ -1,11 +1,11 @@
.body.site-saturday-morning-breakfast-cereal { .body.news-post.site-saturday-morning-breakfast-cereal {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
} }
.body.site-slashdot i { .body.news-post.site-slashdot i {
border-left: 2px solid #ddd; border-left: 2px solid #ddd;
display: block; display: block;
font-style: normal !important; font-style: normal !important;
@ -13,3 +13,12 @@
margin-top: 1em; margin-top: 1em;
padding-left: 1em; padding-left: 1em;
} }
.body.news-post em {
margin: inherit !important;
padding: inherit !important;
font-weight: inherit !important;
border: inherit !important;
display: inline !important;
color: inherit !important;
}