Add Link style Button (#97)
<img width="1305" alt="image" src="https://github.com/user-attachments/assets/ee42d86f-e237-4544-aa2d-1414dabfb55e"> - Update `primary`, `danger`, `outline`, `ghost`, `link` methods to as a builder method to just change style. - Add `compact` used to reduce padding. <img width="1279" alt="image" src="https://github.com/user-attachments/assets/ccbd71c0-9157-4ef8-b164-b99ade24cf92">
This commit is contained in:
parent
4a5b387b40
commit
e9d409a4b1
9 changed files with 490 additions and 178 deletions
1
assets/icons/menu.svg
Normal file
1
assets/icons/menu.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>
|
||||||
|
After Width: | Height: | Size: 327 B |
|
|
@ -5,18 +5,29 @@ use gpui::{
|
||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
button::{Button, ButtonCustomStyle, ButtonStyle},
|
button::{Button, ButtonCustomStyle, ButtonStyle},
|
||||||
|
checkbox::Checkbox,
|
||||||
h_flex,
|
h_flex,
|
||||||
theme::ActiveTheme,
|
theme::ActiveTheme,
|
||||||
v_flex, Clickable, Disableable as _, Icon, IconName, Selectable, Size,
|
v_flex, Clickable, Disableable as _, Icon, IconName, Selectable as _, Size,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::section;
|
use crate::section;
|
||||||
|
|
||||||
pub struct ButtonStory {}
|
pub struct ButtonStory {
|
||||||
|
disabled: bool,
|
||||||
|
loading: bool,
|
||||||
|
selected: bool,
|
||||||
|
compact: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl ButtonStory {
|
impl ButtonStory {
|
||||||
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
pub fn view(cx: &mut WindowContext) -> View<Self> {
|
||||||
cx.new_view(|_| Self {})
|
cx.new_view(|_| Self {
|
||||||
|
disabled: false,
|
||||||
|
loading: false,
|
||||||
|
selected: false,
|
||||||
|
compact: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_click(ev: &ClickEvent, _: &mut WindowContext) {
|
fn on_click(ev: &ClickEvent, _: &mut WindowContext) {
|
||||||
|
|
@ -26,8 +37,54 @@ impl ButtonStory {
|
||||||
|
|
||||||
impl Render for ButtonStory {
|
impl Render for ButtonStory {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
let disabled = self.disabled;
|
||||||
|
let loading = self.loading;
|
||||||
|
let selected = self.selected;
|
||||||
|
let compact = self.compact;
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_3()
|
||||||
|
.child("State")
|
||||||
|
.child(
|
||||||
|
Checkbox::new("disabled-button")
|
||||||
|
.label("Disabled")
|
||||||
|
.checked(self.disabled)
|
||||||
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
|
view.disabled = !view.disabled;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("loading-button")
|
||||||
|
.label("Loading")
|
||||||
|
.checked(self.loading)
|
||||||
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
|
view.loading = !view.loading;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("selected-button")
|
||||||
|
.label("Selected")
|
||||||
|
.checked(self.selected)
|
||||||
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
|
view.selected = !view.selected;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("compact-button")
|
||||||
|
.label("Compact")
|
||||||
|
.checked(self.compact)
|
||||||
|
.on_click(cx.listener(|view, _, cx| {
|
||||||
|
view.compact = !view.compact;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_6()
|
.gap_6()
|
||||||
|
|
@ -35,45 +92,78 @@ impl Render for ButtonStory {
|
||||||
section("Normal Button", cx)
|
section("Normal Button", cx)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-1", cx)
|
Button::new("button-1", cx)
|
||||||
|
.primary()
|
||||||
.label("Primary Button")
|
.label("Primary Button")
|
||||||
.style(ButtonStyle::Primary)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-2", cx)
|
Button::new("button-2", cx)
|
||||||
.label("Secondary Button")
|
.label("Secondary Button")
|
||||||
.style(ButtonStyle::Secondary)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-4", cx)
|
Button::new("button-4", cx)
|
||||||
|
.danger()
|
||||||
.label("Danger Button")
|
.label("Danger Button")
|
||||||
.style(ButtonStyle::Danger)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-5", cx)
|
Button::new("button-5", cx)
|
||||||
|
.outline()
|
||||||
.label("Outline Button")
|
.label("Outline Button")
|
||||||
.style(ButtonStyle::Outline)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-5-ghost", cx)
|
Button::new("button-5-ghost", cx)
|
||||||
|
.ghost()
|
||||||
.label("Ghost Button")
|
.label("Ghost Button")
|
||||||
.style(ButtonStyle::Ghost)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-5-link", cx)
|
||||||
|
.link()
|
||||||
|
.label("Link Button")
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-6-custom", cx)
|
Button::new("button-6-custom", cx)
|
||||||
.label("Custom Button")
|
.custom(
|
||||||
.style(ButtonStyle::Custom(
|
|
||||||
ButtonCustomStyle::new(cx)
|
ButtonCustomStyle::new(cx)
|
||||||
.color(cx.theme().muted)
|
.color(cx.theme().muted)
|
||||||
.foreground(cx.theme().destructive)
|
.foreground(cx.theme().destructive)
|
||||||
.border(cx.theme().scrollbar)
|
.border(cx.theme().scrollbar)
|
||||||
.hover(cx.theme().tab_active_foreground)
|
.hover(cx.theme().tab_active_foreground)
|
||||||
.active(cx.theme().selection),
|
.active(cx.theme().selection),
|
||||||
))
|
)
|
||||||
|
.label("Custom Button")
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -81,23 +171,33 @@ impl Render for ButtonStory {
|
||||||
section("Button with Icon", cx)
|
section("Button with Icon", cx)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-icon-1", cx)
|
Button::new("button-icon-1", cx)
|
||||||
|
.primary()
|
||||||
.label("Confirm")
|
.label("Confirm")
|
||||||
.icon(IconName::Check)
|
.icon(IconName::Check)
|
||||||
.style(ButtonStyle::Primary)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-icon-2", cx)
|
Button::new("button-icon-2", cx)
|
||||||
.label("Abort")
|
.label("Abort")
|
||||||
.icon(IconName::Close)
|
.icon(IconName::Close)
|
||||||
.style(ButtonStyle::Secondary)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-icon-3", cx)
|
Button::new("button-icon-3", cx)
|
||||||
.label("Maximize")
|
.label("Maximize")
|
||||||
.icon(Icon::new(IconName::Maximize))
|
.icon(Icon::new(IconName::Maximize))
|
||||||
.style(ButtonStyle::Secondary)
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -111,6 +211,32 @@ impl Render for ButtonStory {
|
||||||
.child(IconName::ChevronDown)
|
.child(IconName::ChevronDown)
|
||||||
.child(IconName::Eye),
|
.child(IconName::Eye),
|
||||||
)
|
)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-icon-5-ghost", cx)
|
||||||
|
.style(ButtonStyle::Ghost)
|
||||||
|
.icon(IconName::Check)
|
||||||
|
.label("Confirm")
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-icon-6-link", cx)
|
||||||
|
.style(ButtonStyle::Link)
|
||||||
|
.icon(IconName::Check)
|
||||||
|
.label("Link")
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -126,6 +252,10 @@ impl Render for ButtonStory {
|
||||||
.style(ButtonStyle::Primary)
|
.style(ButtonStyle::Primary)
|
||||||
.size(Size::Small)
|
.size(Size::Small)
|
||||||
.loading(true)
|
.loading(true)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -133,6 +263,10 @@ impl Render for ButtonStory {
|
||||||
.label("Secondary Button")
|
.label("Secondary Button")
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.size(Size::Small)
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -140,6 +274,43 @@ impl Render for ButtonStory {
|
||||||
.label("Danger Button")
|
.label("Danger Button")
|
||||||
.style(ButtonStyle::Danger)
|
.style(ButtonStyle::Danger)
|
||||||
.size(Size::Small)
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-8-outline", cx)
|
||||||
|
.label("Outline Button")
|
||||||
|
.style(ButtonStyle::Outline)
|
||||||
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-8-ghost", cx)
|
||||||
|
.label("Ghost Button")
|
||||||
|
.style(ButtonStyle::Ghost)
|
||||||
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("button-8-link", cx)
|
||||||
|
.label("Link Button")
|
||||||
|
.style(ButtonStyle::Link)
|
||||||
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -150,6 +321,10 @@ impl Render for ButtonStory {
|
||||||
.label("Primary Button")
|
.label("Primary Button")
|
||||||
.style(ButtonStyle::Primary)
|
.style(ButtonStyle::Primary)
|
||||||
.size(Size::XSmall)
|
.size(Size::XSmall)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -158,6 +333,10 @@ impl Render for ButtonStory {
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Secondary)
|
||||||
.size(Size::XSmall)
|
.size(Size::XSmall)
|
||||||
.loading(true)
|
.loading(true)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -165,92 +344,103 @@ impl Render for ButtonStory {
|
||||||
.label("Danger Button")
|
.label("Danger Button")
|
||||||
.style(ButtonStyle::Danger)
|
.style(ButtonStyle::Danger)
|
||||||
.size(Size::XSmall)
|
.size(Size::XSmall)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
.on_click(Self::on_click),
|
.on_click(Self::on_click),
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.gap_6()
|
|
||||||
.child(
|
|
||||||
section("Disabled Button", cx)
|
|
||||||
.child(
|
|
||||||
Button::new("button-disabled1", cx)
|
|
||||||
.label("Disabled Button")
|
|
||||||
.style(ButtonStyle::Primary)
|
|
||||||
.on_click(Self::on_click)
|
|
||||||
.disabled(true),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-disabled1", cx)
|
Button::new("button-xs-3-ghost", cx)
|
||||||
.label("Disabled Button")
|
.label("Ghost Button")
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Ghost)
|
||||||
.on_click(Self::on_click)
|
.size(Size::XSmall)
|
||||||
.disabled(true),
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact)
|
||||||
|
.on_click(Self::on_click),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-disabled1", cx)
|
Button::new("button-xs-3-outline", cx)
|
||||||
.label("Disabled Button")
|
.label("Outline Button")
|
||||||
.style(ButtonStyle::Danger)
|
.style(ButtonStyle::Outline)
|
||||||
.on_click(Self::on_click)
|
.size(Size::XSmall)
|
||||||
.disabled(true)
|
.disabled(disabled)
|
||||||
.loading(true),
|
.selected(selected)
|
||||||
),
|
.loading(loading)
|
||||||
)
|
.compact(compact)
|
||||||
.child(
|
.on_click(Self::on_click),
|
||||||
section("Selected Style", cx)
|
|
||||||
.child(
|
|
||||||
Button::new("button-selected-1", cx)
|
|
||||||
.label("Selected Button")
|
|
||||||
.style(ButtonStyle::Primary)
|
|
||||||
.selected(true),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("button-selected-2", cx)
|
Button::new("button-xs-3-link", cx)
|
||||||
.label("Selected Button")
|
.label("Link Button")
|
||||||
.style(ButtonStyle::Secondary)
|
.style(ButtonStyle::Link)
|
||||||
.selected(true),
|
.size(Size::XSmall)
|
||||||
)
|
.disabled(disabled)
|
||||||
.child(
|
.selected(selected)
|
||||||
Button::new("button-selected-3", cx)
|
.loading(loading)
|
||||||
.label("Selected Button")
|
.compact(compact)
|
||||||
.style(ButtonStyle::Danger)
|
.on_click(Self::on_click),
|
||||||
.selected(true),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
section("Icon Button", cx)
|
section("Icon Button", cx)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-0", cx)
|
Button::new("icon-button-primary", cx)
|
||||||
.icon(IconName::Search)
|
.icon(IconName::Search)
|
||||||
.style(ButtonStyle::Primary),
|
.style(ButtonStyle::Primary)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-1", cx)
|
Button::new("icon-button-secondary", cx)
|
||||||
.icon(IconName::Info)
|
.icon(IconName::Info)
|
||||||
.loading(true),
|
.loading(true)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-2", cx)
|
Button::new("icon-button-danger", cx)
|
||||||
.icon(IconName::Close)
|
.icon(IconName::Close)
|
||||||
.style(ButtonStyle::Danger),
|
.style(ButtonStyle::Danger)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-3", cx)
|
Button::new("icon-button-small-primary", cx)
|
||||||
.icon(IconName::Search)
|
.icon(IconName::Search)
|
||||||
.size(Size::Small)
|
.size(Size::Small)
|
||||||
.style(ButtonStyle::Primary),
|
.style(ButtonStyle::Primary)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-0-outline", cx)
|
Button::new("icon-button-outline", cx)
|
||||||
.icon(IconName::Search)
|
.icon(IconName::Search)
|
||||||
.style(ButtonStyle::Outline),
|
.style(ButtonStyle::Outline)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-1", cx)
|
Button::new("icon-button-ghost", cx)
|
||||||
.icon(IconName::Info)
|
.icon(IconName::ArrowLeft)
|
||||||
.style(ButtonStyle::Ghost),
|
.style(ButtonStyle::Ghost)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -258,36 +448,60 @@ impl Render for ButtonStory {
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-4", cx)
|
Button::new("icon-button-4", cx)
|
||||||
.icon(IconName::Info)
|
.icon(IconName::Info)
|
||||||
.size(Size::Small),
|
.size(Size::Small)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-5", cx)
|
Button::new("icon-button-5", cx)
|
||||||
.icon(IconName::Close)
|
.icon(IconName::Close)
|
||||||
.size(Size::Small)
|
.size(Size::Small)
|
||||||
.style(ButtonStyle::Danger),
|
.style(ButtonStyle::Danger)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-6", cx)
|
Button::new("icon-button-6", cx)
|
||||||
.icon(IconName::Search)
|
.icon(IconName::Search)
|
||||||
.size(Size::XSmall)
|
.size(Size::XSmall)
|
||||||
.style(ButtonStyle::Primary),
|
.style(ButtonStyle::Primary)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-7", cx)
|
Button::new("icon-button-7", cx)
|
||||||
.icon(IconName::Info)
|
.icon(IconName::Info)
|
||||||
.size(Size::XSmall),
|
.size(Size::XSmall)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-8", cx)
|
Button::new("icon-button-8", cx)
|
||||||
.icon(IconName::Close)
|
.icon(IconName::Close)
|
||||||
.size(Size::XSmall)
|
.size(Size::XSmall)
|
||||||
.style(ButtonStyle::Danger),
|
.style(ButtonStyle::Danger)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("icon-button-9", cx)
|
Button::new("icon-button-9", cx)
|
||||||
.icon(IconName::Heart)
|
.icon(IconName::Heart)
|
||||||
.size(px(24.))
|
.size(px(24.))
|
||||||
.style(ButtonStyle::Ghost),
|
.style(ButtonStyle::Ghost)
|
||||||
|
.disabled(disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.loading(loading)
|
||||||
|
.compact(compact),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use ui::{
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
prelude::FluentBuilder,
|
prelude::FluentBuilder,
|
||||||
switch::Switch,
|
switch::Switch,
|
||||||
v_flex, Clickable, IconName, Size,
|
v_flex, Clickable as _, IconName, Size,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
|
|
@ -49,7 +49,8 @@ impl Render for Form {
|
||||||
.child("This is a form container.")
|
.child("This is a form container.")
|
||||||
.child(self.input1.clone())
|
.child(self.input1.clone())
|
||||||
.child(
|
.child(
|
||||||
Button::primary("submit", "Submit", cx)
|
Button::new("submit", cx)
|
||||||
|
.primary()
|
||||||
.on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))),
|
.on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +144,7 @@ impl Render for PopoverStory {
|
||||||
.child(
|
.child(
|
||||||
Button::new("info1", cx)
|
Button::new("info1", cx)
|
||||||
.label("Yes")
|
.label("Yes")
|
||||||
.width(px(80.))
|
.w(px(80.))
|
||||||
.size(Size::Small),
|
.size(Size::Small),
|
||||||
)
|
)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
|
@ -166,7 +167,7 @@ impl Render for PopoverStory {
|
||||||
.child(
|
.child(
|
||||||
Button::new("info1", cx)
|
Button::new("info1", cx)
|
||||||
.label("Yes")
|
.label("Yes")
|
||||||
.width(px(80.))
|
.w(px(80.))
|
||||||
.size(Size::Small),
|
.size(Size::Small),
|
||||||
)
|
)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
|
@ -180,7 +181,7 @@ impl Render for PopoverStory {
|
||||||
.child(
|
.child(
|
||||||
Popover::new("popup-menu")
|
Popover::new("popup-menu")
|
||||||
.when(window_mode, |this| this.window_mode())
|
.when(window_mode, |this| this.window_mode())
|
||||||
.trigger(Button::new("popup-menu-1", cx).icon(IconName::Info))
|
.trigger(Button::new("popup-menu-1", cx).icon(IconName::Ellipsis))
|
||||||
.content(move |cx| {
|
.content(move |cx| {
|
||||||
let focus_handle = focus_handle.clone();
|
let focus_handle = focus_handle.clone();
|
||||||
PopupMenu::build(cx, |mut this, _cx| {
|
PopupMenu::build(cx, |mut this, _cx| {
|
||||||
|
|
@ -213,9 +214,7 @@ impl Render for PopoverStory {
|
||||||
.when(self.window_mode, |this| this.window_mode())
|
.when(self.window_mode, |this| this.window_mode())
|
||||||
.anchor(AnchorCorner::BottomLeft)
|
.anchor(AnchorCorner::BottomLeft)
|
||||||
.trigger(
|
.trigger(
|
||||||
Button::new("pop", cx)
|
Button::new("pop", cx).label("Popup with Form").w(px(300.)),
|
||||||
.label("Popup with Form")
|
|
||||||
.width(px(300.)),
|
|
||||||
)
|
)
|
||||||
.content(move |_| form.clone()),
|
.content(move |_| form.clone()),
|
||||||
)
|
)
|
||||||
|
|
@ -227,7 +226,7 @@ impl Render for PopoverStory {
|
||||||
.trigger(
|
.trigger(
|
||||||
Button::new("pop", cx)
|
Button::new("pop", cx)
|
||||||
.label("Mouse Right Click")
|
.label("Mouse Right Click")
|
||||||
.width(px(300.)),
|
.w(px(300.)),
|
||||||
)
|
)
|
||||||
.content(|cx| {
|
.content(|cx| {
|
||||||
PopoverContent::new(cx, |cx| {
|
PopoverContent::new(cx, |cx| {
|
||||||
|
|
@ -238,7 +237,7 @@ impl Render for PopoverStory {
|
||||||
.child(
|
.child(
|
||||||
Button::new("info1", cx)
|
Button::new("info1", cx)
|
||||||
.label("Yes")
|
.label("Yes")
|
||||||
.width(px(80.))
|
.w(px(80.))
|
||||||
.size(Size::Small),
|
.size(Size::Small),
|
||||||
)
|
)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ use crate::{
|
||||||
Clickable, Disableable, Icon, Selectable, Size,
|
Clickable, Disableable, Icon, Selectable, Size,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, DefiniteLength, Div, ElementId,
|
div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, Div, ElementId, FocusHandle,
|
||||||
FocusHandle, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels,
|
Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels, RenderOnce,
|
||||||
RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
|
SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum ButtonRounded {
|
pub enum ButtonRounded {
|
||||||
|
|
@ -24,7 +24,7 @@ impl From<Pixels> for ButtonRounded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct ButtonCustomStyle {
|
pub struct ButtonCustomStyle {
|
||||||
color: Hsla,
|
color: Hsla,
|
||||||
foreground: Hsla,
|
foreground: Hsla,
|
||||||
|
|
@ -70,16 +70,23 @@ impl ButtonCustomStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ButtonStyle {
|
pub enum ButtonStyle {
|
||||||
Primary,
|
Primary,
|
||||||
Secondary,
|
Secondary,
|
||||||
Danger,
|
Danger,
|
||||||
Outline,
|
Outline,
|
||||||
Ghost,
|
Ghost,
|
||||||
|
Link,
|
||||||
Custom(ButtonCustomStyle),
|
Custom(ButtonCustomStyle),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ButtonStyle {
|
||||||
|
fn is_link(&self) -> bool {
|
||||||
|
matches!(self, Self::Link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
pub base: Div,
|
pub base: Div,
|
||||||
|
|
@ -90,11 +97,10 @@ pub struct Button {
|
||||||
children: Vec<AnyElement>,
|
children: Vec<AnyElement>,
|
||||||
disabled: bool,
|
disabled: bool,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
width: Option<DefiniteLength>,
|
|
||||||
height: Option<DefiniteLength>,
|
|
||||||
style: ButtonStyle,
|
style: ButtonStyle,
|
||||||
rounded: ButtonRounded,
|
rounded: ButtonRounded,
|
||||||
size: Size,
|
size: Size,
|
||||||
|
compact: bool,
|
||||||
tooltip: Option<SharedString>,
|
tooltip: Option<SharedString>,
|
||||||
on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||||
loading: bool,
|
loading: bool,
|
||||||
|
|
@ -111,61 +117,65 @@ impl Button {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
style: ButtonStyle::Secondary,
|
style: ButtonStyle::Secondary,
|
||||||
width: None,
|
|
||||||
height: None,
|
|
||||||
rounded: ButtonRounded::Medium,
|
rounded: ButtonRounded::Medium,
|
||||||
size: Size::Medium,
|
size: Size::Medium,
|
||||||
tooltip: None,
|
tooltip: None,
|
||||||
on_click: None,
|
on_click: None,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
compact: false,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary(
|
/// With the primary style for the Button.
|
||||||
id: impl Into<ElementId>,
|
pub fn primary(mut self) -> Self {
|
||||||
label: impl Into<SharedString>,
|
self.style = ButtonStyle::Primary;
|
||||||
cx: &mut WindowContext,
|
|
||||||
) -> Self {
|
|
||||||
Self::new(id, cx).label(label).style(ButtonStyle::Primary)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn danger(
|
|
||||||
id: impl Into<ElementId>,
|
|
||||||
label: impl Into<SharedString>,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) -> Self {
|
|
||||||
Self::new(id, cx).label(label).style(ButtonStyle::Danger)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn small(
|
|
||||||
id: impl Into<ElementId>,
|
|
||||||
label: impl Into<SharedString>,
|
|
||||||
cx: &mut WindowContext,
|
|
||||||
) -> Self {
|
|
||||||
Self::new(id, cx).label(label).size(Size::Small)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
|
|
||||||
self.width = Some(width.into());
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(mut self, height: impl Into<DefiniteLength>) -> Self {
|
/// With the secondary style for the Button.
|
||||||
self.height = Some(height.into());
|
pub fn danger(mut self) -> Self {
|
||||||
|
self.style = ButtonStyle::Danger;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// With the ghost style for the Button.
|
||||||
|
pub fn ghost(mut self) -> Self {
|
||||||
|
self.style = ButtonStyle::Ghost;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// With the outline style for the Button.
|
||||||
|
pub fn outline(mut self) -> Self {
|
||||||
|
self.style = ButtonStyle::Outline;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// With the link style for the Button.
|
||||||
|
pub fn link(mut self) -> Self {
|
||||||
|
self.style = ButtonStyle::Link;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// With the custom style for the Button.
|
||||||
|
pub fn custom(mut self, custom: ButtonCustomStyle) -> Self {
|
||||||
|
self.style = ButtonStyle::Custom(custom);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the border radius of the Button.
|
||||||
pub fn rounded(mut self, rounded: impl Into<ButtonRounded>) -> Self {
|
pub fn rounded(mut self, rounded: impl Into<ButtonRounded>) -> Self {
|
||||||
self.rounded = rounded.into();
|
self.rounded = rounded.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the ui::Size of the Button.
|
||||||
pub fn size(mut self, size: impl Into<Size>) -> Self {
|
pub fn size(mut self, size: impl Into<Size>) -> Self {
|
||||||
self.size = size.into();
|
self.size = size.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set label to the Button, if no label is set, the button will be in Icon Button mode.
|
||||||
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
|
||||||
self.label = Some(label.into());
|
self.label = Some(label.into());
|
||||||
self
|
self
|
||||||
|
|
@ -177,20 +187,29 @@ impl Button {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the tooltip of the button.
|
||||||
pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
|
pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
|
||||||
self.tooltip = Some(tooltip.into());
|
self.tooltip = Some(tooltip.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the ButtonStyle
|
||||||
pub fn style(mut self, style: ButtonStyle) -> Self {
|
pub fn style(mut self, style: ButtonStyle) -> Self {
|
||||||
self.style = style;
|
self.style = style;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set true to show the loading indicator.
|
||||||
pub fn loading(mut self, loading: bool) -> Self {
|
pub fn loading(mut self, loading: bool) -> Self {
|
||||||
self.loading = loading;
|
self.loading = loading;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the button to compact mode, then padding will be reduced.
|
||||||
|
pub fn compact(mut self, compact: bool) -> Self {
|
||||||
|
self.compact = compact;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Disableable for Button {
|
impl Disableable for Button {
|
||||||
|
|
@ -243,9 +262,7 @@ impl RenderOnce for Button {
|
||||||
.items_center()
|
.items_center()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
.when_some(self.width, |this, width| this.w(width))
|
.when(!style.is_link(), |this| {
|
||||||
.when_some(self.height, |this, height| this.h(height))
|
|
||||||
.map(|this| {
|
|
||||||
if self.label.is_none() && self.children.is_empty() {
|
if self.label.is_none() && self.children.is_empty() {
|
||||||
// Icon Button
|
// Icon Button
|
||||||
match self.size {
|
match self.size {
|
||||||
|
|
@ -258,9 +275,17 @@ impl RenderOnce for Button {
|
||||||
// Normal Button
|
// Normal Button
|
||||||
match self.size {
|
match self.size {
|
||||||
Size::Size(size) => this.p(size * 0.2),
|
Size::Size(size) => this.p(size * 0.2),
|
||||||
Size::XSmall => this.px_1().py_1().h_5(),
|
Size::XSmall => this.h_5().p_1(),
|
||||||
Size::Small => this.px_3().py_2().h_6(),
|
Size::Small => this
|
||||||
_ => this.px_4().py_2().h_8(),
|
.px_3()
|
||||||
|
.py_2()
|
||||||
|
.h_6()
|
||||||
|
.when(self.compact, |this| this.p_2()),
|
||||||
|
_ => this
|
||||||
|
.px_4()
|
||||||
|
.py_2()
|
||||||
|
.h_8()
|
||||||
|
.when(self.compact, |this| this.p_2()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -271,22 +296,29 @@ impl RenderOnce for Button {
|
||||||
ButtonRounded::Size(px) => this.rounded(px),
|
ButtonRounded::Size(px) => this.rounded(px),
|
||||||
ButtonRounded::None => this.rounded_none(),
|
ButtonRounded::None => this.rounded_none(),
|
||||||
})
|
})
|
||||||
|
.text_color(normal_style.fg)
|
||||||
.when(self.selected, |this| {
|
.when(self.selected, |this| {
|
||||||
let selected_style = style.selected(cx);
|
let selected_style = style.selected(cx);
|
||||||
this.bg(selected_style.bg)
|
this.bg(selected_style.bg)
|
||||||
.border_color(selected_style.border)
|
.border_color(selected_style.border)
|
||||||
|
.text_color(selected_style.fg)
|
||||||
})
|
})
|
||||||
.when(!self.disabled && !self.selected, |this| {
|
.when(!self.disabled && !self.selected, |this| {
|
||||||
this.hover(|this| {
|
this.border_color(normal_style.border)
|
||||||
let hover_style = style.hovered(cx);
|
.bg(normal_style.bg)
|
||||||
this.bg(hover_style.bg).border_color(hover_style.border)
|
.when(normal_style.underline, |this| this.text_decoration_1())
|
||||||
})
|
.hover(|this| {
|
||||||
.active(|this| {
|
let hover_style = style.hovered(cx);
|
||||||
let active_style = style.active(cx);
|
this.bg(hover_style.bg)
|
||||||
this.bg(active_style.bg).border_color(active_style.border)
|
.border_color(hover_style.border)
|
||||||
})
|
.text_color(crate::red_400())
|
||||||
.border_color(normal_style.border)
|
})
|
||||||
.bg(normal_style.bg)
|
.active(|this| {
|
||||||
|
let active_style = style.active(cx);
|
||||||
|
this.bg(active_style.bg)
|
||||||
|
.border_color(active_style.border)
|
||||||
|
.text_color(active_style.fg)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.when(focused, |this| this.border_color(cx.theme().ring))
|
.when(focused, |this| this.border_color(cx.theme().ring))
|
||||||
.when_some(
|
.when_some(
|
||||||
|
|
@ -305,36 +337,29 @@ impl RenderOnce for Button {
|
||||||
let disabled_style = style.disabled(cx);
|
let disabled_style = style.disabled(cx);
|
||||||
this.cursor_not_allowed()
|
this.cursor_not_allowed()
|
||||||
.bg(disabled_style.bg)
|
.bg(disabled_style.bg)
|
||||||
|
.text_color(disabled_style.fg)
|
||||||
.border_color(disabled_style.border)
|
.border_color(disabled_style.border)
|
||||||
})
|
})
|
||||||
.border_1()
|
.border_1()
|
||||||
.child({
|
.child({
|
||||||
let text_color = if self.disabled {
|
|
||||||
normal_style.fg.opacity(0.6)
|
|
||||||
} else {
|
|
||||||
normal_style.fg
|
|
||||||
};
|
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.id("label")
|
||||||
.items_center()
|
.items_center()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.text_color(text_color)
|
|
||||||
.when(!self.loading, |this| {
|
|
||||||
this.when_some(self.icon, |this, icon| {
|
|
||||||
this.child(div().text_color(text_color).child(icon.size(icon_size)))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.when(self.loading, |this| {
|
|
||||||
this.child(Indicator::new().size(self.size).color(text_color))
|
|
||||||
})
|
|
||||||
.when_some(self.label, |this, label| this.child(label))
|
|
||||||
.children(self.children)
|
|
||||||
.map(|this| match self.size {
|
.map(|this| match self.size {
|
||||||
Size::XSmall => this.text_xs(),
|
Size::XSmall => this.text_xs(),
|
||||||
Size::Small => this.text_sm(),
|
Size::Small => this.text_sm(),
|
||||||
_ => this.text_base(),
|
_ => this.text_base(),
|
||||||
})
|
})
|
||||||
|
.when(!self.loading, |this| {
|
||||||
|
this.when_some(self.icon, |this, icon| this.child(icon.size(icon_size)))
|
||||||
|
})
|
||||||
|
.when(self.loading, |this| {
|
||||||
|
this.child(Indicator::new().size(self.size))
|
||||||
|
})
|
||||||
|
.when_some(self.label, |this, label| this.child(label))
|
||||||
|
.children(self.children)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,6 +368,7 @@ struct ButtonStyles {
|
||||||
bg: Hsla,
|
bg: Hsla,
|
||||||
border: Hsla,
|
border: Hsla,
|
||||||
fg: Hsla,
|
fg: Hsla,
|
||||||
|
underline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonStyle {
|
impl ButtonStyle {
|
||||||
|
|
@ -353,6 +379,7 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive,
|
ButtonStyle::Danger => cx.theme().destructive,
|
||||||
ButtonStyle::Outline => cx.theme().transparent,
|
ButtonStyle::Outline => cx.theme().transparent,
|
||||||
ButtonStyle::Ghost => cx.theme().transparent,
|
ButtonStyle::Ghost => cx.theme().transparent,
|
||||||
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
ButtonStyle::Custom(colors) => colors.color,
|
ButtonStyle::Custom(colors) => colors.color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -364,6 +391,7 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive_foreground,
|
ButtonStyle::Danger => cx.theme().destructive_foreground,
|
||||||
ButtonStyle::Outline => cx.theme().secondary_foreground,
|
ButtonStyle::Outline => cx.theme().secondary_foreground,
|
||||||
ButtonStyle::Ghost => cx.theme().secondary_foreground,
|
ButtonStyle::Ghost => cx.theme().secondary_foreground,
|
||||||
|
ButtonStyle::Link => cx.theme().link,
|
||||||
ButtonStyle::Custom(colors) => colors.foreground,
|
ButtonStyle::Custom(colors) => colors.foreground,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,16 +403,30 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive,
|
ButtonStyle::Danger => cx.theme().destructive,
|
||||||
ButtonStyle::Outline => cx.theme().border,
|
ButtonStyle::Outline => cx.theme().border,
|
||||||
ButtonStyle::Ghost => cx.theme().transparent,
|
ButtonStyle::Ghost => cx.theme().transparent,
|
||||||
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
ButtonStyle::Custom(colors) => colors.border,
|
ButtonStyle::Custom(colors) => colors.border,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn underline(&self, _: &WindowContext) -> bool {
|
||||||
|
match self {
|
||||||
|
ButtonStyle::Link => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn normal(&self, cx: &WindowContext) -> ButtonStyles {
|
fn normal(&self, cx: &WindowContext) -> ButtonStyles {
|
||||||
let bg = self.bg_color(cx);
|
let bg = self.bg_color(cx);
|
||||||
let border = self.border_color(cx);
|
let border = self.border_color(cx);
|
||||||
let fg = self.text_color(cx);
|
let fg = self.text_color(cx);
|
||||||
|
let underline = self.underline(cx);
|
||||||
|
|
||||||
ButtonStyles { bg, border, fg }
|
ButtonStyles {
|
||||||
|
bg,
|
||||||
|
border,
|
||||||
|
fg,
|
||||||
|
underline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hovered(&self, cx: &WindowContext) -> ButtonStyles {
|
fn hovered(&self, cx: &WindowContext) -> ButtonStyles {
|
||||||
|
|
@ -394,12 +436,22 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive_hover,
|
ButtonStyle::Danger => cx.theme().destructive_hover,
|
||||||
ButtonStyle::Outline => cx.theme().secondary_hover,
|
ButtonStyle::Outline => cx.theme().secondary_hover,
|
||||||
ButtonStyle::Ghost => cx.theme().secondary,
|
ButtonStyle::Ghost => cx.theme().secondary,
|
||||||
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
ButtonStyle::Custom(colors) => colors.hover,
|
ButtonStyle::Custom(colors) => colors.hover,
|
||||||
};
|
};
|
||||||
let border = self.border_color(cx);
|
let border = self.border_color(cx);
|
||||||
let fg = self.text_color(cx);
|
let fg = match self {
|
||||||
|
ButtonStyle::Link => cx.theme().link_hover,
|
||||||
|
_ => self.text_color(cx),
|
||||||
|
};
|
||||||
|
let underline = self.underline(cx);
|
||||||
|
|
||||||
ButtonStyles { bg, border, fg }
|
ButtonStyles {
|
||||||
|
bg,
|
||||||
|
border,
|
||||||
|
fg,
|
||||||
|
underline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active(&self, cx: &WindowContext) -> ButtonStyles {
|
fn active(&self, cx: &WindowContext) -> ButtonStyles {
|
||||||
|
|
@ -409,12 +461,22 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive_active,
|
ButtonStyle::Danger => cx.theme().destructive_active,
|
||||||
ButtonStyle::Outline => cx.theme().secondary_active,
|
ButtonStyle::Outline => cx.theme().secondary_active,
|
||||||
ButtonStyle::Ghost => cx.theme().secondary_active,
|
ButtonStyle::Ghost => cx.theme().secondary_active,
|
||||||
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
ButtonStyle::Custom(colors) => colors.active,
|
ButtonStyle::Custom(colors) => colors.active,
|
||||||
};
|
};
|
||||||
let border = self.border_color(cx);
|
let border = self.border_color(cx);
|
||||||
let fg = self.text_color(cx);
|
let fg = match self {
|
||||||
|
ButtonStyle::Link => cx.theme().link_active,
|
||||||
|
_ => self.text_color(cx),
|
||||||
|
};
|
||||||
|
let underline = self.underline(cx);
|
||||||
|
|
||||||
ButtonStyles { bg, border, fg }
|
ButtonStyles {
|
||||||
|
bg,
|
||||||
|
border,
|
||||||
|
fg,
|
||||||
|
underline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected(&self, cx: &WindowContext) -> ButtonStyles {
|
fn selected(&self, cx: &WindowContext) -> ButtonStyles {
|
||||||
|
|
@ -424,19 +486,42 @@ impl ButtonStyle {
|
||||||
ButtonStyle::Danger => cx.theme().destructive_active,
|
ButtonStyle::Danger => cx.theme().destructive_active,
|
||||||
ButtonStyle::Outline => cx.theme().secondary_active,
|
ButtonStyle::Outline => cx.theme().secondary_active,
|
||||||
ButtonStyle::Ghost => cx.theme().secondary_active,
|
ButtonStyle::Ghost => cx.theme().secondary_active,
|
||||||
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
ButtonStyle::Custom(colors) => colors.active,
|
ButtonStyle::Custom(colors) => colors.active,
|
||||||
};
|
};
|
||||||
let border = self.border_color(cx);
|
let border = self.border_color(cx);
|
||||||
let fg = self.text_color(cx);
|
let fg = match self {
|
||||||
|
ButtonStyle::Link => cx.theme().link_active,
|
||||||
|
_ => self.text_color(cx),
|
||||||
|
};
|
||||||
|
let underline = self.underline(cx);
|
||||||
|
|
||||||
ButtonStyles { bg, border, fg }
|
ButtonStyles {
|
||||||
|
bg,
|
||||||
|
border,
|
||||||
|
fg,
|
||||||
|
underline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disabled(&self, cx: &WindowContext) -> ButtonStyles {
|
fn disabled(&self, cx: &WindowContext) -> ButtonStyles {
|
||||||
let bg = self.bg_color(cx).grayscale().opacity(0.9);
|
let bg = match self {
|
||||||
let border = self.border_color(cx).grayscale().opacity(0.9);
|
ButtonStyle::Link => cx.theme().transparent,
|
||||||
let fg = self.text_color(cx).grayscale();
|
_ => cx.theme().secondary.darken(0.2).grayscale(),
|
||||||
|
};
|
||||||
|
let fg = match self {
|
||||||
|
ButtonStyle::Link => cx.theme().link.grayscale(),
|
||||||
|
_ => cx.theme().secondary_foreground.darken(0.2).grayscale(),
|
||||||
|
};
|
||||||
|
|
||||||
ButtonStyles { bg, border, fg }
|
let border = bg;
|
||||||
|
let underline = self.underline(cx);
|
||||||
|
|
||||||
|
ButtonStyles {
|
||||||
|
bg,
|
||||||
|
border,
|
||||||
|
fg,
|
||||||
|
underline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ impl Checkbox {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked(mut self, checked: Selection) -> Self {
|
pub fn checked(mut self, checked: impl Into<Selection>) -> Self {
|
||||||
self.checked = checked;
|
self.checked = checked.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ pub enum IconName {
|
||||||
Sun,
|
Sun,
|
||||||
ThumbsDown,
|
ThumbsDown,
|
||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
|
Menu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconName {
|
impl IconName {
|
||||||
|
|
@ -87,6 +88,7 @@ impl IconName {
|
||||||
IconName::Sun => "icons/sun.svg",
|
IconName::Sun => "icons/sun.svg",
|
||||||
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
||||||
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
||||||
|
IconName::Menu => "icons/menu.svg",
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{theme::ActiveTheme, Icon, IconName, Size};
|
use crate::{Icon, IconName, Size};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, ease_in_out, percentage, Animation, AnimationExt as _, Hsla, IntoElement, ParentElement,
|
div, ease_in_out, percentage, prelude::FluentBuilder as _, Animation, AnimationExt as _, Hsla,
|
||||||
RenderOnce, Styled as _, Transformation,
|
IntoElement, ParentElement, RenderOnce, Styled as _, Transformation,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
|
|
@ -41,13 +41,12 @@ impl Indicator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for Indicator {
|
impl RenderOnce for Indicator {
|
||||||
fn render(self, cx: &mut gpui::WindowContext) -> impl IntoElement {
|
fn render(self, _: &mut gpui::WindowContext) -> impl IntoElement {
|
||||||
let color = self.color.unwrap_or_else(|| cx.theme().indicator);
|
|
||||||
div()
|
div()
|
||||||
.child(
|
.child(
|
||||||
Icon::new(self.icon.clone())
|
Icon::new(self.icon.clone())
|
||||||
.size(self.size)
|
.size(self.size)
|
||||||
.text_color(color)
|
.when_some(self.color, |this, color| this.text_color(color))
|
||||||
.with_animation(
|
.with_animation(
|
||||||
"circle",
|
"circle",
|
||||||
Animation::new(self.speed).repeat().with_easing(ease_in_out),
|
Animation::new(self.speed).repeat().with_easing(ease_in_out),
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,16 @@ pub enum Selection {
|
||||||
Selected,
|
Selected,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Selection {
|
||||||
|
fn from(selected: bool) -> Self {
|
||||||
|
if selected {
|
||||||
|
Self::Selected
|
||||||
|
} else {
|
||||||
|
Self::Unselected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Selection {
|
impl Display for Selection {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,6 @@ pub struct Theme {
|
||||||
pub tab_active: Hsla,
|
pub tab_active: Hsla,
|
||||||
pub tab_foreground: Hsla,
|
pub tab_foreground: Hsla,
|
||||||
pub tab_active_foreground: Hsla,
|
pub tab_active_foreground: Hsla,
|
||||||
pub indicator: Hsla,
|
|
||||||
pub progress_bar: Hsla,
|
pub progress_bar: Hsla,
|
||||||
pub slider_bar: Hsla,
|
pub slider_bar: Hsla,
|
||||||
pub slider_thumb: Hsla,
|
pub slider_thumb: Hsla,
|
||||||
|
|
@ -308,6 +307,8 @@ pub struct Theme {
|
||||||
pub table_active: Hsla,
|
pub table_active: Hsla,
|
||||||
pub table_hover: Hsla,
|
pub table_hover: Hsla,
|
||||||
pub link: Hsla,
|
pub link: Hsla,
|
||||||
|
pub link_hover: Hsla,
|
||||||
|
pub link_active: Hsla,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Global for Theme {}
|
impl Global for Theme {}
|
||||||
|
|
@ -369,7 +370,6 @@ impl From<Colors> for Theme {
|
||||||
tab_active: colors.background,
|
tab_active: colors.background,
|
||||||
tab_foreground: colors.foreground,
|
tab_foreground: colors.foreground,
|
||||||
tab_active_foreground: colors.foreground,
|
tab_active_foreground: colors.foreground,
|
||||||
indicator: colors.secondary_foreground,
|
|
||||||
progress_bar: colors.primary,
|
progress_bar: colors.primary,
|
||||||
slider_bar: colors.primary,
|
slider_bar: colors.primary,
|
||||||
slider_thumb: colors.background,
|
slider_thumb: colors.background,
|
||||||
|
|
@ -384,6 +384,8 @@ impl From<Colors> for Theme {
|
||||||
table_active: colors.list_active,
|
table_active: colors.list_active,
|
||||||
table_hover: colors.list_active.opacity(0.6),
|
table_hover: colors.list_active.opacity(0.6),
|
||||||
link: colors.link,
|
link: colors.link,
|
||||||
|
link_hover: colors.link.lighten(0.2),
|
||||||
|
link_active: colors.link.darken(0.2),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue