web: add scrollbar for read progress
This commit is contained in:
parent
5c813e7350
commit
4faef5e017
@ -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),
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
],
|
||||
/* 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}%")
|
||||
]
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -343,3 +343,9 @@ display: none;
|
||||
.button.spam {
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
progress.read-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user