WIP: Trying to display the toolbar but tired. May be worth discarding this.

Nathan Sobo created

Change summary

assets/icons/hamburger_15.svg     |  3 ++
crates/ai/src/assistant.rs        | 28 ++++++++++++++++++++++--
crates/gpui/src/elements/svg.rs   | 37 +++++++++++++++++++++++++++-----
crates/theme/src/theme.rs         |  7 +++--
crates/theme/src/ui.rs            | 30 ++++----------------------
styles/src/styleTree/assistant.ts | 13 ++++++++++
6 files changed, 80 insertions(+), 38 deletions(-)

Detailed changes

assets/icons/hamburger_15.svg 🔗

@@ -0,0 +1,3 @@
+<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 3C1.22386 3 1 3.22386 1 3.5C1 3.77614 1.22386 4 1.5 4H13.5C13.7761 4 14 3.77614 14 3.5C14 3.22386 13.7761 3 13.5 3H1.5ZM1 7.5C1 7.22386 1.22386 7 1.5 7H13.5C13.7761 7 14 7.22386 14 7.5C14 7.77614 13.7761 8 13.5 8H1.5C1.22386 8 1 7.77614 1 7.5ZM1 11.5C1 11.2239 1.22386 11 1.5 11H13.5C13.7761 11 14 11.2239 14 11.5C14 11.7761 13.7761 12 13.5 12H1.5C1.22386 12 1 11.7761 1 11.5Z" fill="#CCCAC2"/>
+</svg>

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<Self>,
+    ) -> impl Element<Self> {
+        Svg::for_style(style.icon.clone())
+            .contained()
+            .with_style(style.container)
+    }
 }
 
 fn build_api_key_editor(cx: &mut ViewContext<AssistantPanel>) -> ViewHandle<Editor> {
@@ -282,7 +293,8 @@ impl View for AssistantPanel {
     }
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        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()
                         }
                     }),

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<V: View>(style: SvgStyle) -> impl Element<V> {
+        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<V: View> Element<V> 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(

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<ContainedText>,
     pub assistant_sender: Interactive<ContainedText>,

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<V: View>(style: &SvgStyle) -> ConstrainedBox<V> {
     Svg::new(style.asset.clone())
         .with_color(style.color)
@@ -122,8 +102,8 @@ pub fn svg<V: View>(style: &SvgStyle) -> ConstrainedBox<V> {
 
 #[derive(Clone, Deserialize, Default)]
 pub struct IconStyle {
-    icon: SvgStyle,
-    container: ContainerStyle,
+    pub icon: SvgStyle,
+    pub container: ContainerStyle,
 }
 
 pub fn icon<V: View>(style: &IconStyle) -> Container<V> {

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" }),
         },