chore: Update controls detail. (#352)
- Better icon style in Input, Dropdown, DatePicker.
This commit is contained in:
parent
000c0bec57
commit
41c64e2912
25 changed files with 73 additions and 85 deletions
|
|
@ -143,6 +143,7 @@ impl ButtonStyle {
|
|||
}
|
||||
}
|
||||
|
||||
/// A Button element.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Button {
|
||||
pub base: Div,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use crate::{
|
|||
Disableable, Sizable, Size,
|
||||
};
|
||||
|
||||
/// A ButtonGroup element, to wrap multiple buttons in a group.
|
||||
#[derive(IntoElement)]
|
||||
pub struct ButtonGroup {
|
||||
pub base: Div,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
use crate::{h_flex, theme::ActiveTheme, v_flex, Disableable, IconName, Selectable};
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder as _, relative, svg, ElementId, InteractiveElement, IntoElement,
|
||||
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled as _,
|
||||
WindowContext,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
h_flex,
|
||||
theme::{ActiveTheme, Colorize as _},
|
||||
v_flex, Disableable, IconName, Selectable,
|
||||
};
|
||||
|
||||
/// A Checkbox element.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Checkbox {
|
||||
id: ElementId,
|
||||
label: Option<SharedString>,
|
||||
checked: bool,
|
||||
disabled: bool,
|
||||
label: Option<SharedString>,
|
||||
on_click: Option<Box<dyn Fn(&bool, &mut WindowContext) + 'static>>,
|
||||
}
|
||||
|
||||
|
|
@ -23,9 +19,9 @@ impl Checkbox {
|
|||
pub fn new(id: impl Into<ElementId>) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
label: None,
|
||||
checked: false,
|
||||
disabled: false,
|
||||
label: None,
|
||||
on_click: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -65,22 +61,17 @@ impl Selectable for Checkbox {
|
|||
|
||||
impl RenderOnce for Checkbox {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let theme = cx.theme();
|
||||
|
||||
let group_id = format!("checkbox_group_{:?}", self.id);
|
||||
|
||||
let (color, icon_color) = if self.disabled {
|
||||
(
|
||||
theme.primary.opacity(0.5),
|
||||
theme.primary_foreground.opacity(0.5),
|
||||
cx.theme().primary.opacity(0.5),
|
||||
cx.theme().primary_foreground.opacity(0.5),
|
||||
)
|
||||
} else {
|
||||
(theme.primary, theme.primary_foreground)
|
||||
(cx.theme().primary, cx.theme().primary_foreground)
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.id(self.id)
|
||||
.group(group_id.clone())
|
||||
.gap_2()
|
||||
.items_center()
|
||||
.line_height(relative(1.))
|
||||
|
|
@ -93,16 +84,9 @@ impl RenderOnce for Checkbox {
|
|||
.size_4()
|
||||
.flex_shrink_0()
|
||||
.map(|this| match self.checked {
|
||||
false => this.bg(theme.transparent),
|
||||
false => this.bg(cx.theme().transparent),
|
||||
_ => this.bg(color),
|
||||
})
|
||||
.group_hover(group_id, |this| {
|
||||
if self.disabled {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.border_color(theme.primary.divide(0.9))
|
||||
})
|
||||
.child(
|
||||
svg()
|
||||
.absolute()
|
||||
|
|
@ -140,7 +124,6 @@ impl RenderOnce for Checkbox {
|
|||
this.on_click(move |_, cx| {
|
||||
let checked = !self.checked;
|
||||
on_click(&checked, cx);
|
||||
cx.refresh()
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ pub trait ContextMenuExt: ParentElement + Sized {
|
|||
impl<E> ContextMenuExt for Stateful<E> where E: ParentElement {}
|
||||
impl<E> ContextMenuExt for Focusable<E> where E: ParentElement {}
|
||||
|
||||
/// A context menu that can be shown on right-click.
|
||||
pub struct ContextMenu {
|
||||
id: ElementId,
|
||||
menu: Option<Box<dyn Fn(PopupMenu, &mut ViewContext<PopupMenu>) -> PopupMenu + 'static>>,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use gpui::{
|
|||
|
||||
use crate::theme::ActiveTheme;
|
||||
|
||||
/// A divider that can be either vertical or horizontal.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Divider {
|
||||
base: Div,
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ pub enum DropdownEvent<D: DropdownDelegate + 'static> {
|
|||
Confirm(Option<<D::Item as DropdownItem>::Value>),
|
||||
}
|
||||
|
||||
/// A Dropdown element.
|
||||
pub struct Dropdown<D: DropdownDelegate + 'static> {
|
||||
id: ElementId,
|
||||
focus_handle: FocusHandle,
|
||||
|
|
@ -659,9 +660,10 @@ where
|
|||
|
||||
this.child(
|
||||
Icon::new(icon)
|
||||
.xsmall()
|
||||
.text_color(match self.disabled {
|
||||
true => cx.theme().muted_foreground,
|
||||
false => cx.theme().accent_foreground,
|
||||
true => cx.theme().muted_foreground.opacity(0.5),
|
||||
false => cx.theme().muted_foreground,
|
||||
})
|
||||
.when(self.disabled, |this| this.cursor_not_allowed()),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,10 +19,3 @@ pub trait InteractiveElementExt: InteractiveElement {
|
|||
}
|
||||
|
||||
impl<E: InteractiveElement> InteractiveElementExt for Focusable<E> {}
|
||||
|
||||
// impl<E> InteractiveElementExt for Stateful<E>
|
||||
// where
|
||||
// E: Element,
|
||||
// Self: InteractiveElement,
|
||||
// {
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ pub trait HistoryItem: Clone {
|
|||
fn set_version(&mut self, version: usize);
|
||||
}
|
||||
|
||||
/// The History is used to keep track of changes to a model and to allow undo and redo operations.
|
||||
///
|
||||
/// This is now used in Input for undo/redo operations. You can also use this in
|
||||
/// your own models to keep track of changes, for example to track the tab
|
||||
/// history for prev/next features.
|
||||
#[derive(Debug)]
|
||||
pub struct History<I: HistoryItem> {
|
||||
undos: Vec<I>,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
use gpui::{px, WindowContext};
|
||||
use gpui::{Styled, WindowContext};
|
||||
|
||||
use crate::{
|
||||
button::{Button, ButtonStyled as _},
|
||||
IconName, Sizable as _,
|
||||
theme::ActiveTheme as _,
|
||||
Icon, IconName, Sizable as _,
|
||||
};
|
||||
|
||||
pub(crate) struct ClearButton {}
|
||||
|
||||
impl ClearButton {
|
||||
pub fn new(_: &mut WindowContext) -> Button {
|
||||
pub fn new(cx: &mut WindowContext) -> Button {
|
||||
Button::new("clean")
|
||||
.icon(IconName::CircleX)
|
||||
.icon(Icon::new(IconName::CircleX).text_color(cx.theme().muted_foreground))
|
||||
.ghost()
|
||||
.with_size(px(14.))
|
||||
.xsmall()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,9 @@ impl Render for TextInput {
|
|||
input: cx.view().clone(),
|
||||
}),
|
||||
)
|
||||
.when(self.loading, |this| this.child(Indicator::new()))
|
||||
.when(self.loading, |this| {
|
||||
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
||||
})
|
||||
.when(
|
||||
self.cleanable && !self.loading && !self.text.is_empty(),
|
||||
|this| this.child(ClearButton::new(cx).on_click(cx.listener(Self::clean))),
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ pub enum InputOptEvent {
|
|||
Change(SharedString),
|
||||
}
|
||||
|
||||
/// A One Time Password (OTP) input element.
|
||||
///
|
||||
/// This can accept a fixed length number and can be masked.
|
||||
///
|
||||
/// Use case example:
|
||||
///
|
||||
/// - SMS OTP
|
||||
/// - Authenticator OTP
|
||||
pub struct OtpInput {
|
||||
focus_handle: FocusHandle,
|
||||
length: usize,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ use gpui::{
|
|||
|
||||
use crate::{h_flex, theme::ActiveTheme};
|
||||
|
||||
const MASKED: &'static str = "•";
|
||||
|
||||
#[derive(Default, PartialEq, Eq)]
|
||||
pub enum TextAlign {
|
||||
#[default]
|
||||
|
|
@ -63,8 +65,6 @@ impl Styled for Label {
|
|||
}
|
||||
}
|
||||
|
||||
const MASKED: &'static str = "•";
|
||||
|
||||
impl RenderOnce for Label {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let text = self.label;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,14 @@ pub use colors::*;
|
|||
pub use icon::*;
|
||||
pub use svg_img::*;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
rust_i18n::i18n!("locales", fallback = "en");
|
||||
|
||||
/// Initialize the UI module.
|
||||
///
|
||||
/// This must be called before using any of the UI components.
|
||||
/// You can initialize the UI module at your application's entry point.
|
||||
pub fn init(cx: &mut gpui::AppContext) {
|
||||
theme::init(cx);
|
||||
context_menu::init(cx);
|
||||
|
|
@ -75,8 +82,6 @@ pub fn init(cx: &mut gpui::AppContext) {
|
|||
webview::init(cx);
|
||||
}
|
||||
|
||||
rust_i18n::i18n!("locales", fallback = "en");
|
||||
use std::ops::Deref;
|
||||
pub fn locale() -> impl Deref<Target = str> {
|
||||
rust_i18n::locale()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use gpui::{
|
|||
|
||||
use crate::theme::ActiveTheme as _;
|
||||
|
||||
/// A Link element like a `<a>` tag in HTML.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Link {
|
||||
base: Stateful<Div>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::time::Duration;
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
use crate::Icon;
|
||||
use crate::{
|
||||
input::{InputEvent, TextInput},
|
||||
scroll::{Scrollbar, ScrollbarState},
|
||||
|
|
@ -102,7 +103,7 @@ where
|
|||
let query_input = cx.new_view(|cx| {
|
||||
TextInput::new(cx)
|
||||
.appearance(false)
|
||||
.prefix(|_| IconName::Search)
|
||||
.prefix(|cx| Icon::new(IconName::Search).text_color(cx.theme().muted_foreground))
|
||||
.placeholder("Search...")
|
||||
.cleanable()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::{h_flex, theme::ActiveTheme, Disableable, Icon, IconName, Selectable, Sizable as _};
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder as _, AnyElement, ClickEvent, Div, ElementId, InteractiveElement,
|
||||
IntoElement, MouseButton, MouseMoveEvent, ParentElement, RenderOnce, SharedString, Stateful,
|
||||
IntoElement, MouseButton, MouseMoveEvent, ParentElement, RenderOnce, Stateful,
|
||||
StatefulInteractiveElement as _, Styled, WindowContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{h_flex, theme::ActiveTheme, Disableable, Icon, IconName, Selectable, Sizable as _};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct ListItem {
|
||||
id: ElementId,
|
||||
|
|
@ -15,7 +14,6 @@ pub struct ListItem {
|
|||
selected: bool,
|
||||
confirmed: bool,
|
||||
check_icon: Option<Icon>,
|
||||
group_id: Option<SharedString>,
|
||||
on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||
on_mouse_enter: Option<Box<dyn Fn(&MouseMoveEvent, &mut WindowContext) + 'static>>,
|
||||
suffix: Option<Box<dyn Fn(&mut WindowContext) -> AnyElement + 'static>>,
|
||||
|
|
@ -35,17 +33,10 @@ impl ListItem {
|
|||
on_mouse_enter: None,
|
||||
check_icon: None,
|
||||
suffix: None,
|
||||
group_id: None,
|
||||
children: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set group_id
|
||||
pub fn group(mut self, group_id: impl Into<SharedString>) -> Self {
|
||||
self.group_id = Some(group_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set to show check icon, default is None.
|
||||
pub fn check_icon(mut self, icon: IconName) -> Self {
|
||||
self.check_icon = Some(Icon::new(icon));
|
||||
|
|
@ -128,7 +119,6 @@ impl RenderOnce for ListItem {
|
|||
let is_active = self.selected || self.confirmed;
|
||||
|
||||
self.base
|
||||
.when_some(self.group_id, |this, group_id| this.group(group_id))
|
||||
.text_color(cx.theme().foreground)
|
||||
.relative()
|
||||
.items_center()
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ impl From<(TypeId, ElementId)> for NotificationId {
|
|||
}
|
||||
}
|
||||
|
||||
/// A notification element.
|
||||
pub struct Notification {
|
||||
/// The id is used make the notification unique.
|
||||
/// Then you push a notification with the same id, the previous notification will be replaced.
|
||||
|
|
|
|||
|
|
@ -522,10 +522,7 @@ impl Render for PopupMenu {
|
|||
!(*ix == items_count - 1 && item.is_separator())
|
||||
})
|
||||
.map(|(ix, item)| {
|
||||
let group_id = format!("item:{}", ix);
|
||||
|
||||
let this = ListItem::new(("menu-item", ix))
|
||||
.group(group_id.clone())
|
||||
.relative()
|
||||
.text_sm()
|
||||
.py_0()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::theme::ActiveTheme;
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder, px, relative, IntoElement, ParentElement, RenderOnce, Styled,
|
||||
WindowContext,
|
||||
};
|
||||
|
||||
use crate::theme::ActiveTheme;
|
||||
|
||||
/// A Progress bar element.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Progress {
|
||||
value: f32,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use crate::{h_flex, theme::ActiveTheme, IconName};
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder, relative, svg, CursorStyle, ElementId, InteractiveElement,
|
||||
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled,
|
||||
WindowContext,
|
||||
div, prelude::FluentBuilder, relative, svg, ElementId, InteractiveElement, IntoElement,
|
||||
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, Styled, WindowContext,
|
||||
};
|
||||
|
||||
use crate::{h_flex, theme::ActiveTheme, IconName};
|
||||
|
||||
/// A Radio element.
|
||||
///
|
||||
/// This is not included the Radio group implementation, you can manage the group by yourself.
|
||||
#[derive(IntoElement)]
|
||||
pub struct Radio {
|
||||
id: ElementId,
|
||||
|
|
@ -58,7 +59,6 @@ impl RenderOnce for Radio {
|
|||
h_flex()
|
||||
.id(self.id)
|
||||
.gap_x_2()
|
||||
.cursor(CursorStyle::PointingHand)
|
||||
.text_color(cx.theme().foreground)
|
||||
.items_center()
|
||||
.line_height(relative(1.))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
use crate::{
|
||||
drawer::Drawer,
|
||||
modal::Modal,
|
||||
notification::{Notification, NotificationList},
|
||||
theme::ActiveTheme,
|
||||
};
|
||||
use gpui::{
|
||||
div, AnyView, FocusHandle, InteractiveElement, IntoElement, ParentElement as _, Render, Styled,
|
||||
View, ViewContext, VisualContext as _, WindowContext,
|
||||
|
|
@ -7,13 +13,6 @@ use std::{
|
|||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
drawer::Drawer,
|
||||
modal::Modal,
|
||||
notification::{Notification, NotificationList},
|
||||
theme::ActiveTheme,
|
||||
};
|
||||
|
||||
/// Extension trait for [`WindowContext`] and [`ViewContext`] to add drawer functionality.
|
||||
pub trait ContextModal: Sized {
|
||||
/// Opens a Drawer.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::theme::ActiveTheme;
|
||||
use gpui::{
|
||||
bounce, div, ease_in_out, Animation, AnimationExt, Div, IntoElement, ParentElement as _,
|
||||
RenderOnce, Styled,
|
||||
};
|
||||
|
||||
use crate::theme::ActiveTheme;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Skeleton {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub enum SliderEvent {
|
|||
Change(f32),
|
||||
}
|
||||
|
||||
/// A slider component.
|
||||
/// A Slider element.
|
||||
pub struct Slider {
|
||||
axis: Axis,
|
||||
min: f32,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
|
||||
use crate::{h_flex, theme::ActiveTheme, Disableable, Sizable, Size};
|
||||
use gpui::{
|
||||
div, prelude::FluentBuilder as _, px, Animation, AnimationExt as _, AnyElement, Element,
|
||||
ElementId, GlobalElementId, InteractiveElement, IntoElement, LayoutId, ParentElement as _,
|
||||
SharedString, Styled as _, WindowContext,
|
||||
};
|
||||
|
||||
type OnClick = Rc<dyn Fn(&bool, &mut WindowContext)>;
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
|
||||
pub enum LabelSide {
|
||||
Left,
|
||||
|
|
@ -26,7 +23,7 @@ pub struct Switch {
|
|||
disabled: bool,
|
||||
label: Option<SharedString>,
|
||||
label_side: LabelSide,
|
||||
on_click: Option<OnClick>,
|
||||
on_click: Option<Rc<dyn Fn(&bool, &mut WindowContext)>>,
|
||||
size: Size,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ impl Render for DatePicker {
|
|||
.when(!show_clean, |this| {
|
||||
this.child(
|
||||
Icon::new(IconName::Calendar)
|
||||
.xsmall()
|
||||
.text_color(cx.theme().muted_foreground),
|
||||
)
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in a new issue