chat_panel.rs

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