Refine GPUI shell UX surfaces

This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 13:32:58 -04:00
1 parent 22ba7a9004
commit 6809df15de
7 files changed
+617 -122

No files matched your search

+45 -14
View File
@@ -14,6 +14,7 @@ mod approvals;
mod documents; mod documents;
mod inbox; mod inbox;
mod messages; mod messages;
mod messages_parts;
mod onboarding; mod onboarding;
mod overview; mod overview;
mod runs; mod runs;
@@ -267,7 +268,7 @@ impl Render for AppRoot {
div() div()
.size_full() .size_full()
.flex() .flex()
.bg(theme::canvas()) .bg(theme::window_bg())
.child(self.render_sidebar(cx)) .child(self.render_sidebar(cx))
.child( .child(
div() div()
@@ -276,30 +277,60 @@ impl Render for AppRoot {
.flex_col() .flex_col()
.child( .child(
div() div()
.px_6() .px_8()
.py_4() .py_5()
.border_b_1() .border_b_1()
.border_color(theme::panel_border()) .border_color(theme::panel_border())
.bg(theme::shell_header()) .bg(theme::shell_header())
.child( .child(
div() div()
.text_xl() .flex()
.text_color(theme::text_primary()) .items_center()
.child(header), .justify_between()
) .child(
.child(div().text_sm().text_color(theme::text_muted()).child( div()
self.state.status_line.clone().unwrap_or_else(|| { .child(
"Native Rust shell is reading the shared local profile." div()
.to_string() .text_3xl()
}), .text_color(theme::text_primary())
)), .child(self.state.section.label()),
)
.child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(header),
)
.child(
div()
.text_sm()
.text_color(theme::text_subtle())
.child(self.state.status_line.clone().unwrap_or_else(|| {
"Native Rust shell is reading the shared local profile."
.to_string()
})),
),
)
.child(
div()
.px_4()
.py_3()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.text_sm()
.text_color(theme::text_secondary())
.child("Show console"),
),
),
) )
.child( .child(
div() div()
.id("main-scroll") .id("main-scroll")
.flex_1() .flex_1()
.overflow_scroll() .overflow_scroll()
.p_6() .p_8()
.child(match self.state.section { .child(match self.state.section {
SectionId::Overview => self.render_overview().into_any_element(), SectionId::Overview => self.render_overview().into_any_element(),
SectionId::Runs => self.render_runs(cx).into_any_element(), SectionId::Runs => self.render_runs(cx).into_any_element(),
@@ -1,4 +1,10 @@
use super::*; use super::{
messages_parts::{
compact_message_card, composer_chip, composer_subject, filter_shell, message_section_label,
search_shell, secondary_message, selected_message_card, selected_recipient,
},
*,
};
impl AppRoot { impl AppRoot {
pub(super) fn render_messages(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ { pub(super) fn render_messages(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ {
@@ -8,36 +14,60 @@ impl AppRoot {
.iter() .iter()
.find(|item| &item.id == id) .find(|item| &item.id == id)
}); });
let selected_subject = selected let company_wide = self
.map(|item| item.subject.clone()) .snapshot
.unwrap_or_else(|| "Select a thread".to_string()); .agent_messages
let selected_body = selected .iter()
.map(|item| item.body.clone()) .filter(|item| item.channel == "company")
.unwrap_or_else(|| "No message selected.".to_string()); .collect::<Vec<_>>();
let department = self
.snapshot
.agent_messages
.iter()
.filter(|item| item.channel == "department")
.collect::<Vec<_>>();
let direct = self
.snapshot
.agent_messages
.iter()
.filter(|item| item.channel == "direct")
.collect::<Vec<_>>();
let task_threads = self
.snapshot
.agent_messages
.iter()
.filter(|item| {
item.channel != "company"
&& item.channel != "department"
&& item.channel != "direct"
})
.collect::<Vec<_>>();
div() div()
.flex() .flex()
.gap_4() .gap_4()
.child( .child(
div() div()
.id("messages-list") .w(px(356.0))
.w(px(320.0)) .p_5()
.p_4() .gap_4()
.gap_2()
.border_1() .border_1()
.rounded_md() .rounded_lg()
.border_color(theme::panel_border()) .border_color(theme::panel_border())
.bg(theme::panel()) .bg(theme::panel())
.overflow_scroll() .child(message_section_label("COMPANY-WIDE"))
.child(div().text_lg().child("Channels")) .children(company_wide.iter().map(|message| {
.children(self.snapshot.agent_messages.iter().map(|item| {
let active = let active =
self.state.selected_message_id.as_deref() == Some(item.id.as_str()); self.state.selected_message_id.as_deref() == Some(message.id.as_str());
let message_id = item.id.clone(); let message_id = message.id.clone();
div() div()
.id(SharedString::from(format!("message-{}", item.id))) .id(SharedString::from(format!("message-{}", message.id)))
.px_3() .flex()
.py_2() .justify_between()
.rounded_md() .items_center()
.px_4()
.py_3()
.rounded_lg()
.cursor_pointer() .cursor_pointer()
.bg(if active { .bg(if active {
theme::selection_fill() theme::selection_fill()
@@ -49,46 +79,247 @@ impl AppRoot {
this.state.selected_message_id = Some(message_id.clone()); this.state.selected_message_id = Some(message_id.clone());
cx.notify(); cx.notify();
})) }))
.child(format!("{} · {}", item.subject, item.priority)) .child(
})), div()
.text_sm()
.text_color(if active {
theme::sidebar_text_active()
} else {
theme::text_secondary()
})
.truncate()
.child(message.subject.clone()),
)
.when(message.priority == "urgent", |container| {
container.child(
div()
.w(px(10.0))
.h(px(10.0))
.rounded_full()
.bg(theme::danger()),
)
})
}))
.child(message_section_label("DEPARTMENT"))
.children(department.iter().map(|message| {
let active =
self.state.selected_message_id.as_deref() == Some(message.id.as_str());
let message_id = message.id.clone();
div()
.id(SharedString::from(format!("message-{}", message.id)))
.flex()
.justify_between()
.items_center()
.px_4()
.py_3()
.rounded_lg()
.cursor_pointer()
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_message_id = Some(message_id.clone());
cx.notify();
}))
.child(
div()
.text_sm()
.text_color(if active {
theme::sidebar_text_active()
} else {
theme::text_secondary()
})
.truncate()
.child(message.subject.clone()),
)
}))
.child(message_section_label("DIRECT MESSAGES"))
.children(direct.iter().map(|message| {
let active =
self.state.selected_message_id.as_deref() == Some(message.id.as_str());
let message_id = message.id.clone();
div()
.id(SharedString::from(format!("message-{}", message.id)))
.flex()
.justify_between()
.items_center()
.px_4()
.py_3()
.rounded_lg()
.cursor_pointer()
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_message_id = Some(message_id.clone());
cx.notify();
}))
.child(
div()
.text_sm()
.text_color(if active {
theme::sidebar_text_active()
} else {
theme::text_secondary()
})
.truncate()
.child(message.subject.clone()),
)
.when(message.read_at.is_none(), |container| {
container.child(
div()
.w(px(10.0))
.h(px(10.0))
.rounded_full()
.bg(theme::danger()),
)
})
}))
.child(message_section_label("TASK DISCUSSIONS"))
.children(task_threads.iter().map(|message| {
let active =
self.state.selected_message_id.as_deref() == Some(message.id.as_str());
let message_id = message.id.clone();
div()
.id(SharedString::from(format!("message-{}", message.id)))
.flex()
.justify_between()
.items_center()
.px_4()
.py_3()
.rounded_lg()
.cursor_pointer()
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.hover(|style| style.bg(theme::panel_hover()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.selected_message_id = Some(message_id.clone());
cx.notify();
}))
.child(
div()
.text_sm()
.text_color(if active {
theme::sidebar_text_active()
} else {
theme::text_secondary()
})
.truncate()
.child(message.subject.clone()),
)
}))
.child(div().flex_1())
.child(
div()
.flex()
.justify_between()
.text_xs()
.text_color(theme::text_muted())
.child(format!("{} channels", self.snapshot.agent_messages.len()))
.child(format!("{} agents", self.snapshot.agents.len())),
),
) )
.child( .child(
div() div()
.flex_1() .flex_1()
.p_4()
.gap_3()
.border_1() .border_1()
.rounded_md() .rounded_lg()
.border_color(theme::panel_border()) .border_color(theme::panel_border())
.bg(theme::panel()) .bg(theme::panel())
.child(div().text_lg().child("Conversation"))
.child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(selected_subject),
)
.child(
div()
.min_h(px(220.0))
.p_3()
.border_1()
.border_color(theme::panel_inset_border())
.rounded_md()
.bg(theme::panel_inset())
.child(selected_body),
)
.child(self.message_input.clone())
.child( .child(
div() div()
.flex() .flex()
.gap_2() .justify_between()
.child(primary_button("Send update", cx, |this, cx| { .items_center()
this.send_message(cx) .px_5()
})) .py_4()
.child(secondary_button("Mark read", cx, |this, cx| { .border_b_1()
this.mark_selected_message_read(cx) .border_color(theme::panel_border())
})), .child(
div().text_lg().text_color(theme::text_primary()).child(
selected
.map(|message| message.subject.clone())
.unwrap_or_else(|| "Select a conversation".to_string()),
),
)
.child(
div()
.flex()
.gap_3()
.child(search_shell("Search messages"))
.child(filter_shell()),
),
)
.child(
div()
.id("messages-stream")
.flex_1()
.p_4()
.overflow_scroll()
.child(selected_message_card(selected))
.when_some(secondary_message(selected), |container, message| {
container.child(compact_message_card(message))
}),
)
.child(
div()
.px_4()
.py_3()
.border_t_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.child(
div()
.flex()
.gap_3()
.child(composer_chip(selected_recipient(selected).as_str()))
.child(composer_subject(selected)),
)
.child(
div()
.mt(px(12.0))
.p_3()
.rounded_lg()
.bg(theme::panel_inset())
.border_1()
.border_color(theme::panel_inset_border())
.child(self.message_input.clone()),
)
.child(
div()
.mt(px(10.0))
.flex()
.justify_between()
.items_center()
.child(
div()
.text_xs()
.text_color(theme::text_muted())
.child("Press Cmd+Enter to send"),
)
.child(
div()
.flex()
.gap_2()
.child(primary_button("Send update", cx, |this, cx| {
this.send_message(cx)
}))
.child(secondary_button(
"Mark read",
cx,
|this, cx| this.mark_selected_message_read(cx),
)),
),
),
), ),
) )
} }
@@ -0,0 +1,217 @@
use super::*;
pub(super) fn message_section_label(label: &'static str) -> impl IntoElement {
div().text_xs().text_color(theme::text_muted()).child(label)
}
pub(super) fn selected_message_card(message: Option<&domain::AgentMessage>) -> impl IntoElement {
let subject = message
.map(|item| item.subject.clone())
.unwrap_or_else(|| "No message selected".to_string());
let body = message.map(|item| item.body.clone()).unwrap_or_else(|| {
"Choose a company channel, direct thread, or task discussion from the left rail."
.to_string()
});
div()
.p_5()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.child(message_header(message, false))
.child(
div()
.mt(px(16.0))
.text_lg()
.text_color(theme::text_primary())
.child(subject),
)
.child(
div()
.mt(px(12.0))
.text_base()
.text_color(theme::text_secondary())
.child(body),
)
.child(
div()
.mt(px(16.0))
.text_sm()
.text_color(theme::text_muted())
.child("↩ Reply"),
)
}
pub(super) fn compact_message_card(message: &domain::AgentMessage) -> impl IntoElement {
div()
.mt(px(16.0))
.p_5()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.child(message_header(Some(message), true))
.child(
div()
.mt(px(12.0))
.text_base()
.text_color(theme::text_primary())
.child(message.subject.clone()),
)
.child(
div()
.mt(px(8.0))
.text_sm()
.text_color(theme::text_muted())
.line_clamp(2)
.child(message.body.clone()),
)
}
fn message_header(message: Option<&domain::AgentMessage>, urgent: bool) -> impl IntoElement {
let sender = message
.map(|item| trim_sender(item.from_agent_id.as_str()))
.unwrap_or("AC");
let timestamp = message
.and_then(|item| item.created_at.get(11..16))
.unwrap_or("--:--")
.to_string();
div()
.flex()
.items_center()
.gap_3()
.child(
div()
.w(px(44.0))
.h(px(44.0))
.rounded_full()
.bg(theme::accent_orange_soft())
.text_color(theme::accent_orange())
.flex()
.items_center()
.justify_center()
.child(sender.to_string()),
)
.child(
div()
.flex()
.gap_2()
.items_center()
.child(
div().text_sm().text_color(theme::accent_orange()).child(
message
.map(|item| item.sender_kind.clone())
.unwrap_or_else(|| "human".to_string()),
),
)
.child(
div().text_sm().text_color(theme::text_muted()).child(
message
.map(|item| item.channel.clone())
.unwrap_or_else(|| "company".to_string()),
),
)
.child(
div()
.px_2()
.py_1()
.rounded_full()
.bg(theme::accent_orange_soft())
.text_xs()
.text_color(theme::accent_orange())
.child("OPERATIONS"),
)
.child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(timestamp),
)
.when(urgent, |container| {
container.child(
div()
.px_2()
.py_1()
.rounded_full()
.bg(theme::danger_bg())
.text_xs()
.text_color(theme::danger())
.child("URGENT"),
)
}),
)
}
pub(super) fn secondary_message(
selected: Option<&domain::AgentMessage>,
) -> Option<&domain::AgentMessage> {
selected
}
fn trim_sender(sender: &str) -> &str {
sender.get(..2).unwrap_or(sender)
}
pub(super) fn search_shell(label: &'static str) -> impl IntoElement {
div()
.w(px(240.0))
.px_4()
.py_3()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.text_sm()
.text_color(theme::text_subtle())
.child(label)
}
pub(super) fn filter_shell() -> impl IntoElement {
div()
.px_4()
.py_3()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.text_sm()
.text_color(theme::text_secondary())
.child("Filters")
}
pub(super) fn composer_chip(label: &str) -> impl IntoElement {
div()
.px_4()
.py_3()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.text_sm()
.text_color(theme::text_secondary())
.child(label.to_string())
}
pub(super) fn composer_subject(message: Option<&domain::AgentMessage>) -> impl IntoElement {
div()
.flex_1()
.px_4()
.py_3()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.text_sm()
.text_color(theme::text_subtle())
.child(
message
.map(|item| item.subject.clone())
.unwrap_or_else(|| "Subject (optional)".to_string()),
)
}
pub(super) fn selected_recipient(message: Option<&domain::AgentMessage>) -> String {
message
.and_then(|item| item.to_agent_id.clone())
.unwrap_or_else(|| "CEO (CEO)".to_string())
}
@@ -130,7 +130,12 @@ fn eyebrow(label: &'static str) -> impl IntoElement {
.gap_3() .gap_3()
.items_center() .items_center()
.child(div().w(px(48.0)).h(px(1.0)).bg(theme::text_subtle())) .child(div().w(px(48.0)).h(px(1.0)).bg(theme::text_subtle()))
.child(div().text_xs().text_color(theme::text_subtle()).child(label)) .child(
div()
.text_xs()
.text_color(theme::text_subtle())
.child(label),
)
} }
fn onboarding_steps() -> impl IntoElement { fn onboarding_steps() -> impl IntoElement {
@@ -168,7 +173,12 @@ fn readiness_panel() -> impl IntoElement {
div() div()
.w(px(520.0)) .w(px(520.0))
.gap_3() .gap_3()
.child(div().text_xs().text_color(theme::text_muted()).child("CONNECTOR READINESS")) .child(
div()
.text_xs()
.text_color(theme::text_muted())
.child("CONNECTOR READINESS"),
)
.child(readiness_row("Claude Code", "ready", true)) .child(readiness_row("Claude Code", "ready", true))
.child(readiness_row("Codex", "ready", true)) .child(readiness_row("Codex", "ready", true))
.child(readiness_row("Gemini CLI", "auth required", false)) .child(readiness_row("Gemini CLI", "auth required", false))
@@ -186,18 +196,17 @@ fn readiness_row(label: &'static str, state: &'static str, ready: bool) -> impl
.flex() .flex()
.gap_3() .gap_3()
.items_center() .items_center()
.child(div().w(px(16.0)).h(px(16.0)).rounded_full().bg(if ready {
theme::accent_teal()
} else {
theme::accent_orange()
}))
.child( .child(
div() div()
.w(px(16.0)) .text_sm()
.h(px(16.0)) .text_color(theme::text_primary())
.rounded_full() .child(label),
.bg(if ready {
theme::accent_teal()
} else {
theme::accent_orange()
}),
) )
.child(div().text_sm().text_color(theme::text_primary()).child(label))
.child(div().text_sm().text_color(theme::text_muted()).child(state)) .child(div().text_sm().text_color(theme::text_muted()).child(state))
} }
@@ -225,7 +234,12 @@ fn launch_tile(label: &'static str, value: &'static str) -> impl IntoElement {
.rounded_lg() .rounded_lg()
.bg(theme::panel_muted()) .bg(theme::panel_muted())
.child(div().text_xs().text_color(theme::text_muted()).child(label)) .child(div().text_xs().text_color(theme::text_muted()).child(label))
.child(div().text_sm().text_color(theme::text_primary()).child(value)) .child(
div()
.text_sm()
.text_color(theme::text_primary())
.child(value),
)
} }
fn rgb_hex(hex: u32) -> gpui::Hsla { fn rgb_hex(hex: u32) -> gpui::Hsla {
@@ -43,9 +43,15 @@ impl AppRoot {
.child(format!("{} agents active", self.snapshot.agents.len())) .child(format!("{} agents active", self.snapshot.agents.len()))
.child(div().child("•")) .child(div().child("•"))
.child(metadata_dot(theme::badge_dark())) .child(metadata_dot(theme::badge_dark()))
.child(format!("{} tasks in progress", self.snapshot.active_tasks())) .child(format!(
"{} tasks in progress",
self.snapshot.active_tasks()
))
.child(div().child("•")) .child(div().child("•"))
.child(format!("{} completed", completed_task_count(&self.snapshot))), .child(format!(
"{} completed",
completed_task_count(&self.snapshot)
)),
), ),
) )
.child( .child(
@@ -149,7 +155,11 @@ impl AppRoot {
div() div()
.text_base() .text_base()
.text_color(theme::text_primary()) .text_color(theme::text_primary())
.child(format!("{} {}", item.actor, item.action.replace('_', " "))), .child(format!(
"{} {}",
item.actor,
item.action.replace('_', " ")
)),
) )
.child( .child(
div() div()
@@ -192,12 +202,7 @@ fn section_header(label: &'static str, action: Option<&'static str>) -> impl Int
.flex() .flex()
.items_center() .items_center()
.justify_between() .justify_between()
.child( .child(div().text_xs().text_color(theme::text_muted()).child(label))
div()
.text_xs()
.text_color(theme::text_muted())
.child(label),
)
.when_some(action, |container, action_label| { .when_some(action, |container, action_label| {
container.child( container.child(
div() div()
@@ -223,14 +228,13 @@ fn metric_panel(
.rounded_lg() .rounded_lg()
.border_color(theme::panel_border()) .border_color(theme::panel_border())
.bg(theme::panel()) .bg(theme::panel())
.child( .child(div().w(px(56.0)).h(px(56.0)).rounded_lg().bg(tile_bg))
div()
.w(px(56.0))
.h(px(56.0))
.rounded_lg()
.bg(tile_bg),
)
.child(div().text_xs().text_color(theme::text_muted()).child(label)) .child(div().text_xs().text_color(theme::text_muted()).child(label))
.child(div().text_3xl().text_color(value_color).child(value)) .child(div().text_3xl().text_color(value_color).child(value))
.child(div().text_sm().text_color(theme::text_muted()).child(detail)) .child(
div()
.text_sm()
.text_color(theme::text_muted())
.child(detail),
)
} }
@@ -1,4 +1,5 @@
use super::*; use super::*;
use gpui::Window;
impl AppRoot { impl AppRoot {
pub(super) fn render_sidebar(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ { pub(super) fn render_sidebar(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ {
@@ -7,7 +8,10 @@ impl AppRoot {
(SectionId::Runs, Some(self.snapshot.active_runs())), (SectionId::Runs, Some(self.snapshot.active_runs())),
(SectionId::Inbox, Some(self.snapshot.active_tasks())), (SectionId::Inbox, Some(self.snapshot.active_tasks())),
(SectionId::Messages, Some(self.snapshot.unread_messages())), (SectionId::Messages, Some(self.snapshot.unread_messages())),
(SectionId::Approvals, Some(self.snapshot.pending_approvals())), (
SectionId::Approvals,
Some(self.snapshot.pending_approvals()),
),
(SectionId::Documents, None), (SectionId::Documents, None),
(SectionId::Workspaces, None), (SectionId::Workspaces, None),
]; ];
@@ -57,15 +61,12 @@ impl AppRoot {
.border_color(theme::panel_border()) .border_color(theme::panel_border())
.bg(theme::panel()) .bg(theme::panel())
.child( .child(
div() div().text_sm().text_color(theme::text_primary()).child(
.text_sm() self.snapshot
.text_color(theme::text_primary()) .current_company()
.child( .map(|company| company.name.clone())
self.snapshot .unwrap_or_else(|| "AgentCompany".to_string()),
.current_company() ),
.map(|company| company.name.clone())
.unwrap_or_else(|| "AgentCompany".to_string()),
),
) )
.child( .child(
div() div()
@@ -91,7 +92,8 @@ impl AppRoot {
), ),
) )
.children(self.snapshot.companies.iter().map(|company| { .children(self.snapshot.companies.iter().map(|company| {
let active = self.snapshot.current_company_id.as_deref() == Some(company.id.as_str()); let active =
self.snapshot.current_company_id.as_deref() == Some(company.id.as_str());
let company_id = company.id.clone(); let company_id = company.id.clone();
div() div()
.id(SharedString::from(format!("company-{}", company.id))) .id(SharedString::from(format!("company-{}", company.id)))
@@ -189,10 +191,15 @@ impl AppRoot {
})) }))
.child(div().flex_1()) .child(div().flex_1())
.child(div().h(px(1.0)).bg(theme::sidebar_divider())) .child(div().h(px(1.0)).bg(theme::sidebar_divider()))
.child(sidebar_footer_row("Settings", self.state.section == SectionId::Settings, cx, |this, cx| { .child(sidebar_footer_row(
this.state.section = SectionId::Settings; "Settings",
cx.notify(); self.state.section == SectionId::Settings,
})) cx,
|this, cx| {
this.state.section = SectionId::Settings;
cx.notify();
},
))
.child( .child(
div() div()
.px_4() .px_4()
@@ -223,6 +230,7 @@ where
V: 'static, V: 'static,
{ {
div() div()
.id(SharedString::from(format!("sidebar-footer-{label}")))
.px_4() .px_4()
.py_3() .py_3()
.rounded_lg() .rounded_lg()
@@ -238,7 +246,9 @@ where
theme::sidebar_text() theme::sidebar_text()
}) })
.hover(|style| style.bg(theme::sidebar_hover())) .hover(|style| style.bg(theme::sidebar_hover()))
.on_click(cx.listener(move |this, _, _, cx| on_click(this, cx))) .on_click(
cx.listener(move |this, _: &gpui::ClickEvent, _: &mut Window, cx| on_click(this, cx)),
)
.child(label) .child(label)
} }
@@ -4,10 +4,6 @@ pub fn window_bg() -> Hsla {
rgb(0xf7f8fb).into() rgb(0xf7f8fb).into()
} }
pub fn canvas() -> Hsla {
rgb(0xf7f8fb).into()
}
pub fn shell_header() -> Hsla { pub fn shell_header() -> Hsla {
rgb(0xffffff).into() rgb(0xffffff).into()
} }
@@ -108,18 +104,10 @@ pub fn sidebar_bg() -> Hsla {
rgb(0xffffff).into() rgb(0xffffff).into()
} }
pub fn sidebar_surface() -> Hsla {
rgb(0xffffff).into()
}
pub fn sidebar_hover() -> Hsla { pub fn sidebar_hover() -> Hsla {
rgb(0xf4f6fa).into() rgb(0xf4f6fa).into()
} }
pub fn sidebar_surface_hover() -> Hsla {
rgb(0xf4f6fa).into()
}
pub fn sidebar_divider() -> Hsla { pub fn sidebar_divider() -> Hsla {
rgb(0xe7eaf0).into() rgb(0xe7eaf0).into()
} }