Update assistant styles (#2665)
Updates the assistant with some style quality of life changes. ## Changes Restyled the conversation list <img width="646" alt="CleanShot 2023-07-10 at 10 25 23@2x" src="https://github.com/zed-industries/zed/assets/1714999/5c9a4f94-11c1-4d28-8aac-4d38141829a9"> Updated the assistant header to be a bit more compact, and use a new tab bar icon style. The existing tab bar icons will be updated in a later PR. <img width="646" alt="CleanShot 2023-07-10 at 10 26 30@2x" src="https://github.com/zed-industries/zed/assets/1714999/3ef9a053-59fa-4d34-9b76-3bb2701acb33"> Updated the remaining token indicator to have 3 steps: <img width="662" alt="CleanShot 2023-07-10 at 10 29 51@2x" src="https://github.com/zed-industries/zed/assets/1714999/13d31545-5b00-427c-b7da-b4dfeac037d6"> Updated role labels, added a hover state to make it more clear these are interactive <img width="984" alt="CleanShot 2023-07-10 at 10 32 28@2x" src="https://github.com/zed-industries/zed/assets/1714999/24748495-dde4-4ee9-98f1-6a082f0c1d4d"> Release Notes: - Improved the UI of some elements in the Assistant panel.
This commit is contained in:
commit
6739c31594
7 changed files with 163 additions and 199 deletions
4
assets/icons/radix/maximize.svg
Normal file
4
assets/icons/radix/maximize.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.5 1.5H13.5M13.5 1.5V5.5M13.5 1.5C12.1332 2.86683 10.3668 4.63317 9 6" stroke="white" stroke-linecap="round"/>
|
||||||
|
<path d="M1.5 9.5V13.5M1.5 13.5L6 9M1.5 13.5H5.5" stroke="white" stroke-linecap="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 315 B |
4
assets/icons/radix/minimize.svg
Normal file
4
assets/icons/radix/minimize.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13 6L9 6M9 6L9 2M9 6C10.3668 4.63316 12.1332 2.86683 13.5 1.5" stroke="white" stroke-linecap="round"/>
|
||||||
|
<path d="M6 13L6 9M6 9L1.5 13.5M6 9L2 9" stroke="white" stroke-linecap="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 297 B |
|
@ -2061,6 +2061,8 @@ impl ConversationEditor {
|
||||||
let remaining_tokens = self.conversation.read(cx).remaining_tokens()?;
|
let remaining_tokens = self.conversation.read(cx).remaining_tokens()?;
|
||||||
let remaining_tokens_style = if remaining_tokens <= 0 {
|
let remaining_tokens_style = if remaining_tokens <= 0 {
|
||||||
&style.no_remaining_tokens
|
&style.no_remaining_tokens
|
||||||
|
} else if remaining_tokens <= 500 {
|
||||||
|
&style.low_remaining_tokens
|
||||||
} else {
|
} else {
|
||||||
&style.remaining_tokens
|
&style.remaining_tokens
|
||||||
};
|
};
|
||||||
|
|
|
@ -1030,6 +1030,7 @@ pub struct AssistantStyle {
|
||||||
pub system_sender: Interactive<ContainedText>,
|
pub system_sender: Interactive<ContainedText>,
|
||||||
pub model: Interactive<ContainedText>,
|
pub model: Interactive<ContainedText>,
|
||||||
pub remaining_tokens: ContainedText,
|
pub remaining_tokens: ContainedText,
|
||||||
|
pub low_remaining_tokens: ContainedText,
|
||||||
pub no_remaining_tokens: ContainedText,
|
pub no_remaining_tokens: ContainedText,
|
||||||
pub error_icon: Icon,
|
pub error_icon: Icon,
|
||||||
pub api_key_editor: FieldEditor,
|
pub api_key_editor: FieldEditor,
|
||||||
|
|
55
styles/src/component/tab_bar_button.ts
Normal file
55
styles/src/component/tab_bar_button.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { Theme, StyleSets } from "../common"
|
||||||
|
import { interactive } from "../element"
|
||||||
|
import { InteractiveState } from "../element/interactive"
|
||||||
|
import { background, foreground } from "../style_tree/components"
|
||||||
|
|
||||||
|
interface TabBarButtonOptions {
|
||||||
|
icon: string
|
||||||
|
color?: StyleSets
|
||||||
|
}
|
||||||
|
|
||||||
|
type TabBarButtonProps = TabBarButtonOptions & {
|
||||||
|
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tab_bar_button(theme: Theme, { icon, color = "base" }: TabBarButtonProps) {
|
||||||
|
const button_spacing = 8
|
||||||
|
|
||||||
|
return (
|
||||||
|
interactive({
|
||||||
|
base: {
|
||||||
|
icon: {
|
||||||
|
color: foreground(theme.middle, color),
|
||||||
|
asset: icon,
|
||||||
|
dimensions: {
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
corner_radius: 4,
|
||||||
|
padding: {
|
||||||
|
top: 4, bottom: 4, left: 4, right: 4
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
left: button_spacing / 2,
|
||||||
|
right: button_spacing / 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
hovered: {
|
||||||
|
container: {
|
||||||
|
background: background(theme.middle, color, "hovered"),
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clicked: {
|
||||||
|
container: {
|
||||||
|
background: background(theme.middle, color, "pressed"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,233 +1,133 @@
|
||||||
import { text, border, background, foreground } from "./components"
|
import { text, border, background, foreground, TextStyle } from "./components"
|
||||||
import { interactive } from "../element"
|
import { Interactive, interactive } from "../element"
|
||||||
import { useTheme } from "../theme"
|
import { tab_bar_button } from "../component/tab_bar_button"
|
||||||
|
import { StyleSets, useTheme } from "../theme"
|
||||||
|
|
||||||
|
type RoleCycleButton = TextStyle & {
|
||||||
|
background?: string
|
||||||
|
}
|
||||||
|
// TODO: Replace these with zed types
|
||||||
|
type RemainingTokens = TextStyle & {
|
||||||
|
background: string,
|
||||||
|
margin: { top: number, right: number },
|
||||||
|
padding: {
|
||||||
|
right: number,
|
||||||
|
left: number,
|
||||||
|
top: number,
|
||||||
|
bottom: number,
|
||||||
|
},
|
||||||
|
corner_radius: number,
|
||||||
|
}
|
||||||
|
|
||||||
export default function assistant(): any {
|
export default function assistant(): any {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
|
||||||
|
const interactive_role = (color: StyleSets): Interactive<RoleCycleButton> => {
|
||||||
|
return (
|
||||||
|
interactive({
|
||||||
|
base: {
|
||||||
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
hovered: {
|
||||||
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
|
background: background(theme.highest, color, "hovered"),
|
||||||
|
},
|
||||||
|
clicked: {
|
||||||
|
...text(theme.highest, "sans", color, { size: "sm" }),
|
||||||
|
background: background(theme.highest, color, "pressed"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokens_remaining = (color: StyleSets): RemainingTokens => {
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
...text(theme.highest, "mono", color, { size: "xs" }),
|
||||||
|
background: background(theme.highest, "on", "default"),
|
||||||
|
margin: { top: 12, right: 20 },
|
||||||
|
padding: { right: 4, left: 4, top: 1, bottom: 1 },
|
||||||
|
corner_radius: 6,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
background: background(theme.highest),
|
background: background(theme.highest),
|
||||||
padding: { left: 12 },
|
padding: { left: 12 },
|
||||||
},
|
},
|
||||||
message_header: {
|
message_header: {
|
||||||
margin: { bottom: 6, top: 6 },
|
margin: { bottom: 4, top: 4 },
|
||||||
background: background(theme.highest),
|
background: background(theme.highest),
|
||||||
},
|
},
|
||||||
hamburger_button: interactive({
|
hamburger_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/hamburger_15.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/hamburger_15.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 12, right: 8.5 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
split_button: interactive({
|
|
||||||
base: {
|
split_button: tab_bar_button(theme, {
|
||||||
icon: {
|
icon: "icons/split_message_15.svg",
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/split_message_15.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 8.5, right: 8.5 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
quote_button: interactive({
|
quote_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/radix/quote.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/quote_15.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 8.5, right: 8.5 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
assist_button: interactive({
|
assist_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/radix/magic-wand.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/assist_15.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 15,
|
|
||||||
height: 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 8.5, right: 8.5 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
zoom_in_button: interactive({
|
zoom_in_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/radix/maximize.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/maximize_8.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 10, right: 10 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
zoom_out_button: interactive({
|
zoom_out_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/radix/minimize.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/minimize_8.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 10, right: 10 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
plus_button: interactive({
|
plus_button: tab_bar_button(theme, {
|
||||||
base: {
|
icon: "icons/radix/plus.svg",
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "variant"),
|
|
||||||
asset: "icons/plus_12.svg",
|
|
||||||
dimensions: {
|
|
||||||
width: 12,
|
|
||||||
height: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
padding: { left: 10, right: 10 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
hovered: {
|
|
||||||
icon: {
|
|
||||||
color: foreground(theme.highest, "hovered"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
title: {
|
title: {
|
||||||
...text(theme.highest, "sans", "default", { size: "sm" }),
|
...text(theme.highest, "sans", "default", { size: "xs" }),
|
||||||
},
|
},
|
||||||
saved_conversation: {
|
saved_conversation: {
|
||||||
container: interactive({
|
container: interactive({
|
||||||
base: {
|
base: {
|
||||||
background: background(theme.highest, "on"),
|
background: background(theme.middle),
|
||||||
padding: { top: 4, bottom: 4 },
|
padding: { top: 4, bottom: 4 },
|
||||||
|
border: border(theme.middle, "default", { top: true, overlay: true }),
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
hovered: {
|
hovered: {
|
||||||
background: background(theme.highest, "on", "hovered"),
|
background: background(theme.middle, "hovered"),
|
||||||
},
|
},
|
||||||
|
clicked: {
|
||||||
|
background: background(theme.middle, "pressed"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
saved_at: {
|
saved_at: {
|
||||||
margin: { left: 8 },
|
margin: { left: 8 },
|
||||||
...text(theme.highest, "sans", "default", { size: "xs" }),
|
...text(theme.highest, "sans", "variant", { size: "xs" }),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
margin: { left: 16 },
|
margin: { left: 12 },
|
||||||
...text(theme.highest, "sans", "default", {
|
...text(theme.highest, "sans", "default", {
|
||||||
size: "sm",
|
size: "sm",
|
||||||
weight: "bold",
|
weight: "bold",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
user_sender: {
|
user_sender: interactive_role("base"),
|
||||||
default: {
|
assistant_sender: interactive_role("accent"),
|
||||||
...text(theme.highest, "sans", "default", {
|
system_sender: interactive_role("warning"),
|
||||||
size: "sm",
|
|
||||||
weight: "bold",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
assistant_sender: {
|
|
||||||
default: {
|
|
||||||
...text(theme.highest, "sans", "accent", {
|
|
||||||
size: "sm",
|
|
||||||
weight: "bold",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
system_sender: {
|
|
||||||
default: {
|
|
||||||
...text(theme.highest, "sans", "variant", {
|
|
||||||
size: "sm",
|
|
||||||
weight: "bold",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sent_at: {
|
sent_at: {
|
||||||
margin: { top: 2, left: 8 },
|
margin: { top: 2, left: 8 },
|
||||||
...text(theme.highest, "sans", "default", { size: "2xs" }),
|
...text(theme.highest, "sans", "variant", { size: "2xs" }),
|
||||||
},
|
},
|
||||||
model: interactive({
|
model: interactive({
|
||||||
base: {
|
base: {
|
||||||
background: background(theme.highest, "on"),
|
background: background(theme.highest),
|
||||||
margin: { left: 12, right: 12, top: 12 },
|
margin: { left: 12, right: 4, top: 12 },
|
||||||
padding: 4,
|
padding: { right: 4, left: 4, top: 1, bottom: 1 },
|
||||||
corner_radius: 4,
|
corner_radius: 4,
|
||||||
...text(theme.highest, "sans", "default", { size: "xs" }),
|
...text(theme.highest, "sans", "default", { size: "xs" }),
|
||||||
},
|
},
|
||||||
|
@ -238,20 +138,9 @@ export default function assistant(): any {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
remaining_tokens: {
|
remaining_tokens: tokens_remaining("positive"),
|
||||||
background: background(theme.highest, "on"),
|
low_remaining_tokens: tokens_remaining("warning"),
|
||||||
margin: { top: 12, right: 24 },
|
no_remaining_tokens: tokens_remaining("negative"),
|
||||||
padding: 4,
|
|
||||||
corner_radius: 4,
|
|
||||||
...text(theme.highest, "sans", "positive", { size: "xs" }),
|
|
||||||
},
|
|
||||||
no_remaining_tokens: {
|
|
||||||
background: background(theme.highest, "on"),
|
|
||||||
margin: { top: 12, right: 24 },
|
|
||||||
padding: 4,
|
|
||||||
corner_radius: 4,
|
|
||||||
...text(theme.highest, "sans", "negative", { size: "xs" }),
|
|
||||||
},
|
|
||||||
error_icon: {
|
error_icon: {
|
||||||
margin: { left: 8 },
|
margin: { left: 8 },
|
||||||
color: foreground(theme.highest, "negative"),
|
color: foreground(theme.highest, "negative"),
|
||||||
|
@ -259,7 +148,7 @@ export default function assistant(): any {
|
||||||
},
|
},
|
||||||
api_key_editor: {
|
api_key_editor: {
|
||||||
background: background(theme.highest, "on"),
|
background: background(theme.highest, "on"),
|
||||||
corner_radius: 6,
|
corner_radius: 4,
|
||||||
text: text(theme.highest, "mono", "on"),
|
text: text(theme.highest, "mono", "on"),
|
||||||
placeholder_text: text(theme.highest, "mono", "on", "disabled", {
|
placeholder_text: text(theme.highest, "mono", "on", "disabled", {
|
||||||
size: "xs",
|
size: "xs",
|
||||||
|
|
|
@ -12,8 +12,17 @@ export interface Theme {
|
||||||
name: string
|
name: string
|
||||||
is_light: boolean
|
is_light: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App background, other elements that should sit directly on top of the background.
|
||||||
|
*/
|
||||||
lowest: Layer
|
lowest: Layer
|
||||||
|
/**
|
||||||
|
* Panels, tabs, other UI surfaces that sit on top of the background.
|
||||||
|
*/
|
||||||
middle: Layer
|
middle: Layer
|
||||||
|
/**
|
||||||
|
* Editors like code buffers, conversation editors, etc.
|
||||||
|
*/
|
||||||
highest: Layer
|
highest: Layer
|
||||||
|
|
||||||
ramps: RampSet
|
ramps: RampSet
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue