web: only use one view function, desktop/tablet/mobile handled in CSS
This commit is contained in:
parent
ea280dd366
commit
25d31a6ce7
@ -507,6 +507,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
});
|
||||
}
|
||||
Msg::WindowScrolled => {
|
||||
info!("WindowScrolled");
|
||||
if let Some(el) = model.content_el.get() {
|
||||
let ih = window()
|
||||
.inner_height()
|
||||
@ -515,6 +516,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
.value_of();
|
||||
|
||||
let r = el.get_bounding_client_rect();
|
||||
info!("r {r:?} ih {ih}");
|
||||
if r.height() < ih {
|
||||
// The whole content fits in the window, no scrollbar
|
||||
orders.send_msg(Msg::SetProgress(0.));
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
use seed::{prelude::*, *};
|
||||
use seed_hooks::topo;
|
||||
|
||||
use crate::{
|
||||
graphql::show_thread_query::*,
|
||||
state::{Context, Model, Msg},
|
||||
view::{self, reading_progress, view_header, view_search_results},
|
||||
};
|
||||
|
||||
#[topo::nested]
|
||||
pub(super) fn view(model: &Model) -> Node<Msg> {
|
||||
let show_icon_text = true;
|
||||
// Do two queries, one without `unread` so it loads fast, then a second with unread.
|
||||
let content = match &model.context {
|
||||
Context::None => div![h1!["Loading"]],
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||
open_messages,
|
||||
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::NewsPost(post),
|
||||
..
|
||||
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||
Context::SearchResult {
|
||||
query,
|
||||
results,
|
||||
count,
|
||||
pager,
|
||||
selected_threads,
|
||||
} => view_search_results(
|
||||
&query,
|
||||
results.as_slice(),
|
||||
*count,
|
||||
pager,
|
||||
selected_threads,
|
||||
show_icon_text,
|
||||
),
|
||||
};
|
||||
div![
|
||||
C!["flex"],
|
||||
reading_progress(model.read_completion_ratio),
|
||||
div![view::tags(model), view::versions(&model.versions)],
|
||||
div![
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
content,
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use crate::{
|
||||
api::urls,
|
||||
graphql::{front_page_query::*, show_thread_query::*},
|
||||
state::{Context, Model, Msg},
|
||||
view::{
|
||||
self, human_age, pretty_authors, reading_progress, search_toolbar, set_title, tags_chiclet,
|
||||
view_header,
|
||||
},
|
||||
};
|
||||
|
||||
pub(super) fn view(model: &Model) -> Node<Msg> {
|
||||
let show_icon_text = false;
|
||||
let content = match &model.context {
|
||||
Context::None => div![h1!["Loading"]],
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||
open_messages,
|
||||
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::NewsPost(post),
|
||||
..
|
||||
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||
Context::SearchResult {
|
||||
query,
|
||||
results,
|
||||
count,
|
||||
pager,
|
||||
selected_threads,
|
||||
} => search_results(
|
||||
&query,
|
||||
results.as_slice(),
|
||||
*count,
|
||||
pager,
|
||||
selected_threads,
|
||||
show_icon_text,
|
||||
),
|
||||
};
|
||||
div![
|
||||
reading_progress(model.read_completion_ratio),
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
content,
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
div![view::tags(model), view::versions(&model.versions)]
|
||||
]
|
||||
}
|
||||
|
||||
fn search_results(
|
||||
query: &str,
|
||||
results: &[FrontPageQuerySearchNodes],
|
||||
count: usize,
|
||||
pager: &FrontPageQuerySearchPageInfo,
|
||||
selected_threads: &HashSet<String>,
|
||||
show_icon_text: bool,
|
||||
) -> Node<Msg> {
|
||||
if query.is_empty() {
|
||||
set_title("all mail");
|
||||
} else {
|
||||
set_title(query);
|
||||
}
|
||||
let rows = results.iter().map(|r| {
|
||||
let tid = r.thread.clone();
|
||||
let check_tid = r.thread.clone();
|
||||
let datetime = human_age(r.timestamp as i64);
|
||||
let unread_idx = r.tags.iter().position(|e| e == &"unread");
|
||||
let mut tags = r.tags.clone();
|
||||
if let Some(idx) = unread_idx {
|
||||
tags.remove(idx);
|
||||
};
|
||||
div![
|
||||
C!["NOTPORTED", "row"],
|
||||
label![
|
||||
C!["NOTPORTED", "b-checkbox", "checkbox", "is-large"],
|
||||
input![attrs! {
|
||||
At::Type=>"checkbox",
|
||||
At::Checked=>selected_threads.contains(&tid).as_at_value(),
|
||||
}],
|
||||
span![C!["NOTPORTED", "check"]],
|
||||
ev(Ev::Input, move |e| {
|
||||
if let Some(input) = e
|
||||
.target()
|
||||
.as_ref()
|
||||
.expect("failed to get reference to target")
|
||||
.dyn_ref::<web_sys::HtmlInputElement>()
|
||||
{
|
||||
if input.checked() {
|
||||
Msg::SelectionAddThread(check_tid)
|
||||
} else {
|
||||
Msg::SelectionRemoveThread(check_tid)
|
||||
}
|
||||
} else {
|
||||
Msg::Noop
|
||||
}
|
||||
}),
|
||||
],
|
||||
a![
|
||||
C!["NOTPORTED", "has-text-light", "summary"],
|
||||
IF!(unread_idx.is_some() => C!["NOTPORTED","unread"]),
|
||||
attrs! {
|
||||
At::Href => urls::thread(&tid)
|
||||
},
|
||||
div![C!["NOTPORTED", "subject"], &r.subject],
|
||||
span![
|
||||
C!["NOTPORTED", "from", "is-size-7"],
|
||||
pretty_authors(&r.authors)
|
||||
],
|
||||
div![
|
||||
span![C!["NOTPORTED", "is-size-7"], tags_chiclet(&tags, true)],
|
||||
span![
|
||||
C!["NOTPORTED", "is-size-7", "float-right", "date"],
|
||||
datetime
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
});
|
||||
let show_bulk_edit = !selected_threads.is_empty();
|
||||
div![
|
||||
C!["NOTPORTED", "search-results"],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text),
|
||||
div![C!["NOTPORTED", "index"], rows],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text),
|
||||
]
|
||||
}
|
||||
@ -12,17 +12,140 @@ use web_sys::HtmlElement;
|
||||
use crate::{
|
||||
api::urls,
|
||||
graphql::{front_page_query::*, show_thread_query::*},
|
||||
state::{unread_query, Model, Msg, RefreshingState, Tag},
|
||||
state::{unread_query, Context, Model, Msg, RefreshingState, Tag},
|
||||
};
|
||||
|
||||
mod desktop;
|
||||
mod mobile;
|
||||
mod tablet;
|
||||
|
||||
// TODO(wathiede): create a QueryString enum that wraps single and multiple message ids and thread
|
||||
// ids, and has a to_query_string() that knows notmuch's syntax. Then remove the smattering of
|
||||
// format!() calls all over with magic strings representing notmuch specific syntax.
|
||||
const MAX_RAW_MESSAGE_SIZE: usize = 100_000;
|
||||
|
||||
pub fn view(model: &Model) -> Node<Msg> {
|
||||
let show_icon_text = true;
|
||||
let content = match &model.context {
|
||||
Context::None => div![h1!["Loading"]],
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::EmailThread(thread_data),
|
||||
open_messages,
|
||||
} => thread(
|
||||
thread_data,
|
||||
open_messages,
|
||||
show_icon_text,
|
||||
&model.content_el,
|
||||
),
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::NewsPost(post),
|
||||
..
|
||||
} => news_post(post, show_icon_text, &model.content_el),
|
||||
Context::SearchResult {
|
||||
query,
|
||||
results,
|
||||
count,
|
||||
pager,
|
||||
selected_threads,
|
||||
} => search_results(
|
||||
&query,
|
||||
results.as_slice(),
|
||||
*count,
|
||||
pager,
|
||||
selected_threads,
|
||||
show_icon_text,
|
||||
),
|
||||
};
|
||||
div![
|
||||
C!["flex", "flex-wrap-reverse"],
|
||||
div![
|
||||
C!["w-48", "flex-none", "flex", "flex-col"],
|
||||
tags(model),
|
||||
versions(&model.versions)
|
||||
],
|
||||
reading_progress(model.read_completion_ratio),
|
||||
div![
|
||||
C!["flex-auto"],
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
content,
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
fn search_results(
|
||||
query: &str,
|
||||
results: &[FrontPageQuerySearchNodes],
|
||||
count: usize,
|
||||
pager: &FrontPageQuerySearchPageInfo,
|
||||
selected_threads: &HashSet<String>,
|
||||
show_icon_text: bool,
|
||||
) -> Node<Msg> {
|
||||
if query.is_empty() {
|
||||
set_title("all mail");
|
||||
} else {
|
||||
set_title(query);
|
||||
}
|
||||
let rows = results.iter().map(|r| {
|
||||
let tid = r.thread.clone();
|
||||
let check_tid = r.thread.clone();
|
||||
let datetime = human_age(r.timestamp as i64);
|
||||
let unread_idx = r.tags.iter().position(|e| e == &"unread");
|
||||
let mut tags = r.tags.clone();
|
||||
if let Some(idx) = unread_idx {
|
||||
tags.remove(idx);
|
||||
};
|
||||
div![
|
||||
C!["NOTPORTED", "row"],
|
||||
label![
|
||||
C!["NOTPORTED", "b-checkbox", "checkbox", "is-large"],
|
||||
input![attrs! {
|
||||
At::Type=>"checkbox",
|
||||
At::Checked=>selected_threads.contains(&tid).as_at_value(),
|
||||
}],
|
||||
span![C!["NOTPORTED", "check"]],
|
||||
ev(Ev::Input, move |e| {
|
||||
if let Some(input) = e
|
||||
.target()
|
||||
.as_ref()
|
||||
.expect("failed to get reference to target")
|
||||
.dyn_ref::<web_sys::HtmlInputElement>()
|
||||
{
|
||||
if input.checked() {
|
||||
Msg::SelectionAddThread(check_tid)
|
||||
} else {
|
||||
Msg::SelectionRemoveThread(check_tid)
|
||||
}
|
||||
} else {
|
||||
Msg::Noop
|
||||
}
|
||||
}),
|
||||
],
|
||||
a![
|
||||
C!["NOTPORTED", "has-text-light", "summary"],
|
||||
IF!(unread_idx.is_some() => C!["NOTPORTED","unread"]),
|
||||
attrs! {
|
||||
At::Href => urls::thread(&tid)
|
||||
},
|
||||
div![C!["NOTPORTED", "subject"], &r.subject],
|
||||
span![
|
||||
C!["NOTPORTED", "from", "is-size-7"],
|
||||
pretty_authors(&r.authors)
|
||||
],
|
||||
div![
|
||||
span![C!["NOTPORTED", "is-size-7"], tags_chiclet(&tags, true)],
|
||||
span![
|
||||
C!["NOTPORTED", "is-size-7", "float-right", "date"],
|
||||
datetime
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
});
|
||||
let show_bulk_edit = !selected_threads.is_empty();
|
||||
div![
|
||||
C!["NOTPORTED", "search-results"],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text),
|
||||
div![C!["NOTPORTED", "index"], rows],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text),
|
||||
]
|
||||
}
|
||||
fn set_title(title: &str) {
|
||||
seed::document().set_title(&format!("lb: {}", title));
|
||||
}
|
||||
@ -916,25 +1039,6 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node<Msg> {
|
||||
]
|
||||
}
|
||||
|
||||
// `view` describes what to display.
|
||||
pub fn view(model: &Model) -> Node<Msg> {
|
||||
let win = seed::window();
|
||||
let w = win
|
||||
.inner_width()
|
||||
.expect("window width")
|
||||
.as_f64()
|
||||
.expect("window width f64");
|
||||
let _h = win
|
||||
.inner_height()
|
||||
.expect("window height")
|
||||
.as_f64()
|
||||
.expect("window height f64");
|
||||
div![match w {
|
||||
w if w < 800. => div![C!["NOTPORTED", "mobile"], mobile::view(model)],
|
||||
w if w < 1024. => div![C!["NOTPORTED", "tablet"], tablet::view(model)],
|
||||
_ => div![C!["NOTPORTED", "desktop"], desktop::view(model)],
|
||||
},]
|
||||
}
|
||||
pub fn tags(model: &Model) -> Node<Msg> {
|
||||
fn view_tag_li(display_name: &str, indent: usize, t: &Tag, search_unread: bool) -> Node<Msg> {
|
||||
let href = if search_unread {
|
||||
@ -977,7 +1081,7 @@ pub fn tags(model: &Model) -> Node<Msg> {
|
||||
for t in tags {
|
||||
let parts: Vec<_> = t.name.split('/').collect();
|
||||
let mut n = matches(&last, &parts);
|
||||
if n <= parts.len() - 2 && parts.len() > 1 {
|
||||
if n + 2 <= parts.len() && parts.len() > 1 {
|
||||
// Synthesize fake tags for proper indenting.
|
||||
for i in n..parts.len() - 1 {
|
||||
let display_name = parts[n];
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use crate::{
|
||||
graphql::show_thread_query::*,
|
||||
state::{Context, Model, Msg},
|
||||
view::{self, reading_progress, view_header, view_search_results},
|
||||
};
|
||||
|
||||
pub(super) fn view(model: &Model) -> Node<Msg> {
|
||||
let show_icon_text = false;
|
||||
// Do two queries, one without `unread` so it loads fast, then a second with unread.
|
||||
let content = match &model.context {
|
||||
Context::None => div![h1!["Loading"]],
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::EmailThread(thread),
|
||||
open_messages,
|
||||
} => view::thread(thread, open_messages, show_icon_text, &model.content_el),
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::NewsPost(post),
|
||||
..
|
||||
} => view::news_post(post, show_icon_text, &model.content_el),
|
||||
Context::SearchResult {
|
||||
query,
|
||||
results,
|
||||
count,
|
||||
pager,
|
||||
selected_threads,
|
||||
} => view_search_results(
|
||||
&query,
|
||||
results.as_slice(),
|
||||
*count,
|
||||
pager,
|
||||
selected_threads,
|
||||
show_icon_text,
|
||||
),
|
||||
};
|
||||
div![
|
||||
C!["NOTPORTED", "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::tags(model),
|
||||
view::versions(&model.versions)
|
||||
]
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user