Rework theme2 with new theme structure (#3194)

This PR reworks the theme definition in the `theme2` crate to be based
off of the new theme work that @iamnbutler has been working on.

We're still developing the new theme system, but it is complete enough
that we can now load the default theme and use it to theme the storybook
(albeit with some further refining of the color palette required).

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Marshall Bowers <marshall@zed.dev>
This commit is contained in:
Marshall Bowers 2023-11-01 03:23:00 +01:00 committed by GitHub
parent ed5f1d3bdd
commit 18431051d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 1615 additions and 494 deletions

View file

@ -19,24 +19,22 @@ impl Breadcrumb {
}
fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Div<V> {
let theme = theme(cx);
div().child(" ").text_color(theme.text_muted)
div()
.child(" ")
.text_color(cx.theme().colors().text_muted)
}
fn render<V: 'static>(self, view_state: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let symbols_len = self.symbols.len();
h_stack()
.id("breadcrumb")
.px_1()
.text_sm()
.text_color(theme.text_muted)
.text_color(cx.theme().colors().text_muted)
.rounded_md()
.hover(|style| style.bg(theme.ghost_element_hover))
.active(|style| style.bg(theme.ghost_element_active))
.hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
.active(|style| style.bg(cx.theme().colors().ghost_element_active))
.child(self.path.clone().to_str().unwrap().to_string())
.child(if !self.symbols.is_empty() {
self.render_separator(cx)
@ -84,8 +82,6 @@ mod stories {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, Breadcrumb>(cx))
.child(Story::label(cx, "Default"))
@ -95,21 +91,21 @@ mod stories {
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: theme.syntax.color("keyword"),
color: cx.theme().syntax_color("keyword"),
},
HighlightedText {
text: "BreadcrumbStory".to_string(),
color: theme.syntax.color("function"),
color: cx.theme().syntax_color("function"),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: theme.syntax.color("keyword"),
color: cx.theme().syntax_color("keyword"),
},
HighlightedText {
text: "render".to_string(),
color: theme.syntax.color("function"),
color: cx.theme().syntax_color("function"),
},
]),
],

View file

@ -155,18 +155,16 @@ impl Buffer {
}
fn render_row<V: 'static>(row: BufferRow, cx: &WindowContext) -> impl Component<V> {
let theme = theme(cx);
let line_background = if row.current {
theme.editor_active_line
cx.theme().colors().editor_active_line
} else {
theme.transparent
cx.theme().styles.system.transparent
};
let line_number_color = if row.current {
theme.text
cx.theme().colors().text
} else {
theme.syntax.get("comment").color.unwrap_or_default()
cx.theme().syntax_color("comment")
};
h_stack()
@ -216,14 +214,13 @@ impl Buffer {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let rows = self.render_rows(cx);
v_stack()
.flex_1()
.w_full()
.h_full()
.bg(theme.editor)
.bg(cx.theme().colors().editor)
.children(rows)
}
}
@ -246,8 +243,6 @@ mod stories {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, Buffer>(cx))
.child(Story::label(cx, "Default"))
@ -257,14 +252,14 @@ mod stories {
div()
.w(rems(64.))
.h_96()
.child(hello_world_rust_buffer_example(&theme)),
.child(hello_world_rust_buffer_example(cx)),
)
.child(Story::label(cx, "Hello World (Rust) with Status"))
.child(
div()
.w(rems(64.))
.h_96()
.child(hello_world_rust_buffer_with_status_example(&theme)),
.child(hello_world_rust_buffer_with_status_example(cx)),
)
}
}

View file

