diff --git a/web/index.html b/web/index.html
index 3ae058a..24460e1 100644
--- a/web/index.html
+++ b/web/index.html
@@ -23,6 +23,7 @@
+
diff --git a/web/src/tailwind.css b/web/src/tailwind.css
new file mode 100644
index 0000000..b5c61c9
--- /dev/null
+++ b/web/src/tailwind.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/web/src/view/mod.rs b/web/src/view/mod.rs
index 3126e66..bc2bb75 100644
--- a/web/src/view/mod.rs
+++ b/web/src/view/mod.rs
@@ -425,7 +425,11 @@ fn render_avatar(avatar: Option, from: &str) -> Node {
let h = 64;
let from_color = compute_color(from);
svg![
- attrs! {At::ViewBox=>format!("0 0 {w} {h}") },
+ attrs! {
+ At::Width=>w,
+ At::Height=>h,
+ At::ViewBox=>format!("0 0 {w} {h}")
+ },
style! {
St::Display => "block",
St::FontFamily => "Poppins",
@@ -460,6 +464,16 @@ fn render_avatar(avatar: Option, from: &str) -> Node {
}
}
+fn copy_text_widget(text: &str) -> Node {
+ let text = text.to_string();
+ span![
+ i![C!["far", "fa-clone"]],
+ ev(Ev::Click, move |e| {
+ e.stop_propagation();
+ Msg::CopyToClipboard(text)
+ })
+ ]
+}
fn render_open_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Node {
let (from, from_detail) = match &msg.from {
Some(ShowThreadQueryThreadOnEmailThreadMessagesFrom {
@@ -477,127 +491,166 @@ fn render_open_header(msg: &ShowThreadQueryThreadOnEmailThreadMessages) -> Node<
let id = msg.id.clone();
let is_unread = has_unread(&msg.tags);
let img = render_avatar(avatar, &from);
- article![
- C!["media"],
- figure![C!["media-left"], p![C!["image", "is-64x64"], img]],
- div![
- C!["media-content"],
+ div![
+ figure![
+ C!["flex"],
+ div![C!["w-16", "h-16", "mx-auto", "h-auto"], &img],
div![
- C!["content"],
- p![
- strong![from],
- br![],
- small![
- &from_detail,
+ C!["px-4"],
+ &from,
+ " ",
+ from_detail.as_ref().map(|text| copy_text_widget(&text)),
+ IF!(!msg.to.is_empty() =>div![
+ "To: ",
+ msg.to.iter().map(|to| {
+ let ShowThreadQueryThreadOnEmailThreadMessagesTo { name, addr } = to;
+ span![
+ C!["text-nowrap"],
+ &name,
" ",
- from_detail.map(|detail| span![
+ span![
i![C!["far", "fa-clone"]],
- ev(Ev::Click, move |e| {
+ addr.clone().map(|addr| ev(Ev::Click, move |e| {
e.stop_propagation();
- Msg::CopyToClipboard(detail.to_string())
- })
- ])
- ],
- table![
- IF!(!msg.to.is_empty() =>
- tr![
- td![ "To:" ],
- //td![ if i==0 { "To" }else { "" } ],
- td![
- msg.to.iter().enumerate().map(|(i, to)|
- small![
- if i>0 { ", " }else { "" },
- {
- let to = match to {
- ShowThreadQueryThreadOnEmailThreadMessagesTo {
- name: Some(name),
- addr:Some(addr),
- } => format!("{name} <{addr}>"),
- ShowThreadQueryThreadOnEmailThreadMessagesTo {
- name: Some(name),
- addr:None
- } => format!("{name}"),
- ShowThreadQueryThreadOnEmailThreadMessagesTo {
- addr: Some(addr), ..
- } => format!("{addr}"),
- _ => String::from("UNKNOWN"),
- };
- span![
- &to, " ",
+ Msg::CopyToClipboard(addr)
+ }))
+ ],
+ " "
+ ]
+ })]),
+ IF!(!msg.cc.is_empty() =>div![
+ "CC: ",
+ msg.cc.iter().map(|cc| {
+ let ShowThreadQueryThreadOnEmailThreadMessagesCc { name, addr } = cc;
+ span![
+ C!["text-nowrap"],
+ &name,
+ " ",
+ span![
+ i![C!["far", "fa-clone"]],
+ addr.clone().map(|addr| ev(Ev::Click, move |e| {
+ e.stop_propagation();
+ Msg::CopyToClipboard(addr)
+ }))
+ ],
+ " "
+ ]
+ })]),
+ msg.timestamp.map(|ts| span![C!["header"], human_age(ts)]),
+ span![
+ C!["read-status"],
+ i![C![
+ "far",
+ if is_unread {
+ "fa-envelope"
+ } else {
+ "fa-envelope-open"
+ },
+ ]],
+ {
+ // TODO remove clone and code block when removing article![] below
+ let id = id.clone();
+ ev(Ev::Click, move |e| {
+ e.stop_propagation();
+ Msg::SetUnread(id, !is_unread)
+ })
+ }
+ ]
+ ]
+ ],
+ hr![],
+ article![
+ C!["media"],
+ figure![C!["media-left"], p![C!["image", "is-64x64"], img]],
+ div![
+ C!["media-content"],
+ div![
+ C!["content"],
+ p![
+ //C!["text-nowrap"],
+ strong![from],
+ " ",
+ from_detail.map(|text| copy_text_widget(&text)),
+ table![
+ IF!(!msg.to.is_empty() =>
+ tr![
+ td![ "To:" ],
+ //td![ if i==0 { "To" }else { "" } ],
+ td![
+ msg.to.iter().map(|to|
+ small![
+ " ",
+ {
+ let ShowThreadQueryThreadOnEmailThreadMessagesTo{name, addr} = to;
span![
- i![C!["far", "fa-clone"]],
- ev(Ev::Click, move |e| {
- e.stop_propagation();
- Msg::CopyToClipboard(to)
- })
+ //C!["text-nowrap"],
+ &name, " ",
+ span![
+ i![C!["far", "fa-clone"]],
+ addr.clone().map(|addr| ev(Ev::Click,
+ move |e| {
+ e.stop_propagation();
+ Msg::CopyToClipboard(addr)
+ }
+ ))
+ ]
]
- ]
- }
-
- ])
- ]
- ]),
- IF!(!msg.cc.is_empty() =>
- tr![
- td![ "CC:" ],
- td![
- msg.cc.iter().enumerate().map(|(i, cc)|
- small![
- if i>0 { ", " }else { "" },
- {
- let cc = match cc {
- ShowThreadQueryThreadOnEmailThreadMessagesCc {
- name: Some(name),
- addr:Some(addr),
- } => format!("{name} <{addr}>"),
- ShowThreadQueryThreadOnEmailThreadMessagesCc {
- name: Some(name),
- addr:None
- } => format!("{name}"),
- ShowThreadQueryThreadOnEmailThreadMessagesCc {
- addr: Some(addr), ..
- } => format!("<{addr}>"),
- _ => String::from("UNKNOWN"),
- };
- span![
- &cc, " ",
+ }
+ ])
+ ]
+ ]),
+ IF!(!msg.cc.is_empty() =>
+ tr![
+ td![ "CC:" ],
+ td![
+ msg.cc.iter().map(|cc|
+ small![
+ " ",
+ {
+ let ShowThreadQueryThreadOnEmailThreadMessagesCc{name, addr} = cc;
span![
- i![C!["far", "fa-clone"]],
- ev(Ev::Click, move |e| {
- e.stop_propagation();
- Msg::CopyToClipboard(cc)
- })
+ //C!["text-nowrap"],
+ &name, " ",
+ span![
+ i![C!["far", "fa-clone"]],
+ addr.clone().map(|addr| ev(Ev::Click,
+ move |e| {
+ e.stop_propagation();
+ Msg::CopyToClipboard(addr)
+ }
+ ))
+ ]
]
- ]
- }
- ])
- ]
- ]),
- tr![td![
- attrs! {At::ColSpan=>2},
- msg.timestamp.map(|ts| span![C!["header"], human_age(ts)])
- ]]
+ }
+ ])
+ ]
+ ]),
+ tr![td![
+ attrs! {At::ColSpan=>2},
+ msg.timestamp.map(|ts| span![C!["header"], human_age(ts)])
+ ]]
+ ],
],
],
],
- ],
- div![
- C!["media-right"],
- span![
- C!["read-status"],
- i![C![
- "far",
- if is_unread {
- "fa-envelope"
- } else {
- "fa-envelope-open"
- },
- ]]
- ],
- ev(Ev::Click, move |e| {
- e.stop_propagation();
- Msg::SetUnread(id, !is_unread)
- })
+ div![
+ C!["media-right"],
+ span![
+ C!["read-status"],
+ i![C![
+ "far",
+ if is_unread {
+ "fa-envelope"
+ } else {
+ "fa-envelope-open"
+ },
+ ]]
+ ],
+ ev(Ev::Click, move |e| {
+ e.stop_propagation();
+ Msg::SetUnread(id, !is_unread)
+ })
+ ]
]
]
}
@@ -1127,7 +1180,6 @@ fn news_post(
}
fn render_news_post_header(post: &ShowThreadQueryThreadOnNewsPost) -> Node {
let from = &post.site;
- let from_detail = post.url.clone();
let avatar: Option = None;
//let avatar: Option = Some(String::from("https://bulma.io/images/placeholders/64x64.png"));
let id = post.thread_id.clone();
diff --git a/web/tailwind.config.js b/web/tailwind.config.js
new file mode 100644
index 0000000..c3481c0
--- /dev/null
+++ b/web/tailwind.config.js
@@ -0,0 +1,9 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.rs'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
+