diff --git a/server/src/custom.css b/server/src/custom.css deleted file mode 100644 index e00c7f0..0000000 --- a/server/src/custom.css +++ /dev/null @@ -1,8 +0,0 @@ -pre { - background-color: var(--color-bg); - color: var(--color-text); -} - -code { - background-color: var(--color-bg-secondary); -} diff --git a/server/src/lib.rs b/server/src/lib.rs index 4e0bf30..4729098 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -117,26 +117,7 @@ struct InlineRemoteStyle<'a> { #[async_trait] impl<'a> Transformer for InlineRemoteStyle<'a> { async fn transform(&self, _: &Option, html: &str) -> Result { - let css = concat!( - "/* chrome-default.css */\n", - include_str!("chrome-default.css"), - "\n/* mvp.css */\n", - include_str!("mvp.css"), - "\n/* Xinu Specific overrides */\n", - include_str!("custom.css"), - ); - let inline_opts = InlineOptions { - //inline_style_tags: true, - //keep_style_tags: false, - //keep_link_tags: true, - base_url: self.base_url.clone(), - //load_remote_stylesheets: true, - //preallocate_node_capacity: 32, - ..InlineOptions::default() - }; - //info!("HTML:\n{html}"); - info!("base_url: {:#?}", self.base_url); Ok( match CSSInliner::options() .base_url(self.base_url.clone()) @@ -160,10 +141,10 @@ impl Transformer for InlineStyle { let css = concat!( "/* chrome-default.css */\n", include_str!("chrome-default.css"), - "\n/* mvp.css */\n", - include_str!("mvp.css"), - "\n/* Xinu Specific overrides */\n", - include_str!("custom.css"), + //"\n/* mvp.css */\n", + //include_str!("mvp.css"), + //"\n/* Xinu Specific overrides */\n", + //include_str!("custom.css"), ); let inline_opts = InlineOptions { inline_style_tags: true, @@ -288,13 +269,25 @@ impl SlurpContents { #[async_trait] impl Transformer for SlurpContents { - fn should_run(&self, link: &Option, _: &str) -> bool { + fn should_run(&self, link: &Option, html: &str) -> bool { + let mut will_slurp = false; if let Some(link) = link { - return self.get_selectors(link).is_some(); + will_slurp = self.get_selectors(link).is_some(); } - false + if !will_slurp && self.inline_css { + return InlineStyle {}.should_run(link, html); + } + will_slurp } async fn transform(&self, link: &Option, html: &str) -> Result { + if let Some(test_link) = link { + // If SlurpContents is configured for inline CSS, but no + // configuration found for this site, use the local InlineStyle + // transform. + if self.inline_css && self.get_selectors(test_link).is_none() { + return InlineStyle {}.transform(link, html).await; + } + } let Some(link) = link else { return Ok(html.to_string()); }; @@ -303,7 +296,6 @@ impl Transformer for SlurpContents { }; let cacher = self.cacher.lock().await; let body = if let Some(body) = cacher.get(link.as_str()) { - info!("cache hit for {link}"); String::from_utf8_lossy(&body).to_string() } else { let body = reqwest::get(link.as_str()).await?.text().await?; @@ -315,8 +307,17 @@ impl Transformer for SlurpContents { let body = if self.inline_css { let inner_body = Arc::clone(&body); let res = tokio::task::spawn_blocking(move || { + let css = concat!( + "/* chrome-default.css */\n", + include_str!("chrome-default.css"), + "\n/* vars.css */\n", + include_str!("../../web/static/vars.css"), + //"\n/* Xinu Specific overrides */\n", + //include_str!("custom.css"), + ); let res = CSSInliner::options() .base_url(base_url) + .extra_css(Some(std::borrow::Cow::Borrowed(css))) .build() .inline(&inner_body); diff --git a/server/src/newsreader.rs b/server/src/newsreader.rs index 586aca8..bfa289d 100644 --- a/server/src/newsreader.rs +++ b/server/src/newsreader.rs @@ -15,9 +15,8 @@ use crate::{ config::Config, error::ServerError, graphql::{Corpus, NewsPost, Tag, Thread, ThreadSummary}, - thread_summary_from_row, AddOutlink, EscapeHtml, FrameImages, InlineRemoteStyle, Query, - SanitizeHtml, SlurpContents, ThreadSummaryRecord, Transformer, NEWSREADER_TAG_PREFIX, - NEWSREADER_THREAD_PREFIX, + thread_summary_from_row, AddOutlink, FrameImages, Query, SanitizeHtml, SlurpContents, + ThreadSummaryRecord, Transformer, NEWSREADER_TAG_PREFIX, NEWSREADER_THREAD_PREFIX, }; pub fn is_newsreader_query(query: &Query) -> bool { @@ -196,8 +195,7 @@ pub async fn thread( let body_tranformers: Vec> = vec![ Box::new(SlurpContents { cacher, - // TODO: make this true when bulma is finally removed - inline_css: false, + inline_css: true, site_selectors: hashmap![ "atmeta.com".to_string() => vec![ Selector::parse("div.entry-content").unwrap(), @@ -239,6 +237,14 @@ pub async fn thread( Selector::parse("span.story-byline").unwrap(), Selector::parse("div.p").unwrap(), ], + "theonion.com".to_string() => vec![ + // Single cartoon + Selector::parse("article > div > div > figure").unwrap(), + // Image at top of article + Selector::parse("article > header > div > div > figure").unwrap(), + // Article body + Selector::parse("article .entry-content > *").unwrap(), + ], "trofi.github.io".to_string() => vec![ Selector::parse("#content").unwrap(), ], diff --git a/web/index.html b/web/index.html index 156d34d..9a2e73d 100644 --- a/web/index.html +++ b/web/index.html @@ -13,7 +13,9 @@ + + diff --git a/web/src/view/mod.rs b/web/src/view/mod.rs index 52c687c..474d175 100644 --- a/web/src/view/mod.rs +++ b/web/src/view/mod.rs @@ -86,7 +86,13 @@ pub fn view(model: &Model) -> Node { } => search_results(&query, results.as_slice(), *count, pager, selected_threads), }; div![ - C!["flex", "flex-wrap-reverse", "bg-black", "text-white"], + C![ + "flex", + "flex-wrap-reverse", + "bg-black", + "text-white", + "lg:flex-nowrap" + ], div![ C!["w-full", "lg:w-48", "flex-none", "flex", "flex-col"], tags(model), @@ -190,6 +196,7 @@ fn set_title(title: &str) { seed::document().set_title(&format!("lb: {}", title)); } +// TODO: unifiy tags_chiclet, removable_tags_chiclet, and tags inside news_post() fn tags_chiclet(tags: &[String], is_mobile: bool) -> impl Iterator> + '_ { tags.iter().map(move |tag| { let hex = compute_color(tag); @@ -1147,8 +1154,6 @@ pub fn tags(model: &Model) -> Node { ] } fn news_post(post: &ShowThreadQueryThreadOnNewsPost, content_el: &ElRef) -> Node { - // TODO remove and replace with CSS styling - let show_icon_text = true; let subject = &post.title; set_title(subject); let read_thread_id = post.thread_id.clone(); @@ -1156,94 +1161,68 @@ fn news_post(post: &ShowThreadQueryThreadOnNewsPost, content_el: &ElRef Node { let hex = compute_color(&tag); let style = style! {St::BackgroundColor=>hex}; - let classes = C!["NOTPORTED", "tag", IF!(is_mobile => "is-small")]; let attrs = attrs! { At::Href => urls::search(&format!("tag:{tag}"), 0) }; let tag = tag.clone(); - div![ - C![ - "NOTPORTED", - "message-tags", - "field", - "is-grouped", - "is-grouped-multiline" - ], - div![ - C!["NOTPORTED", "control"], - div![ - C!["NOTPORTED", "tags", "has-addons"], - a![ - classes, - attrs, - style, - match tag.as_str() { - "attachment" => span!["📎"], - "replied" => span![i![C!["NOTPORTED", "fa-solid", "fa-reply"]]], - _ => span![&tag], - }, - ev(Ev::Click, move |_| Msg::FrontPageRequest { - query: format!("tag:{tag}"), - after: None, - before: None, - first: None, - last: None, - }) - ] - ] - ] + a![ + attrs, + span![C![&tw_classes::TAG], style, &tag], + ev(Ev::Click, move |_| Msg::FrontPageRequest { + query: format!("tag:{tag}"), + after: None, + before: None, + first: None, + last: None, + }) ] } div![ - C!["NOTPORTED", "thread"], - h3![C!["NOTPORTED", "is-size-5"], subject], - tag(format!("News/{}", post.slug), false), + C!["lg:p-4", "max-w-4xl"], div![ - C!["NOTPORTED", "level", "is-mobile"], + C!["p-4", "lg:p-0"], + h3![C!["text-xl"], subject], + span![tag(format!("News/{}", post.slug), false)], div![ - C!["NOTPORTED", "level-item"], + C!["pt-4", "gap-2", "flex", "justify-around"], div![ - C!["NOTPORTED", "buttons", "has-addons"], button![ - C!["NOTPORTED", "button", "mark-read"], + C![&tw_classes::BUTTON, "rounded-r-none"], attrs! {At::Title => "Mark as read"}, - span![ - C!["NOTPORTED", "icon", "is-small"], - i![C!["NOTPORTED", "far", "fa-envelope-open"]] - ], - IF!(show_icon_text=>span!["Read"]), + span![i![C!["far", "fa-envelope-open"]]], + span![C!["pl-2", "hidden", "md:inline"], "Read"], ev(Ev::Click, move |_| Msg::MultiMsg(vec![ Msg::SetUnread(read_thread_id, false), Msg::GoToSearchResults ])), ], button![ - C!["NOTPORTED", "button", "mark-unread"], + C![&tw_classes::BUTTON, "rounded-l-none"], attrs! {At::Title => "Mark as unread"}, - span![ - C!["NOTPORTED", "icon", "is-small"], - i![C!["NOTPORTED", "far", "fa-envelope"]] - ], - IF!(show_icon_text=>span!["Unread"]), + span![i![C!["far", "fa-envelope"]]], + span![C!["pl-2", "hidden", "md:inline"], "Unread"], ev(Ev::Click, move |_| Msg::MultiMsg(vec![ Msg::SetUnread(unread_thread_id, true), Msg::GoToSearchResults ])), ], ], + // Placeholder for symmetry with email view that has Spam button + div![], ], - // This would be the holder for spam buttons on emails, needed to keep layout - // consistent - div![C!["NOTPORTED", "level-item"], div![]] ], div![ - C!["NOTPORTED", "message"], - div![C!["NOTPORTED", "header"], render_news_post_header(&post)], + C!["lg:mt-4"], + div![render_news_post_header(&post)], div![ C![ - "NOTPORTED", - "body", + "bg-white", + "text-black", + "p-4", + "lg:mb-4", + "min-w-full", + "overflow-x-auto", "news-post", format!("site-{}", post.slug) ], @@ -1251,12 +1230,6 @@ fn news_post(post: &ShowThreadQueryThreadOnNewsPost, content_el: &ElRefapi::original(&thread_node.0.as_ref().expect("message missing").id)}, - "Original" - ], - */ click_to_top(), ] } @@ -1289,7 +1262,7 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node ], ]; div![ - C!["flex", "p-4"], + C!["flex", "p-4", "bg-neutral-800"], div![favicon], div![ C!["px-4", "mr-auto"], @@ -1329,6 +1302,7 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node ] } fn reading_progress(ratio: f64) -> Node { + return div![]; let percent = ratio * 100.; info!("percent {percent}"); div![ @@ -1336,7 +1310,7 @@ fn reading_progress(ratio: f64) -> Node { "fixed", "top-0", "left-0", - "w-screen", + "w-full", "h-1", "bg-gray-200", IF!(percent<1. => "hidden") diff --git a/web/static/overrides.css b/web/static/overrides.css new file mode 100644 index 0000000..eee1885 --- /dev/null +++ b/web/static/overrides.css @@ -0,0 +1,33 @@ +html { + background-color: black; +} + +.news-post a { + color: var(--color-link) !important; + text-decoration: underline; +} + +.news-post br { + display: block; + margin-top: 1em; + content: " "; +} + +.news-post h1, +.news-post h2, +.news-post h3, +.news-post h4 { + margin-top: 1em !important; + margin-bottom: 1em !important; +} + +.news-post p { + margin-bottom: 1em; +} + +.news-post pre, +.news-post code { + font-family: monospace; + background-color: #eee !important; + padding: 0.5em !important; +} \ No newline at end of file diff --git a/web/static/vars.css b/web/static/vars.css new file mode 100644 index 0000000..cc126e1 --- /dev/null +++ b/web/static/vars.css @@ -0,0 +1,42 @@ +:root { + --active-brightness: 0.85; + --border-radius: 5px; + --box-shadow: 2px 2px 10px; + --color-accent: #118bee15; + --color-bg: #fff; + --color-bg-secondary: #e9e9e9; + --color-link: #118bee; + --color-secondary: #920de9; + --color-secondary-accent: #920de90b; + --color-shadow: #f4f4f4; + --color-table: #118bee; + --color-text: #000; + --color-text-secondary: #999; + --color-scrollbar: #cacae8; + --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + --hover-brightness: 1.2; + --justify-important: center; + --justify-normal: left; + --line-height: 1.5; + /* + --width-card: 285px; + --width-card-medium: 460px; + --width-card-wide: 800px; +*/ + --width-content: 1080px; +} + +@media (prefers-color-scheme: dark) { + :root[color-mode="user"] { + --color-accent: #0097fc4f; + --color-bg: #333; + --color-bg-secondary: #555; + --color-link: #0097fc; + --color-secondary: #e20de9; + --color-secondary-accent: #e20de94f; + --color-shadow: #bbbbbb20; + --color-table: #0097fc; + --color-text: #f7f7f7; + --color-text-secondary: #aaa; + } +} \ No newline at end of file