Compare commits
33 Commits
letterbox-
...
4c2c2ff7a1
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c2c2ff7a1 | |||
| f175faed98 | |||
| 8971c16117 | |||
| fbecf564b5 | |||
| e5643c6fd0 | |||
| a8734269f7 | |||
| cab4e571f3 | |||
| 4d6c6af7d9 | |||
| cf08831ed1 | |||
| e1509c5978 | |||
| 13db8e6f1f | |||
| 136a837fa4 | |||
| 1ea058c664 | |||
| f4c11c5b3f | |||
| 8dc8f3a0f8 | |||
| 7b9450b65b | |||
| b5de0719dd | |||
| 58da28a19b | |||
| 75ad27ec2f | |||
| f904fa0001 | |||
| b94596bf65 | |||
| aa24599921 | |||
| c81a8c1cd3 | |||
| 7c3cfec3d1 | |||
| a2920fde3b | |||
| 8bc449ae6e | |||
| 0febd0535a | |||
| a9e00a54e4 | |||
| 6811c689ff | |||
| 8ba6b3d0b0 | |||
| a7c5585e80 | |||
| 4ef4d49113 | |||
| f8af303110 |
1348
Cargo.lock
generated
1348
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ authors = ["Bill Thiede <git@xinu.tv>"]
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "UNLICENSED"
|
license = "UNLICENSED"
|
||||||
publish = ["xinu"]
|
publish = ["xinu"]
|
||||||
version = "0.17.23"
|
version = "0.17.25"
|
||||||
repository = "https://git.z.xinu.tv/wathiede/letterbox"
|
repository = "https://git.z.xinu.tv/wathiede/letterbox"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ async-graphql-axum = "7.0.16"
|
|||||||
async-trait = "0.1.88"
|
async-trait = "0.1.88"
|
||||||
axum = { version = "0.8.3", features = ["ws"] }
|
axum = { version = "0.8.3", features = ["ws"] }
|
||||||
axum-macros = "0.5.0"
|
axum-macros = "0.5.0"
|
||||||
build-info = "0.0.40"
|
build-info = "0.0.41"
|
||||||
cacher = { version = "0.2.0", registry = "xinu" }
|
cacher = { version = "0.2.0", registry = "xinu" }
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.40"
|
||||||
clap = { version = "4.5.37", features = ["derive"] }
|
clap = { version = "4.5.37", features = ["derive"] }
|
||||||
css-inline = "0.14.4"
|
css-inline = "0.15.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
headers = "0.4.0"
|
headers = "0.4.0"
|
||||||
html-escape = "0.2.13"
|
html-escape = "0.2.13"
|
||||||
letterbox-notmuch = { path = "../notmuch", version = "0.17.23", registry = "xinu" }
|
letterbox-notmuch = { path = "../notmuch", version = "0.17.25", registry = "xinu" }
|
||||||
letterbox-shared = { path = "../shared", version = "0.17.23", registry = "xinu" }
|
letterbox-shared = { path = "../shared", version = "0.17.25", registry = "xinu" }
|
||||||
linkify = "0.10.0"
|
linkify = "0.10.0"
|
||||||
lol_html = "2.3.0"
|
lol_html = "2.3.0"
|
||||||
mailparse = "0.16.1"
|
mailparse = "0.16.1"
|
||||||
@@ -52,7 +52,7 @@ urlencoding = "2.1.3"
|
|||||||
xtracing = { version = "0.3.2", registry = "xinu" }
|
xtracing = { version = "0.3.2", registry = "xinu" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build-info-build = "0.0.40"
|
build-info-build = "0.0.41"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
#default = [ "tantivy" ]
|
#default = [ "tantivy" ]
|
||||||
|
|||||||
@@ -352,6 +352,9 @@ fn slurp_contents_selectors() -> HashMap<String, Vec<Selector>> {
|
|||||||
"natwelch.com".to_string() => vec![
|
"natwelch.com".to_string() => vec![
|
||||||
Selector::parse("article div.prose").unwrap(),
|
Selector::parse("article div.prose").unwrap(),
|
||||||
],
|
],
|
||||||
|
"seiya.me".to_string() => vec![
|
||||||
|
Selector::parse("header + div").unwrap(),
|
||||||
|
],
|
||||||
"rustacean-station.org".to_string() => vec![
|
"rustacean-station.org".to_string() => vec![
|
||||||
Selector::parse("article").unwrap(),
|
Selector::parse("article").unwrap(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ version.workspace = true
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
build-info = "0.0.40"
|
build-info = "0.0.41"
|
||||||
letterbox-notmuch = { path = "../notmuch", version = "0.17.23", registry = "xinu" }
|
letterbox-notmuch = { path = "../notmuch", version = "0.17.25", registry = "xinu" }
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
sqlx = "0.8.5"
|
sqlx = "0.8.5"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ repository.workspace = true
|
|||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build-info-build = "0.0.40"
|
build-info-build = "0.0.41"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.50"
|
wasm-bindgen-test = "0.3.50"
|
||||||
@@ -28,7 +28,7 @@ graphql_client = "0.14.0"
|
|||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
gloo-net = { version = "0.6.0", features = ["json", "serde_json"] }
|
gloo-net = { version = "0.6.0", features = ["json", "serde_json"] }
|
||||||
human_format = "1.1.0"
|
human_format = "1.1.0"
|
||||||
build-info = "0.0.40"
|
build-info = "0.0.41"
|
||||||
wasm-bindgen = "=0.2.100"
|
wasm-bindgen = "=0.2.100"
|
||||||
uuid = { version = "1.16.0", features = [
|
uuid = { version = "1.16.0", features = [
|
||||||
"js",
|
"js",
|
||||||
|
|||||||
@@ -72,10 +72,6 @@ fn on_url_changed(old: &Url, mut new: Url) -> Msg {
|
|||||||
if did_change {
|
if did_change {
|
||||||
messages.push(Msg::ScrollToTop)
|
messages.push(Msg::ScrollToTop)
|
||||||
}
|
}
|
||||||
info!(
|
|
||||||
"url changed\nold '{old}'\nnew '{new}', history {}",
|
|
||||||
history().length().unwrap_or(0)
|
|
||||||
);
|
|
||||||
let hpp = new.remaining_hash_path_parts();
|
let hpp = new.remaining_hash_path_parts();
|
||||||
let msg = match hpp.as_slice() {
|
let msg = match hpp.as_slice() {
|
||||||
["t", tid] => Msg::ShowThreadRequest {
|
["t", tid] => Msg::ShowThreadRequest {
|
||||||
@@ -553,7 +549,6 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Msg::ScrollToTop => {
|
Msg::ScrollToTop => {
|
||||||
info!("scrolling to the top");
|
|
||||||
web_sys::window().unwrap().scroll_to_with_x_and_y(0., 0.);
|
web_sys::window().unwrap().scroll_to_with_x_and_y(0., 0.);
|
||||||
}
|
}
|
||||||
Msg::WindowScrolled => {
|
Msg::WindowScrolled => {
|
||||||
@@ -619,6 +614,36 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
orders.send_msg(Msg::CatchupRequest { query });
|
orders.send_msg(Msg::CatchupRequest { query });
|
||||||
}
|
}
|
||||||
Msg::CatchupKeepUnread => {
|
Msg::CatchupKeepUnread => {
|
||||||
|
if let Some(thread_id) = current_thread_id(&model.context) {
|
||||||
|
if let Context::ThreadResult {
|
||||||
|
thread:
|
||||||
|
ShowThreadQueryThread::EmailThread(ShowThreadQueryThreadOnEmailThread {
|
||||||
|
messages,
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
} = &model.context
|
||||||
|
{
|
||||||
|
//orders.send_msg(Msg::SetUnread(thread_id, false));
|
||||||
|
let unread_messages: Vec<_> = messages
|
||||||
|
.iter()
|
||||||
|
.filter(|msg| msg.tags.iter().any(|t| t == "unread"))
|
||||||
|
.map(|msg| &msg.id)
|
||||||
|
.collect();
|
||||||
|
if unread_messages.is_empty() {
|
||||||
|
// All messages are read, so mark them all unread
|
||||||
|
orders.send_msg(Msg::SetUnread(thread_id, true));
|
||||||
|
} else {
|
||||||
|
// Do nothing if there are some messages unread
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// News post, not email, just mark unread
|
||||||
|
orders.send_msg(Msg::SetUnread(thread_id, true));
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// This shouldn't happen
|
||||||
|
warn!("no current thread_id");
|
||||||
|
}
|
||||||
orders.send_msg(Msg::CatchupNext);
|
orders.send_msg(Msg::CatchupNext);
|
||||||
}
|
}
|
||||||
Msg::CatchupMarkAsRead => {
|
Msg::CatchupMarkAsRead => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::VecDeque, rc::Rc};
|
use std::{collections::VecDeque, rc::Rc};
|
||||||
|
|
||||||
use letterbox_shared::WebsocketMessage;
|
use letterbox_shared::WebsocketMessage;
|
||||||
use log::{error, info};
|
use log::{debug, error};
|
||||||
use seed::prelude::*;
|
use seed::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@@ -122,13 +122,13 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
match msg {
|
match msg {
|
||||||
Msg::WebSocketOpened => {
|
Msg::WebSocketOpened => {
|
||||||
model.web_socket_reconnector = None;
|
model.web_socket_reconnector = None;
|
||||||
info!("WebSocket connection is open now");
|
debug!("WebSocket connection is open now");
|
||||||
}
|
}
|
||||||
Msg::TextMessageReceived(msg) => {
|
Msg::TextMessageReceived(msg) => {
|
||||||
model.updates.push_back(msg);
|
model.updates.push_back(msg);
|
||||||
}
|
}
|
||||||
Msg::WebSocketClosed(close_event) => {
|
Msg::WebSocketClosed(close_event) => {
|
||||||
info!(
|
debug!(
|
||||||
r#"==================
|
r#"==================
|
||||||
WebSocket connection was closed:
|
WebSocket connection was closed:
|
||||||
Clean: {0}
|
Clean: {0}
|
||||||
@@ -148,7 +148,7 @@ Reason: {2}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::WebSocketFailed => {
|
Msg::WebSocketFailed => {
|
||||||
info!("WebSocket failed");
|
debug!("WebSocket failed");
|
||||||
if model.web_socket_reconnector.is_none() {
|
if model.web_socket_reconnector.is_none() {
|
||||||
model.web_socket_reconnector = Some(
|
model.web_socket_reconnector = Some(
|
||||||
orders.stream_with_handle(streams::backoff(None, Msg::ReconnectWebSocket)),
|
orders.stream_with_handle(streams::backoff(None, Msg::ReconnectWebSocket)),
|
||||||
@@ -156,7 +156,7 @@ Reason: {2}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::ReconnectWebSocket(retries) => {
|
Msg::ReconnectWebSocket(retries) => {
|
||||||
info!("Reconnect attempt: {}", retries);
|
debug!("Reconnect attempt: {}", retries);
|
||||||
model.web_socket = create_websocket(&model.ws_url, orders).unwrap();
|
model.web_socket = create_websocket(&model.ws_url, orders).unwrap();
|
||||||
}
|
}
|
||||||
Msg::SendMessage(msg) => {
|
Msg::SendMessage(msg) => {
|
||||||
@@ -177,16 +177,16 @@ fn create_websocket(url: &str, orders: &impl Orders<Msg>) -> Result<EventClient,
|
|||||||
|
|
||||||
let send = msg_sender.clone();
|
let send = msg_sender.clone();
|
||||||
client.set_on_connection(Some(Box::new(move |client: &EventClient| {
|
client.set_on_connection(Some(Box::new(move |client: &EventClient| {
|
||||||
info!("{:#?}", client.status);
|
debug!("{:#?}", client.status);
|
||||||
let msg = match *client.status.borrow() {
|
let msg = match *client.status.borrow() {
|
||||||
ConnectionStatus::Connecting => {
|
ConnectionStatus::Connecting => {
|
||||||
info!("Connecting...");
|
debug!("Connecting...");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
ConnectionStatus::Connected => Some(Msg::WebSocketOpened),
|
ConnectionStatus::Connected => Some(Msg::WebSocketOpened),
|
||||||
ConnectionStatus::Error => Some(Msg::WebSocketFailed),
|
ConnectionStatus::Error => Some(Msg::WebSocketFailed),
|
||||||
ConnectionStatus::Disconnected => {
|
ConnectionStatus::Disconnected => {
|
||||||
info!("Disconnected");
|
debug!("Disconnected");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -195,7 +195,7 @@ fn create_websocket(url: &str, orders: &impl Orders<Msg>) -> Result<EventClient,
|
|||||||
|
|
||||||
let send = msg_sender.clone();
|
let send = msg_sender.clone();
|
||||||
client.set_on_close(Some(Box::new(move |ev| {
|
client.set_on_close(Some(Box::new(move |ev| {
|
||||||
info!("WS: Connection closed");
|
debug!("WS: Connection closed");
|
||||||
send(Some(Msg::WebSocketClosed(ev)));
|
send(Some(Msg::WebSocketClosed(ev)));
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ html {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.news-post.site-seiya-me figure>pre,
|
||||||
|
.news-post.site-seiya-me figure>pre>code {
|
||||||
|
background-color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
.news-post.site-slashdot .story-byline {
|
.news-post.site-slashdot .story-byline {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
height: initial !important;
|
height: initial !important;
|
||||||
|
|||||||
Reference in New Issue
Block a user