chat_panel.rs

  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}