Add hover state to assistant buttons
This commit is contained in:
parent
723c8b98b3
commit
e77abbf64f
3 changed files with 249 additions and 183 deletions
|
@ -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()
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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" })
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue