Compare commits

..

14 Commits

Author SHA1 Message Date
9f63205ff3 chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 37s
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / build (push) Successful in 47s
Continuous integration / Disallow unused dependencies (push) Successful in 57s
2025-04-10 12:35:10 -07:00
5a0378948d web: apply title wrapping on search results page 2025-04-10 12:32:46 -07:00
2b4c45be74 web: conditionally wrap title when large words found 2025-04-10 12:16:53 -07:00
147896dc80 chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 1m20s
Continuous integration / Test Suite (push) Successful in 39s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / build (push) Successful in 47s
Continuous integration / Disallow unused dependencies (push) Successful in 57s
Continuous integration / Trunk (push) Successful in 11m34s
2025-04-09 20:35:49 -07:00
1ff6ec7653 web: wrap long titles on message view 2025-04-09 20:35:33 -07:00
acd590111e chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 36s
Continuous integration / Test Suite (push) Successful in 41s
Continuous integration / Trunk (push) Successful in 45s
Continuous integration / Rustfmt (push) Successful in 54s
Continuous integration / build (push) Successful in 1m35s
Continuous integration / Disallow unused dependencies (push) Successful in 3m30s
2025-04-09 19:17:52 -07:00
b5f24ba1f2 server: strip element sizing attributes and inline style 2025-04-09 19:17:19 -07:00
79ed24135f fix(deps): update rust crate tantivy to 0.24.0
All checks were successful
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Check (push) Successful in 1m19s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 37s
Continuous integration / build (push) Successful in 48s
Continuous integration / Disallow unused dependencies (push) Successful in 2m3s
2025-04-09 18:01:42 +00:00
a4949a25b5 fix(deps): update rust crate cacher to 0.2.0
All checks were successful
Continuous integration / Check (push) Successful in 35s
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 44s
Continuous integration / build (push) Successful in 47s
Continuous integration / Disallow unused dependencies (push) Successful in 2m21s
2025-04-07 03:46:21 +00:00
f16edef124 chore(deps): lock file maintenance
All checks were successful
Continuous integration / Check (push) Successful in 35s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 31s
Continuous integration / build (push) Successful in 1m6s
Continuous integration / Test Suite (push) Successful in 3m2s
Continuous integration / Disallow unused dependencies (push) Successful in 56s
2025-04-07 00:01:51 +00:00
2fd6479cb9 fix(deps): update rust crate tokio to v1.44.2
All checks were successful
Continuous integration / Test Suite (push) Successful in 1m15s
Continuous integration / Trunk (push) Successful in 37s
Continuous integration / Rustfmt (push) Successful in 30s
Continuous integration / build (push) Successful in 45s
Continuous integration / Check (push) Successful in 4m17s
Continuous integration / Disallow unused dependencies (push) Successful in 57s
2025-04-05 15:47:48 +00:00
85a6b3a9a4 chore: Release
All checks were successful
Continuous integration / Check (push) Successful in 36s
Continuous integration / Test Suite (push) Successful in 40s
Continuous integration / Trunk (push) Successful in 38s
Continuous integration / Rustfmt (push) Successful in 38s
Continuous integration / build (push) Successful in 48s
Continuous integration / Disallow unused dependencies (push) Successful in 2m6s
2025-04-02 16:53:57 -07:00
9ac5216d6e web: more pre/code css tweaks 2025-04-02 16:53:37 -07:00
82987dbd20 web: tweak stype of code blocks 2025-04-02 16:46:24 -07:00
8 changed files with 360 additions and 208 deletions

416
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ authors = ["Bill Thiede <git@xinu.tv>"]
edition = "2021"
license = "UNLICENSED"
publish = ["xinu"]
version = "0.10.8"
version = "0.10.12"
repository = "https://git.z.xinu.tv/wathiede/letterbox"
[profile.dev]

View File

