tag: Add rounded to Tag and support outline for all variants. (#923)
<img width="1316" alt="image" src="https://github.com/user-attachments/assets/e06f672d-f311-4dc2-b62a-c1f5cbce6973" />
This commit is contained in:
parent
e3e00a38b8
commit
d598e58666
2 changed files with 193 additions and 52 deletions
|
|
@ -1,8 +1,9 @@
|
|||
use gpui::{
|
||||
App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement, Render, Styled, Window,
|
||||
px, App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement, Render, Styled,
|
||||
Window,
|
||||
};
|
||||
|
||||
use gpui_component::{h_flex, tag::Tag, v_flex, yellow_500, yellow_800, ColorName, Sizable};
|
||||
use gpui_component::{h_flex, indigo_500, tag::Tag, v_flex, ColorName, Sizable};
|
||||
|
||||
use crate::section;
|
||||
|
||||
|
|
@ -45,32 +46,84 @@ impl Render for TagStory {
|
|||
v_flex()
|
||||
.gap_6()
|
||||
.child(
|
||||
section("Tag")
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().small().child("Tag"))
|
||||
.child(Tag::secondary().small().child("Secondary"))
|
||||
.child(Tag::outline().small().child("Outline"))
|
||||
.child(Tag::danger().small().child("danger"))
|
||||
.child(
|
||||
Tag::custom(yellow_500(), yellow_800(), yellow_500())
|
||||
.small()
|
||||
.child("Custom"),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().child("Tag"))
|
||||
.child(Tag::secondary().child("Secondary"))
|
||||
.child(Tag::outline().child("Outline"))
|
||||
.child(Tag::danger().child("danger"))
|
||||
.child(
|
||||
Tag::custom(yellow_500(), yellow_800(), yellow_500())
|
||||
.child("Custom"),
|
||||
),
|
||||
),
|
||||
section("Tag (default)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().child("Tag"))
|
||||
.child(Tag::secondary().child("Secondary"))
|
||||
.child(Tag::danger().child("Danger"))
|
||||
.child(Tag::success().child("Success"))
|
||||
.child(Tag::warning().child("Warning"))
|
||||
.child(Tag::info().child("Info"))
|
||||
.child(
|
||||
Tag::custom(indigo_500(), indigo_500(), indigo_500()).child("Custom"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Tag (outline)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().outline().child("Tag"))
|
||||
.child(Tag::secondary().outline().child("Secondary"))
|
||||
.child(Tag::danger().outline().child("Danger"))
|
||||
.child(Tag::success().outline().child("Success"))
|
||||
.child(Tag::warning().outline().child("Warning"))
|
||||
.child(Tag::info().outline().child("Info"))
|
||||
.child(
|
||||
Tag::custom(indigo_500(), indigo_500(), indigo_500())
|
||||
.outline()
|
||||
.child("Custom"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Tag (small)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().small().child("Tag"))
|
||||
.child(Tag::secondary().small().child("Secondary"))
|
||||
.child(Tag::danger().small().child("Danger"))
|
||||
.child(Tag::success().small().child("Success"))
|
||||
.child(Tag::warning().small().child("Warning"))
|
||||
.child(Tag::info().small().child("Info")),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Tag (rounded full)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().rounded_full().child("Tag"))
|
||||
.child(Tag::secondary().rounded_full().child("Secondary"))
|
||||
.child(Tag::danger().rounded_full().child("Danger"))
|
||||
.child(Tag::success().rounded_full().child("Success"))
|
||||
.child(Tag::warning().rounded_full().child("Warning"))
|
||||
.child(Tag::info().rounded_full().child("Info")),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Tag (small with rounded full)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().small().rounded_full().child("Tag"))
|
||||
.child(Tag::secondary().small().rounded_full().child("Secondary"))
|
||||
.child(Tag::danger().small().rounded_full().child("Danger"))
|
||||
.child(Tag::success().small().rounded_full().child("Success"))
|
||||
.child(Tag::warning().small().rounded_full().child("Warning"))
|
||||
.child(Tag::info().small().rounded_full().child("Info")),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Tag (rounded 0px)").child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Tag::primary().small().rounded(px(0.)).child("Tag"))
|
||||
.child(Tag::secondary().small().rounded(px(0.)).child("Secondary"))
|
||||
.child(Tag::danger().small().rounded(px(0.)).child("Danger"))
|
||||
.child(Tag::success().small().rounded(px(0.)).child("Success"))
|
||||
.child(Tag::warning().small().rounded(px(0.)).child("Warning"))
|
||||
.child(Tag::info().small().rounded(px(0.)).child("Info")),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
section("Color Tags").child(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
use crate::{theme::ActiveTheme as _, ColorName, Sizable, Size};
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder as _, relative, transparent_black, AnyElement, App, Div, Hsla,
|
||||
InteractiveElement as _, IntoElement, ParentElement, RenderOnce, Styled, Window,
|
||||
div, prelude::FluentBuilder as _, relative, rems, transparent_white, AbsoluteLength,
|
||||
AnyElement, App, Div, Hsla, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
|
||||
Styled, Window,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum TagVariant {
|
||||
#[default]
|
||||
Outline,
|
||||
Primary,
|
||||
#[default]
|
||||
Secondary,
|
||||
Danger,
|
||||
Success,
|
||||
Warning,
|
||||
Info,
|
||||
Color(ColorName),
|
||||
Custom {
|
||||
color: Hsla,
|
||||
|
|
@ -24,8 +27,10 @@ impl TagVariant {
|
|||
match self {
|
||||
Self::Primary => cx.theme().primary,
|
||||
Self::Secondary => cx.theme().secondary,
|
||||
Self::Outline => transparent_black(),
|
||||
Self::Danger => cx.theme().danger,
|
||||
Self::Success => cx.theme().success,
|
||||
Self::Warning => cx.theme().warning,
|
||||
Self::Info => cx.theme().info,
|
||||
Self::Color(color) => {
|
||||
if cx.theme().is_dark() {
|
||||
color.scale(950).opacity(0.5)
|
||||
|
|
@ -40,9 +45,11 @@ impl TagVariant {
|
|||
fn border(&self, cx: &App) -> Hsla {
|
||||
match self {
|
||||
Self::Primary => cx.theme().primary,
|
||||
Self::Secondary => cx.theme().secondary,
|
||||
Self::Outline => cx.theme().border,
|
||||
Self::Secondary => cx.theme().border,
|
||||
Self::Danger => cx.theme().danger,
|
||||
Self::Success => cx.theme().success,
|
||||
Self::Warning => cx.theme().warning,
|
||||
Self::Info => cx.theme().info,
|
||||
Self::Color(color) => {
|
||||
if cx.theme().is_dark() {
|
||||
color.scale(800).opacity(0.5)
|
||||
|
|
@ -54,12 +61,50 @@ impl TagVariant {
|
|||
}
|
||||
}
|
||||
|
||||
fn fg(&self, cx: &App) -> Hsla {
|
||||
fn fg(&self, outline: bool, cx: &App) -> Hsla {
|
||||
match self {
|
||||
Self::Primary => cx.theme().primary_foreground,
|
||||
Self::Secondary => cx.theme().secondary_foreground,
|
||||
Self::Outline => cx.theme().foreground,
|
||||
Self::Danger => cx.theme().danger_foreground,
|
||||
Self::Primary => {
|
||||
if outline {
|
||||
cx.theme().primary
|
||||
} else {
|
||||
cx.theme().primary_foreground
|
||||
}
|
||||
}
|
||||
Self::Secondary => {
|
||||
if outline {
|
||||
cx.theme().muted_foreground
|
||||
} else {
|
||||
cx.theme().secondary_foreground
|
||||
}
|
||||
}
|
||||
Self::Danger => {
|
||||
if outline {
|
||||
cx.theme().danger
|
||||
} else {
|
||||
cx.theme().danger_foreground
|
||||
}
|
||||
}
|
||||
Self::Success => {
|
||||
if outline {
|
||||
cx.theme().success
|
||||
} else {
|
||||
cx.theme().success_foreground
|
||||
}
|
||||
}
|
||||
Self::Warning => {
|
||||
if outline {
|
||||
cx.theme().warning
|
||||
} else {
|
||||
cx.theme().warning_foreground
|
||||
}
|
||||
}
|
||||
Self::Info => {
|
||||
if outline {
|
||||
cx.theme().info
|
||||
} else {
|
||||
cx.theme().info_foreground
|
||||
}
|
||||
}
|
||||
Self::Color(color) => {
|
||||
if cx.theme().is_dark() {
|
||||
color.scale(300)
|
||||
|
|
@ -79,14 +124,18 @@ impl TagVariant {
|
|||
pub struct Tag {
|
||||
base: Div,
|
||||
variant: TagVariant,
|
||||
outline: bool,
|
||||
size: Size,
|
||||
rounded: Option<AbsoluteLength>,
|
||||
}
|
||||
impl Tag {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
base: div().flex().items_center().border_1(),
|
||||
variant: TagVariant::default(),
|
||||
outline: false,
|
||||
size: Size::default(),
|
||||
rounded: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +144,12 @@ impl Tag {
|
|||
self
|
||||
}
|
||||
|
||||
/// Use outline style
|
||||
pub fn outline(mut self) -> Self {
|
||||
self.outline = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Primary`]).
|
||||
pub fn primary() -> Self {
|
||||
Self::new().with_variant(TagVariant::Primary)
|
||||
|
|
@ -105,18 +160,26 @@ impl Tag {
|
|||
Self::new().with_variant(TagVariant::Secondary)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Outline`]).
|
||||
///
|
||||
/// See also [`Tag::new`].
|
||||
pub fn outline() -> Self {
|
||||
Self::new().with_variant(TagVariant::Outline)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Danger`]).
|
||||
pub fn danger() -> Self {
|
||||
Self::new().with_variant(TagVariant::Danger)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Success`]).
|
||||
pub fn success() -> Self {
|
||||
Self::new().with_variant(TagVariant::Success)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Warning`]).
|
||||
pub fn warning() -> Self {
|
||||
Self::new().with_variant(TagVariant::Warning)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Info`]).
|
||||
pub fn info() -> Self {
|
||||
Self::new().with_variant(TagVariant::Info)
|
||||
}
|
||||
|
||||
/// Create a new tag with default variant ([`TagVariant::Custom`]).
|
||||
pub fn custom(color: Hsla, foreground: Hsla, border: Hsla) -> Self {
|
||||
Self::new().with_variant(TagVariant::Custom {
|
||||
|
|
@ -130,7 +193,20 @@ impl Tag {
|
|||
pub fn color(color: impl Into<ColorName>) -> Self {
|
||||
Self::new().with_variant(TagVariant::Color(color.into()))
|
||||
}
|
||||
|
||||
/// Set rounded corners.
|
||||
pub fn rounded(mut self, radius: impl Into<AbsoluteLength>) -> Self {
|
||||
self.rounded = Some(radius.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set rounded full
|
||||
pub fn rounded_full(mut self) -> Self {
|
||||
self.rounded = Some(rems(1.).into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Sizable for Tag {
|
||||
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
||||
self.size = size.into();
|
||||
|
|
@ -144,20 +220,32 @@ impl ParentElement for Tag {
|
|||
}
|
||||
impl RenderOnce for Tag {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let bg = self.variant.bg(cx);
|
||||
let fg = self.variant.fg(cx);
|
||||
let bg = if self.outline {
|
||||
transparent_white()
|
||||
} else {
|
||||
self.variant.bg(cx)
|
||||
};
|
||||
let fg = self.variant.fg(self.outline, cx);
|
||||
let border = self.variant.border(cx);
|
||||
let rounded = self.rounded.unwrap_or(
|
||||
match self.size {
|
||||
Size::XSmall | Size::Small => cx.theme().radius / 2.,
|
||||
_ => cx.theme().radius,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
||||
self.base
|
||||
.line_height(relative(1.3))
|
||||
.line_height(relative(1.))
|
||||
.text_xs()
|
||||
.map(|this| match self.size {
|
||||
Size::XSmall | Size::Small => this.px_1p5().py_0().rounded(cx.theme().radius / 2.),
|
||||
_ => this.px_2p5().py_0p5().rounded(cx.theme().radius),
|
||||
Size::XSmall | Size::Small => this.px_1p5().py_0p5(),
|
||||
_ => this.px_2p5().py_1(),
|
||||
})
|
||||
.bg(bg)
|
||||
.text_color(fg)
|
||||
.border_color(border)
|
||||
.rounded(rounded)
|
||||
.hover(|this| this.opacity(0.9))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue