diff --git a/assets/icons/hamburger_15.svg b/assets/icons/hamburger_15.svg
new file mode 100644
index 0000000000..060caeecbf
--- /dev/null
+++ b/assets/icons/hamburger_15.svg
@@ -0,0 +1,3 @@
+
diff --git a/crates/ai/src/assistant.rs b/crates/ai/src/assistant.rs
index eff3b7b5b4..dac3d8dda0 100644
--- a/crates/ai/src/assistant.rs
+++ b/crates/ai/src/assistant.rs
@@ -30,6 +30,7 @@ use std::{
borrow::Cow, cell::RefCell, cmp, env, fmt::Write, io, iter, ops::Range, path::PathBuf, rc::Rc,
sync::Arc, time::Duration,
};
+use theme::{ui::IconStyle, IconButton, Theme};
use util::{
channel::ReleaseChannel, paths::CONVERSATIONS_DIR, post_inc, truncate_and_trailoff, ResultExt,
TryFutureExt,
@@ -259,6 +260,16 @@ impl AssistantPanel {
self.conversation_editors
.get(self.active_conversation_index)
}
+
+ fn render_hamburger_button(
+ &self,
+ style: &IconStyle,
+ cx: &ViewContext,
+ ) -> impl Element {
+ Svg::for_style(style.icon.clone())
+ .contained()
+ .with_style(style.container)
+ }
}
fn build_api_key_editor(cx: &mut ViewContext) -> ViewHandle {
@@ -282,7 +293,8 @@ impl View for AssistantPanel {
}
fn render(&mut self, cx: &mut ViewContext) -> AnyElement {
- let style = &theme::current(cx).assistant;
+ let theme = &theme::current(cx);
+ let style = &theme.assistant;
if let Some(api_key_editor) = self.api_key_editor.as_ref() {
Flex::column()
.with_child(
@@ -303,7 +315,17 @@ impl View for AssistantPanel {
.aligned()
.into_any()
} else if let Some(editor) = self.active_conversation_editor() {
- ChildView::new(editor, cx).into_any()
+ Flex::column()
+ .with_child(
+ Flex::row()
+ .with_child(self.render_hamburger_button(&style.hamburger_button, cx))
+ .contained()
+ .with_style(theme.workspace.tab_bar.container)
+ .constrained()
+ .with_height(theme.workspace.tab_bar.height),
+ )
+ .with_child(ChildView::new(editor, cx).flex(1., true))
+ .into_any()
} else {
Empty::new().into_any()
}
@@ -1401,7 +1423,7 @@ impl ConversationEditor {
.aligned()
.left()
.contained()
- .with_style(style.header)
+ .with_style(style.message_header)
.into_any()
}
}),
diff --git a/crates/gpui/src/elements/svg.rs b/crates/gpui/src/elements/svg.rs
index 5444221322..a6b4fab980 100644
--- a/crates/gpui/src/elements/svg.rs
+++ b/crates/gpui/src/elements/svg.rs
@@ -1,7 +1,5 @@
-use std::{borrow::Cow, ops::Range};
-
-use serde_json::json;
-
+use super::constrain_size_preserving_aspect_ratio;
+use crate::json::ToJson;
use crate::{
color::Color,
geometry::{
@@ -10,6 +8,9 @@ use crate::{
},
scene, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
};
+use serde_derive::Deserialize;
+use serde_json::json;
+use std::{borrow::Cow, ops::Range};
pub struct Svg {
path: Cow<'static, str>,
@@ -24,6 +25,15 @@ impl Svg {
}
}
+ pub fn for_style(style: SvgStyle) -> impl Element {
+ Self::new(style.asset)
+ .with_color(style.color)
+ .constrained()
+ .constrained()
+ .with_width(style.dimensions.width)
+ .with_height(style.dimensions.height)
+ }
+
pub fn with_color(mut self, color: Color) -> Self {
self.color = color;
self
@@ -105,9 +115,24 @@ impl Element for Svg {
}
}
-use crate::json::ToJson;
+#[derive(Clone, Deserialize, Default)]
+pub struct SvgStyle {
+ pub color: Color,
+ pub asset: String,
+ pub dimensions: Dimensions,
+}
-use super::constrain_size_preserving_aspect_ratio;
+#[derive(Clone, Deserialize, Default)]
+pub struct Dimensions {
+ pub width: f32,
+ pub height: f32,
+}
+
+impl Dimensions {
+ pub fn to_vec(&self) -> Vector2F {
+ vec2f(self.width, self.height)
+ }
+}
fn from_usvg_rect(rect: usvg::Rect) -> RectF {
RectF::new(
diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs
index c7563ec87a..38e66cbb4c 100644
--- a/crates/theme/src/theme.rs
+++ b/crates/theme/src/theme.rs
@@ -4,7 +4,7 @@ pub mod ui;
use gpui::{
color::Color,
- elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, TooltipStyle},
+ elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
fonts::{HighlightStyle, TextStyle},
platform, AppContext, AssetSource, Border, MouseState,
};
@@ -12,7 +12,7 @@ use serde::{de::DeserializeOwned, Deserialize};
use serde_json::Value;
use settings::SettingsStore;
use std::{collections::HashMap, sync::Arc};
-use ui::{ButtonStyle, CheckboxStyle, IconStyle, ModalStyle, SvgStyle};
+use ui::{ButtonStyle, CheckboxStyle, IconStyle, ModalStyle};
pub use theme_registry::*;
pub use theme_settings::*;
@@ -994,7 +994,8 @@ pub struct TerminalStyle {
#[derive(Clone, Deserialize, Default)]
pub struct AssistantStyle {
pub container: ContainerStyle,
- pub header: ContainerStyle,
+ pub hamburger_button: IconStyle,
+ pub message_header: ContainerStyle,
pub sent_at: ContainedText,
pub user_sender: Interactive,
pub assistant_sender: Interactive,
diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs
index b86bfca8c4..058123e53d 100644
--- a/crates/theme/src/ui.rs
+++ b/crates/theme/src/ui.rs
@@ -1,13 +1,12 @@
use std::borrow::Cow;
use gpui::{
- color::Color,
elements::{
- ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label,
- MouseEventHandler, ParentElement, Stack, Svg,
+ ConstrainedBox, Container, ContainerStyle, Dimensions, Empty, Flex, KeystrokeLabel, Label,
+ MouseEventHandler, ParentElement, Stack, Svg, SvgStyle,
},
fonts::TextStyle,
- geometry::vector::{vec2f, Vector2F},
+ geometry::vector::Vector2F,
platform,
platform::MouseButton,
scene::MouseClick,
@@ -93,25 +92,6 @@ where
.with_cursor_style(platform::CursorStyle::PointingHand)
}
-#[derive(Clone, Deserialize, Default)]
-pub struct SvgStyle {
- pub color: Color,
- pub asset: String,
- pub dimensions: Dimensions,
-}
-
-#[derive(Clone, Deserialize, Default)]
-pub struct Dimensions {
- pub width: f32,
- pub height: f32,
-}
-
-impl Dimensions {
- pub fn to_vec(&self) -> Vector2F {
- vec2f(self.width, self.height)
- }
-}
-
pub fn svg(style: &SvgStyle) -> ConstrainedBox {
Svg::new(style.asset.clone())
.with_color(style.color)
@@ -122,8 +102,8 @@ pub fn svg(style: &SvgStyle) -> ConstrainedBox {
#[derive(Clone, Deserialize, Default)]
pub struct IconStyle {
- icon: SvgStyle,
- container: ContainerStyle,
+ pub icon: SvgStyle,
+ pub container: ContainerStyle,
}
pub fn icon(style: &IconStyle) -> Container {
diff --git a/styles/src/styleTree/assistant.ts b/styles/src/styleTree/assistant.ts
index bbb4aae5e1..0f294dcc51 100644
--- a/styles/src/styleTree/assistant.ts
+++ b/styles/src/styleTree/assistant.ts
@@ -9,11 +9,22 @@ export default function assistant(colorScheme: ColorScheme) {
background: editor(colorScheme).background,
padding: { left: 12 },
},
- header: {
+ messageHeader: {
border: border(layer, "default", { bottom: true, top: true }),
margin: { bottom: 6, top: 6 },
background: editor(colorScheme).background,
},
+ hamburgerButton: {
+ icon: {
+ color: text(layer, "sans", "default", { size: "sm" }).color,
+ asset: "icons/hamburger.svg",
+ dimensions: {
+ width: 15,
+ height: 15,
+ },
+ },
+ container: {}
+ },
userSender: {
...text(layer, "sans", "default", { size: "sm", weight: "bold" }),
},