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