web: add scrollbar for read progress

This commit is contained in:
Bill Thiede 2024-08-31 16:08:06 -07:00
parent 5c813e7350
commit 4faef5e017
6 changed files with 65 additions and 10 deletions

View File

@ -37,15 +37,36 @@ pub fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
// 'notmuch new' on the server periodically?
orders.stream(streams::interval(30_000, || Msg::RefreshStart));
orders.subscribe(on_url_changed);
orders.stream(streams::window_event(Ev::Scroll, |_| {
compute_scroll_ratio()
}));
Model {
context: Context::None,
query: "".to_string(),
refreshing_state: RefreshingState::None,
tags: None,
read_completion_ratio: 0.,
}
}
fn compute_scroll_ratio() -> Msg {
// TODO: compute completion based on contents of the post, not the overall body (which includes
// the tags at the end on mobile/tablet).
let body = document().body().expect("body");
let sh = body.scroll_height() as f64;
let window = window();
let ih = window
.inner_height()
.expect("window height")
.unchecked_into::<js_sys::Number>()
.value_of();
let scroll_y = window.scroll_y().expect("scroll Y");
let end = sh - ih;
let ratio = scroll_y / end;
Msg::SetProgress(ratio)
}
fn on_url_changed(uc: subs::UrlChanged) -> Msg {
let mut url = uc.0;
info!(
@ -489,6 +510,9 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.expect("failed to copy to clipboard");
});
}
Msg::SetProgress(ratio) => {
model.read_completion_ratio = ratio;
}
}
}
// `Model` describes our app state.
@ -497,6 +521,7 @@ pub struct Model {
pub context: Context,
pub refreshing_state: RefreshingState,
pub tags: Option<Vec<Tag>>,
pub read_completion_ratio: f64,
}
#[derive(Error, Debug)]
@ -590,4 +615,6 @@ pub enum Msg {
MultiMsg(Vec<Msg>),
CopyToClipboard(String),
SetProgress(f64),
}

View File

@ -5,7 +5,7 @@ use crate::{
api::urls,
graphql::show_thread_query::*,
state::{Context, Model, Msg},
view::{self, view_header, view_search_results, view_tags},
view::{self, reading_progress, view_header, view_search_results, view_tags},
};
#[topo::nested]
@ -40,6 +40,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
};
div![
C!["main-content"],
reading_progress(model.read_completion_ratio),
view_tags(model),
div![
view_header(&model.query, &model.refreshing_state),

View File

@ -7,8 +7,8 @@ use crate::{
graphql::{front_page_query::*, show_thread_query::*},
state::{Context, Model, Msg},
view::{
self, human_age, pretty_authors, search_toolbar, set_title, tags_chiclet, view_header,
view_tags,
self, human_age, pretty_authors, reading_progress, search_toolbar, set_title, tags_chiclet,
view_header, view_tags,
},
};
@ -41,6 +41,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
),
};
div![
reading_progress(model.read_completion_ratio),
view_header(&model.query, &model.refreshing_state),
content,
view_header(&model.query, &model.refreshing_state),

View File

@ -1117,12 +1117,14 @@ fn news_post(post: &ShowThreadQueryThreadOnNewsPost, show_icon_text: bool) -> No
C!["body", "news-post", format!("site-{}", post.slug)],
raw![&post.body]
]
] /* TODO(wathiede): plumb in orignal id
a![
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
"Original"
],
*/
],
/* TODO(wathiede): plumb in orignal id
a![
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
"Original"
],
*/
ev(Ev::Scroll, |e| info!("scroll event {e:?}"))
]
}
fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg> {
@ -1181,3 +1183,20 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg>
]
]
}
fn reading_progress(ratio: f64) -> Node<Msg> {
let percent = ratio * 100.;
progress![
C![
"read-progress",
"progress",
"is-success",
"is-small",
IF!(percent<5. => "is-invisible")
],
attrs! {
At::Value=>percent,
At::Max=>"100"
},
format!("{percent}%")
]
}

View File

@ -4,7 +4,7 @@ use seed::{prelude::*, *};
use crate::{
graphql::show_thread_query::*,
state::{Context, Model, Msg},
view::{self, view_header, view_search_results, view_tags},
view::{self, reading_progress, view_header, view_search_results, view_tags},
};
pub(super) fn view(model: &Model) -> Node<Msg> {
@ -39,6 +39,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
div![
C!["main-content"],
div![
reading_progress(model.read_completion_ratio),
view_header(&model.query, &model.refreshing_state),
content,
view_header(&model.query, &model.refreshing_state),

View File

@ -343,3 +343,9 @@ display: none;
.button.spam {
color: #f00;
}
progress.read-progress {
position: fixed;
top: 0;
z-index: 999;
}