diff --git a/crates/assistant2/src/ui.rs b/crates/assistant2/src/ui.rs index cfe0e7bf2471e42b7e06c8962e39f983dcca3e05..25b367949e9fd560d273ba9a244c61a6742c78ea 100644 --- a/crates/assistant2/src/ui.rs +++ b/crates/assistant2/src/ui.rs @@ -1,10 +1,12 @@ mod chat_message; +mod chat_notice; mod composer; #[cfg(feature = "stories")] mod stories; pub use chat_message::*; +pub use chat_notice::*; pub use composer::*; #[cfg(feature = "stories")] diff --git a/crates/assistant2/src/ui/chat_message.rs b/crates/assistant2/src/ui/chat_message.rs index 816515d4175db1dcda588901efbae6ecc2fe29ac..ab269798970d29f0d572954dc05eea3be804a26b 100644 --- a/crates/assistant2/src/ui/chat_message.rs +++ b/crates/assistant2/src/ui/chat_message.rs @@ -118,7 +118,7 @@ impl RenderOnce for ChatMessageHeader { h_flex() .gap_3() .map(|this| { - let avatar_size = rems(20.0 / 16.0); + let avatar_size = rems_from_px(20.); if let Some(avatar_uri) = avatar_uri { this.child(Avatar::new(avatar_uri).size(avatar_size)) } else { diff --git a/crates/assistant2/src/ui/chat_notice.rs b/crates/assistant2/src/ui/chat_notice.rs new file mode 100644 index 0000000000000000000000000000000000000000..5001d2d23e8a00ec857b180fa1c133842274e5de --- /dev/null +++ b/crates/assistant2/src/ui/chat_notice.rs @@ -0,0 +1,71 @@ +use ui::{prelude::*, Avatar, IconButtonShape}; + +#[derive(IntoElement)] +pub struct ChatNotice { + message: SharedString, + meta: Option, +} + +impl ChatNotice { + pub fn new(message: impl Into) -> Self { + Self { + message: message.into(), + meta: None, + } + } + + pub fn meta(mut self, meta: impl Into) -> Self { + self.meta = Some(meta.into()); + self + } +} + +impl RenderOnce for ChatNotice { + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + h_flex() + .w_full() + .items_start() + .mt_4() + .gap_3() + .child( + // TODO: Replace with question mark. + Avatar::new("https://zed.dev/assistant_avatar.png").size(rems_from_px(20.)), + ) + .child( + v_flex() + .size_full() + .gap_1() + .pr_4() + .overflow_hidden() + .child( + h_flex() + .justify_between() + .overflow_hidden() + .child( + h_flex() + .flex_none() + .overflow_hidden() + .child(Label::new(self.message)), + ) + .child( + h_flex() + .flex_shrink_0() + .gap_1() + .child(Button::new("allow", "Allow")) + .child( + IconButton::new("deny", IconName::Close) + .shape(IconButtonShape::Square) + .icon_color(Color::Muted) + .size(ButtonSize::None) + .icon_size(IconSize::XSmall), + ), + ), + ) + .children( + self.meta.map(|meta| { + Label::new(meta).size(LabelSize::Small).color(Color::Muted) + }), + ), + ) + } +} diff --git a/crates/assistant2/src/ui/composer.rs b/crates/assistant2/src/ui/composer.rs index a0da37f21f523ff3e89ec95118e75bc59af618c4..7e07be4c309e17cd11226961be25e3a5e6200e55 100644 --- a/crates/assistant2/src/ui/composer.rs +++ b/crates/assistant2/src/ui/composer.rs @@ -38,10 +38,10 @@ impl Composer { impl RenderOnce for Composer { fn render(self, cx: &mut WindowContext) -> impl IntoElement { - let mut player_avatar = div().size(rems(20.0 / 16.0)).into_any_element(); + let mut player_avatar = div().size(rems_from_px(20.)).into_any_element(); if let Some(player) = self.player.clone() { player_avatar = Avatar::new(player.avatar_uri.clone()) - .size(rems(20.0 / 16.0)) + .size(rems_from_px(20.)) .into_any_element(); } diff --git a/crates/assistant2/src/ui/stories.rs b/crates/assistant2/src/ui/stories.rs index 2aca1f06760edd6381957744d4dc89345b4706c3..8bc2b30d662471b49a2db2c4f5cb5d4b223ca4b1 100644 --- a/crates/assistant2/src/ui/stories.rs +++ b/crates/assistant2/src/ui/stories.rs @@ -1,3 +1,5 @@ mod chat_message; +mod chat_notice; pub use chat_message::*; +pub use chat_notice::*; diff --git a/crates/assistant2/src/ui/stories/chat_notice.rs b/crates/assistant2/src/ui/stories/chat_notice.rs new file mode 100644 index 0000000000000000000000000000000000000000..ad8eef92c73cbcbb03965d8353bf4e59ac13693f --- /dev/null +++ b/crates/assistant2/src/ui/stories/chat_notice.rs @@ -0,0 +1,22 @@ +use story::{StoryContainer, StoryItem, StorySection}; +use ui::prelude::*; + +use crate::ui::ChatNotice; + +pub struct ChatNoticeStory; + +impl Render for ChatNoticeStory { + fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + StoryContainer::new( + "ChatNotice Story", + "crates/assistant2/src/ui/stories/chat_notice.rs", + ) + .child( + StorySection::new().child(StoryItem::new( + "Project index request", + ChatNotice::new("Allow assistant to index your project?") + .meta("Enabling will allow responses more relevant to this project."), + )), + ) + } +} diff --git a/crates/storybook/src/story_selector.rs b/crates/storybook/src/story_selector.rs index 5087295ca9b101e735de2752ee59ea52b2dfcee8..b4b20b9087dd366cfbc60bcb3418b64255d1f202 100644 --- a/crates/storybook/src/story_selector.rs +++ b/crates/storybook/src/story_selector.rs @@ -13,6 +13,7 @@ use ui::prelude::*; #[strum(serialize_all = "snake_case")] pub enum ComponentStory { AssistantChatMessage, + AssistantChatNotice, AutoHeightEditor, Avatar, Button, @@ -46,6 +47,7 @@ impl ComponentStory { Self::AssistantChatMessage => { cx.new_view(|_cx| assistant2::ui::ChatMessageStory).into() } + Self::AssistantChatNotice => cx.new_view(|_cx| assistant2::ui::ChatNoticeStory).into(), Self::AutoHeightEditor => AutoHeightEditorStory::new(cx).into(), Self::Avatar => cx.new_view(|_| ui::AvatarStory).into(), Self::Button => cx.new_view(|_| ui::ButtonStory).into(),