diff --git a/web/src/view/mod.rs b/web/src/view/mod.rs index 65b61d1..ea0ba6c 100644 --- a/web/src/view/mod.rs +++ b/web/src/view/mod.rs @@ -20,22 +20,35 @@ 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", -]; +mod styles { + pub const BUTTON: &[&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 const CHECKBOX: &[&str] = &[ + "w-8", + "h-8", + "accent-green-600", + "appearance-none", + "checked:appearance-auto", + "rounded", + "border", + "border-gray-500", + ]; +} pub fn view(model: &Model) -> Node { let content = match &model.context { @@ -65,7 +78,7 @@ pub fn view(model: &Model) -> Node { ], reading_progress(model.read_completion_ratio), div![ - C!["flex-auto", "p-4"], + C!["flex-auto"], view_header(&model.query, &model.refreshing_state, true), content, view_header(&model.query, &model.refreshing_state, false), @@ -94,15 +107,27 @@ fn search_results( if let Some(idx) = unread_idx { tags.remove(idx); }; + let is_unread = unread_idx.is_some(); + // TODO: add check-all button, and tristate indicator 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"]], + C![ + "flex", + "flex-nowrap", + "w-auto", + "flex-auto", + "py-4", + "border-b", + "border-gray-800" + ], + div![ + C!["flex", "items-center", "mr-4"], + input![ + C![&styles::CHECKBOX], + attrs! { + At::Type=>"checkbox", + At::Checked=>selected_threads.contains(&tid).as_at_value(), + } + ], ev(Ev::Input, move |e| { if let Some(input) = e .target() @@ -121,29 +146,24 @@ fn search_results( }), ], a![ - C!["NOTPORTED", "has-text-light", "summary"], - IF!(unread_idx.is_some() => C!["NOTPORTED","unread"]), + C!["flex-grow"], + IF!(is_unread => C!["font-bold"]), attrs! { At::Href => urls::thread(&tid) }, - div![C!["NOTPORTED", "subject"], &r.subject], - span![ - C!["NOTPORTED", "from", "is-size-7"], - pretty_authors(&r.authors) - ], + div![&r.subject], + span![C!["text-xs"], 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 - ] + C!["flex", "flex-wrap", "justify-between"], + span![tags_chiclet(&tags, true)], + span![C!["text-sm"], datetime] ] ] ] }); let show_bulk_edit = !selected_threads.is_empty(); div![ - C!["flex", "flex-col"], + C!["flex", "flex-col", "flex-auto", "p-4"], search_toolbar(count, pager, show_bulk_edit), div![rows], search_toolbar(count, pager, show_bulk_edit), @@ -158,11 +178,18 @@ fn tags_chiclet(tags: &[String], is_mobile: bool) -> impl Iteratorhex}; - let classes = C!["NOTPORTED", "tag", IF!(is_mobile => "is-small")]; + let classes = C![ + "rounded-md", + "px-2", + "py-1", + "mr-1", + "text-xs", + "[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]", + ]; let tag = tag.clone(); a![match tag.as_str() { "attachment" => span![classes, style, "📎"], - "replied" => span![classes, style, i![C!["NOTPORTED", "fa-solid", "fa-reply"]]], + "replied" => span![classes, style, i![C!["fa-solid", "fa-reply"]]], _ => span![classes, style, &tag], },] }) @@ -363,19 +390,11 @@ fn view_search_results( ] ] }); - + return h1!["HELLO"]; div![ - C!["NOTPORTED", "search-results"], + C!["flex"], search_toolbar(count, pager, show_bulk_edit), - table![ - C![ - "table", - "index", - "is-fullwidth", - "is-hoverable", - "is-narrow", - "is-striped", - ], + div![ thead![tr![ th![ C!["NOTPORTED", "edit"], @@ -420,14 +439,14 @@ fn search_toolbar( div![ div![ button![ - C![&BUTTON_CLASSES, "rounded-r-none"], + C![&styles::BUTTON, "rounded-r-none"], attrs!{At::Title => "Mark as read"}, span![i![C!["far", "fa-envelope-open"]]], span![C!["pl-2", "hidden", "md:inline"], "Read"], ev(Ev::Click, |_| Msg::SelectionMarkAsRead) ], button![ - C![&BUTTON_CLASSES, "rounded-l-none"], + C![&styles::BUTTON, "rounded-l-none"], attrs!{At::Title => "Mark as unread"}, span![i![C!["far", "fa-envelope"]]], span![C!["pl-2", "hidden", "md:inline"], "Unread"], @@ -439,7 +458,7 @@ fn search_toolbar( div![ div![ button![ - C![&BUTTON_CLASSES, "text-red-500"], + C![&styles::BUTTON, "text-red-500"], attrs!{At::Title => "Mark as spam"}, span![i![C!["far", "fa-hand"]]], span![C!["pl-2", "hidden", "md:inline"], "Spam"], @@ -457,13 +476,13 @@ fn search_toolbar( C!["flex", "gap-2", "items-center"], p![format!("{count} results")], button![ - C![&BUTTON_CLASSES], + C![&styles::BUTTON], IF!(!pager.has_previous_page => attrs!{ At::Disabled=>true }), "<", IF!(pager.has_previous_page => ev(Ev::Click, |_| Msg::PreviousPage)), ], button![ - C![&BUTTON_CLASSES], + C![&styles::BUTTON], IF!(!pager.has_next_page => attrs!{ At::Disabled=>true }), ">", IF!(pager.has_next_page => ev(Ev::Click, |_| Msg::NextPage)) @@ -979,10 +998,10 @@ fn view_header( }; let query = Url::decode_uri_component(query).unwrap_or("".to_string()); nav![ - C!["flex"], + C!["flex", "p-4"], a![ C![IF![is_error => "bg-red-500"], "rounded-r-none"], - C![&BUTTON_CLASSES], + C![&styles::BUTTON], span![i![C![ "fa-solid", "fa-arrow-rotate-right", @@ -991,7 +1010,7 @@ fn view_header( ev(Ev::Click, |_| Msg::RefreshStart), ], a![ - C![&BUTTON_CLASSES], + C![&styles::BUTTON], C!["px-4", "rounded-none"], attrs! { At::Href => urls::search(unread_query(), 0) @@ -999,7 +1018,7 @@ fn view_header( "Unread", ], a![ - C![&BUTTON_CLASSES], + C![&styles::BUTTON], C!["px-4", "rounded-none"], attrs! { At::Href => urls::search("", 0) @@ -1007,7 +1026,7 @@ fn view_header( "All", ], input![ - C!["grow", "px-4", "text-black"], + C!["grow", "pl-4", "text-black", "rounded-r"], attrs! { At::Placeholder => "Search"; At::AutoFocus => auto_focus_search.as_at_value();