Mainline GPUI2 UI work (#3062)

This PR mainlines the current state of new GPUI2-based UI from the
`gpui2-ui` branch.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Nate <nate@zed.dev>
Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Marshall Bowers 2023-09-28 19:36:21 -04:00 committed by GitHub
parent e7ee8a95f6
commit f26ca0866c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
85 changed files with 4658 additions and 1623 deletions

View file

@ -1,66 +1,127 @@
use std::marker::PhantomData;
use gpui2::elements::div::ScrollState;
use gpui2::style::StyleHelpers;
use gpui2::{elements::div, IntoElement};
use gpui2::{Element, ParentElement, ViewContext};
use chrono::NaiveDateTime;
use crate::prelude::*;
use crate::theme::theme;
use crate::{icon_button, IconAsset};
use crate::{Icon, IconButton, Input, Label, LabelColor, Panel, PanelSide};
#[derive(Element)]
pub struct ChatPanel<V: 'static> {
view_type: PhantomData<V>,
scroll_state: ScrollState,
}
pub fn chat_panel<V: 'static>(scroll_state: ScrollState) -> ChatPanel<V> {
ChatPanel {
view_type: PhantomData,
scroll_state,
}
current_side: PanelSide,
messages: Vec<ChatMessage>,
}
impl<V: 'static> ChatPanel<V> {
pub fn new(scroll_state: ScrollState) -> Self {
Self {
view_type: PhantomData,
scroll_state,
current_side: PanelSide::default(),
messages: Vec::new(),
}
}
pub fn side(mut self, side: PanelSide) -> Self {
self.current_side = side;
self
}
pub fn with_messages(mut self, messages: Vec<ChatMessage>) -> Self {
self.messages = messages;
self
}
fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
let theme = theme(cx);
div()
.h_full()
.flex()
// Header
.child(
div()
.px_2()
.flex()
.gap_2()
// Nav Buttons
.child("#gpui2"),
)
// Chat Body
.child(
div()
.w_full()
struct PanelPayload {
pub scroll_state: ScrollState,
pub messages: Vec<ChatMessage>,
}
Panel::new(
self.scroll_state.clone(),
|_, payload| {
let payload = payload.downcast_ref::<PanelPayload>().unwrap();
vec![div()
.flex()
.flex_col()
.overflow_y_scroll(self.scroll_state.clone())
.child("body"),
)
// Composer
.child(
div()
.h_full()
.px_2()
.flex()
.gap_2()
// Nav Buttons
// Header
.child(
div()
.flex()
.items_center()
.gap_px()
.child(icon_button().icon(IconAsset::Plus))
.child(icon_button().icon(IconAsset::Split)),
),
)
.justify_between()
.gap_2()
.child(div().flex().child(Label::new("#design")))
.child(
div()
.flex()
.items_center()
.gap_px()
.child(IconButton::new(Icon::File))
.child(IconButton::new(Icon::AudioOn)),
),
)
// Chat Body
.child(
div()
.w_full()
.flex()
.flex_col()
.gap_3()
.overflow_y_scroll(payload.scroll_state.clone())
.children(payload.messages.clone()),
)
// Composer
.child(div().flex().gap_2().child(Input::new("Message #design")))
.into_any()]
},
Box::new(PanelPayload {
scroll_state: self.scroll_state.clone(),
messages: self.messages.clone(),
}),
)
.side(self.current_side)
}
}
#[derive(Element, Clone)]
pub struct ChatMessage {
author: String,
text: String,
sent_at: NaiveDateTime,
}
impl ChatMessage {
pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self {
Self {
author,
text,
sent_at,
}
}
fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
div()
.flex()
.flex_col()
.child(
div()
.flex()
.gap_2()
.child(Label::new(self.author.clone()))
.child(
Label::new(self.sent_at.format("%m/%d/%Y").to_string())
.color(LabelColor::Muted),
),
)
.child(div().child(Label::new(self.text.clone())))
}
}