mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-21 03:18:47 +03:00
Add DecoratedIcon (#11512)
This allows us to create icons with dynamic decorations drawn on top like these: ![image](https://github.com/zed-industries/zed/assets/1714999/1d1a22df-8f90-47f2-abbd-ed7afa8fc641) ### Examples: ```rust div() .child(DecoratedIcon::new( Icon::new(IconName::Bell).color(Color::Muted), IconDecoration::IndicatorDot, )) .child( DecoratedIcon::new(Icon::new(IconName::Bell), IconDecoration::IndicatorDot) .decoration_color(Color::Accent), ) .child(DecoratedIcon::new( Icon::new(IconName::Bell).color(Color::Muted), IconDecoration::Strikethrough, )) .child( DecoratedIcon::new(Icon::new(IconName::Bell), IconDecoration::X) .decoration_color(Color::Error), ) ``` Release Notes: - N/A
This commit is contained in:
parent
768b63a497
commit
47ca343803
3
assets/icons/indicator.svg
Normal file
3
assets/icons/indicator.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.5 15C13.433 15 15 13.433 15 11.5C15 9.567 13.433 8 11.5 8C9.567 8 8 9.567 8 11.5C8 13.433 9.567 15 11.5 15Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 240 B |
3
assets/icons/indicator_x.svg
Normal file
3
assets/icons/indicator_x.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4662 14.9152C13.5801 15.0291 13.7648 15.0291 13.8787 14.9152L14.9145 13.8793C15.0284 13.7654 15.0284 13.5807 14.9145 13.4667L12.9483 11.5004L14.9145 9.53392C15.0285 9.42004 15.0285 9.23533 14.9145 9.12137L13.8787 8.08547C13.7648 7.97154 13.5801 7.97154 13.4662 8.08547L11.5 10.0519L9.53376 8.08545C9.41988 7.97152 9.23517 7.97152 9.12124 8.08545L8.08543 9.12136C7.97152 9.23533 7.97152 9.42004 8.08543 9.53392L10.0517 11.5004L8.08545 13.4667C7.97155 13.5807 7.97155 13.7654 8.08545 13.8793L9.12126 14.9152C9.23517 15.0292 9.41988 15.0292 9.53376 14.9152L11.5 12.9489L13.4662 14.9152Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 756 B |
3
assets/icons/strikethrough.svg
Normal file
3
assets/icons/strikethrough.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 4L13 12" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 181 B |
@ -41,6 +41,17 @@ impl RenderOnce for AnyIcon {
|
||||
}
|
||||
}
|
||||
|
||||
/// The decoration for an icon.
|
||||
///
|
||||
/// For example, this can show an indicator, an "x",
|
||||
/// or a diagonal strkethrough to indicate something is disabled.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, EnumIter)]
|
||||
pub enum IconDecoration {
|
||||
Strikethrough,
|
||||
IndicatorDot,
|
||||
X,
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Copy, Clone)]
|
||||
pub enum IconSize {
|
||||
Indicator,
|
||||
@ -119,6 +130,8 @@ pub enum IconName {
|
||||
FolderX,
|
||||
Github,
|
||||
Hash,
|
||||
Indicator,
|
||||
IndicatorX,
|
||||
InlayHint,
|
||||
Link,
|
||||
MagicWand,
|
||||
@ -159,6 +172,7 @@ pub enum IconName {
|
||||
SupermavenDisabled,
|
||||
SupermavenError,
|
||||
SupermavenInit,
|
||||
Strikethrough,
|
||||
Tab,
|
||||
Terminal,
|
||||
Trash,
|
||||
@ -229,6 +243,8 @@ impl IconName {
|
||||
IconName::FolderX => "icons/stop_sharing.svg",
|
||||
IconName::Github => "icons/github.svg",
|
||||
IconName::Hash => "icons/hash.svg",
|
||||
IconName::Indicator => "icons/indicator.svg",
|
||||
IconName::IndicatorX => "icons/indicator_x.svg",
|
||||
IconName::InlayHint => "icons/inlay_hint.svg",
|
||||
IconName::Link => "icons/link.svg",
|
||||
IconName::MagicWand => "icons/magic_wand.svg",
|
||||
@ -269,6 +285,7 @@ impl IconName {
|
||||
IconName::SupermavenDisabled => "icons/supermaven_disabled.svg",
|
||||
IconName::SupermavenError => "icons/supermaven_error.svg",
|
||||
IconName::SupermavenInit => "icons/supermaven_init.svg",
|
||||
IconName::Strikethrough => "icons/strikethrough.svg",
|
||||
IconName::Tab => "icons/tab.svg",
|
||||
IconName::Terminal => "icons/terminal.svg",
|
||||
IconName::Trash => "icons/trash.svg",
|
||||
@ -344,6 +361,80 @@ impl RenderOnce for Icon {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct DecoratedIcon {
|
||||
icon: Icon,
|
||||
decoration: IconDecoration,
|
||||
decoration_color: Color,
|
||||
parent_background: Option<Hsla>,
|
||||
}
|
||||
|
||||
impl DecoratedIcon {
|
||||
pub fn new(icon: Icon, decoration: IconDecoration) -> Self {
|
||||
Self {
|
||||
icon,
|
||||
decoration,
|
||||
decoration_color: Color::Default,
|
||||
parent_background: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decoration_color(mut self, color: Color) -> Self {
|
||||
self.decoration_color = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parent_background(mut self, background: Option<Hsla>) -> Self {
|
||||
self.parent_background = background;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for DecoratedIcon {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let background = self
|
||||
.parent_background
|
||||
.unwrap_or(cx.theme().colors().background);
|
||||
|
||||
let size = self.icon.size;
|
||||
|
||||
let decoration_icon = match self.decoration {
|
||||
IconDecoration::Strikethrough => IconName::Strikethrough,
|
||||
IconDecoration::IndicatorDot => IconName::Indicator,
|
||||
IconDecoration::X => IconName::IndicatorX,
|
||||
};
|
||||
|
||||
let decoration_svg = |icon: IconName| {
|
||||
svg()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.path(icon.path())
|
||||
.size(size)
|
||||
.flex_none()
|
||||
.text_color(self.decoration_color.color(cx))
|
||||
};
|
||||
|
||||
let decoration_knockout = |icon: IconName| {
|
||||
svg()
|
||||
.absolute()
|
||||
.top(-rems_from_px(2.))
|
||||
.left(-rems_from_px(3.))
|
||||
.path(icon.path())
|
||||
.size(size + rems_from_px(2.))
|
||||
.flex_none()
|
||||
.text_color(background)
|
||||
};
|
||||
|
||||
div()
|
||||
.relative()
|
||||
.size(self.icon.size)
|
||||
.child(self.icon)
|
||||
.child(decoration_knockout(decoration_icon))
|
||||
.child(decoration_svg(decoration_icon))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct IconWithIndicator {
|
||||
icon: Icon,
|
||||
|
@ -2,7 +2,7 @@ use gpui::Render;
|
||||
use story::Story;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{prelude::*, DecoratedIcon, IconDecoration};
|
||||
use crate::{Icon, IconName};
|
||||
|
||||
pub struct IconStory;
|
||||
@ -13,6 +13,23 @@ impl Render for IconStory {
|
||||
|
||||
Story::container()
|
||||
.child(Story::title_for::<Icon>())
|
||||
.child(Story::label("DecoratedIcon"))
|
||||
.child(DecoratedIcon::new(
|
||||
Icon::new(IconName::Bell).color(Color::Muted),
|
||||
IconDecoration::IndicatorDot,
|
||||
))
|
||||
.child(
|
||||
DecoratedIcon::new(Icon::new(IconName::Bell), IconDecoration::IndicatorDot)
|
||||
.decoration_color(Color::Accent),
|
||||
)
|
||||
.child(DecoratedIcon::new(
|
||||
Icon::new(IconName::Bell).color(Color::Muted),
|
||||
IconDecoration::Strikethrough,
|
||||
))
|
||||
.child(
|
||||
DecoratedIcon::new(Icon::new(IconName::Bell), IconDecoration::X)
|
||||
.decoration_color(Color::Error),
|
||||
)
|
||||
.child(Story::label("All Icons"))
|
||||
.child(div().flex().gap_3().children(icons.map(Icon::new)))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user