@ -30,9 +30,7 @@ impl Render for BufferSearch {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
let theme = theme(cx);
h_stack().bg(theme.toolbar).p_2().child(
h_stack().bg(cx.theme().colors().toolbar).p_2().child(
h_stack().child(Input::new("Search")).child(
IconButton::<Self>::new("replace", Icon::Replace)
.when(self.is_replace_open, |this| this.color(IconColor::Accent))

View file

@ -15,27 +15,29 @@ impl CollabPanel {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
v_stack()
.id(self.id.clone())
.h_full()
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.child(
v_stack()
.id("crdb")
.w_full()
.overflow_y_scroll()
.child(
div().pb_1().border_color(theme.border).border_b().child(
List::new(static_collab_panel_current_call())
.header(
ListHeader::new("CRDB")
.left_icon(Icon::Hash.into())
.toggle(ToggleState::Toggled),
)
.toggle(ToggleState::Toggled),
),
div()
.pb_1()
.border_color(cx.theme().colors().border)
.border_b()
.child(
List::new(static_collab_panel_current_call())
.header(
ListHeader::new("CRDB")
.left_icon(Icon::Hash.into())
.toggle(ToggleState::Toggled),
)
.toggle(ToggleState::Toggled),
),
)
.child(
v_stack().id("channels").py_1().child(
@ -71,13 +73,13 @@ impl CollabPanel {
.h_7()
.px_2()
.border_t()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.flex()
.items_center()
.child(
div()
.text_sm()
.text_color(theme.text_placeholder)
.text_color(cx.theme().colors().text_placeholder)
.child("Find..."),
),
)

View file

@ -44,13 +44,11 @@ impl ContextMenu {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
v_stack()
.flex()
.bg(theme.elevated_surface)
.bg(cx.theme().colors().elevated_surface)
.border()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.child(
List::new(
self.items

View file

@ -66,8 +66,6 @@ impl<V: 'static> IconButton<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let icon_color = match (self.state, self.color) {
(InteractionState::Disabled, _) => IconColor::Disabled,
_ => self.color,
@ -75,14 +73,14 @@ impl<V: 'static> IconButton<V> {
let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
ButtonVariant::Filled => (
theme.filled_element,
theme.filled_element_hover,
theme.filled_element_active,
cx.theme().colors().element,
cx.theme().colors().element_hover,
cx.theme().colors().element_active,
),
ButtonVariant::Ghost => (
theme.ghost_element,
theme.ghost_element_hover,
theme.ghost_element_active,
cx.theme().colors().ghost_element,
cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active,
),
};

View file

@ -60,15 +60,13 @@ impl Key {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
div()
.px_2()
.py_0()
.rounded_md()
.text_sm()
.text_color(theme.text)
.bg(theme.filled_element)
.text_color(cx.theme().colors().text)
.bg(cx.theme().colors().element)
.child(self.key.clone())
}
}

View file

@ -89,8 +89,6 @@ impl ListHeader {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let is_toggleable = self.toggleable != Toggleable::NotToggleable;
let is_toggled = self.toggleable.is_toggled();
@ -99,9 +97,10 @@ impl ListHeader {
h_stack()
.flex_1()
.w_full()
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.when(self.state == InteractionState::Focused, |this| {
this.border().border_color(theme.border_focused)
this.border()
.border_color(cx.theme().colors().border_focused)
})
.relative()
.child(
@ -363,7 +362,6 @@ impl ListEntry {
fn render<V: 'static>(mut self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let settings = user_settings(cx);
let theme = theme(cx);
let left_content = match self.left_content.clone() {
Some(LeftContent::Icon(i)) => Some(
@ -385,9 +383,10 @@ impl ListEntry {
div()
.relative()
.group("")
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.when(self.state == InteractionState::Focused, |this| {
this.border().border_color(theme.border_focused)
this.border()
.border_color(cx.theme().colors().border_focused)
})
.child(
sized_item
@ -399,11 +398,11 @@ impl ListEntry {
.h_full()
.flex()
.justify_center()
.group_hover("", |style| style.bg(theme.border_focused))
.group_hover("", |style| style.bg(cx.theme().colors().border_focused))
.child(
h_stack()
.child(div().w_px().h_full())
.child(div().w_px().h_full().bg(theme.border)),
.child(div().w_px().h_full().bg(cx.theme().colors().border)),
)
}))
.flex()
@ -472,19 +471,18 @@ impl<V: 'static> ListDetailsEntry<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let settings = user_settings(cx);
let (item_bg, item_bg_hover, item_bg_active) = match self.seen {
true => (
theme.ghost_element,
theme.ghost_element_hover,
theme.ghost_element_active,
cx.theme().colors().ghost_element,
cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active,
),
false => (
theme.filled_element,
theme.filled_element_hover,
theme.filled_element_active,
cx.theme().colors().element,
cx.theme().colors().element_hover,
cx.theme().colors().element_active,
),
};
@ -524,9 +522,7 @@ impl ListSeparator {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
div().h_px().w_full().bg(theme.border)
div().h_px().w_full().bg(cx.theme().colors().border)
}
}

View file

@ -39,22 +39,20 @@ impl<V: 'static> Modal<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
v_stack()
.id(self.id.clone())
.w_96()
// .rounded_xl()
.bg(theme.background)
.bg(cx.theme().colors().background)
.border()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.shadow_2xl()
.child(
h_stack()
.justify_between()
.p_1()
.border_b()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.child(div().children(self.title.clone().map(|t| Label::new(t))))
.child(IconButton::new("close", Icon::Close)),
)
@ -65,7 +63,7 @@ impl<V: 'static> Modal<V> {
this.child(
h_stack()
.border_t()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.p_1()
.justify_end()
.children(self.secondary_action)

View file

@ -12,8 +12,6 @@ impl MultiBuffer {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
v_stack()
.w_full()
.h_full()
@ -26,7 +24,7 @@ impl MultiBuffer {
.items_center()
.justify_between()
.p_4()
.bg(theme.editor_subheader)
.bg(cx.theme().colors().editor_subheader)
.child(Label::new("main.rs"))
.child(IconButton::new("arrow_up_right", Icon::ArrowUpRight)),
)
@ -50,17 +48,15 @@ mod stories {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, MultiBuffer>(cx))
.child(Story::label(cx, "Default"))
.child(MultiBuffer::new(vec![
hello_world_rust_buffer_example(&theme),
hello_world_rust_buffer_example(&theme),
hello_world_rust_buffer_example(&theme),
hello_world_rust_buffer_example(&theme),
hello_world_rust_buffer_example(&theme),
hello_world_rust_buffer_example(cx),
hello_world_rust_buffer_example(cx),
hello_world_rust_buffer_example(cx),
hello_world_rust_buffer_example(cx),
hello_world_rust_buffer_example(cx),
]))
}
}

View file

@ -1,6 +1,7 @@
use gpui2::rems;
use crate::{h_stack, prelude::*, Icon};
use crate::prelude::*;
use crate::{h_stack, Icon};
#[derive(Component)]
pub struct NotificationToast {
@ -22,8 +23,6 @@ impl NotificationToast {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
h_stack()
.z_index(5)
.absolute()
@ -35,7 +34,7 @@ impl NotificationToast {
.px_1p5()
.rounded_lg()
.shadow_md()
.bg(theme.elevated_surface)
.bg(cx.theme().colors().elevated_surface)
.child(div().size_full().child(self.label.clone()))
}
}

View file

@ -12,15 +12,13 @@ impl NotificationsPanel {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
div()
.id(self.id.clone())
.flex()
.flex_col()
.w_full()
.h_full()
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.child(
div()
.id("header")

View file

@ -43,22 +43,20 @@ impl Palette {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
v_stack()
.id(self.id.clone())
.w_96()
.rounded_lg()
.bg(theme.elevated_surface)
.bg(cx.theme().colors().elevated_surface)
.border()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.child(
v_stack()
.gap_px()
.child(v_stack().py_0p5().px_1().child(div().px_2().py_0p5().child(
Label::new(self.input_placeholder.clone()).color(LabelColor::Placeholder),
)))
.child(div().h_px().w_full().bg(theme.filled_element))
.child(div().h_px().w_full().bg(cx.theme().colors().element))
.child(
v_stack()
.id("items")
@ -88,8 +86,12 @@ impl Palette {
.px_2()
.py_0p5()
.rounded_lg()
.hover(|style| style.bg(theme.ghost_element_hover))
.active(|style| style.bg(theme.ghost_element_active))
.hover(|style| {
style.bg(cx.theme().colors().ghost_element_hover)
})
.active(|style| {
style.bg(cx.theme().colors().ghost_element_active)
})
.child(item)
})),
),

View file

@ -93,8 +93,6 @@ impl<V: 'static> Panel<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let current_size = self.width.unwrap_or(self.initial_width);
v_stack()
@ -111,8 +109,8 @@ impl<V: 'static> Panel<V> {
.when(self.current_side == PanelSide::Bottom, |this| {
this.border_b().w_full().h(current_size)
})
.bg(theme.surface)
.border_color(theme.border)
.bg(cx.theme().colors().surface)
.border_color(cx.theme().colors().border)
.children(self.children)
}
}

View file

@ -90,8 +90,6 @@ impl<V: 'static> PaneGroup<V> {
}
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
if !self.panes.is_empty() {
let el = div()
.flex()
@ -115,7 +113,7 @@ impl<V: 'static> PaneGroup<V> {
.gap_px()
.w_full()
.h_full()
.bg(theme.editor)
.bg(cx.theme().colors().editor)
.children(self.groups.into_iter().map(|group| group.render(view, cx)));
if self.split_direction == SplitDirection::Horizontal {

View file

@ -14,9 +14,7 @@ impl PlayerStack {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let player = self.player_with_call_status.get_player();
self.player_with_call_status.get_call_status();
let followers = self
.player_with_call_status
@ -50,7 +48,7 @@ impl PlayerStack {
.pl_1()
.rounded_lg()
.bg(if followers.is_none() {
theme.transparent
cx.theme().styles.system.transparent
} else {
player.selection_color(cx)
})

View file

@ -14,15 +14,13 @@ impl ProjectPanel {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
div()
.id(self.id.clone())
.flex()
.flex_col()
.w_full()
.h_full()
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.child(
div()
.id("project-panel-contents")

View file

@ -86,8 +86,6 @@ impl StatusBar {
view: &mut Workspace,
cx: &mut ViewContext<Workspace>,
) -> impl Component<Workspace> {
let theme = theme(cx);
div()
.py_0p5()
.px_1()
@ -95,7 +93,7 @@ impl StatusBar {
.items_center()
.justify_between()
.w_full()
.bg(theme.status_bar)
.bg(cx.theme().colors().status_bar)
.child(self.left_tools(view, cx))
.child(self.right_tools(view, cx))
}

View file

@ -87,7 +87,6 @@ impl Tab {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
let is_deleted = self.fs_status == FileSystemStatus::Deleted;
@ -110,14 +109,14 @@ impl Tab {
let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
true => (
theme.ghost_element,
theme.ghost_element_hover,
theme.ghost_element_active,
cx.theme().colors().ghost_element,
cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active,
),
false => (
theme.filled_element,
theme.filled_element_hover,
theme.filled_element_active,
cx.theme().colors().element,
cx.theme().colors().element_hover,
cx.theme().colors().element_active,
),
};

View file

@ -24,15 +24,13 @@ impl TabBar {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let (can_navigate_back, can_navigate_forward) = self.can_navigate;
div()
.id(self.id.clone())
.w_full()
.flex()
.bg(theme.tab_bar)
.bg(cx.theme().colors().tab_bar)
// Left Side
.child(
div()

View file

@ -12,8 +12,6 @@ impl Terminal {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let can_navigate_back = true;
let can_navigate_forward = false;
@ -26,7 +24,7 @@ impl Terminal {
div()
.w_full()
.flex()
.bg(theme.surface)
.bg(cx.theme().colors().surface)
.child(
div().px_1().flex().flex_none().gap_2().child(
div()
@ -73,7 +71,7 @@ impl Terminal {
height: rems(36.).into(),
},
)
.child(crate::static_data::terminal_buffer(&theme)),
.child(crate::static_data::terminal_buffer(cx)),
)
}
}

View file

@ -89,7 +89,6 @@ impl Render for TitleBar {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
let theme = theme(cx);
let settings = user_settings(cx);
// let has_focus = cx.window_is_active();
@ -106,7 +105,7 @@ impl Render for TitleBar {
.items_center()
.justify_between()
.w_full()
.bg(theme.background)
.bg(cx.theme().colors().background)
.py_1()
.child(
div()

View file

@ -37,8 +37,6 @@ impl<V: 'static> Toast<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let mut div = div();
if self.origin == ToastOrigin::Bottom {
@ -56,7 +54,7 @@ impl<V: 'static> Toast<V> {
.rounded_lg()
.shadow_md()
.overflow_hidden()
.bg(theme.elevated_surface)
.bg(cx.theme().colors().elevated_surface)
.children(self.children)
}
}

View file

@ -55,10 +55,8 @@ impl<V: 'static> Toolbar<V> {
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
div()
.bg(theme.toolbar)
.bg(cx.theme().colors().toolbar)
.p_2()
.flex()
.justify_between()
@ -87,8 +85,6 @@ mod stories {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let theme = theme(cx);
Story::container(cx)
.child(Story::title_for::<_, Toolbar<Self>>(cx))
.child(Story::label(cx, "Default"))
@ -100,21 +96,21 @@ mod stories {
Symbol(vec![
HighlightedText {
text: "impl ".to_string(),
color: theme.syntax.color("keyword"),
color: cx.theme().syntax_color("keyword"),
},
HighlightedText {
text: "ToolbarStory".to_string(),
color: theme.syntax.color("function"),
color: cx.theme().syntax_color("function"),
},
]),
Symbol(vec![
HighlightedText {
text: "fn ".to_string(),
color: theme.syntax.color("keyword"),
color: cx.theme().syntax_color("keyword"),
},
HighlightedText {
text: "render".to_string(),
color: theme.syntax.color("function"),
color: cx.theme().syntax_color("function"),
},
]),
],

View file

@ -22,13 +22,13 @@ impl TrafficLight {
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
let theme = theme(cx);
let system_colors = &cx.theme().styles.system;
let fill = match (self.window_has_focus, self.color) {
(true, TrafficLightColor::Red) => theme.mac_os_traffic_light_red,
(true, TrafficLightColor::Yellow) => theme.mac_os_traffic_light_yellow,
(true, TrafficLightColor::Green) => theme.mac_os_traffic_light_green,
(false, _) => theme.filled_element,
(true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red,
(true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow,
(true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green,
(false, _) => cx.theme().colors().element,
};
div().w_3().h_3().rounded_full().bg(fill)

View file

@ -179,8 +179,6 @@ impl Render for Workspace {
type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
let theme = theme(cx);
// HACK: This should happen inside of `debug_toggle_user_settings`, but
// we don't have `cx.global::<FakeSettings>()` in event handlers at the moment.
// Need to talk with Nathan/Antonio about this.
@ -216,8 +214,8 @@ impl Render for Workspace {
.gap_0()
.justify_start()
.items_start()
.text_color(theme.text)
.bg(theme.background)
.text_color(cx.theme().colors().text)
.bg(cx.theme().colors().background)
.child(self.title_bar.clone())
.child(
div()
@ -228,7 +226,7 @@ impl Render for Workspace {
.overflow_hidden()
.border_t()
.border_b()
.border_color(theme.border)
.border_color(cx.theme().colors().border)
.children(
Some(
Panel::new("project-panel-outer", cx)