chat_panel.rs

  1use chrono::NaiveDateTime;
  2
  3use crate::prelude::*;
  4use crate::{Icon, IconButton, Input, Label, LabelColor};
  5
  6#[derive(Component)]
  7pub struct ChatPanel {
  8    element_id: ElementId,
  9    messages: Vec<ChatMessage>,
 10}
 11
 12impl ChatPanel {
 13    pub fn new(element_id: impl Into<ElementId>) -> Self {
 14        Self {
 15            element_id: element_id.into(),
 16            messages: Vec::new(),
 17        }
 18    }
 19
 20    pub fn messages(mut self, messages: Vec<ChatMessage>) -> Self {
 21        self.messages = messages;
 22        self
 23    }
 24
 25    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 26        div()
 27            .id(self.element_id.clone())
 28            .flex()
 29            .flex_col()
 30            .justify_between()
 31            .h_full()
 32            .px_2()
 33            .gap_2()
 34            // Header
 35            .child(
 36                div()
 37                    .flex()
 38                    .justify_between()
 39                    .py_2()
 40                    .child(div().flex().child(Label::new("#design")))
 41                    .child(
 42                        div()
 43                            .flex()
 44                            .items_center()
 45                            .gap_px()
 46                            .child(IconButton::new("file", Icon::File))
 47                            .child(IconButton::new("audio_on", Icon::AudioOn)),
 48                    ),
 49            )
 50            .child(
 51                div()
 52                    .flex()
 53                    .flex_col()
 54                    // Chat Body
 55                    .child(
 56                        div()
 57                            .id("chat-body")
 58                            .w_full()
 59                            .flex()
 60                            .flex_col()
 61                            .gap_3()
 62                            .overflow_y_scroll()
 63                            .children(self.messages),
 64                    )
 65                    // Composer
 66                    .child(div().flex().my_2().child(Input::new("Message #design"))),
 67            )
 68    }
 69}
 70
 71#[derive(Component)]
 72pub struct ChatMessage {
 73    author: String,
 74    text: String,
 75    sent_at: NaiveDateTime,
 76}
 77
 78impl ChatMessage {
 79    pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self {
 80        Self {
 81            author,
 82            text,
 83            sent_at,
 84        }
 85    }
 86
 87    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 88        div()
 89            .flex()
 90            .flex_col()
 91            .child(
 92                div()
 93                    .flex()
 94                    .gap_2()
 95                    .child(Label::new(self.author.clone()))
 96                    .child(
 97                        Label::new(self.sent_at.format("%m/%d/%Y").to_string())
 98                            .color(LabelColor::Muted),
 99                    ),
100            )
101            .child(div().child(Label::new(self.text.clone())))
102    }
103}
104
105#[cfg(feature = "stories")]
106pub use stories::*;
107
108#[cfg(feature = "stories")]
109mod stories {
110    use chrono::DateTime;
111    use gpui2::{Div, Render};
112
113    use crate::{Panel, Story};
114
115    use super::*;
116
117    pub struct ChatPanelStory;
118
119    impl Render for ChatPanelStory {
120        type Element = Div<Self>;
121
122        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
123            Story::container(cx)
124                .child(Story::title_for::<_, ChatPanel>(cx))
125                .child(Story::label(cx, "Default"))
126                .child(
127                    Panel::new("chat-panel-1-outer", cx)
128                        .child(ChatPanel::new("chat-panel-1-inner")),
129                )
130                .child(Story::label(cx, "With Mesages"))
131                .child(Panel::new("chat-panel-2-outer", cx).child(
132                    ChatPanel::new("chat-panel-2-inner").messages(vec![
133                        ChatMessage::new(
134                            "osiewicz".to_string(),
135                            "is this thing on?".to_string(),
136                            DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
137                                .unwrap()
138                                .naive_local(),
139                        ),
140                        ChatMessage::new(
141                            "maxdeviant".to_string(),
142                            "Reading you loud and clear!".to_string(),
143                            DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
144                                .unwrap()
145                                .naive_local(),
146                        ),
147                    ]),
148                ))
149        }
150    }
151}