@@ -18,7 +18,7 @@ async-graphql = { version = "7", features = ["log"] }
async-graphql-rocket = "7"
async-trait = "0.1.81"
build-info = "0.0.40"
cacher = { version = "0.1.0", registry = "xinu" }
cacher = { version = "0.2.0", registry = "xinu" }
chrono = "0.4.39"
clap = { version = "4.5.23", features = ["derive"] }
css-inline = "0.14.0"
@@ -38,7 +38,7 @@ scraper = "0.23.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.87"
sqlx = { version = "0.8.2", features = ["postgres", "runtime-tokio", "time"] }
tantivy = { version = "0.22.0", optional = true }
tantivy = { version = "0.24.0", optional = true }
thiserror = "2.0.0"
tokio = "1.26.0"
tracing = "0.1.41"
@@ -47,8 +47,8 @@ urlencoding = "2.1.3"
#xtracing = { path = "../../xtracing" }
#xtracing = { git = "http://git-private.h.xinu.tv/wathiede/xtracing.git" }
xtracing = { version = "0.3.0", registry = "xinu" }
letterbox-notmuch = { version = "0.10.8", path = "../notmuch", registry = "xinu" }
letterbox-shared = { version = "0.10.8", path = "../shared", registry = "xinu" }
letterbox-notmuch = { version = "0.10.12", path = "../notmuch", registry = "xinu" }
letterbox-shared = { version = "0.10.12", path = "../shared", registry = "xinu" }
[build-dependencies]
build-info-build = "0.0.40"

View File

