Add hover state to assistant buttons

This commit is contained in:
Antonio Scandurra 2023-06-26 17:48:43 +02:00
parent 723c8b98b3
commit e77abbf64f
3 changed files with 249 additions and 183 deletions

View file

@ -38,7 +38,7 @@ use std::{
sync::Arc, sync::Arc,
time::Duration, time::Duration,
}; };
use theme::{ui::IconStyle, AssistantStyle}; use theme::AssistantStyle;
use util::{channel::ReleaseChannel, paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt}; use util::{channel::ReleaseChannel, paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt};
use workspace::{ use workspace::{
dock::{DockPosition, Panel}, dock::{DockPosition, Panel},
@ -343,131 +343,140 @@ impl AssistantPanel {
self.editors.get(self.active_editor_index?) self.editors.get(self.active_editor_index?)
} }
fn render_hamburger_button(style: &IconStyle) -> impl Element<Self> { fn render_hamburger_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
enum ListConversations {} enum ListConversations {}
Svg::for_style(style.icon.clone()) let theme = theme::current(cx);
.contained() MouseEventHandler::<ListConversations, _>::new(0, cx, |state, _| {
.with_style(style.container) let style = theme.assistant.hamburger_button.style_for(state);
.mouse::<ListConversations>(0) Svg::for_style(style.icon.clone())
.with_cursor_style(CursorStyle::PointingHand) .contained()
.on_click(MouseButton::Left, |_, this: &mut Self, cx| { .with_style(style.container)
if this.active_editor().is_some() { })
this.set_active_editor_index(None, cx); .with_cursor_style(CursorStyle::PointingHand)
} else { .on_click(MouseButton::Left, |_, this: &mut Self, cx| {
this.set_active_editor_index(this.prev_active_editor_index, 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( fn render_editor_tools(&self, cx: &mut ViewContext<Self>) -> Vec<AnyElement<Self>> {
&self,
style: &AssistantStyle,
cx: &mut ViewContext<Self>,
) -> Vec<AnyElement<Self>> {
if self.active_editor().is_some() { if self.active_editor().is_some() {
vec![ vec![
Self::render_split_button(&style.split_button, cx).into_any(), Self::render_split_button(cx).into_any(),
Self::render_quote_button(&style.quote_button, cx).into_any(), Self::render_quote_button(cx).into_any(),
Self::render_assist_button(&style.assist_button, cx).into_any(), Self::render_assist_button(cx).into_any(),
] ]
} else { } else {
Default::default() Default::default()
} }
} }
fn render_split_button(style: &IconStyle, cx: &mut ViewContext<Self>) -> impl Element<Self> { fn render_split_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
let theme = theme::current(cx);
let tooltip_style = theme::current(cx).tooltip.clone(); let tooltip_style = theme::current(cx).tooltip.clone();
Svg::for_style(style.icon.clone()) MouseEventHandler::<Split, _>::new(0, cx, |state, _| {
.contained() let style = theme.assistant.split_button.style_for(state);
.with_style(style.container) Svg::for_style(style.icon.clone())
.mouse::<Split>(0) .contained()
.with_cursor_style(CursorStyle::PointingHand) .with_style(style.container)
.on_click(MouseButton::Left, |_, this: &mut Self, cx| { })
if let Some(active_editor) = this.active_editor() { .with_cursor_style(CursorStyle::PointingHand)
active_editor.update(cx, |editor, cx| editor.split(&Default::default(), cx)); .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::<Split>( }
1, })
"Split Message".into(), .with_tooltip::<Split>(
Some(Box::new(Split)), 1,
tooltip_style, "Split Message".into(),
cx, Some(Box::new(Split)),
) tooltip_style,
cx,
)
} }
fn render_assist_button(style: &IconStyle, cx: &mut ViewContext<Self>) -> impl Element<Self> { fn render_assist_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
let theme = theme::current(cx);
let tooltip_style = theme::current(cx).tooltip.clone(); let tooltip_style = theme::current(cx).tooltip.clone();
Svg::for_style(style.icon.clone()) MouseEventHandler::<Assist, _>::new(0, cx, |state, _| {
.contained() let style = theme.assistant.assist_button.style_for(state);
.with_style(style.container) Svg::for_style(style.icon.clone())
.mouse::<Assist>(0) .contained()
.with_cursor_style(CursorStyle::PointingHand) .with_style(style.container)
.on_click(MouseButton::Left, |_, this: &mut Self, cx| { })
if let Some(active_editor) = this.active_editor() { .with_cursor_style(CursorStyle::PointingHand)
active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx)); .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::<Assist>( }
1, })
"Assist".into(), .with_tooltip::<Assist>(
Some(Box::new(Assist)), 1,
tooltip_style, "Assist".into(),
cx, Some(Box::new(Assist)),
) tooltip_style,
cx,
)
} }
fn render_quote_button(style: &IconStyle, cx: &mut ViewContext<Self>) -> impl Element<Self> { fn render_quote_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
let theme = theme::current(cx);
let tooltip_style = theme::current(cx).tooltip.clone(); let tooltip_style = theme::current(cx).tooltip.clone();
Svg::for_style(style.icon.clone()) MouseEventHandler::<QuoteSelection, _>::new(0, cx, |state, _| {
.contained() let style = theme.assistant.quote_button.style_for(state);
.with_style(style.container) Svg::for_style(style.icon.clone())
.mouse::<QuoteSelection>(0) .contained()
.with_cursor_style(CursorStyle::PointingHand) .with_style(style.container)
.on_click(MouseButton::Left, |_, this: &mut Self, cx| { })
if let Some(workspace) = this.workspace.upgrade(cx) { .with_cursor_style(CursorStyle::PointingHand)
cx.window_context().defer(move |cx| { .on_click(MouseButton::Left, |_, this: &mut Self, cx| {
workspace.update(cx, |workspace, cx| { if let Some(workspace) = this.workspace.upgrade(cx) {
ConversationEditor::quote_selection(workspace, &Default::default(), cx) cx.window_context().defer(move |cx| {
}); workspace.update(cx, |workspace, cx| {
ConversationEditor::quote_selection(workspace, &Default::default(), cx)
}); });
} });
}) }
.with_tooltip::<QuoteSelection>( })
1, .with_tooltip::<QuoteSelection>(
"Assist".into(), 1,
Some(Box::new(QuoteSelection)), "Assist".into(),
tooltip_style, Some(Box::new(QuoteSelection)),
cx, tooltip_style,
) cx,
)
} }
fn render_plus_button(style: &IconStyle) -> impl Element<Self> { fn render_plus_button(cx: &mut ViewContext<Self>) -> impl Element<Self> {
enum AddConversation {} enum AddConversation {}
Svg::for_style(style.icon.clone()) let theme = theme::current(cx);
.contained() MouseEventHandler::<AddConversation, _>::new(0, cx, |state, _| {
.with_style(style.container) let style = theme.assistant.plus_button.style_for(state);
.mouse::<AddConversation>(0) Svg::for_style(style.icon.clone())
.with_cursor_style(CursorStyle::PointingHand) .contained()
.on_click(MouseButton::Left, |_, this: &mut Self, cx| { .with_style(style.container)
this.new_conversation(cx); })
}) .with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, |_, this: &mut Self, cx| {
this.new_conversation(cx);
})
} }
fn render_zoom_button( fn render_zoom_button(&self, cx: &mut ViewContext<Self>) -> impl Element<Self> {
&self,
style: &AssistantStyle,
cx: &mut ViewContext<Self>,
) -> impl Element<Self> {
enum ToggleZoomButton {} enum ToggleZoomButton {}
let theme = theme::current(cx);
let style = if self.zoomed { let style = if self.zoomed {
&style.zoom_out_button &theme.assistant.zoom_out_button
} else { } else {
&style.zoom_in_button &theme.assistant.zoom_in_button
}; };
MouseEventHandler::<ToggleZoomButton, _>::new(0, cx, |_, _| { MouseEventHandler::<ToggleZoomButton, _>::new(0, cx, |state, _| {
let style = style.style_for(state);
Svg::for_style(style.icon.clone()) Svg::for_style(style.icon.clone())
.contained() .contained()
.with_style(style.container) .with_style(style.container)
@ -605,21 +614,15 @@ impl View for AssistantPanel {
Flex::column() Flex::column()
.with_child( .with_child(
Flex::row() Flex::row()
.with_child( .with_child(Self::render_hamburger_button(cx).aligned())
Self::render_hamburger_button(&style.hamburger_button).aligned(),
)
.with_children(title) .with_children(title)
.with_children( .with_children(
self.render_editor_tools(&style, cx) self.render_editor_tools(cx)
.into_iter() .into_iter()
.map(|tool| tool.aligned().flex_float()), .map(|tool| tool.aligned().flex_float()),
) )
.with_child( .with_child(Self::render_plus_button(cx).aligned().flex_float())
Self::render_plus_button(&style.plus_button) .with_child(self.render_zoom_button(cx).aligned())
.aligned()
.flex_float(),
)
.with_child(self.render_zoom_button(&style, cx).aligned())
.contained() .contained()
.with_style(theme.workspace.tab_bar.container) .with_style(theme.workspace.tab_bar.container)
.expanded() .expanded()

View file

@ -993,13 +993,13 @@ pub struct TerminalStyle {
#[derive(Clone, Deserialize, Default, JsonSchema)] #[derive(Clone, Deserialize, Default, JsonSchema)]
pub struct AssistantStyle { pub struct AssistantStyle {
pub container: ContainerStyle, pub container: ContainerStyle,
pub hamburger_button: IconStyle, pub hamburger_button: Interactive<IconStyle>,
pub split_button: IconStyle, pub split_button: Interactive<IconStyle>,
pub assist_button: IconStyle, pub assist_button: Interactive<IconStyle>,
pub quote_button: IconStyle, pub quote_button: Interactive<IconStyle>,
pub zoom_in_button: IconStyle, pub zoom_in_button: Interactive<IconStyle>,
pub zoom_out_button: IconStyle, pub zoom_out_button: Interactive<IconStyle>,
pub plus_button: IconStyle, pub plus_button: Interactive<IconStyle>,
pub title: ContainedText, pub title: ContainedText,
pub message_header: ContainerStyle, pub message_header: ContainerStyle,
pub sent_at: ContainedText, pub sent_at: ContainedText,

View file

@ -15,97 +15,160 @@ export default function assistant(colorScheme: ColorScheme) {
margin: { bottom: 6, top: 6 }, margin: { bottom: 6, top: 6 },
background: editor(colorScheme).background, background: editor(colorScheme).background,
}, },
hamburgerButton: { hamburgerButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/hamburger_15.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/hamburger_15.svg",
width: 15, dimensions: {
height: 15, width: 15,
height: 15,
},
}, },
container: {
margin: { left: 12 },
}
}, },
container: { state: {
margin: { left: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
splitButton: { splitButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/split_message_15.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/split_message_15.svg",
width: 15, dimensions: {
height: 15, width: 15,
height: 15,
},
}, },
container: {
margin: { left: 12 },
}
}, },
container: { state: {
margin: { left: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
quoteButton: { quoteButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/quote_15.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/quote_15.svg",
width: 15, dimensions: {
height: 15, width: 15,
height: 15,
},
}, },
container: {
margin: { left: 12 },
}
}, },
container: { state: {
margin: { left: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
assistButton: { assistButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/assist_15.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/assist_15.svg",
width: 15, dimensions: {
height: 15, width: 15,
height: 15,
},
}, },
container: {
margin: { left: 12, right: 24 },
}
}, },
container: { state: {
margin: { left: 12, right: 24 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
zoomInButton: { zoomInButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/maximize_8.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/maximize_8.svg",
width: 12, dimensions: {
height: 12, width: 12,
height: 12,
},
}, },
container: {
margin: { right: 12 },
}
}, },
container: { state: {
margin: { right: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
zoomOutButton: { zoomOutButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/minimize_8.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/minimize_8.svg",
width: 12, dimensions: {
height: 12, width: 12,
height: 12,
},
}, },
container: {
margin: { right: 12 },
}
}, },
container: { state: {
margin: { right: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
plusButton: { plusButton: interactive({
icon: { base: {
color: text(layer, "sans", "default", { size: "sm" }).color, icon: {
asset: "icons/plus_12.svg", color: foreground(layer, "variant"),
dimensions: { asset: "icons/plus_12.svg",
width: 12, dimensions: {
height: 12, width: 12,
height: 12,
},
}, },
container: {
margin: { right: 12 },
}
}, },
container: { state: {
margin: { right: 12 }, hovered: {
icon: {
color: foreground(layer, "hovered")
}
}
} }
}, }),
title: { title: {
margin: { left: 12 }, margin: { left: 12 },
...text(layer, "sans", "default", { size: "sm" }) ...text(layer, "sans", "default", { size: "sm" })