diff --git a/assets/themes/cave-dark.json b/assets/themes/cave-dark.json index a33125d5b3..4afb38f6f9 100644 --- a/assets/themes/cave-dark.json +++ b/assets/themes/cave-dark.json @@ -21,29 +21,19 @@ "color": "#576ddb", "weight": "bold", "size": 14 + }, + "active": { + "background": "#5852607a", + "text": { + "family": "Zed Sans", + "color": "#e2dfe7", + "size": 14 + } + }, + "hover": { + "background": "#58526052" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#e2dfe7", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#576ddb", - "weight": "bold", - "size": 14 - }, - "background": "#5852607a" - }, "border": { "color": "#19171c", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#efecf4", + "size": 12 + } } } }, diff --git a/assets/themes/cave-light.json b/assets/themes/cave-light.json index 0b1551942d..bf2f968715 100644 --- a/assets/themes/cave-light.json +++ b/assets/themes/cave-light.json @@ -21,29 +21,19 @@ "color": "#576ddb", "weight": "bold", "size": 14 + }, + "active": { + "background": "#8b87922e", + "text": { + "family": "Zed Sans", + "color": "#26232a", + "size": 14 + } + }, + "hover": { + "background": "#8b87921f" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#26232a", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#576ddb", - "weight": "bold", - "size": 14 - }, - "background": "#8b87922e" - }, "border": { "color": "#efecf4", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#19171c", + "size": 12 + } } } }, diff --git a/assets/themes/dark.json b/assets/themes/dark.json index 616b15f005..2f227aa6ed 100644 --- a/assets/themes/dark.json +++ b/assets/themes/dark.json @@ -21,29 +21,19 @@ "color": "#4f8ff7", "weight": "bold", "size": 14 + }, + "active": { + "background": "#2b2b2b", + "text": { + "family": "Zed Sans", + "color": "#f1f1f1", + "size": 14 + } + }, + "hover": { + "background": "#232323" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#f1f1f1", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#4f8ff7", - "weight": "bold", - "size": 14 - }, - "background": "#2b2b2b" - }, "border": { "color": "#070707", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#ffffff", + "size": 12 + } } } }, diff --git a/assets/themes/light.json b/assets/themes/light.json index 71a4a65b62..291e0e6e12 100644 --- a/assets/themes/light.json +++ b/assets/themes/light.json @@ -21,29 +21,19 @@ "color": "#484bed", "weight": "bold", "size": 14 + }, + "active": { + "background": "#e3e3e3", + "text": { + "family": "Zed Sans", + "color": "#2b2b2b", + "size": 14 + } + }, + "hover": { + "background": "#eaeaea" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#2b2b2b", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#484bed", - "weight": "bold", - "size": 14 - }, - "background": "#e3e3e3" - }, "border": { "color": "#d5d5d5", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#000000", + "size": 12 + } } } }, diff --git a/assets/themes/solarized-dark.json b/assets/themes/solarized-dark.json index b8ac7767d0..ef7a0d9a19 100644 --- a/assets/themes/solarized-dark.json +++ b/assets/themes/solarized-dark.json @@ -21,29 +21,19 @@ "color": "#268bd2", "weight": "bold", "size": 14 + }, + "active": { + "background": "#586e757a", + "text": { + "family": "Zed Sans", + "color": "#eee8d5", + "size": 14 + } + }, + "hover": { + "background": "#586e7552" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#eee8d5", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#268bd2", - "weight": "bold", - "size": 14 - }, - "background": "#586e757a" - }, "border": { "color": "#002b36", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#fdf6e3", + "size": 12 + } } } }, diff --git a/assets/themes/solarized-light.json b/assets/themes/solarized-light.json index d8aaa3f130..5636449549 100644 --- a/assets/themes/solarized-light.json +++ b/assets/themes/solarized-light.json @@ -21,29 +21,19 @@ "color": "#268bd2", "weight": "bold", "size": 14 + }, + "active": { + "background": "#93a1a12e", + "text": { + "family": "Zed Sans", + "color": "#073642", + "size": 14 + } + }, + "hover": { + "background": "#93a1a11f" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#073642", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#268bd2", - "weight": "bold", - "size": 14 - }, - "background": "#93a1a12e" - }, "border": { "color": "#fdf6e3", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#002b36", + "size": 12 + } } } }, diff --git a/assets/themes/sulphurpool-dark.json b/assets/themes/sulphurpool-dark.json index c278439765..cf9b21b7b4 100644 --- a/assets/themes/sulphurpool-dark.json +++ b/assets/themes/sulphurpool-dark.json @@ -21,29 +21,19 @@ "color": "#3d8fd1", "weight": "bold", "size": 14 + }, + "active": { + "background": "#5e66877a", + "text": { + "family": "Zed Sans", + "color": "#dfe2f1", + "size": 14 + } + }, + "hover": { + "background": "#5e668752" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#dfe2f1", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#3d8fd1", - "weight": "bold", - "size": 14 - }, - "background": "#5e66877a" - }, "border": { "color": "#202746", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#f5f7ff", + "size": 12 + } } } }, diff --git a/assets/themes/sulphurpool-light.json b/assets/themes/sulphurpool-light.json index f537a7110e..47bd33309e 100644 --- a/assets/themes/sulphurpool-light.json +++ b/assets/themes/sulphurpool-light.json @@ -21,29 +21,19 @@ "color": "#3d8fd1", "weight": "bold", "size": 14 + }, + "active": { + "background": "#979db42e", + "text": { + "family": "Zed Sans", + "color": "#293256", + "size": 14 + } + }, + "hover": { + "background": "#979db41f" } }, - "active_item": { - "padding": { - "bottom": 4, - "left": 12, - "right": 12, - "top": 4 - }, - "corner_radius": 8, - "text": { - "family": "Zed Sans", - "color": "#293256", - "size": 14 - }, - "highlight_text": { - "family": "Zed Sans", - "color": "#3d8fd1", - "weight": "bold", - "size": 14 - }, - "background": "#979db42e" - }, "border": { "color": "#f5f7ff", "width": 1 @@ -906,6 +896,13 @@ }, "margin": { "left": 2 + }, + "active": { + "text": { + "family": "Zed Mono", + "color": "#202746", + "size": 12 + } } } }, diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 7f14747903..b6058c01e5 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -1,7 +1,7 @@ use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ actions, - elements::{ChildView, Flex, Label, ParentElement}, + elements::{ChildView, Flex, Label, MouseState, ParentElement}, keymap::Keystroke, Action, Element, Entity, MutableAppContext, View, ViewContext, ViewHandle, }; @@ -200,17 +200,19 @@ impl PickerDelegate for CommandPalette { } } - fn render_match(&self, ix: usize, selected: bool, cx: &gpui::AppContext) -> gpui::ElementBox { + fn render_match( + &self, + ix: usize, + mouse_state: &MouseState, + selected: bool, + cx: &gpui::AppContext, + ) -> gpui::ElementBox { let mat = &self.matches[ix]; let command = &self.actions[mat.candidate_id]; let settings = cx.global::(); let theme = &settings.theme; - let style = if selected { - &theme.picker.active_item - } else { - &theme.picker.item - }; - let key_style = &theme.command_palette.key; + let style = theme.picker.item.style_for(mouse_state, selected); + let key_style = &theme.command_palette.key.style_for(mouse_state, selected); let keystroke_spacing = theme.command_palette.keystroke_spacing; Flex::row() diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 06b14698cd..39b5437a6a 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -95,12 +95,8 @@ impl View for DiagnosticIndicator { .theme .workspace .status_bar - .diagnostic_summary; - let style = if state.hovered { - style.hover() - } else { - &style.default - }; + .diagnostic_summary + .style_for(state, false); let mut summary_row = Flex::row(); if self.summary.error_count > 0 { @@ -190,11 +186,7 @@ impl View for DiagnosticIndicator { MouseEventHandler::new::(1, cx, |state, _| { Label::new( diagnostic.message.split('\n').next().unwrap().to_string(), - if state.hovered { - message_style.hover().text.clone() - } else { - message_style.default.text.clone() - }, + message_style.style_for(state, false).text.clone(), ) .aligned() .contained() diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 84378bfd24..ae176dccaa 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -223,14 +223,16 @@ impl PickerDelegate for FileFinder { cx.emit(Event::Dismissed); } - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox { + fn render_match( + &self, + ix: usize, + mouse_state: &MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox { let path_match = &self.matches[ix]; let settings = cx.global::(); - let style = if selected { - &settings.theme.picker.active_item - } else { - &settings.theme.picker.item - }; + let style = settings.theme.picker.item.style_for(mouse_state, selected); let (file_name, file_name_positions, full_path, full_path_positions) = self.labels_for_match(path_match); Flex::column() diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index a8216038c8..5658cf2011 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -228,14 +228,16 @@ impl PickerDelegate for OutlineView { cx.emit(Event::Dismissed); } - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox { + fn render_match( + &self, + ix: usize, + mouse_state: &MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox { let settings = cx.global::(); let string_match = &self.matches[ix]; - let style = if selected { - &settings.theme.picker.active_item - } else { - &settings.theme.picker.item - }; + let style = settings.theme.picker.item.style_for(mouse_state, selected); let outline_item = &self.outline.items[string_match.candidate_id]; Text::new(outline_item.text.clone(), style.label.text.clone()) diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index d5bd2dcfea..67db36208b 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -1,12 +1,14 @@ use editor::Editor; use gpui::{ elements::{ - ChildView, EventHandler, Flex, Label, ParentElement, ScrollTarget, UniformList, - UniformListState, + ChildView, Flex, Label, MouseEventHandler, MouseState, ParentElement, ScrollTarget, + UniformList, UniformListState, }, geometry::vector::{vec2f, Vector2F}, - keymap, AppContext, Axis, Element, ElementBox, Entity, MutableAppContext, RenderContext, Task, - View, ViewContext, ViewHandle, WeakViewHandle, + keymap, + platform::CursorStyle, + AppContext, Axis, Element, ElementBox, Entity, MutableAppContext, RenderContext, Task, View, + ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; use std::cmp; @@ -29,7 +31,13 @@ pub trait PickerDelegate: View { fn update_matches(&mut self, query: String, cx: &mut ViewContext) -> Task<()>; fn confirm(&mut self, cx: &mut ViewContext); fn dismiss(&mut self, cx: &mut ViewContext); - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox; + fn render_match( + &self, + ix: usize, + state: &MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox; fn center_selection_after_match_updates(&self) -> bool { false } @@ -73,18 +81,18 @@ impl View for Picker { self.list_state.clone(), match_count, move |mut range, items, cx| { - let cx = cx.as_ref(); let delegate = delegate.upgrade(cx).unwrap(); - let delegate = delegate.read(cx); - let selected_ix = delegate.selected_index(); - range.end = cmp::min(range.end, delegate.match_count()); + let selected_ix = delegate.read(cx).selected_index(); + range.end = cmp::min(range.end, delegate.read(cx).match_count()); items.extend(range.map(move |ix| { - EventHandler::new(delegate.render_match(ix, ix == selected_ix, cx)) - .on_mouse_down(move |cx| { - cx.dispatch_action(SelectIndex(ix)); - true - }) - .boxed() + MouseEventHandler::new::(ix, cx, |state, cx| { + delegate + .read(cx) + .render_match(ix, state, ix == selected_ix, cx) + }) + .on_mouse_down(move |cx| cx.dispatch_action(SelectIndex(ix))) + .with_cursor_style(CursorStyle::PointingHand) + .boxed() })); }, ) diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index a4e3d6360e..a35d44a810 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -220,14 +220,17 @@ impl PickerDelegate for ProjectSymbolsView { Task::ready(()) } - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox { + fn render_match( + &self, + ix: usize, + mouse_state: &MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox { let string_match = &self.matches[ix]; let settings = cx.global::(); - let style = if selected { - &settings.theme.picker.active_item - } else { - &settings.theme.picker.item - }; + let style = &settings.theme.picker.item; + let current_style = style.style_for(mouse_state, selected); let symbol = &self.symbols[string_match.candidate_id]; let syntax_runs = styled_runs_for_code_label(&symbol.label, &settings.theme.editor.syntax); @@ -246,11 +249,11 @@ impl PickerDelegate for ProjectSymbolsView { Flex::column() .with_child( - Text::new(symbol.label.text.clone(), style.label.text.clone()) + Text::new(symbol.label.text.clone(), current_style.label.text.clone()) .with_soft_wrap(false) .with_highlights(combine_syntax_and_fuzzy_match_highlights( &symbol.label.text, - style.label.text.clone().into(), + current_style.label.text.clone().into(), syntax_runs, &string_match.positions, )) @@ -259,10 +262,10 @@ impl PickerDelegate for ProjectSymbolsView { .with_child( // Avoid styling the path differently when it is selected, since // the symbol's syntax highlighting doesn't change when selected. - Label::new(path.to_string(), settings.theme.picker.item.label.clone()).boxed(), + Label::new(path.to_string(), style.default.label.clone()).boxed(), ) .contained() - .with_style(style.container) + .with_style(current_style.container) .boxed() } } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index bc9bf5643d..9b700e5b1e 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -2,7 +2,7 @@ mod theme_registry; use gpui::{ color::Color, - elements::{ContainerStyle, ImageStyle, LabelStyle}, + elements::{ContainerStyle, ImageStyle, LabelStyle, MouseState}, fonts::{HighlightStyle, TextStyle}, Border, }; @@ -229,7 +229,7 @@ pub struct ProjectPanelEntry { #[derive(Debug, Deserialize, Default)] pub struct CommandPalette { - pub key: ContainedLabel, + pub key: Interactive, pub keystroke_spacing: f32, } @@ -293,8 +293,7 @@ pub struct Picker { pub container: ContainerStyle, pub empty: ContainedLabel, pub input_editor: FieldEditor, - pub item: ContainedLabel, - pub active_item: ContainedLabel, + pub item: Interactive, } #[derive(Clone, Debug, Deserialize, Default)] @@ -419,16 +418,23 @@ pub struct Interactive { } impl Interactive { - pub fn active(&self) -> &T { - self.active.as_ref().unwrap_or(&self.default) - } - - pub fn hover(&self) -> &T { - self.hover.as_ref().unwrap_or(&self.default) - } - - pub fn active_hover(&self) -> &T { - self.active_hover.as_ref().unwrap_or(self.active()) + pub fn style_for(&self, state: &MouseState, active: bool) -> &T { + if active { + if state.hovered { + self.active_hover + .as_ref() + .or(self.active.as_ref()) + .unwrap_or(&self.default) + } else { + self.active.as_ref().unwrap_or(&self.default) + } + } else { + if state.hovered { + self.hover.as_ref().unwrap_or(&self.default) + } else { + &self.default + } + } } } diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 0eff202ea5..1904ed89d9 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -203,15 +203,17 @@ impl PickerDelegate for ThemeSelector { }) } - fn render_match(&self, ix: usize, selected: bool, cx: &AppContext) -> ElementBox { + fn render_match( + &self, + ix: usize, + mouse_state: &MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox { let settings = cx.global::(); let theme = &settings.theme; let theme_match = &self.matches[ix]; - let style = if selected { - &theme.picker.active_item - } else { - &theme.picker.item - }; + let style = theme.picker.item.style_for(mouse_state, selected); Label::new(theme_match.string.clone(), style.label.clone()) .with_highlights(theme_match.positions.clone()) diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index 5f185e47bf..2f13469cec 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -193,13 +193,7 @@ impl View for SidebarButtons { Flex::row() .with_children(items.iter().enumerate().map(|(ix, item)| { MouseEventHandler::new::(ix, cx, move |state, _| { - let style = if Some(ix) == active_ix { - item_style.active() - } else if state.hovered { - item_style.hover() - } else { - &item_style.default - }; + let style = item_style.style_for(state, Some(ix) == active_ix); Svg::new(item.icon_path) .with_color(style.icon_color) .constrained() diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 3b8c132fc3..79b5afbce8 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1574,11 +1574,11 @@ impl Workspace { } else { Some( MouseEventHandler::new::(0, cx, |state, _| { - let style = if state.hovered { - &theme.workspace.titlebar.sign_in_prompt.hover() - } else { - &theme.workspace.titlebar.sign_in_prompt.default - }; + let style = theme + .workspace + .titlebar + .sign_in_prompt + .style_for(state, false); Label::new("Sign in".to_string(), style.text.clone()) .contained() .with_style(style.container) @@ -1649,18 +1649,11 @@ impl Workspace { { Some( MouseEventHandler::new::(0, cx, |state, cx| { - let style = &theme.workspace.titlebar.share_icon; - let style = if self.project().read(cx).is_shared() { - if state.hovered { - style.active_hover() - } else { - &style.active() - } - } else if state.hovered { - &style.active() - } else { - &style.default - }; + let style = &theme + .workspace + .titlebar + .share_icon + .style_for(state, self.project().read(cx).is_shared()); Svg::new("icons/share.svg") .with_color(style.color) .constrained() diff --git a/styles/src/styleTree/commandPalette.ts b/styles/src/styleTree/commandPalette.ts index fbd9bea9b0..0dd290a91c 100644 --- a/styles/src/styleTree/commandPalette.ts +++ b/styles/src/styleTree/commandPalette.ts @@ -18,6 +18,9 @@ export default function commandPalette(theme: Theme) { margin: { left: 2 }, + active: { + text: text(theme, "mono", "active", { size: "xs" }), + } } } } diff --git a/styles/src/styleTree/picker.ts b/styles/src/styleTree/picker.ts index d20bb9dc93..e783945dd1 100644 --- a/styles/src/styleTree/picker.ts +++ b/styles/src/styleTree/picker.ts @@ -2,30 +2,28 @@ import Theme from "../themes/theme"; import { backgroundColor, border, player, shadow, text } from "./components"; export default function picker(theme: Theme) { - const item = { - padding: { - bottom: 4, - left: 12, - right: 12, - top: 4, - }, - cornerRadius: 8, - text: text(theme, "sans", "secondary"), - highlightText: text(theme, "sans", "feature", { weight: "bold" }), - }; - - const activeItem = { - ...item, - background: backgroundColor(theme, 300, "active"), - text: text(theme, "sans", "primary"), - }; - return { background: backgroundColor(theme, 300), cornerRadius: 8, padding: 8, - item, - activeItem, + item: { + padding: { + bottom: 4, + left: 12, + right: 12, + top: 4, + }, + cornerRadius: 8, + text: text(theme, "sans", "secondary"), + highlightText: text(theme, "sans", "feature", { weight: "bold" }), + active: { + background: backgroundColor(theme, 300, "active"), + text: text(theme, "sans", "primary"), + }, + hover: { + background: backgroundColor(theme, 300, "hovered"), + } + }, border: border(theme, "primary"), empty: { text: text(theme, "sans", "placeholder"),