web: style search toolbar
This commit is contained in:
parent
b2879211e4
commit
89897aa48f
@ -20,37 +20,41 @@ use crate::{
|
||||
// format!() calls all over with magic strings representing notmuch specific syntax.
|
||||
const MAX_RAW_MESSAGE_SIZE: usize = 100_000;
|
||||
|
||||
const BUTTON_CLASSES: &[&str] = &[
|
||||
"bg-slate-900",
|
||||
"rounded-md",
|
||||
"p-2",
|
||||
"border",
|
||||
"border-slate-700",
|
||||
"text-center",
|
||||
"text-sm",
|
||||
"transition-all",
|
||||
"shadow-md",
|
||||
"hover:shadow-lg",
|
||||
"hover:bg-slate-700",
|
||||
"disabled:pointer-events-none",
|
||||
"disabled:opacity-50",
|
||||
"disabled:shadow-none",
|
||||
];
|
||||
|
||||
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,
|
||||
),
|
||||
} => thread(thread_data, open_messages, &model.content_el),
|
||||
Context::ThreadResult {
|
||||
thread: ShowThreadQueryThread::NewsPost(post),
|
||||
..
|
||||
} => news_post(post, show_icon_text, &model.content_el),
|
||||
} => news_post(post, &model.content_el),
|
||||
Context::SearchResult {
|
||||
query,
|
||||
results,
|
||||
count,
|
||||
pager,
|
||||
selected_threads,
|
||||
} => search_results(
|
||||
&query,
|
||||
results.as_slice(),
|
||||
*count,
|
||||
pager,
|
||||
selected_threads,
|
||||
show_icon_text,
|
||||
),
|
||||
} => search_results(&query, results.as_slice(), *count, pager, selected_threads),
|
||||
};
|
||||
div![
|
||||
C!["flex", "flex-wrap-reverse", "bg-black", "text-white"],
|
||||
@ -61,10 +65,10 @@ pub fn view(model: &Model) -> Node<Msg> {
|
||||
],
|
||||
reading_progress(model.read_completion_ratio),
|
||||
div![
|
||||
C!["flex-auto"],
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
C!["flex-auto", "p-4"],
|
||||
view_header(&model.query, &model.refreshing_state, true),
|
||||
content,
|
||||
view_header(&model.query, &model.refreshing_state),
|
||||
view_header(&model.query, &model.refreshing_state, false),
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -75,7 +79,6 @@ fn search_results(
|
||||
count: usize,
|
||||
pager: &FrontPageQuerySearchPageInfo,
|
||||
selected_threads: &HashSet<String>,
|
||||
show_icon_text: bool,
|
||||
) -> Node<Msg> {
|
||||
if query.is_empty() {
|
||||
set_title("all mail");
|
||||
@ -140,12 +143,13 @@ fn search_results(
|
||||
});
|
||||
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),
|
||||
C!["flex", "flex-col"],
|
||||
search_toolbar(count, pager, show_bulk_edit),
|
||||
div![rows],
|
||||
search_toolbar(count, pager, show_bulk_edit),
|
||||
]
|
||||
}
|
||||
|
||||
fn set_title(title: &str) {
|
||||
seed::document().set_title(&format!("lb: {}", title));
|
||||
}
|
||||
@ -275,7 +279,6 @@ fn view_search_results(
|
||||
count: usize,
|
||||
pager: &FrontPageQuerySearchPageInfo,
|
||||
selected_threads: &HashSet<String>,
|
||||
show_icon_text: bool,
|
||||
) -> Node<Msg> {
|
||||
if query.is_empty() {
|
||||
set_title("all mail");
|
||||
@ -363,7 +366,7 @@ fn view_search_results(
|
||||
|
||||
div![
|
||||
C!["NOTPORTED", "search-results"],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text),
|
||||
search_toolbar(count, pager, show_bulk_edit),
|
||||
table![
|
||||
C![
|
||||
"table",
|
||||
@ -399,7 +402,7 @@ fn view_search_results(
|
||||
]],
|
||||
tbody![rows]
|
||||
],
|
||||
search_toolbar(count, pager, show_bulk_edit, show_icon_text)
|
||||
search_toolbar(count, pager, show_bulk_edit)
|
||||
]
|
||||
}
|
||||
|
||||
@ -407,41 +410,39 @@ fn search_toolbar(
|
||||
count: usize,
|
||||
pager: &FrontPageQuerySearchPageInfo,
|
||||
show_bulk_edit: bool,
|
||||
show_icon_text: bool,
|
||||
) -> Node<Msg> {
|
||||
info!("pager {pager:#?}");
|
||||
nav![
|
||||
C!["NOTPORTED", "level", "is-mobile"],
|
||||
C!["p-4", "flex", "w-full", "justify-between"],
|
||||
div![
|
||||
C!["NOTPORTED", "level-left"],
|
||||
C!["gap-2", "flex"],
|
||||
IF!(show_bulk_edit =>
|
||||
div![
|
||||
C!["NOTPORTED","level-item"],
|
||||
div![C!["NOTPORTED","buttons", "has-addons"],
|
||||
div![
|
||||
button![
|
||||
C!["NOTPORTED","button", "mark-read"],
|
||||
C![&BUTTON_CLASSES, "rounded-r-none"],
|
||||
attrs!{At::Title => "Mark as read"},
|
||||
span![C!["NOTPORTED","icon", "is-small"], i![C!["NOTPORTED","far", "fa-envelope-open"]]],
|
||||
IF!(show_icon_text=>span!["Read"]),
|
||||
span![i![C!["far", "fa-envelope-open"]]],
|
||||
span![C!["pl-2", "hidden", "md:inline"], "Read"],
|
||||
ev(Ev::Click, |_| Msg::SelectionMarkAsRead)
|
||||
],
|
||||
button![
|
||||
C!["NOTPORTED","button", "mark-unread"],
|
||||
C![&BUTTON_CLASSES, "rounded-l-none"],
|
||||
attrs!{At::Title => "Mark as unread"},
|
||||
span![C!["NOTPORTED","icon", "is-small"], i![C!["NOTPORTED","far", "fa-envelope"]]],
|
||||
IF!(show_icon_text=>span!["Unread"]),
|
||||
span![i![C!["far", "fa-envelope"]]],
|
||||
span![C!["pl-2", "hidden", "md:inline"], "Unread"],
|
||||
ev(Ev::Click, |_| Msg::SelectionMarkAsUnread)
|
||||
]
|
||||
]
|
||||
]),
|
||||
IF!(show_bulk_edit =>
|
||||
div![
|
||||
C!["NOTPORTED","level-item"],
|
||||
div![C!["NOTPORTED","buttons", "has-addons"],
|
||||
div![
|
||||
button![
|
||||
C!["NOTPORTED","button", "spam"],
|
||||
C![&BUTTON_CLASSES, "text-red-500"],
|
||||
attrs!{At::Title => "Mark as spam"},
|
||||
span![C!["NOTPORTED","icon", "is-small"], i![C!["NOTPORTED","far", "fa-hand"]]],
|
||||
IF!(show_icon_text=>span!["Spam"]),
|
||||
span![i![C!["far", "fa-hand"]]],
|
||||
span![C!["pl-2", "hidden", "md:inline"], "Spam"],
|
||||
ev(Ev::Click, |_|
|
||||
Msg::MultiMsg(vec![
|
||||
Msg::SelectionAddTag("Spam".to_string()),
|
||||
@ -450,36 +451,22 @@ fn search_toolbar(
|
||||
)
|
||||
],
|
||||
],
|
||||
])
|
||||
]),
|
||||
],
|
||||
div![
|
||||
C!["NOTPORTED", "level-right"],
|
||||
nav![
|
||||
C!["NOTPORTED", "level-item", "pagination"],
|
||||
a![
|
||||
C![
|
||||
"pagination-previous",
|
||||
"button",
|
||||
//IF!(!pager.has_previous_page => "is-static"),
|
||||
],
|
||||
IF!(!pager.has_previous_page => attrs!{ At::Disabled=>true }),
|
||||
"<",
|
||||
IF!(pager.has_previous_page => ev(Ev::Click, |_| Msg::PreviousPage)),
|
||||
],
|
||||
a![
|
||||
C![
|
||||
"pagination-next",
|
||||
"button",
|
||||
//IF!(!pager.has_next_page => "is-static")
|
||||
],
|
||||
IF!(!pager.has_next_page => attrs!{ At::Disabled=>true }),
|
||||
">",
|
||||
IF!(pager.has_next_page => ev(Ev::Click, |_| Msg::NextPage))
|
||||
],
|
||||
ul![
|
||||
C!["NOTPORTED", "pagination-list"],
|
||||
li![format!("{count} results")],
|
||||
],
|
||||
C!["flex", "gap-2", "items-center"],
|
||||
p![format!("{count} results")],
|
||||
button![
|
||||
C![&BUTTON_CLASSES],
|
||||
IF!(!pager.has_previous_page => attrs!{ At::Disabled=>true }),
|
||||
"<",
|
||||
IF!(pager.has_previous_page => ev(Ev::Click, |_| Msg::PreviousPage)),
|
||||
],
|
||||
button![
|
||||
C![&BUTTON_CLASSES],
|
||||
IF!(!pager.has_next_page => attrs!{ At::Disabled=>true }),
|
||||
">",
|
||||
IF!(pager.has_next_page => ev(Ev::Click, |_| Msg::NextPage))
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -854,9 +841,10 @@ fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool)
|
||||
fn thread(
|
||||
thread: &ShowThreadQueryThreadOnEmailThread,
|
||||
open_messages: &HashSet<String>,
|
||||
show_icon_text: bool,
|
||||
content_el: &ElRef<HtmlElement>,
|
||||
) -> Node<Msg> {
|
||||
// TODO remove and replace with CSS styling
|
||||
let show_icon_text = true;
|
||||
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
||||
let subject = if thread.subject.is_empty() {
|
||||
"(no subject)"
|
||||
@ -977,7 +965,11 @@ fn view_content_tree(content_tree: &str) -> Node<Msg> {
|
||||
]
|
||||
}
|
||||
|
||||
fn view_header(query: &str, refresh_request: &RefreshingState) -> Node<Msg> {
|
||||
fn view_header(
|
||||
query: &str,
|
||||
refresh_request: &RefreshingState,
|
||||
auto_focus_search: bool,
|
||||
) -> Node<Msg> {
|
||||
let is_loading = refresh_request == &RefreshingState::Loading;
|
||||
let is_error = if let RefreshingState::Error(err) = refresh_request {
|
||||
error!("Failed to refresh: {err:?}");
|
||||
@ -987,54 +979,47 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node<Msg> {
|
||||
};
|
||||
let query = Url::decode_uri_component(query).unwrap_or("".to_string());
|
||||
nav![
|
||||
C!["NOTPORTED", "navbar"],
|
||||
attrs! {At::Role=>"navigation"},
|
||||
div![
|
||||
C!["NOTPORTED", "navbar-start"],
|
||||
a![
|
||||
C![
|
||||
"NOTPORTED",
|
||||
"navbar-item",
|
||||
"button",
|
||||
IF![is_error => "is-danger"]
|
||||
],
|
||||
span![i![C![
|
||||
"fa-solid",
|
||||
"fa-arrow-rotate-right",
|
||||
"refresh",
|
||||
IF![is_loading => "loading"],
|
||||
]]],
|
||||
ev(Ev::Click, |_| Msg::RefreshStart),
|
||||
],
|
||||
a![
|
||||
C!["NOTPORTED", "navbar-item", "button"],
|
||||
attrs! {
|
||||
At::Href => urls::search(unread_query(), 0)
|
||||
},
|
||||
"Unread",
|
||||
],
|
||||
a![
|
||||
C!["NOTPORTED", "navbar-item", "button"],
|
||||
attrs! {
|
||||
At::Href => urls::search("", 0)
|
||||
},
|
||||
"All",
|
||||
],
|
||||
input![
|
||||
C!["NOTPORTED", "navbar-item", "input"],
|
||||
attrs! {
|
||||
At::Placeholder => "Search";
|
||||
At::AutoFocus => true.as_at_value();
|
||||
At::Value => query,
|
||||
},
|
||||
input_ev(Ev::Input, |q| Msg::UpdateQuery(q)),
|
||||
// Send search on enter.
|
||||
keyboard_ev(Ev::KeyUp, move |e| if e.key_code() == 0x0d {
|
||||
Msg::SearchQuery(query)
|
||||
} else {
|
||||
Msg::Noop
|
||||
}),
|
||||
]
|
||||
C!["flex"],
|
||||
a![
|
||||
C![IF![is_error => "bg-red-500"], "rounded-r-none"],
|
||||
C![&BUTTON_CLASSES],
|
||||
span![i![C![
|
||||
"fa-solid",
|
||||
"fa-arrow-rotate-right",
|
||||
IF![is_loading => "animate-spin"],
|
||||
]]],
|
||||
ev(Ev::Click, |_| Msg::RefreshStart),
|
||||
],
|
||||
a![
|
||||
C![&BUTTON_CLASSES],
|
||||
C!["px-4", "rounded-none"],
|
||||
attrs! {
|
||||
At::Href => urls::search(unread_query(), 0)
|
||||
},
|
||||
"Unread",
|
||||
],
|
||||
a![
|
||||
C![&BUTTON_CLASSES],
|
||||
C!["px-4", "rounded-none"],
|
||||
attrs! {
|
||||
At::Href => urls::search("", 0)
|
||||
},
|
||||
"All",
|
||||
],
|
||||
input![
|
||||
C!["grow", "px-4", "text-black"],
|
||||
attrs! {
|
||||
At::Placeholder => "Search";
|
||||
At::AutoFocus => auto_focus_search.as_at_value();
|
||||
At::Value => query,
|
||||
},
|
||||
input_ev(Ev::Input, |q| Msg::UpdateQuery(q)),
|
||||
// Send search on enter.
|
||||
keyboard_ev(Ev::KeyUp, move |e| if e.key_code() == 0x0d {
|
||||
Msg::SearchQuery(query)
|
||||
} else {
|
||||
Msg::Noop
|
||||
}),
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -1153,11 +1138,9 @@ pub fn tags(model: &Model) -> Node<Msg> {
|
||||
]
|
||||
]
|
||||
}
|
||||
fn news_post(
|
||||
post: &ShowThreadQueryThreadOnNewsPost,
|
||||
show_icon_text: bool,
|
||||
content_el: &ElRef<HtmlElement>,
|
||||
) -> Node<Msg> {
|
||||
fn news_post(post: &ShowThreadQueryThreadOnNewsPost, content_el: &ElRef<HtmlElement>) -> Node<Msg> {
|
||||
// TODO remove and replace with CSS styling
|
||||
let show_icon_text = true;
|
||||
let subject = &post.title;
|
||||
set_title(subject);
|
||||
let read_thread_id = post.thread_id.clone();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user