1use std::marker::PhantomData;
2
3use chrono::NaiveDateTime;
4
5use crate::prelude::*;
6use crate::theme::theme;
7use crate::{Icon, IconButton, Input, Label, LabelColor};
8
9#[derive(Element)]
10pub struct ChatPanel<V: 'static> {
11 view_type: PhantomData<V>,
12 scroll_state: ScrollState,
13 messages: Vec<ChatMessage>,
14}
15
16impl<V: 'static> ChatPanel<V> {
17 pub fn new(scroll_state: ScrollState) -> Self {
18 Self {
19 view_type: PhantomData,
20 scroll_state,
21 messages: Vec::new(),
22 }
23 }
24
25 pub fn with_messages(mut self, messages: Vec<ChatMessage>) -> Self {
26 self.messages = messages;
27 self
28 }
29
30 fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
31 let theme = theme(cx);
32
33 div()
34 .flex()
35 .flex_col()
36 .justify_between()
37 .h_full()
38 .px_2()
39 .gap_2()
40 // Header
41 .child(
42 div()
43 .flex()
44 .justify_between()
45 .py_2()
46 .child(div().flex().child(Label::new("#design")))
47 .child(
48 div()
49 .flex()
50 .items_center()
51 .gap_px()
52 .child(IconButton::new(Icon::File))
53 .child(IconButton::new(Icon::AudioOn)),
54 ),
55 )
56 .child(
57 div()
58 .flex()
59 .flex_col()
60 // Chat Body
61 .child(
62 div()
63 .w_full()
64 .flex()
65 .flex_col()
66 .gap_3()
67 .overflow_y_scroll(self.scroll_state.clone())
68 .children(self.messages.clone()),
69 )
70 // Composer
71 .child(div().flex().my_2().child(Input::new("Message #design"))),
72 )
73 }
74}
75
76#[derive(Element, Clone)]
77pub struct ChatMessage {
78 author: String,
79 text: String,
80 sent_at: NaiveDateTime,
81}
82
83impl ChatMessage {
84 pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self {
85 Self {
86 author,
87 text,
88 sent_at,
89 }
90 }
91
92 fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
93 div()
94 .flex()
95 .flex_col()
96 .child(
97 div()
98 .flex()
99 .gap_2()
100 .child(Label::new(self.author.clone()))
101 .child(
102 Label::new(self.sent_at.format("%m/%d/%Y").to_string())
103 .color(LabelColor::Muted),
104 ),
105 )
106 .child(div().child(Label::new(self.text.clone())))
107 }
108}