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?
|
// 'notmuch new' on the server periodically?
|
||||||
orders.stream(streams::interval(30_000, || Msg::RefreshStart));
|
orders.stream(streams::interval(30_000, || Msg::RefreshStart));
|
||||||
orders.subscribe(on_url_changed);
|
orders.subscribe(on_url_changed);
|
||||||
|
orders.stream(streams::window_event(Ev::Scroll, |_| {
|
||||||
|
compute_scroll_ratio()
|
||||||
|
}));
|
||||||
|
|
||||||
Model {
|
Model {
|
||||||
context: Context::None,
|
context: Context::None,
|
||||||
query: "".to_string(),
|
query: "".to_string(),
|
||||||
refreshing_state: RefreshingState::None,
|
refreshing_state: RefreshingState::None,
|
||||||
tags: 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 {
|
fn on_url_changed(uc: subs::UrlChanged) -> Msg {
|
||||||
let mut url = uc.0;
|
let mut url = uc.0;
|
||||||
info!(
|
info!(
|
||||||
@ -489,6 +510,9 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
.expect("failed to copy to clipboard");
|
.expect("failed to copy to clipboard");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Msg::SetProgress(ratio) => {
|
||||||
|
model.read_completion_ratio = ratio;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `Model` describes our app state.
|
// `Model` describes our app state.
|
||||||
@ -497,6 +521,7 @@ pub struct Model {
|
|||||||
pub context: Context,
|
pub context: Context,
|
||||||
pub refreshing_state: RefreshingState,
|
pub refreshing_state: RefreshingState,
|
||||||
pub tags: Option<Vec<Tag>>,
|
pub tags: Option<Vec<Tag>>,
|
||||||
|
pub read_completion_ratio: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@ -590,4 +615,6 @@ pub enum Msg {
|
|||||||
MultiMsg(Vec<Msg>),
|
MultiMsg(Vec<Msg>),
|
||||||
|
|
||||||
CopyToClipboard(String),
|
CopyToClipboard(String),
|
||||||
|
|
||||||
|
SetProgress(f64),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::{
|
|||||||
api::urls,
|
api::urls,
|
||||||
graphql::show_thread_query::*,
|
graphql::show_thread_query::*,
|
||||||
state::{Context, Model, Msg},
|
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]
|
#[topo::nested]
|
||||||
@ -40,6 +40,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
};
|
};
|
||||||
div![
|
div![
|
||||||
C!["main-content"],
|
C!["main-content"],
|
||||||
|
reading_progress(model.read_completion_ratio),
|
||||||
view_tags(model),
|
view_tags(model),
|
||||||
div![
|
div![
|
||||||
view_header(&model.query, &model.refreshing_state),
|
view_header(&model.query, &model.refreshing_state),
|
||||||
|
|||||||
@ -7,8 +7,8 @@ use crate::{
|
|||||||
graphql::{front_page_query::*, show_thread_query::*},
|
graphql::{front_page_query::*, show_thread_query::*},
|
||||||
state::{Context, Model, Msg},
|
state::{Context, Model, Msg},
|
||||||
view::{
|
view::{
|
||||||
self, human_age, pretty_authors, search_toolbar, set_title, tags_chiclet, view_header,
|
self, human_age, pretty_authors, reading_progress, search_toolbar, set_title, tags_chiclet,
|
||||||
view_tags,
|
view_header, view_tags,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
div![
|
div![
|
||||||
|
reading_progress(model.read_completion_ratio),
|
||||||
view_header(&model.query, &model.refreshing_state),
|
view_header(&model.query, &model.refreshing_state),
|
||||||
content,
|
content,
|
||||||
view_header(&model.query, &model.refreshing_state),
|
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)],
|
C!["body", "news-post", format!("site-{}", post.slug)],
|
||||||
raw![&post.body]
|
raw![&post.body]
|
||||||
]
|
]
|
||||||
] /* TODO(wathiede): plumb in orignal id
|
],
|
||||||
|
/* TODO(wathiede): plumb in orignal id
|
||||||
a![
|
a![
|
||||||
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
|
attrs! {At::Href=>api::original(&thread_node.0.as_ref().expect("message missing").id)},
|
||||||
"Original"
|
"Original"
|
||||||
],
|
],
|
||||||
*/
|
*/
|
||||||
|
ev(Ev::Scroll, |e| info!("scroll event {e:?}"))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg> {
|
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::{
|
use crate::{
|
||||||
graphql::show_thread_query::*,
|
graphql::show_thread_query::*,
|
||||||
state::{Context, Model, Msg},
|
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> {
|
pub(super) fn view(model: &Model) -> Node<Msg> {
|
||||||
@ -39,6 +39,7 @@ pub(super) fn view(model: &Model) -> Node<Msg> {
|
|||||||
div![
|
div![
|
||||||
C!["main-content"],
|
C!["main-content"],
|
||||||
div![
|
div![
|
||||||
|
reading_progress(model.read_completion_ratio),
|
||||||
view_header(&model.query, &model.refreshing_state),
|
view_header(&model.query, &model.refreshing_state),
|
||||||
content,
|
content,
|
||||||
view_header(&model.query, &model.refreshing_state),
|
view_header(&model.query, &model.refreshing_state),
|
||||||
|
|||||||
@ -343,3 +343,9 @@ display: none;
|
|||||||
.button.spam {
|
.button.spam {
|
||||||
color: #f00;
|
color: #f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress.read-progress {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user