chat_panel.rs

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