@@ -441,6 +441,38 @@ pub fn sanitize_html(
}
};
let mut element_content_handlers = vec![
// Remove width and height attributes on elements
element!("[width],[height]", |el| {
println!("width or height {el:?}");
el.remove_attribute("width");
el.remove_attribute("height");
Ok(())
}),
// Remove width and height values from inline styles
element!("[style]", |el| {
println!("style {el:?}");
let style = el.get_attribute("style").unwrap();
let style = style
.split(";")
.filter(|s| {
println!("s {s}");
let Some((k, _)) = s.split_once(':') else {
return true;
};
match k {
"width" | "max-width" | "min-width" | "height" | "max-height"
| "min-height" => false,
_ => true,
}
})
.collect::<Vec<_>>()
.join(";");
println!("style: {style}");
if let Err(e) = el.set_attribute("style", &style) {
error!("Failed to set style attribute: {e}");
}
Ok(())
}),
// Open links in new tab
element!("a[href]", |el| {
el.set_attribute("target", "_blank").unwrap();
@@ -913,3 +945,21 @@ async fn clean_title(title: &str) -> Result<String, ServerError> {
}
Ok(title)
}
#[cfg(test)]
mod tests {
use super::{SanitizeHtml, Transformer};
#[tokio::test]
async fn strip_sizes() -> Result<(), Box<dyn std::error::Error>> {
let ss = SanitizeHtml {
cid_prefix: "",
base_url: &None,
};
let input = r#"<p width=16 height=16 style="color:blue;width:16px;height:16px;">This el has width and height attributes and inline styles</p>"#;
let want = r#"<p style="color:blue;">This el has width and height attributes and inline styles</p>"#;
let got = ss.transform(&None, input).await?;
assert_eq!(got, want);
Ok(())
}
}

View File

@@ -12,5 +12,5 @@ version.workspace = true
[dependencies]
build-info = "0.0.40"
letterbox-notmuch = { version = "0.10.8", path = "../notmuch", registry = "xinu" }
letterbox-notmuch = { version = "0.10.12", path = "../notmuch", registry = "xinu" }
serde = { version = "1.0.147", features = ["derive"] }

View File

@@ -33,8 +33,8 @@ wasm-bindgen = "=0.2.100"
uuid = { version = "1.13.1", features = [
"js",
] } # direct dep to set js feature, prevents Rng issues
letterbox-shared = { version = "0.10.8", path = "../shared", registry = "xinu" }
letterbox-notmuch = { version = "0.10.8", path = "../notmuch", registry = "xinu" }
letterbox-shared = { version = "0.10.12", path = "../shared", registry = "xinu" }
letterbox-notmuch = { version = "0.10.12", path = "../notmuch", registry = "xinu" }
seed_hooks = { version = "0.4.0", registry = "xinu" }
strum_macros = "0.27.1"

View File

@@ -273,6 +273,13 @@ fn search_results(
tags.remove(idx);
};
let is_unread = unread_idx.is_some();
let mut title_break = None;
const TITLE_LENGTH_WRAP_LIMIT: usize = 40;
for w in r.subject.split_whitespace() {
if w.len() > TITLE_LENGTH_WRAP_LIMIT {
title_break = Some(C!["break-all", "text-pretty"]);
}
}
div![
C![
"flex",
@@ -315,7 +322,7 @@ fn search_results(
attrs! {
At::Href => urls::thread(&tid)
},
div![&r.subject],
div![title_break, &r.subject],
span![C!["text-xs"], pretty_authors(&r.authors)],
div![
C!["flex", "flex-wrap", "justify-between"],
@@ -1097,11 +1104,18 @@ fn thread(
let unread_thread_id = thread.thread_id.clone();
let spam_add_thread_id = thread.thread_id.clone();
let spam_unread_thread_id = thread.thread_id.clone();
let mut title_break = None;
const TITLE_LENGTH_WRAP_LIMIT: usize = 40;
for w in subject.split_whitespace() {
if w.len() > TITLE_LENGTH_WRAP_LIMIT {
title_break = Some(C!["break-all", "text-pretty"]);
}
}
div![
C!["lg:p-4", "max-w-4xl"],
div![
C!["p-4", "lg:p-0"],
h3![C!["text-xl"], subject],
h3![C!["text-xl"], title_break, subject],
span![removable_tags_chiclet(&thread.thread_id, &tags)],
IF!(!catchup_mode => div![
C!["pt-4", "gap-2", "flex", "justify-around"],
@@ -1397,11 +1411,18 @@ fn news_post(
]
}
let mut title_break = None;
const TITLE_LENGTH_WRAP_LIMIT: usize = 40;
for w in subject.split_whitespace() {
if w.len() > TITLE_LENGTH_WRAP_LIMIT {
title_break = Some(C!["break-all", "text-pretty"]);
}
}
div![
C!["lg:p-4", "max-w-4xl"],
div![
C!["p-4", "lg:p-0"],
h3![C!["text-xl"], subject],
h3![C!["text-xl"], title_break, subject],
span![tag(format!("News/{}", post.slug))],
IF!(!catchup_mode => div![
C!["pt-4", "gap-2", "flex", "justify-around"],

View File

@@ -1,18 +1,18 @@
html {
background-color: black;
background-color: black;
}
.mail-thread a,
.news-post a {
color: var(--color-link) !important;
text-decoration: underline;
color: var(--color-link) !important;
text-decoration: underline;
}
.mail-thread br,
.news-post br {
display: block;
margin-top: 1em;
content: " ";
display: block;
margin-top: 1em;
content: " ";
}
.mail-thread h1,
@@ -23,56 +23,61 @@ html {
.news-post h2,
.news-post h3,
.news-post h4 {
margin-top: 1em !important;
margin-bottom: 1em !important;
margin-top: 1em !important;
margin-bottom: 1em !important;
}
.mail-thread p,
.news-post p {
margin-bottom: 1em;
margin-bottom: 1em;
}
.mail-thread pre,
.news-post pre {
font-family: monospace;
background-color: #eee !important;
padding: 0.5em;
white-space: break-spaces;
}
.mail-thread code,
.news-post pre,
.news-post code {
font-family: monospace;
background-color: #eee !important;
padding: 0.5em !important;
font-family: monospace;
white-space: break-spaces;
}
.mail-thread blockquote {
padding-left: 1em;
border-left: 2px solid #ddd;
padding-left: 1em;
border-left: 2px solid #ddd;
}
.mail-thread ol,
.mail-thread ul {
margin-left: 2em;
margin-left: 2em;
}
.mail-thread .noreply-news-bloomberg-com img.logo-image {
width: initial !important;
max-width: 100% !important;
.mail-thread .noreply-news-bloomberg-com a {
background-color: initial !important;
}
.mail-thread .noreply-news-bloomberg-com h2 {
margin: 0 !important;
padding: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
/* Hackaday figures have unreadable black on dark grey */
.news-post figcaption.wp-caption-text {
background-color: initial !important;
background-color: initial !important;
}
.news-post.site-nautilus .article-ad,
.news-post.site-nautilus .primis-ad {
display: none !important;
display: none !important;
}
.news-post.site-slashdot .story-byline {
display: block !important;
height: initial !important;
overflow: auto !important;
position: static !important;
display: block !important;
height: initial !important;
overflow: auto !important;
position: static !important;
}