web: update style for rendering emails, including attachments
This commit is contained in:
parent
87321fb669
commit
fb73d8272e
@ -223,7 +223,7 @@ pub async fn thread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
r#"<p class="view-part-text-plain">{}</p>"#,
|
r#"<p class="view-part-text-plain font-mono whitespace-pre">{}</p>"#,
|
||||||
// Trim newlines to prevent excessive white space at the beginning/end of
|
// Trim newlines to prevent excessive white space at the beginning/end of
|
||||||
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
||||||
// header on the first line.
|
// header on the first line.
|
||||||
@ -578,7 +578,7 @@ fn flatten_body_parts(parts: &[Body]) -> Body {
|
|||||||
.map(|p| match p {
|
.map(|p| match p {
|
||||||
Body::PlainText(PlainText { text, .. }) => {
|
Body::PlainText(PlainText { text, .. }) => {
|
||||||
format!(
|
format!(
|
||||||
r#"<p class="view-part-text-plain">{}</p>"#,
|
r#"<p class="view-part-text-plain font-mono whitespace-pre">{}</p>"#,
|
||||||
// Trim newlines to prevent excessive white space at the beginning/end of
|
// Trim newlines to prevent excessive white space at the beginning/end of
|
||||||
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
||||||
// header on the first line.
|
// header on the first line.
|
||||||
|
|||||||
@ -30,7 +30,7 @@ mod tw_classes {
|
|||||||
];
|
];
|
||||||
pub const TAG_X: &[&str] = &[
|
pub const TAG_X: &[&str] = &[
|
||||||
"rounded-r",
|
"rounded-r",
|
||||||
"bg-slate-800",
|
"bg-neutral-800",
|
||||||
"px-2",
|
"px-2",
|
||||||
"py-1",
|
"py-1",
|
||||||
"mr-1",
|
"mr-1",
|
||||||
@ -38,17 +38,17 @@ mod tw_classes {
|
|||||||
"[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]",
|
"[text-shadow:_0_1px_0_rgb(0_0_0_/_40%)]",
|
||||||
];
|
];
|
||||||
pub const BUTTON: &[&str] = &[
|
pub const BUTTON: &[&str] = &[
|
||||||
"bg-slate-900",
|
"bg-neutral-900",
|
||||||
"rounded-md",
|
"rounded-md",
|
||||||
"p-2",
|
"p-2",
|
||||||
"border",
|
"border",
|
||||||
"border-slate-700",
|
"border-neutral-700",
|
||||||
"text-center",
|
"text-center",
|
||||||
"text-sm",
|
"text-sm",
|
||||||
"transition-all",
|
"transition-all",
|
||||||
"shadow-md",
|
"shadow-md",
|
||||||
"hover:shadow-lg",
|
"hover:shadow-lg",
|
||||||
"hover:bg-slate-700",
|
"hover:bg-neutral-700",
|
||||||
"disabled:pointer-events-none",
|
"disabled:pointer-events-none",
|
||||||
"disabled:opacity-50",
|
"disabled:opacity-50",
|
||||||
"disabled:shadow-none",
|
"disabled:shadow-none",
|
||||||
@ -62,7 +62,7 @@ mod tw_classes {
|
|||||||
"checked:appearance-auto",
|
"checked:appearance-auto",
|
||||||
"rounded",
|
"rounded",
|
||||||
"border",
|
"border",
|
||||||
"border-gray-500",
|
"border-neutral-500",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ fn search_results(
|
|||||||
"flex-auto",
|
"flex-auto",
|
||||||
"py-4",
|
"py-4",
|
||||||
"border-b",
|
"border-b",
|
||||||
"border-gray-800"
|
"border-neutral-800"
|
||||||
],
|
],
|
||||||
div![
|
div![
|
||||||
C!["flex", "items-center", "mr-4"],
|
C!["flex", "items-center", "mr-4"],
|
||||||
@ -432,14 +432,12 @@ fn search_toolbar(
|
|||||||
pager: &FrontPageQuerySearchPageInfo,
|
pager: &FrontPageQuerySearchPageInfo,
|
||||||
show_bulk_edit: bool,
|
show_bulk_edit: bool,
|
||||||
) -> Node<Msg> {
|
) -> Node<Msg> {
|
||||||
info!("pager {pager:#?}");
|
|
||||||
nav![
|
nav![
|
||||||
C!["p-4", "flex", "w-full", "justify-between"],
|
C!["p-4", "flex", "w-full", "justify-between"],
|
||||||
div![
|
div![
|
||||||
C!["gap-2", "flex"],
|
C!["gap-2", "flex"],
|
||||||
IF!(show_bulk_edit =>
|
IF!(show_bulk_edit =>
|
||||||
div![
|
div![
|
||||||
div![
|
|
||||||
button![
|
button![
|
||||||
C![&tw_classes::BUTTON, "rounded-r-none"],
|
C![&tw_classes::BUTTON, "rounded-r-none"],
|
||||||
attrs!{At::Title => "Mark as read"},
|
attrs!{At::Title => "Mark as read"},
|
||||||
@ -454,11 +452,9 @@ fn search_toolbar(
|
|||||||
span![C!["pl-2", "hidden", "md:inline"], "Unread"],
|
span![C!["pl-2", "hidden", "md:inline"], "Unread"],
|
||||||
ev(Ev::Click, |_| Msg::SelectionMarkAsUnread)
|
ev(Ev::Click, |_| Msg::SelectionMarkAsUnread)
|
||||||
]
|
]
|
||||||
]
|
|
||||||
]),
|
]),
|
||||||
IF!(show_bulk_edit =>
|
IF!(show_bulk_edit =>
|
||||||
div![
|
div![
|
||||||
div![
|
|
||||||
button![
|
button![
|
||||||
C![&tw_classes::BUTTON, "text-red-500"],
|
C![&tw_classes::BUTTON, "text-red-500"],
|
||||||
attrs!{At::Title => "Mark as spam"},
|
attrs!{At::Title => "Mark as spam"},
|
||||||
@ -470,8 +466,7 @@ fn search_toolbar(
|
|||||||
Msg::SelectionMarkAsRead
|
Msg::SelectionMarkAsRead
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
],
|
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
div![
|
div![
|
||||||
@ -503,7 +498,7 @@ fn raw_text_message(contents: &str) -> Node<Msg> {
|
|||||||
(contents, None)
|
(contents, None)
|
||||||
};
|
};
|
||||||
div![
|
div![
|
||||||
C!["NOTPORTED", "view-part-text-plain"],
|
C!["view-part-text-plain", "font-mono", "whitespace-pre"],
|
||||||
contents,
|
contents,
|
||||||
truncated_msg,
|
truncated_msg,
|
||||||
]
|
]
|
||||||
@ -582,7 +577,7 @@ fn render_open_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Node<
|
|||||||
let avatar = render_avatar(photo_url, &from, true);
|
let avatar = render_avatar(photo_url, &from, true);
|
||||||
let unknown = "UNKNOWN".to_string();
|
let unknown = "UNKNOWN".to_string();
|
||||||
div![
|
div![
|
||||||
C!["flex", "p-4"],
|
C!["flex", "p-4", "bg-neutral-800"],
|
||||||
div![avatar],
|
div![avatar],
|
||||||
div![
|
div![
|
||||||
C!["px-4", "mr-auto"],
|
C!["px-4", "mr-auto"],
|
||||||
@ -679,7 +674,7 @@ fn render_closed_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Nod
|
|||||||
let avatar = render_avatar(photo_url, &from, false);
|
let avatar = render_avatar(photo_url, &from, false);
|
||||||
let unknown = "UNKNOWN".to_string();
|
let unknown = "UNKNOWN".to_string();
|
||||||
div![
|
div![
|
||||||
C!["flex", "p-4"],
|
C!["flex", "p-4", "bg-neutral-800"],
|
||||||
div![avatar],
|
div![avatar],
|
||||||
div![
|
div![
|
||||||
C!["px-4", "mr-auto"],
|
C!["px-4", "mr-auto"],
|
||||||
@ -754,6 +749,7 @@ fn render_closed_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Nod
|
|||||||
fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool) -> Node<Msg> {
|
fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool) -> Node<Msg> {
|
||||||
let expand_id = msg.id.clone();
|
let expand_id = msg.id.clone();
|
||||||
div![
|
div![
|
||||||
|
C!["lg:mb-4"],
|
||||||
div![
|
div![
|
||||||
if open {
|
if open {
|
||||||
render_open_header(&msg)
|
render_open_header(&msg)
|
||||||
@ -771,13 +767,13 @@ fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool)
|
|||||||
],
|
],
|
||||||
IF!(open =>
|
IF!(open =>
|
||||||
div![
|
div![
|
||||||
C![],
|
C!["bg-white", "text-black", "p-4", "min-w-full", "w-0","overflow-x-auto"],
|
||||||
match &msg.body {
|
match &msg.body {
|
||||||
ShowThreadQueryThreadOnEmailThreadMessagesBody::UnhandledContentType(
|
ShowThreadQueryThreadOnEmailThreadMessagesBody::UnhandledContentType(
|
||||||
ShowThreadQueryThreadOnEmailThreadMessagesBodyOnUnhandledContentType { contents ,content_tree},
|
ShowThreadQueryThreadOnEmailThreadMessagesBodyOnUnhandledContentType { contents ,content_tree},
|
||||||
) => div![
|
) => div![
|
||||||
raw_text_message(&contents),
|
raw_text_message(&contents),
|
||||||
div![C!["NOTPORTED","error"],
|
div![C!["bg-red-500","p-4", "min-w-full", "w-0", "overflow-x-auto"],
|
||||||
view_content_tree(&content_tree),
|
view_content_tree(&content_tree),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@ -796,59 +792,9 @@ fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool)
|
|||||||
content_tree,
|
content_tree,
|
||||||
},
|
},
|
||||||
) => div![
|
) => div![
|
||||||
C!["NOTPORTED","view-part-text-html"],
|
C!["view-part-text-html"],
|
||||||
raw![contents],
|
raw![contents],
|
||||||
IF!(!msg.attachments.is_empty() =>
|
IF!(!msg.attachments.is_empty() => render_attachements(&msg.attachments)),
|
||||||
div![
|
|
||||||
C!["NOTPORTED","attachments"],
|
|
||||||
hr![],
|
|
||||||
h2!["NOTPORTED","Attachments"],
|
|
||||||
div![C!["NOTPORTED","grid","is-col-min-6"],
|
|
||||||
msg.attachments
|
|
||||||
.iter()
|
|
||||||
.map(|a| {
|
|
||||||
let default = "UNKNOWN_FILE".to_string();
|
|
||||||
let filename = a.filename.as_ref().unwrap_or(&default);
|
|
||||||
let host = seed::window().location().host().expect("couldn't get host");
|
|
||||||
let url = shared::urls::download_attachment(Some(&host), &a.id, &a.idx, filename);
|
|
||||||
let mut fmtr = Formatter::new();
|
|
||||||
fmtr.with_separator(" ");
|
|
||||||
fmtr.with_scales(Scales::Binary());
|
|
||||||
|
|
||||||
div![
|
|
||||||
C!["NOTPORTED","attachment", "card"],
|
|
||||||
a.content_type.as_ref().map(|content_type|
|
|
||||||
IF!(content_type.starts_with("image/") =>
|
|
||||||
div![C!["NOTPORTED","card-image","is-1by1"],
|
|
||||||
div![
|
|
||||||
C!["NOTPORTED","image","is-1by1"],
|
|
||||||
style!{
|
|
||||||
St::BackgroundImage=>format!(r#"url("{url}");"#),
|
|
||||||
St::BackgroundSize=>"cover",
|
|
||||||
St::BackgroundPosition=>"center",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
)),
|
|
||||||
div![C!["NOTPORTED","card-content"],
|
|
||||||
div![C!["NOTPORTED","content"],
|
|
||||||
&a.filename, br![],
|
|
||||||
small![ fmtr.format(a.size as f64),"B"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
footer![
|
|
||||||
C!["NOTPORTED","card-footer"],
|
|
||||||
a![C!["NOTPORTED","card-footer-item"],span![C!["NOTPORTED","icon"], i![C!["NOTPORTED","fas", "fa-download"]]],
|
|
||||||
ev(Ev::Click, move |_| {
|
|
||||||
seed::window().location().set_href(&url
|
|
||||||
).expect("failed to set URL");
|
|
||||||
})
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
})
|
|
||||||
]
|
|
||||||
]),
|
|
||||||
view_content_tree(&content_tree),
|
view_content_tree(&content_tree),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -856,14 +802,76 @@ fn message_render(msg: &ShowThreadQueryThreadOnEmailThreadMessages, open: bool)
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_attachements(
|
||||||
|
attachments: &[ShowThreadQueryThreadOnEmailThreadMessagesAttachments],
|
||||||
|
) -> Node<Msg> {
|
||||||
|
div![
|
||||||
|
C!["border-t", "border-neutral-200", "mt-2", "pt-2"],
|
||||||
|
h2![C!["text-lg"], "Attachments"],
|
||||||
|
div![
|
||||||
|
C!["flex", "flex-wrap", "gap-2"],
|
||||||
|
attachments.iter().map(|a| {
|
||||||
|
let default = "UNKNOWN_FILE".to_string();
|
||||||
|
let filename = a.filename.as_ref().unwrap_or(&default);
|
||||||
|
let host = seed::window().location().host().expect("couldn't get host");
|
||||||
|
let url = shared::urls::download_attachment(Some(&host), &a.id, &a.idx, filename);
|
||||||
|
let mut fmtr = Formatter::new();
|
||||||
|
fmtr.with_separator(" ");
|
||||||
|
fmtr.with_scales(Scales::Binary());
|
||||||
|
|
||||||
|
div![
|
||||||
|
C![
|
||||||
|
"flex",
|
||||||
|
"flex-col",
|
||||||
|
"flex-none",
|
||||||
|
"p-2",
|
||||||
|
"bg-neutral-200",
|
||||||
|
"border",
|
||||||
|
"border-neutral-400",
|
||||||
|
],
|
||||||
|
a.content_type.as_ref().map(
|
||||||
|
|content_type| IF!(content_type.starts_with("image/") => img![
|
||||||
|
C!["w-32", "h-32", "md:w-64", "md:h-64", "object-cover"],
|
||||||
|
attrs!{At::Src=>url},
|
||||||
|
])
|
||||||
|
),
|
||||||
|
div![
|
||||||
|
C!["py-2", "flex", "flex-nowrap", "items-center"],
|
||||||
|
div![
|
||||||
|
C!["flex", "flex-col", "grow", "w-16", "md:w-32"],
|
||||||
|
span![C!["shrink", "truncate"], &a.filename],
|
||||||
|
span![C!["text-xs"], fmtr.format(a.size as f64), "B"]
|
||||||
|
],
|
||||||
|
a![
|
||||||
|
C![
|
||||||
|
"aspect-square",
|
||||||
|
"px-2",
|
||||||
|
"pt-1",
|
||||||
|
"bg-neutral-300",
|
||||||
|
"border",
|
||||||
|
"border-neutral-400"
|
||||||
|
],
|
||||||
|
span![i![C!["fas", "fa-download"]]],
|
||||||
|
ev(Ev::Click, move |_| {
|
||||||
|
seed::window()
|
||||||
|
.location()
|
||||||
|
.set_href(&url)
|
||||||
|
.expect("failed to set URL");
|
||||||
|
})
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
#[topo::nested]
|
#[topo::nested]
|
||||||
fn thread(
|
fn thread(
|
||||||
thread: &ShowThreadQueryThreadOnEmailThread,
|
thread: &ShowThreadQueryThreadOnEmailThread,
|
||||||
open_messages: &HashSet<String>,
|
open_messages: &HashSet<String>,
|
||||||
content_el: &ElRef<HtmlElement>,
|
content_el: &ElRef<HtmlElement>,
|
||||||
) -> Node<Msg> {
|
) -> 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
|
// TODO(wathiede): show per-message subject if it changes significantly from top-level subject
|
||||||
let subject = if thread.subject.is_empty() {
|
let subject = if thread.subject.is_empty() {
|
||||||
"(no subject)"
|
"(no subject)"
|
||||||
@ -890,68 +898,49 @@ fn thread(
|
|||||||
let spam_add_thread_id = thread.thread_id.clone();
|
let spam_add_thread_id = thread.thread_id.clone();
|
||||||
let spam_unread_thread_id = thread.thread_id.clone();
|
let spam_unread_thread_id = thread.thread_id.clone();
|
||||||
div![
|
div![
|
||||||
C!["p-4"],
|
C!["lg:p-4"],
|
||||||
h3![C!["text-xl"], subject],
|
|
||||||
span![
|
|
||||||
C!["NOTPORTED", "tags"],
|
|
||||||
removable_tags_chiclet(&thread.thread_id, &tags, false)
|
|
||||||
],
|
|
||||||
div![
|
div![
|
||||||
C!["NOTPORTED", "level", "is-mobile"],
|
C!["p-4", "lg:p-0"],
|
||||||
|
h3![C!["text-xl"], subject],
|
||||||
|
span![removable_tags_chiclet(&thread.thread_id, &tags, false)],
|
||||||
div![
|
div![
|
||||||
C!["NOTPORTED", "level-item"],
|
C!["pt-4", "gap-2", "flex", "justify-around"],
|
||||||
div![
|
div![
|
||||||
C!["NOTPORTED", "buttons", "has-addons"],
|
|
||||||
button![
|
button![
|
||||||
C!["NOTPORTED", "button", "mark-read"],
|
C![&tw_classes::BUTTON, "rounded-r-none"],
|
||||||
attrs! {At::Title => "Mark as read"},
|
attrs! {At::Title => "Mark as read"},
|
||||||
span![
|
span![i![C!["far", "fa-envelope-open"]]],
|
||||||
C!["NOTPORTED", "icon", "is-small"],
|
span![C!["pl-2", "hidden", "md:inline"], "Read"],
|
||||||
i![C!["NOTPORTED", "far", "fa-envelope-open"]]
|
|
||||||
],
|
|
||||||
IF!(show_icon_text=>span!["Read"]),
|
|
||||||
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
||||||
Msg::SetUnread(read_thread_id, false),
|
Msg::SetUnread(read_thread_id, false),
|
||||||
Msg::GoToSearchResults
|
Msg::GoToSearchResults
|
||||||
])),
|
])),
|
||||||
],
|
],
|
||||||
button![
|
button![
|
||||||
C!["NOTPORTED", "button", "mark-unread"],
|
C![&tw_classes::BUTTON, "rounded-l-none"],
|
||||||
attrs! {At::Title => "Mark as unread"},
|
attrs! {At::Title => "Mark as unread"},
|
||||||
span![
|
span![i![C!["far", "fa-envelope"]]],
|
||||||
C!["NOTPORTED", "icon", "is-small"],
|
span![C!["pl-2", "hidden", "md:inline"], "Unread"],
|
||||||
i![C!["NOTPORTED", "far", "fa-envelope"]]
|
|
||||||
],
|
|
||||||
IF!(show_icon_text=>span!["Unread"]),
|
|
||||||
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
||||||
Msg::SetUnread(unread_thread_id, true),
|
Msg::SetUnread(unread_thread_id, true),
|
||||||
Msg::GoToSearchResults
|
Msg::GoToSearchResults
|
||||||
])),
|
])),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
div![button![
|
||||||
div![
|
C![&tw_classes::BUTTON, "text-red-500"],
|
||||||
C!["NOTPORTED", "level-item"],
|
attrs! {At::Title => "Spam"},
|
||||||
div![
|
span![i![C!["far", "fa-hand"]]],
|
||||||
C!["NOTPORTED", "buttons", "has-addons"],
|
span![C!["pl-2", "hidden", "md:inline"], "Spam"],
|
||||||
button![
|
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
||||||
C!["NOTPORTED", "button", "spam"],
|
Msg::AddTag(spam_add_thread_id, "Spam".to_string()),
|
||||||
attrs! {At::Title => "Spam"},
|
Msg::SetUnread(spam_unread_thread_id, false),
|
||||||
span![
|
Msg::GoToSearchResults
|
||||||
C!["NOTPORTED", "icon", "is-small"],
|
])),
|
||||||
i![C!["NOTPORTED", "far", "fa-hand"]]
|
]]
|
||||||
],
|
|
||||||
IF!(show_icon_text=>span!["Spam"]),
|
|
||||||
ev(Ev::Click, move |_| Msg::MultiMsg(vec![
|
|
||||||
Msg::AddTag(spam_add_thread_id, "Spam".to_string()),
|
|
||||||
Msg::SetUnread(spam_unread_thread_id, false),
|
|
||||||
Msg::GoToSearchResults
|
|
||||||
])),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
div![el_ref(content_el), messages, click_to_top()],
|
div![C!["lg:mt-4"], el_ref(content_el), messages, click_to_top()],
|
||||||
/* 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)},
|
||||||
@ -998,7 +987,7 @@ fn view_header(
|
|||||||
};
|
};
|
||||||
let query = Url::decode_uri_component(query).unwrap_or("".to_string());
|
let query = Url::decode_uri_component(query).unwrap_or("".to_string());
|
||||||
nav![
|
nav![
|
||||||
C!["flex", "p-4"],
|
C!["flex", "px-4", "pt-4"],
|
||||||
a![
|
a![
|
||||||
C![IF![is_error => "bg-red-500"], "rounded-r-none"],
|
C![IF![is_error => "bg-red-500"], "rounded-r-none"],
|
||||||
C![&tw_classes::BUTTON],
|
C![&tw_classes::BUTTON],
|
||||||
@ -1081,7 +1070,7 @@ pub fn tags(model: &Model) -> Node<Msg> {
|
|||||||
"self-center",
|
"self-center",
|
||||||
"justify-self-end",
|
"justify-self-end",
|
||||||
"text-sm",
|
"text-sm",
|
||||||
"text-gray-400"
|
"text-neutral-400"
|
||||||
],
|
],
|
||||||
IF!(t.unread>0 => format!("{}", t.unread))
|
IF!(t.unread>0 => format!("{}", t.unread))
|
||||||
],
|
],
|
||||||
@ -1305,7 +1294,7 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg>
|
|||||||
div![
|
div![
|
||||||
C!["px-4", "mr-auto"],
|
C!["px-4", "mr-auto"],
|
||||||
div![
|
div![
|
||||||
span![C!["font-semibold", "text-sm"], from,],
|
span![C!["font-semibold", "text-sm"], from],
|
||||||
div![
|
div![
|
||||||
C!["text-xs"],
|
C!["text-xs"],
|
||||||
small![a![
|
small![a![
|
||||||
@ -1341,15 +1330,23 @@ fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node<Msg>
|
|||||||
}
|
}
|
||||||
fn reading_progress(ratio: f64) -> Node<Msg> {
|
fn reading_progress(ratio: f64) -> Node<Msg> {
|
||||||
let percent = ratio * 100.;
|
let percent = ratio * 100.;
|
||||||
// TODO: percent broken with no styles
|
|
||||||
info!("percent {percent}");
|
info!("percent {percent}");
|
||||||
progress![
|
div![
|
||||||
C!["absolute", "w-screen", IF!(percent<1. => "hidden")],
|
C![
|
||||||
attrs! {
|
"fixed",
|
||||||
At::Value=>percent,
|
"top-0",
|
||||||
At::Max=>"100"
|
"left-0",
|
||||||
},
|
"w-screen",
|
||||||
format!("{percent}%")
|
"h-1",
|
||||||
|
"bg-gray-200",
|
||||||
|
IF!(percent<1. => "hidden")
|
||||||
|
],
|
||||||
|
div![
|
||||||
|
C!["h-1", "bg-green-500"],
|
||||||
|
style! {
|
||||||
|
St::Width => format!("{}%", percent)
|
||||||
|
}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
pub fn versions(versions: &crate::state::Version) -> Node<Msg> {
|
pub fn versions(versions: &crate::state::Version) -> Node<Msg> {
|
||||||
@ -1372,12 +1369,9 @@ pub fn versions(versions: &crate::state::Version) -> Node<Msg> {
|
|||||||
|
|
||||||
fn click_to_top() -> Node<Msg> {
|
fn click_to_top() -> Node<Msg> {
|
||||||
button![
|
button![
|
||||||
C!["NOTPORTED", "button", "is-danger", "is-small"],
|
C![&tw_classes::BUTTON, "bg-red-500", "lg:m-0", "m-4"],
|
||||||
span!["Top"],
|
span!["Top"],
|
||||||
span![
|
span![i![C!["fas", "fa-arrow-turn-up"]]],
|
||||||
C!["NOTPORTED", "icon"],
|
|
||||||
i![C!["NOTPORTED", "fas", "fa-arrow-turn-up"]]
|
|
||||||
],
|
|
||||||
ev(Ev::Click, |_| web_sys::window()
|
ev(Ev::Click, |_| web_sys::window()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.scroll_to_with_x_and_y(0., 0.))
|
.scroll_to_with_x_and_y(0., 0.))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user