From 895386cfaf33c775205d870f1b7ad620cdb01077 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 22 Sep 2023 19:14:12 -0400 Subject: [PATCH] Mainline `Icon` and `IconButton` changes (#3022) This PR mainlines the `Icon` and `IconButton` changes from the `gpui2-ui` branch. Release Notes: - N/A Co-authored-by: Nate Butler --- crates/ui/src/components/toolbar.rs | 8 +-- crates/ui/src/elements/icon.rs | 89 +++++++++++++++++++++++++-- crates/ui/src/elements/icon_button.rs | 46 +++++++++----- crates/ui/src/templates/chat_panel.rs | 9 +-- crates/ui/src/templates/status_bar.rs | 21 ++++--- crates/ui/src/templates/tab_bar.rs | 16 ++--- crates/ui/src/templates/title_bar.rs | 19 ++++-- 7 files changed, 159 insertions(+), 49 deletions(-) diff --git a/crates/ui/src/components/toolbar.rs b/crates/ui/src/components/toolbar.rs index cc493c00f4..08e671311f 100644 --- a/crates/ui/src/components/toolbar.rs +++ b/crates/ui/src/components/toolbar.rs @@ -2,7 +2,7 @@ use gpui2::elements::div; use gpui2::style::StyleHelpers; use gpui2::{Element, IntoElement, ParentElement, ViewContext}; -use crate::{breadcrumb, icon_button, theme}; +use crate::{breadcrumb, theme, IconAsset, IconButton}; pub struct ToolbarItem {} @@ -27,9 +27,9 @@ impl Toolbar { .child( div() .flex() - .child(icon_button("icons/inlay_hint.svg")) - .child(icon_button("icons/magnifying_glass.svg")) - .child(icon_button("icons/magic-wand.svg")), + .child(IconButton::new(IconAsset::InlayHint)) + .child(IconButton::new(IconAsset::MagnifyingGlass)) + .child(IconButton::new(IconAsset::MagicWand)), ) } } diff --git a/crates/ui/src/elements/icon.rs b/crates/ui/src/elements/icon.rs index 08b8e3e7c5..7d2bb45b49 100644 --- a/crates/ui/src/elements/icon.rs +++ b/crates/ui/src/elements/icon.rs @@ -1,8 +1,41 @@ +use std::sync::Arc; + use crate::theme::theme; +use crate::Theme; use gpui2::elements::svg; use gpui2::style::StyleHelpers; -use gpui2::IntoElement; use gpui2::{Element, ViewContext}; +use gpui2::{Hsla, IntoElement}; + +#[derive(Default, PartialEq, Copy, Clone)] +pub enum IconColor { + #[default] + Default, + Muted, + Disabled, + Placeholder, + Accent, + Error, + Warning, + Success, + Info, +} + +impl IconColor { + pub fn color(self, theme: Arc) -> Hsla { + match self { + IconColor::Default => theme.lowest.base.default.foreground, + IconColor::Muted => theme.lowest.variant.default.foreground, + IconColor::Disabled => theme.lowest.base.disabled.foreground, + IconColor::Placeholder => theme.lowest.base.disabled.foreground, + IconColor::Accent => theme.lowest.accent.default.foreground, + IconColor::Error => theme.lowest.negative.default.foreground, + IconColor::Warning => theme.lowest.warning.default.foreground, + IconColor::Success => theme.lowest.positive.default.foreground, + IconColor::Info => theme.lowest.accent.default.foreground, + } + } +} #[derive(Default, PartialEq, Copy, Clone)] pub enum IconAsset { @@ -10,21 +43,40 @@ pub enum IconAsset { ArrowLeft, ArrowRight, ArrowUpRight, + AudioOff, + AudioOn, Bolt, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, - #[default] + Close, + ExclamationTriangle, File, FileDoc, FileGit, FileLock, FileRust, FileToml, + FileTree, Folder, FolderOpen, + FolderX, + #[default] Hash, + InlayHint, + MagicWand, + MagnifyingGlass, + MessageBubbles, + Mic, + MicMute, + Plus, + Screen, + Split, + Terminal, + XCircle, + Copilot, + Envelope, } impl IconAsset { @@ -34,20 +86,39 @@ impl IconAsset { IconAsset::ArrowLeft => "icons/arrow_left.svg", IconAsset::ArrowRight => "icons/arrow_right.svg", IconAsset::ArrowUpRight => "icons/arrow_up_right.svg", + IconAsset::AudioOff => "icons/speaker-off.svg", + IconAsset::AudioOn => "icons/speaker-loud.svg", IconAsset::Bolt => "icons/bolt.svg", IconAsset::ChevronDown => "icons/chevron_down.svg", IconAsset::ChevronLeft => "icons/chevron_left.svg", IconAsset::ChevronRight => "icons/chevron_right.svg", IconAsset::ChevronUp => "icons/chevron_up.svg", + IconAsset::Close => "icons/x.svg", + IconAsset::ExclamationTriangle => "icons/warning.svg", IconAsset::File => "icons/file_icons/file.svg", IconAsset::FileDoc => "icons/file_icons/book.svg", IconAsset::FileGit => "icons/file_icons/git.svg", IconAsset::FileLock => "icons/file_icons/lock.svg", IconAsset::FileRust => "icons/file_icons/rust.svg", IconAsset::FileToml => "icons/file_icons/toml.svg", + IconAsset::FileTree => "icons/project.svg", IconAsset::Folder => "icons/file_icons/folder.svg", IconAsset::FolderOpen => "icons/file_icons/folder_open.svg", + IconAsset::FolderX => "icons/stop_sharing.svg", IconAsset::Hash => "icons/hash.svg", + IconAsset::InlayHint => "icons/inlay_hint.svg", + IconAsset::MagicWand => "icons/magic-wand.svg", + IconAsset::MagnifyingGlass => "icons/magnifying_glass.svg", + IconAsset::MessageBubbles => "icons/conversations.svg", + IconAsset::Mic => "icons/mic.svg", + IconAsset::MicMute => "icons/mic-mute.svg", + IconAsset::Plus => "icons/plus.svg", + IconAsset::Screen => "icons/desktop.svg", + IconAsset::Split => "icons/split.svg", + IconAsset::Terminal => "icons/terminal.svg", + IconAsset::XCircle => "icons/error.svg", + IconAsset::Copilot => "icons/copilot.svg", + IconAsset::Envelope => "icons/feedback.svg", } } } @@ -55,20 +126,30 @@ impl IconAsset { #[derive(Element, Clone)] pub struct Icon { asset: IconAsset, + color: IconColor, } pub fn icon(asset: IconAsset) -> Icon { - Icon { asset } + Icon { + asset, + color: IconColor::default(), + } } impl Icon { + pub fn color(mut self, color: IconColor) -> Self { + self.color = color; + self + } + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); + let fill = self.color.color(theme); svg() .flex_none() .path(self.asset.path()) .size_4() - .fill(theme.lowest.variant.default.foreground) + .fill(fill) } } diff --git a/crates/ui/src/elements/icon_button.rs b/crates/ui/src/elements/icon_button.rs index 4270e0ca5d..893d41871d 100644 --- a/crates/ui/src/elements/icon_button.rs +++ b/crates/ui/src/elements/icon_button.rs @@ -1,26 +1,47 @@ -use gpui2::elements::{div, svg}; +use gpui2::elements::div; use gpui2::style::{StyleHelpers, Styleable}; use gpui2::{Element, IntoElement, ParentElement, ViewContext}; -use crate::prelude::*; -use crate::theme; +use crate::{icon, theme, IconColor}; +use crate::{prelude::*, IconAsset}; #[derive(Element)] pub struct IconButton { - path: &'static str, + icon: IconAsset, + color: IconColor, variant: ButtonVariant, state: InteractionState, } -pub fn icon_button(path: &'static str) -> IconButton { +pub fn icon_button() -> IconButton { IconButton { - path, + icon: IconAsset::default(), + color: IconColor::default(), variant: ButtonVariant::default(), state: InteractionState::default(), } } impl IconButton { + pub fn new(icon: IconAsset) -> Self { + Self { + icon, + color: IconColor::default(), + variant: ButtonVariant::default(), + state: InteractionState::default(), + } + } + + pub fn icon(mut self, icon: IconAsset) -> Self { + self.icon = icon; + self + } + + pub fn color(mut self, color: IconColor) -> Self { + self.color = color; + self + } + pub fn variant(mut self, variant: ButtonVariant) -> Self { self.variant = variant; self @@ -34,13 +55,10 @@ impl IconButton { fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); - let icon_color; - - if self.state == InteractionState::Disabled { - icon_color = theme.highest.base.disabled.foreground; - } else { - icon_color = theme.highest.base.default.foreground; - } + let icon_color = match (self.state, self.color) { + (InteractionState::Disabled, _) => IconColor::Disabled, + _ => self.color, + }; let mut div = div(); if self.variant == ButtonVariant::Filled { @@ -57,6 +75,6 @@ impl IconButton { .fill(theme.highest.base.hovered.background) .active() .fill(theme.highest.base.pressed.background) - .child(svg().path(self.path).w_4().h_4().fill(icon_color)) + .child(icon(self.icon).color(icon_color)) } } diff --git a/crates/ui/src/templates/chat_panel.rs b/crates/ui/src/templates/chat_panel.rs index 7c3462b3fe..2e3f73d30f 100644 --- a/crates/ui/src/templates/chat_panel.rs +++ b/crates/ui/src/templates/chat_panel.rs @@ -1,12 +1,13 @@ use std::marker::PhantomData; -use crate::icon_button; -use crate::theme::theme; use gpui2::elements::div::ScrollState; use gpui2::style::StyleHelpers; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use crate::theme::theme; +use crate::{icon_button, IconAsset}; + #[derive(Element)] pub struct ChatPanel { view_type: PhantomData, @@ -57,8 +58,8 @@ impl ChatPanel { .flex() .items_center() .gap_px() - .child(icon_button("icons/plus.svg")) - .child(icon_button("icons/split.svg")), + .child(icon_button().icon(IconAsset::Plus)) + .child(icon_button().icon(IconAsset::Split)), ), ) } diff --git a/crates/ui/src/templates/status_bar.rs b/crates/ui/src/templates/status_bar.rs index 22a99fdbf8..21f792c358 100644 --- a/crates/ui/src/templates/status_bar.rs +++ b/crates/ui/src/templates/status_bar.rs @@ -1,11 +1,12 @@ use std::marker::PhantomData; -use crate::theme::{theme, Theme}; -use crate::{icon_button, text_button, tool_divider}; use gpui2::style::StyleHelpers; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use crate::theme::{theme, Theme}; +use crate::{icon_button, text_button, tool_divider, IconAsset}; + #[derive(Default, PartialEq)] pub enum Tool { #[default] @@ -105,10 +106,10 @@ impl StatusBar { .flex() .items_center() .gap_1() - .child(icon_button("icons/project.svg")) - .child(icon_button("icons/hash.svg")) + .child(icon_button().icon(IconAsset::FileTree)) + .child(icon_button().icon(IconAsset::Hash)) .child(tool_divider()) - .child(icon_button("icons/error.svg")) + .child(icon_button().icon(IconAsset::XCircle)) } fn right_tools(&self, theme: &Theme) -> impl Element { div() @@ -129,8 +130,8 @@ impl StatusBar { .flex() .items_center() .gap_1() - .child(icon_button("icons/copilot.svg")) - .child(icon_button("icons/feedback.svg")), + .child(icon_button().icon(IconAsset::Copilot)) + .child(icon_button().icon(IconAsset::Envelope)), ) .child(tool_divider()) .child( @@ -138,9 +139,9 @@ impl StatusBar { .flex() .items_center() .gap_1() - .child(icon_button("icons/terminal.svg")) - .child(icon_button("icons/conversations.svg")) - .child(icon_button("icons/ai.svg")), + .child(icon_button().icon(IconAsset::Terminal)) + .child(icon_button().icon(IconAsset::MessageBubbles)) + .child(icon_button().icon(IconAsset::Ai)), ) } } diff --git a/crates/ui/src/templates/tab_bar.rs b/crates/ui/src/templates/tab_bar.rs index e1ca6b1dc7..c8892b4697 100644 --- a/crates/ui/src/templates/tab_bar.rs +++ b/crates/ui/src/templates/tab_bar.rs @@ -1,13 +1,14 @@ use std::marker::PhantomData; -use crate::prelude::InteractionState; -use crate::theme::theme; -use crate::{icon_button, tab}; use gpui2::elements::div::ScrollState; use gpui2::style::StyleHelpers; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use crate::prelude::InteractionState; +use crate::theme::theme; +use crate::{icon_button, tab, IconAsset}; + #[derive(Element)] pub struct TabBar { view_type: PhantomData, @@ -43,11 +44,12 @@ impl TabBar { .items_center() .gap_px() .child( - icon_button("icons/arrow_left.svg") + icon_button() + .icon(IconAsset::ArrowLeft) .state(InteractionState::Enabled.if_enabled(can_navigate_back)), ) .child( - icon_button("icons/arrow_right.svg").state( + icon_button().icon(IconAsset::ArrowRight).state( InteractionState::Enabled.if_enabled(can_navigate_forward), ), ), @@ -83,8 +85,8 @@ impl TabBar { .flex() .items_center() .gap_px() - .child(icon_button("icons/plus.svg")) - .child(icon_button("icons/split.svg")), + .child(icon_button().icon(IconAsset::Plus)) + .child(icon_button().icon(IconAsset::Split)), ), ) } diff --git a/crates/ui/src/templates/title_bar.rs b/crates/ui/src/templates/title_bar.rs index 82c5c0234b..f926adbd26 100644 --- a/crates/ui/src/templates/title_bar.rs +++ b/crates/ui/src/templates/title_bar.rs @@ -5,7 +5,10 @@ use gpui2::style::StyleHelpers; use gpui2::{Element, IntoElement, ParentElement, ViewContext}; use crate::prelude::Shape; -use crate::{avatar, follow_group, icon_button, text_button, theme, tool_divider, traffic_lights}; +use crate::{ + avatar, follow_group, icon_button, text_button, theme, tool_divider, traffic_lights, IconAsset, + IconColor, +}; #[derive(Element)] pub struct TitleBar { @@ -65,8 +68,8 @@ impl TitleBar { .flex() .items_center() .gap_1() - .child(icon_button("icons/stop_sharing.svg")) - .child(icon_button("icons/exit.svg")), + .child(icon_button().icon(IconAsset::FolderX)) + .child(icon_button().icon(IconAsset::Close)), ) .child(tool_divider()) .child( @@ -75,9 +78,13 @@ impl TitleBar { .flex() .items_center() .gap_1() - .child(icon_button("icons/mic.svg")) - .child(icon_button("icons/speaker-loud.svg")) - .child(icon_button("icons/desktop.svg")), + .child(icon_button().icon(IconAsset::Mic)) + .child(icon_button().icon(IconAsset::AudioOn)) + .child( + icon_button() + .icon(IconAsset::Screen) + .color(IconColor::Accent), + ), ) .child( div().px_2().flex().items_center().child(