From e77abbf64f3d5f0309f6f149f333d8dbcb2b4c3d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 26 Jun 2023 17:48:43 +0200 Subject: [PATCH] Add hover state to assistant buttons --- crates/ai/src/assistant.rs | 215 +++++++++++++++--------------- crates/theme/src/theme.rs | 14 +- styles/src/styleTree/assistant.ts | 203 ++++++++++++++++++---------- 3 files changed, 249 insertions(+), 183 deletions(-) diff --git a/crates/ai/src/assistant.rs b/crates/ai/src/assistant.rs index 78ab13fbb1..2d3c21ba31 100644 --- a/crates/ai/src/assistant.rs +++ b/crates/ai/src/assistant.rs @@ -38,7 +38,7 @@ use std::{ sync::Arc, time::Duration, }; -use theme::{ui::IconStyle, AssistantStyle}; +use theme::AssistantStyle; use util::{channel::ReleaseChannel, paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt}; use workspace::{ dock::{DockPosition, Panel}, @@ -343,131 +343,140 @@ impl AssistantPanel { self.editors.get(self.active_editor_index?) } - fn render_hamburger_button(style: &IconStyle) -> impl Element { + fn render_hamburger_button(cx: &mut ViewContext) -> impl Element { enum ListConversations {} - Svg::for_style(style.icon.clone()) - .contained() - .with_style(style.container) - .mouse::(0) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this: &mut Self, cx| { - if this.active_editor().is_some() { - this.set_active_editor_index(None, cx); - } else { - this.set_active_editor_index(this.prev_active_editor_index, cx); - } - }) + let theme = theme::current(cx); + MouseEventHandler::::new(0, cx, |state, _| { + let style = theme.assistant.hamburger_button.style_for(state); + Svg::for_style(style.icon.clone()) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, this: &mut Self, cx| { + if this.active_editor().is_some() { + this.set_active_editor_index(None, cx); + } else { + this.set_active_editor_index(this.prev_active_editor_index, cx); + } + }) } - fn render_editor_tools( - &self, - style: &AssistantStyle, - cx: &mut ViewContext, - ) -> Vec> { + fn render_editor_tools(&self, cx: &mut ViewContext) -> Vec> { if self.active_editor().is_some() { vec![ - Self::render_split_button(&style.split_button, cx).into_any(), - Self::render_quote_button(&style.quote_button, cx).into_any(), - Self::render_assist_button(&style.assist_button, cx).into_any(), + Self::render_split_button(cx).into_any(), + Self::render_quote_button(cx).into_any(), + Self::render_assist_button(cx).into_any(), ] } else { Default::default() } } - fn render_split_button(style: &IconStyle, cx: &mut ViewContext) -> impl Element { + fn render_split_button(cx: &mut ViewContext) -> impl Element { + let theme = theme::current(cx); let tooltip_style = theme::current(cx).tooltip.clone(); - Svg::for_style(style.icon.clone()) - .contained() - .with_style(style.container) - .mouse::(0) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this: &mut Self, cx| { - if let Some(active_editor) = this.active_editor() { - active_editor.update(cx, |editor, cx| editor.split(&Default::default(), cx)); - } - }) - .with_tooltip::( - 1, - "Split Message".into(), - Some(Box::new(Split)), - tooltip_style, - cx, - ) + MouseEventHandler::::new(0, cx, |state, _| { + let style = theme.assistant.split_button.style_for(state); + Svg::for_style(style.icon.clone()) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, this: &mut Self, cx| { + if let Some(active_editor) = this.active_editor() { + active_editor.update(cx, |editor, cx| editor.split(&Default::default(), cx)); + } + }) + .with_tooltip::( + 1, + "Split Message".into(), + Some(Box::new(Split)), + tooltip_style, + cx, + ) } - fn render_assist_button(style: &IconStyle, cx: &mut ViewContext) -> impl Element { + fn render_assist_button(cx: &mut ViewContext) -> impl Element { + let theme = theme::current(cx); let tooltip_style = theme::current(cx).tooltip.clone(); - Svg::for_style(style.icon.clone()) - .contained() - .with_style(style.container) - .mouse::(0) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this: &mut Self, cx| { - if let Some(active_editor) = this.active_editor() { - active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx)); - } - }) - .with_tooltip::( - 1, - "Assist".into(), - Some(Box::new(Assist)), - tooltip_style, - cx, - ) + MouseEventHandler::::new(0, cx, |state, _| { + let style = theme.assistant.assist_button.style_for(state); + Svg::for_style(style.icon.clone()) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, this: &mut Self, cx| { + if let Some(active_editor) = this.active_editor() { + active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx)); + } + }) + .with_tooltip::( + 1, + "Assist".into(), + Some(Box::new(Assist)), + tooltip_style, + cx, + ) } - fn render_quote_button(style: &IconStyle, cx: &mut ViewContext) -> impl Element { + fn render_quote_button(cx: &mut ViewContext) -> impl Element { + let theme = theme::current(cx); let tooltip_style = theme::current(cx).tooltip.clone(); - Svg::for_style(style.icon.clone()) - .contained() - .with_style(style.container) - .mouse::(0) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this: &mut Self, cx| { - if let Some(workspace) = this.workspace.upgrade(cx) { - cx.window_context().defer(move |cx| { - workspace.update(cx, |workspace, cx| { - ConversationEditor::quote_selection(workspace, &Default::default(), cx) - }); + MouseEventHandler::::new(0, cx, |state, _| { + let style = theme.assistant.quote_button.style_for(state); + Svg::for_style(style.icon.clone()) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, this: &mut Self, cx| { + if let Some(workspace) = this.workspace.upgrade(cx) { + cx.window_context().defer(move |cx| { + workspace.update(cx, |workspace, cx| { + ConversationEditor::quote_selection(workspace, &Default::default(), cx) }); - } - }) - .with_tooltip::( - 1, - "Assist".into(), - Some(Box::new(QuoteSelection)), - tooltip_style, - cx, - ) + }); + } + }) + .with_tooltip::( + 1, + "Assist".into(), + Some(Box::new(QuoteSelection)), + tooltip_style, + cx, + ) } - fn render_plus_button(style: &IconStyle) -> impl Element { + fn render_plus_button(cx: &mut ViewContext) -> impl Element { enum AddConversation {} - Svg::for_style(style.icon.clone()) - .contained() - .with_style(style.container) - .mouse::(0) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, this: &mut Self, cx| { - this.new_conversation(cx); - }) + let theme = theme::current(cx); + MouseEventHandler::::new(0, cx, |state, _| { + let style = theme.assistant.plus_button.style_for(state); + Svg::for_style(style.icon.clone()) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, this: &mut Self, cx| { + this.new_conversation(cx); + }) } - fn render_zoom_button( - &self, - style: &AssistantStyle, - cx: &mut ViewContext, - ) -> impl Element { + fn render_zoom_button(&self, cx: &mut ViewContext) -> impl Element { enum ToggleZoomButton {} + let theme = theme::current(cx); let style = if self.zoomed { - &style.zoom_out_button + &theme.assistant.zoom_out_button } else { - &style.zoom_in_button + &theme.assistant.zoom_in_button }; - MouseEventHandler::::new(0, cx, |_, _| { + MouseEventHandler::::new(0, cx, |state, _| { + let style = style.style_for(state); Svg::for_style(style.icon.clone()) .contained() .with_style(style.container) @@ -605,21 +614,15 @@ impl View for AssistantPanel { Flex::column() .with_child( Flex::row() - .with_child( - Self::render_hamburger_button(&style.hamburger_button).aligned(), - ) + .with_child(Self::render_hamburger_button(cx).aligned()) .with_children(title) .with_children( - self.render_editor_tools(&style, cx) + self.render_editor_tools(cx) .into_iter() .map(|tool| tool.aligned().flex_float()), ) - .with_child( - Self::render_plus_button(&style.plus_button) - .aligned() - .flex_float(), - ) - .with_child(self.render_zoom_button(&style, cx).aligned()) + .with_child(Self::render_plus_button(cx).aligned().flex_float()) + .with_child(self.render_zoom_button(cx).aligned()) .contained() .with_style(theme.workspace.tab_bar.container) .expanded() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index e828f8ba97..f93063be2e 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -993,13 +993,13 @@ pub struct TerminalStyle { #[derive(Clone, Deserialize, Default, JsonSchema)] pub struct AssistantStyle { pub container: ContainerStyle, - pub hamburger_button: IconStyle, - pub split_button: IconStyle, - pub assist_button: IconStyle, - pub quote_button: IconStyle, - pub zoom_in_button: IconStyle, - pub zoom_out_button: IconStyle, - pub plus_button: IconStyle, + pub hamburger_button: Interactive, + pub split_button: Interactive, + pub assist_button: Interactive, + pub quote_button: Interactive, + pub zoom_in_button: Interactive, + pub zoom_out_button: Interactive, + pub plus_button: Interactive, pub title: ContainedText, pub message_header: ContainerStyle, pub sent_at: ContainedText, diff --git a/styles/src/styleTree/assistant.ts b/styles/src/styleTree/assistant.ts index db3f419b14..91b52f20ad 100644 --- a/styles/src/styleTree/assistant.ts +++ b/styles/src/styleTree/assistant.ts @@ -15,97 +15,160 @@ export default function assistant(colorScheme: ColorScheme) { margin: { bottom: 6, top: 6 }, background: editor(colorScheme).background, }, - hamburgerButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/hamburger_15.svg", - dimensions: { - width: 15, - height: 15, + hamburgerButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/hamburger_15.svg", + dimensions: { + width: 15, + height: 15, + }, }, + container: { + margin: { left: 12 }, + } }, - container: { - margin: { left: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - splitButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/split_message_15.svg", - dimensions: { - width: 15, - height: 15, + }), + splitButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/split_message_15.svg", + dimensions: { + width: 15, + height: 15, + }, }, + container: { + margin: { left: 12 }, + } }, - container: { - margin: { left: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - quoteButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/quote_15.svg", - dimensions: { - width: 15, - height: 15, + }), + quoteButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/quote_15.svg", + dimensions: { + width: 15, + height: 15, + }, }, + container: { + margin: { left: 12 }, + } }, - container: { - margin: { left: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - assistButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/assist_15.svg", - dimensions: { - width: 15, - height: 15, + }), + assistButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/assist_15.svg", + dimensions: { + width: 15, + height: 15, + }, }, + container: { + margin: { left: 12, right: 24 }, + } }, - container: { - margin: { left: 12, right: 24 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - zoomInButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/maximize_8.svg", - dimensions: { - width: 12, - height: 12, + }), + zoomInButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/maximize_8.svg", + dimensions: { + width: 12, + height: 12, + }, }, + container: { + margin: { right: 12 }, + } }, - container: { - margin: { right: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - zoomOutButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/minimize_8.svg", - dimensions: { - width: 12, - height: 12, + }), + zoomOutButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/minimize_8.svg", + dimensions: { + width: 12, + height: 12, + }, }, + container: { + margin: { right: 12 }, + } }, - container: { - margin: { right: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, - plusButton: { - icon: { - color: text(layer, "sans", "default", { size: "sm" }).color, - asset: "icons/plus_12.svg", - dimensions: { - width: 12, - height: 12, + }), + plusButton: interactive({ + base: { + icon: { + color: foreground(layer, "variant"), + asset: "icons/plus_12.svg", + dimensions: { + width: 12, + height: 12, + }, }, + container: { + margin: { right: 12 }, + } }, - container: { - margin: { right: 12 }, + state: { + hovered: { + icon: { + color: foreground(layer, "hovered") + } + } } - }, + }), title: { margin: { left: 12 }, ...text(layer, "sans", "default", { size: "sm" })