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::{
|
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;
|
use crate::section;
|
||||||
|
|
||||||
|
|
@ -45,32 +46,84 @@ impl Render for TagStory {
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
.child(
|
.child(
|
||||||
section("Tag")
|
section("Tag (default)").child(
|
||||||
.child(
|
h_flex()
|
||||||
h_flex()
|
.gap_2()
|
||||||
.gap_2()
|
.child(Tag::primary().child("Tag"))
|
||||||
.child(Tag::primary().small().child("Tag"))
|
.child(Tag::secondary().child("Secondary"))
|
||||||
.child(Tag::secondary().small().child("Secondary"))
|
.child(Tag::danger().child("Danger"))
|
||||||
.child(Tag::outline().small().child("Outline"))
|
.child(Tag::success().child("Success"))
|
||||||
.child(Tag::danger().small().child("danger"))
|
.child(Tag::warning().child("Warning"))
|
||||||
.child(
|
.child(Tag::info().child("Info"))
|
||||||
Tag::custom(yellow_500(), yellow_800(), yellow_500())
|
.child(
|
||||||
.small()
|
Tag::custom(indigo_500(), indigo_500(), indigo_500()).child("Custom"),
|
||||||
.child("Custom"),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
section("Tag (outline)").child(
|
||||||
.gap_2()
|
h_flex()
|
||||||
.child(Tag::primary().child("Tag"))
|
.gap_2()
|
||||||
.child(Tag::secondary().child("Secondary"))
|
.child(Tag::primary().outline().child("Tag"))
|
||||||
.child(Tag::outline().child("Outline"))
|
.child(Tag::secondary().outline().child("Secondary"))
|
||||||
.child(Tag::danger().child("danger"))
|
.child(Tag::danger().outline().child("Danger"))
|
||||||
.child(
|
.child(Tag::success().outline().child("Success"))
|
||||||
Tag::custom(yellow_500(), yellow_800(), yellow_500())
|
.child(Tag::warning().outline().child("Warning"))
|
||||||
.child("Custom"),
|
.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(
|
.child(
|
||||||
section("Color Tags").child(
|
section("Color Tags").child(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
use crate::{theme::ActiveTheme as _, ColorName, Sizable, Size};
|
use crate::{theme::ActiveTheme as _, ColorName, Sizable, Size};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, relative, transparent_black, AnyElement, App, Div, Hsla,
|
div, prelude::FluentBuilder as _, relative, rems, transparent_white, AbsoluteLength,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, RenderOnce, Styled, Window,
|
AnyElement, App, Div, Hsla, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
|
||||||
|
Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub enum TagVariant {
|
pub enum TagVariant {
|
||||||
#[default]
|
|
||||||
Outline,
|
|
||||||
Primary,
|
Primary,
|
||||||
|
#[default]
|
||||||
Secondary,
|
Secondary,
|
||||||
Danger,
|
Danger,
|
||||||
|
Success,
|
||||||
|
Warning,
|
||||||
|
Info,
|
||||||
Color(ColorName),
|
Color(ColorName),
|
||||||
Custom {
|
Custom {
|
||||||
color: Hsla,
|
color: Hsla,
|
||||||
|
|
@ -24,8 +27,10 @@ impl TagVariant {
|
||||||
match self {
|
match self {
|
||||||
Self::Primary => cx.theme().primary,
|
Self::Primary => cx.theme().primary,
|
||||||
Self::Secondary => cx.theme().secondary,
|
Self::Secondary => cx.theme().secondary,
|
||||||
Self::Outline => transparent_black(),
|
|
||||||
Self::Danger => cx.theme().danger,
|
Self::Danger => cx.theme().danger,
|
||||||
|
Self::Success => cx.theme().success,
|
||||||
|
Self::Warning => cx.theme().warning,
|
||||||
|
Self::Info => cx.theme().info,
|
||||||
Self::Color(color) => {
|
Self::Color(color) => {
|
||||||
if cx.theme().is_dark() {
|
if cx.theme().is_dark() {
|
||||||
color.scale(950).opacity(0.5)
|
color.scale(950).opacity(0.5)
|
||||||
|
|
@ -40,9 +45,11 @@ impl TagVariant {
|
||||||
fn border(&self, cx: &App) -> Hsla {
|
fn border(&self, cx: &App) -> Hsla {
|
||||||
match self {
|
match self {
|
||||||
Self::Primary => cx.theme().primary,
|
Self::Primary => cx.theme().primary,
|
||||||
Self::Secondary => cx.theme().secondary,
|
Self::Secondary => cx.theme().border,
|
||||||
Self::Outline => cx.theme().border,
|
|
||||||
Self::Danger => cx.theme().danger,
|
Self::Danger => cx.theme().danger,
|
||||||
|
Self::Success => cx.theme().success,
|
||||||
|
Self::Warning => cx.theme().warning,
|
||||||
|
Self::Info => cx.theme().info,
|
||||||
Self::Color(color) => {
|
Self::Color(color) => {
|
||||||
if cx.theme().is_dark() {
|
if cx.theme().is_dark() {
|
||||||
color.scale(800).opacity(0.5)
|
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 {
|
match self {
|
||||||
Self::Primary => cx.theme().primary_foreground,
|
Self::Primary => {
|
||||||
Self::Secondary => cx.theme().secondary_foreground,
|
if outline {
|
||||||
Self::Outline => cx.theme().foreground,
|
cx.theme().primary
|
||||||
Self::Danger => cx.theme().danger_foreground,
|
} 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) => {
|
Self::Color(color) => {
|
||||||
if cx.theme().is_dark() {
|
if cx.theme().is_dark() {
|
||||||
color.scale(300)
|
color.scale(300)
|
||||||
|
|
@ -79,14 +124,18 @@ impl TagVariant {
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
base: Div,
|
base: Div,
|
||||||
variant: TagVariant,
|
variant: TagVariant,
|
||||||
|
outline: bool,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
rounded: Option<AbsoluteLength>,
|
||||||
}
|
}
|
||||||
impl Tag {
|
impl Tag {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: div().flex().items_center().border_1(),
|
base: div().flex().items_center().border_1(),
|
||||||
variant: TagVariant::default(),
|
variant: TagVariant::default(),
|
||||||
|
outline: false,
|
||||||
size: Size::default(),
|
size: Size::default(),
|
||||||
|
rounded: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +144,12 @@ impl Tag {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use outline style
|
||||||
|
pub fn outline(mut self) -> Self {
|
||||||
|
self.outline = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new tag with default variant ([`TagVariant::Primary`]).
|
/// Create a new tag with default variant ([`TagVariant::Primary`]).
|
||||||
pub fn primary() -> Self {
|
pub fn primary() -> Self {
|
||||||
Self::new().with_variant(TagVariant::Primary)
|
Self::new().with_variant(TagVariant::Primary)
|
||||||
|
|
@ -105,18 +160,26 @@ impl Tag {
|
||||||
Self::new().with_variant(TagVariant::Secondary)
|
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`]).
|
/// Create a new tag with default variant ([`TagVariant::Danger`]).
|
||||||
pub fn danger() -> Self {
|
pub fn danger() -> Self {
|
||||||
Self::new().with_variant(TagVariant::Danger)
|
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`]).
|
/// Create a new tag with default variant ([`TagVariant::Custom`]).
|
||||||
pub fn custom(color: Hsla, foreground: Hsla, border: Hsla) -> Self {
|
pub fn custom(color: Hsla, foreground: Hsla, border: Hsla) -> Self {
|
||||||
Self::new().with_variant(TagVariant::Custom {
|
Self::new().with_variant(TagVariant::Custom {
|
||||||
|
|
@ -130,7 +193,20 @@ impl Tag {
|
||||||
pub fn color(color: impl Into<ColorName>) -> Self {
|
pub fn color(color: impl Into<ColorName>) -> Self {
|
||||||
Self::new().with_variant(TagVariant::Color(color.into()))
|
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 {
|
impl Sizable for Tag {
|
||||||
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
||||||
self.size = size.into();
|
self.size = size.into();
|
||||||
|
|
@ -144,20 +220,32 @@ impl ParentElement for Tag {
|
||||||
}
|
}
|
||||||
impl RenderOnce for Tag {
|
impl RenderOnce for Tag {
|
||||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let bg = self.variant.bg(cx);
|
let bg = if self.outline {
|
||||||
let fg = self.variant.fg(cx);
|
transparent_white()
|
||||||
|
} else {
|
||||||
|
self.variant.bg(cx)
|
||||||
|
};
|
||||||
|
let fg = self.variant.fg(self.outline, cx);
|
||||||
let border = self.variant.border(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
|
self.base
|
||||||
.line_height(relative(1.3))
|
.line_height(relative(1.))
|
||||||
.text_xs()
|
.text_xs()
|
||||||
.map(|this| match self.size {
|
.map(|this| match self.size {
|
||||||
Size::XSmall | Size::Small => this.px_1p5().py_0().rounded(cx.theme().radius / 2.),
|
Size::XSmall | Size::Small => this.px_1p5().py_0p5(),
|
||||||
_ => this.px_2p5().py_0p5().rounded(cx.theme().radius),
|
_ => this.px_2p5().py_1(),
|
||||||
})
|
})
|
||||||
.bg(bg)
|
.bg(bg)
|
||||||
.text_color(fg)
|
.text_color(fg)
|
||||||
.border_color(border)
|
.border_color(border)
|
||||||
|
.rounded(rounded)
|
||||||
.hover(|this| this.opacity(0.9))
|
.hover(|this| this.opacity(0.9))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue